Skip to content

Commit

Permalink
Handle abstract properties (#2333)
Browse files Browse the repository at this point in the history
Part of #2330.

<img width="366" alt="Screenshot 2024-11-15 at 4 40 29 PM"
src="https://github.com/user-attachments/assets/8fc4b404-9489-4131-ba14-70e7af30cc5a">

## FYI: attributes don't have modifiers

Our old code would try to remove modifiers for `py.attribute`, but that
was not necessary because they cannot be set. (An attribute is the
default, like setting a value in `__init__`; a property is when you set
`@property` on a function)

Modifiers are only set on properties. This is evidenced by `npm run
regen-api` not changing despite removing code to handle `py.attribute`.

## PR does not preserve `property` modifier

For a typical end-user, an attribute and `property` are essentially the
same. The only time I think it'd be relevant is if you're subclassing
the class; otherwise, I think `property` is distracting.

So, we continue to not preserve `property`, the same as before.

## `abstract` vs `abstract property`

We capture the whole `abstract property` because the phrase is much more
meaningful than `abstract`.
  • Loading branch information
Eric-Arellano authored Nov 18, 2024
1 parent 32b1837 commit 113a406
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ python_api_name: qiskit.aqua.algorithms.MinimumEigensolver

### aux\_operators

<Attribute id="qiskit.aqua.algorithms.MinimumEigensolver.aux_operators" attributeTypeHint="Optional[List[Optional[qiskit.aqua.operators.operator_base.OperatorBase]]]">
<Attribute id="qiskit.aqua.algorithms.MinimumEigensolver.aux_operators" attributeTypeHint="Optional[List[Optional[qiskit.aqua.operators.operator_base.OperatorBase]]]" modifiers="abstract property">
Returns the auxiliary operators.

**Return type**
Expand All @@ -31,7 +31,7 @@ python_api_name: qiskit.aqua.algorithms.MinimumEigensolver

### operator

<Attribute id="qiskit.aqua.algorithms.MinimumEigensolver.operator" attributeTypeHint="Optional[Union[qiskit.aqua.operators.operator_base.OperatorBase, qiskit.aqua.operators.legacy.base_operator.LegacyBaseOperator]]">
<Attribute id="qiskit.aqua.algorithms.MinimumEigensolver.operator" attributeTypeHint="Optional[Union[qiskit.aqua.operators.operator_base.OperatorBase, qiskit.aqua.operators.legacy.base_operator.LegacyBaseOperator]]" modifiers="abstract property">
Return the operator.

**Return type**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ python_api_name: qiskit.aqua.components.oracles.Oracle

### ancillary\_register

<Attribute id="qiskit.aqua.components.oracles.Oracle.ancillary_register">
<Attribute id="qiskit.aqua.components.oracles.Oracle.ancillary_register" modifiers="abstract property">
returns ancillary register
</Attribute>

Expand All @@ -38,15 +38,15 @@ python_api_name: qiskit.aqua.components.oracles.Oracle

### output\_register

<Attribute id="qiskit.aqua.components.oracles.Oracle.output_register">
<Attribute id="qiskit.aqua.components.oracles.Oracle.output_register" modifiers="abstract property">
returns output register
</Attribute>

<span id="oracle-variable-register" />

### variable\_register

<Attribute id="qiskit.aqua.components.oracles.Oracle.variable_register">
<Attribute id="qiskit.aqua.components.oracles.Oracle.variable_register" modifiers="abstract property">
returns variable register
</Attribute>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ python_api_name: qiskit.aqua.operators.OperatorBase

### num\_qubits

<Attribute id="qiskit.aqua.operators.OperatorBase.num_qubits" attributeTypeHint="int">
<Attribute id="qiskit.aqua.operators.OperatorBase.num_qubits" attributeTypeHint="int" modifiers="abstract property">
The number of qubits over which the Operator is defined. If `op.num_qubits == 5`, then `op.eval('1' * 5)` will be valid, but `op.eval('11')` will not.

**Return type**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ python_api_name: qiskit.aqua.operators.legacy.LegacyBaseOperator

### num\_qubits

<Attribute id="qiskit.aqua.operators.legacy.LegacyBaseOperator.num_qubits">
<Attribute id="qiskit.aqua.operators.legacy.LegacyBaseOperator.num_qubits" modifiers="abstract property">
Returns number of qubits for operator
</Attribute>

Expand Down
29 changes: 22 additions & 7 deletions scripts/js/lib/api/generateApiComponents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,16 +116,9 @@ function prepareProps(

const githubSourceLink = prepareGitHubLink($child, apiType === "method");

// Remove the attributes and properties modifiers as we don't show their signatures,
// but we still use them to create their headers
if (apiType == "attribute" || apiType == "property") {
findByText($, $child, "em.property", apiType).remove();
}

if (!(apiType in preparePropsPerApiType)) {
throw new Error(`Unhandled Python type: ${apiType}`);
}

return preparePropsPerApiType[apiType]();
}

Expand Down Expand Up @@ -207,6 +200,27 @@ function prepareAttributeOrPropertyProps(
githubSourceLink: string | undefined,
id: string,
): ComponentProps {
// Properties/attributes have multiple `em.property` values to set:
//
// - the modifiers, like `property` or `abstract property`
// - the type hint
// - the default value
//
// We need to remove the modifiers `em.property` to not mess up creating the heading, although
// we must first extract any modifiers. Attributes will not have modifiers, whereas
// properties will have `property` or possibly `abstract property`. If the modifier is simply
// `property`, then we do not save its value because there is no practical difference for end-users
// between an attribute and property. However, we preserve the full string if it's `abstract property`.
//
// Meanwhile, we preserve the non-modifier `em.property` elements to be processed below.
const rawModifiers = $child
.find("em.property")
.filter((i, el) => $(el).text().includes("property"));
const modifiersText = rawModifiers.text().trim();
const filteredModifiers =
modifiersText === "property" ? undefined : modifiersText;
rawModifiers.remove();

const text = $child.text();

// Index of the default value of the attribute
Expand Down Expand Up @@ -235,6 +249,7 @@ function prepareAttributeOrPropertyProps(
attributeTypeHint,
attributeValue,
githubSourceLink,
modifiers: filteredModifiers,
};

if (!priorApiType && id) {
Expand Down
49 changes: 49 additions & 0 deletions scripts/js/lib/api/htmlToMd.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -748,6 +748,55 @@ test("convert class property headings", async () => {
});
});

test("convert abstract class property headings", async () => {
expect(
await toMd(
`<div role='main'>
<h1>Estimator.circuits<a class='headerlink' href='#estimator' title='Permalink to this heading'>¶</a></h1>
<dl class='py property'>
<dt class='sig sig-object py' id='qiskit_ibm_runtime.Estimator.circuits'>
<em class='property'
><span class='pre'>abstract</span><span class='w'> </span><span class='pre'>property</span><span class='w'> </span></em
><span class='sig-prename descclassname'
><span class='pre'>Estimator.</span></span
><span class='sig-name descname'><span class='pre'>circuits</span></span
><em class='property'
><span class='p'><span class='pre'>:</span></span
><span class='w'> </span><span class='pre'>tuple</span
><span class='p'><span class='pre'>[</span></span
><span class='pre'>qiskit.circuit.quantumcircuit.QuantumCircuit</span
><span class='p'><span class='pre'>,</span></span
><span class='w'> </span
><span class='p'><span class='pre'>...</span></span
><span class='p'><span class='pre'>]</span></span></em
><a
class='headerlink'
href='#qiskit_ibm_runtime.Estimator.circuits'
title='Permalink to this definition'
>¶</a
>
</dt>
<dd><p>Quantum circuits that represents quantum states.</p></dd>
</dl>
</div>
`,
true,
),
).toEqual({
images: [],
isReleaseNotes: false,
markdown: `# circuits
<Attribute id="qiskit_ibm_runtime.Estimator.circuits" attributeTypeHint="tuple[qiskit.circuit.quantumcircuit.QuantumCircuit, ...]" isDedicatedPage={true} modifiers="abstract property">
Quantum circuits that represents quantum states.
</Attribute>\n`,
meta: {
apiName: "qiskit_ibm_runtime.Estimator.circuits",
apiType: "property",
},
});
});

test("convert class method headings", async () => {
expect(
await toMd(
Expand Down
2 changes: 1 addition & 1 deletion scripts/js/lib/api/processHtml.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -583,7 +583,7 @@ marked as builtins since they are not actually present in any include file this
const meta: Metadata = { apiType: "module", apiName: "my_module" };
await processMembersAndSetMeta(doc.$, doc.$main, meta);
doc.expectHtml(`
<h3 data-header-type="attribute-header">qiskit.qasm2.LEGACY_CUSTOM_INSTRUCTIONS¶</h3><div><attribute id="qiskit.qasm2.LEGACY_CUSTOM_INSTRUCTIONS" attributetypehint="" attributevalue="" isdedicatedpage="undefined" github="undefined" signature="" modifiers="undefined" extrasignatures="[]">
<h3 data-header-type="attribute-header">qiskit.qasm2.LEGACY_CUSTOM_INSTRUCTIONS¶</h3><div><attribute id="qiskit.qasm2.LEGACY_CUSTOM_INSTRUCTIONS" attributetypehint="" attributevalue="" isdedicatedpage="undefined" github="undefined" signature="" modifiers="" extrasignatures="[]">
<div><p>A tuple containing the extra <cite>custom_instructions</cite> that Qiskit’s legacy built-in converters used
if <code class="docutils literal notranslate"><span class="pre">qelib1.inc</span></code> is included, and there is any definition of a <code class="docutils literal notranslate"><span class="pre">delay</span></code> instruction. The gates
Expand Down

0 comments on commit 113a406

Please sign in to comment.