Skip to content

Commit 833a717

Browse files
authored
fix(pyhon): under-qualified types used by dynamic type checking (#3688)
The types must be referenced from the current module's root, including nesting class names, or the names will not be defined.
1 parent f372e93 commit 833a717

File tree

6 files changed

+38
-20
lines changed

6 files changed

+38
-20
lines changed

packages/@jsii/python-runtime/tests/test_runtime_type_checking.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import pytest
22
import re
33

4+
from scope.jsii_calc_lib.custom_submodule_name import NestingClass
45
import jsii_calc
56

67

@@ -114,3 +115,7 @@ def test_setter_to_union(self):
114115
),
115116
):
116117
subject.union_property = jsii_calc.StringEnum.B # type:ignore
118+
119+
def test_nested_struct(self):
120+
# None of these should throw...
121+
NestingClass.NestedStruct(name="Queen B")

packages/jsii-pacmak/lib/targets/python.ts

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
PythonImports,
2525
mergePythonImports,
2626
toPackageName,
27+
toPythonFullName,
2728
} from './python/type-name';
2829
import { die, toPythonIdentifier } from './python/util';
2930
import { toPythonVersionRange, toReleaseVersion } from './version-utils';
@@ -466,7 +467,6 @@ abstract class BaseMethod implements PythonBase {
466467
private readonly returns: spec.OptionalValue | undefined,
467468
public readonly docs: spec.Docs | undefined,
468469
public readonly isStatic: boolean,
469-
private readonly pythonParent: PythonType,
470470
opts: BaseMethodOpts,
471471
) {
472472
this.abstract = !!opts.abstract;
@@ -674,7 +674,9 @@ abstract class BaseMethod implements PythonBase {
674674
emitParameterTypeChecks(
675675
code,
676676
pythonParams.slice(1),
677-
`${this.pythonParent.pythonName}.${this.pythonName}`,
677+
`${toPythonFullName(this.parent.fqn, context.assembly)}.${
678+
this.pythonName
679+
}`,
678680
);
679681
}
680682
this.emitBody(
@@ -867,7 +869,6 @@ abstract class BaseProperty implements PythonBase {
867869
private readonly jsName: string,
868870
private readonly type: spec.OptionalValue,
869871
public readonly docs: spec.Docs | undefined,
870-
private readonly pythonParent: PythonType,
871872
opts: BasePropertyOpts,
872873
) {
873874
const { abstract = false, immutable = false, isStatic = false } = opts;
@@ -952,9 +953,10 @@ abstract class BaseProperty implements PythonBase {
952953
// In order to get a property accessor, we must resort to getting the
953954
// attribute on the type, instead of the value (where the getter would
954955
// be implicitly invoked for us...)
955-
`getattr(${this.pythonParent.pythonName}, ${JSON.stringify(
956-
this.pythonName,
957-
)}).fset`,
956+
`getattr(${toPythonFullName(
957+
this.parent.fqn,
958+
context.assembly,
959+
)}, ${JSON.stringify(this.pythonName)}).fset`,
958960
);
959961
code.line(
960962
`jsii.${this.jsiiSetMethod}(${this.implicitParameter}, "${this.jsName}", value)`,
@@ -1141,7 +1143,11 @@ class Struct extends BasePythonClassType {
11411143
code.line(`${member.pythonName} = ${typeName}(**${member.pythonName})`);
11421144
code.closeBlock();
11431145
}
1144-
emitParameterTypeChecks(code, kwargs, `${this.pythonName}.__init__`);
1146+
emitParameterTypeChecks(
1147+
code,
1148+
kwargs,
1149+
`${toPythonFullName(this.spec.fqn, context.assembly)}.__init__`,
1150+
);
11451151

11461152
// Required properties, those will always be put into the dict
11471153
assignDictionary(
@@ -2605,7 +2611,6 @@ class PythonGenerator extends Generator {
26052611
undefined,
26062612
cls.initializer.docs,
26072613
false, // Never static
2608-
klass,
26092614
{ liftedProp: this.getliftedProp(cls.initializer), parent: cls },
26102615
),
26112616
);
@@ -2628,7 +2633,6 @@ class PythonGenerator extends Generator {
26282633
method.returns,
26292634
method.docs,
26302635
true, // Always static
2631-
klass,
26322636
{
26332637
abstract: method.abstract,
26342638
liftedProp: this.getliftedProp(method),
@@ -2647,7 +2651,6 @@ class PythonGenerator extends Generator {
26472651
prop.name,
26482652
prop,
26492653
prop.docs,
2650-
klass,
26512654
{
26522655
abstract: prop.abstract,
26532656
immutable: prop.immutable,
@@ -2673,7 +2676,6 @@ class PythonGenerator extends Generator {
26732676
method.returns,
26742677
method.docs,
26752678
!!method.static,
2676-
klass,
26772679
{
26782680
abstract: method.abstract,
26792681
liftedProp: this.getliftedProp(method),
@@ -2691,7 +2693,6 @@ class PythonGenerator extends Generator {
26912693
method.returns,
26922694
method.docs,
26932695
!!method.static,
2694-
klass,
26952696
{
26962697
abstract: method.abstract,
26972698
liftedProp: this.getliftedProp(method),
@@ -2711,7 +2712,6 @@ class PythonGenerator extends Generator {
27112712
prop.name,
27122713
prop,
27132714
prop.docs,
2714-
klass,
27152715
{
27162716
abstract: prop.abstract,
27172717
immutable: prop.immutable,
@@ -2773,7 +2773,6 @@ class PythonGenerator extends Generator {
27732773
method.returns,
27742774
method.docs,
27752775
!!method.static,
2776-
klass,
27772776
{ liftedProp: this.getliftedProp(method), parent: ifc },
27782777
),
27792778
);
@@ -2793,7 +2792,6 @@ class PythonGenerator extends Generator {
27932792
prop.name,
27942793
prop,
27952794
prop.docs,
2796-
klass,
27972795
{ immutable: prop.immutable, isStatic: prop.static, parent: ifc },
27982796
);
27992797
}

packages/jsii-pacmak/lib/targets/python/type-name.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,20 @@ export function toPythonFqn(fqn: string, rootAssm: Assembly) {
403403
return { assemblyName, packageName, pythonFqn: fqnParts.join('.') };
404404
}
405405

406+
/**
407+
* Computes the nesting-qualified name of a type.
408+
*
409+
* @param fqn the fully qualified jsii name of the type.
410+
* @param rootAssm the root assembly for the project.
411+
*
412+
* @returns the nesting-qualified python type name (the name of the class,
413+
* qualified with all nesting parent classes).
414+
*/
415+
export function toPythonFullName(fqn: string, rootAssm: Assembly): string {
416+
const { packageName, pythonFqn } = toPythonFqn(fqn, rootAssm);
417+
return pythonFqn.slice(packageName.length + 1);
418+
}
419+
406420
/**
407421
* Computes the python relative import path from `fromModule` to `toModule`.
408422
*

packages/jsii-pacmak/test/generated-code/__snapshots__/examples.test.js.snap

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/jsii-pacmak/test/generated-code/__snapshots__/target-python.test.js.snap

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/jsii-rosetta/jest.config.mjs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { createRequire } from 'node:module';
2-
import { overriddenConfig } from '../../jest.config.mjs';
2+
import { default as defaultConfig, overriddenConfig } from '../../jest.config.mjs';
33

44
export default overriddenConfig({
55
setupFiles: [createRequire(import.meta.url).resolve('./jestsetup.js')],
6+
testTimeout: process.env.CI ? 30_000 : defaultConfig.testTimeout,
67
});

0 commit comments

Comments
 (0)