@suss/adapter-python 0.21.1 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -2,7 +2,8 @@ import { TypeShape, BehavioralSummary } from '@suss/behavioral-ir';
2
2
  import { Tree, Node } from 'web-tree-sitter';
3
3
  export { Node as PyNode, Tree as PyTree } from 'web-tree-sitter';
4
4
  import { Database } from '@suss/datalog';
5
- import { ExtractorOptions, RawCodeStructure } from '@suss/extractor';
5
+ import { ExtractorOptions, RawCodeStructure, TimingReport, ExtractionReport, CacheDiagnostic } from '@suss/extractor';
6
+ import { WhyExplained } from '@suss/resolution';
6
7
 
7
8
  /**
8
9
  * A new `Parser` for every call, so that parses running at the same time do
@@ -10,6 +11,18 @@ import { ExtractorOptions, RawCodeStructure } from '@suss/extractor';
10
11
  * is loaded once per process and shared.
11
12
  */
12
13
  declare function parsePython(source: string): Promise<Tree>;
14
+ /**
15
+ * Load the grammar ahead of time, for a caller whose own entry point is
16
+ * async but whose parsing happens later through `parsePythonSync`. Loading
17
+ * the WASM grammar is the only async part; parsing a tree from it is not.
18
+ */
19
+ declare function preloadPythonGrammar(): Promise<void>;
20
+ /**
21
+ * `parsePython` without the await, for a caller that cannot itself be
22
+ * async. Throws if `preloadPythonGrammar` (or `parsePython`) has not
23
+ * already loaded the grammar in this process.
24
+ */
25
+ declare function parsePythonSync(source: string): Tree;
13
26
 
14
27
  /**
15
28
  * The lexical binder. It builds module, class, and function scopes over one
@@ -184,6 +197,22 @@ declare function classifyDecorator(decoratorNode: Node, scope: Scope): Decorator
184
197
  */
185
198
  interface PythonPack {
186
199
  name: string;
200
+ /**
201
+ * Pack version stamp, which feeds the cache invalidation key. Bump on
202
+ * any change that affects discovered units or extracted summaries.
203
+ * The CLI folds a hash of the loaded pack file and its config into
204
+ * this stamp on top, so a pack run through the CLI invalidates on an
205
+ * edit whether or not it declares a version of its own.
206
+ */
207
+ version?: string;
208
+ /**
209
+ * Files under the project this pack reads that are not among the
210
+ * `.py` files a run walks, given the files the run is about to walk.
211
+ * Their content feeds the same cache key the pack's own config does,
212
+ * so an edit to one of them re-extracts instead of handing back the
213
+ * previous answer.
214
+ */
215
+ discoveryInputs?: (files: readonly string[]) => string[];
187
216
  /** Wire protocol for the produced boundary bindings, e.g. "http". */
188
217
  protocol: string;
189
218
  discovery: PythonDiscoveryPattern[];
@@ -394,13 +423,16 @@ type NoValuePrefix = "unstated" | "unreadable";
394
423
  */
395
424
  type PathRepeatedSlashes = "kept" | "merged";
396
425
 
426
+ /**
427
+ * What discovery uses for one file. `factsPath` is the path the facts were
428
+ * keyed under, which is the absolute one, while a summary shows the short one.
429
+ */
397
430
  interface StorageLookup {
398
431
  readonly facts: Database;
399
432
  readonly factsPath: string;
400
433
  readonly patterns: readonly StoragePattern[];
401
434
  readonly definitionAt: (key: string) => Node | undefined;
402
435
  readonly couldMatch: ReadonlySet<string>;
403
- readonly leadsToStorage: ReadonlySet<string>;
404
436
  /** What a pack says about statements a project writes as SQL itself. */
405
437
  readonly rawSql?: readonly RawSqlPattern[];
406
438
  }
@@ -554,6 +586,12 @@ declare function objectReturnedBy(db: Database, callKey: string): string | null;
554
586
  * call and its callee start at the same offset.
555
587
  */
556
588
  declare function nodeId(filePath: string, node: Node): string;
589
+ /**
590
+ * The key a read of this expression joins on, for a caller that has an
591
+ * expression in hand and wants to ask the rules about it. `enclosing` is
592
+ * the function the expression is written in, or null at module level.
593
+ */
594
+ declare function readKey(filePath: string, node: Node, enclosing: Node | null): string;
557
595
  /**
558
596
  * Walk a module and emit the value facts. A nested function is walked in its
559
597
  * own right, so a body's returns and calls belong to the function that wrote
@@ -561,6 +599,59 @@ declare function nodeId(filePath: string, node: Node): string;
561
599
  */
562
600
  declare function emitValueFacts(db: Database, filePath: string, root: Node): void;
563
601
 
602
+ /**
603
+ * The session behind `suss ask why` on a Python project: a tree-sitter
604
+ * parse of the asked-about source, a way to point at the expression
605
+ * somebody spelled, and the witness proof of what it resolved to,
606
+ * rendered through `@suss/resolution`'s phrases.
607
+ *
608
+ * It parses every file under the root and emits the same value facts
609
+ * `extractPythonProject` does, keeping a location for every fact key so
610
+ * a proof's atoms can point back at source. A handle this session hands
611
+ * back pairs a tree-sitter node with the file it came from, since a
612
+ * node alone does not say which file parsed it.
613
+ */
614
+
615
+ interface PythonWhySessionOptions {
616
+ /** The project root, which paths in every answer come out relative to. */
617
+ dir: string;
618
+ }
619
+ /** A found node, paired with the file it was parsed from. */
620
+ interface PythonValueHandle {
621
+ file: string;
622
+ node: Node;
623
+ }
624
+ declare class PythonWhySession {
625
+ private readonly root;
626
+ private readonly db;
627
+ private readonly locations;
628
+ private readonly trees;
629
+ constructor(options: PythonWhySessionOptions);
630
+ /**
631
+ * The smallest expression on `line` of `file` whose text is exactly
632
+ * `text`, or null.
633
+ */
634
+ findExpression(file: string, line: number, text: string): PythonValueHandle | null;
635
+ /**
636
+ * The callee of the call written as `calleeText` between `startLine`
637
+ * and `endLine` of `file`, or null.
638
+ */
639
+ findCallee(file: string, startLine: number, endLine: number, calleeText: string): PythonValueHandle | null;
640
+ /**
641
+ * Why `value` resolves to what it does: the witness proof, flattened
642
+ * to the chain and rendered. Null when the value does not resolve,
643
+ * which the caller says in its own words.
644
+ */
645
+ explain(value: PythonValueHandle, options?: {
646
+ maxDepth?: number;
647
+ }): WhyExplained | null;
648
+ private locate;
649
+ private rootOf;
650
+ private pathOf;
651
+ /** A file path said relative to the root, or as given when it is outside the root. */
652
+ private displayPath;
653
+ }
654
+
564
655
  /**
565
656
  * The name is part of the key because the range is measured in lines, two
566
657
  * units can start on the same line, and `entry` is a set, so keying on the range
@@ -589,8 +680,18 @@ interface ExtractPythonOptions {
589
680
  roots: string[];
590
681
  /** When set, `location.file` on each summary is relativized against this. */
591
682
  workspaceRoot?: string;
683
+ /** The directory a summary's id measures its file from, when that differs from `workspaceRoot`. */
684
+ projectRoot?: string;
592
685
  /** As well as deciding how much of what nobody could read reaches a summary, "strict" lets a route that cannot be built stop the run. */
593
686
  gapHandling?: ExtractorOptions["gapHandling"];
687
+ /** Called once with the run's per-phase wall time, for `suss extract --timing`. */
688
+ onTiming?: (report: TimingReport) => void;
689
+ /** Called once with the file-by-file funnel, for `suss extract --explain`. */
690
+ onExtractionReport?: (report: ExtractionReport) => void;
691
+ /** Called once with what the cache decided, for `suss extract --timing`. */
692
+ onCacheDiagnostic?: (diagnostic: CacheDiagnostic) => void;
693
+ /** Absolute. `<projectRoot>/.suss/cache` by default; `null` turns it off. */
694
+ cacheDir?: string | null;
594
695
  }
595
696
  interface ExtractPythonResult {
596
697
  summaries: BehavioralSummary[];
@@ -600,4 +701,48 @@ declare function extractPythonProject(options: ExtractPythonOptions): Promise<Ex
600
701
  /** Every `.py` file under `root`, depth-first, skipping the usual non-source directories. */
601
702
  declare function findPythonFiles(root: string): string[];
602
703
 
603
- export { type AnnotationContext, type Binding, type BoundPythonFile, type DecoratedClassRoute, type DecoratedFunctionRoute, type DecoratorArg, type DecoratorClassification, type DiscoveryOptions, type ExtractPythonOptions, type ExtractPythonResult, type ModuleBinding, type ModuleResolution, type ModuleResolverOptions, type MountObjectCarrier, type MountObjectPrefix, type MountPrefixEffect, type NoValuePrefix, type PathRepeatedSlashes, type PrefixTrailingSlash, type PythonDiscoveryPattern, type PythonPack, type RawSqlPattern, type RelativeModuleSpec, type RouteConventions, type RoutePrefixResolution, type RouterComposition, type RouterIndex, type Scope, type ScopeKind, type StoragePattern, annotationToShape, bindModule, buildRouterIndex, classifyDecorator, containedValues, discoverUnits, emitEntryFact, emitModuleImportFacts, emitValueFacts, extractPythonProject, findPythonFiles, nodeId, objectReturnedBy, parsePython, resolveAbsoluteModule, resolveCalls, resolveModule, resolveName, resolveRelativeModule, shapeFromName, unitKey };
704
+ /**
705
+ * Evidence for drafting a project-wrapper dependency stub: every
706
+ * import, anywhere in the project, of the asked module or one of its
707
+ * submodules. A Python decorator pattern matches a wrapper's import
708
+ * module exactly (see discovery.ts's `importModule.includes`), so a
709
+ * stub covers one imported module at a time rather than one package,
710
+ * and this groups by the exact module text a project writes.
711
+ *
712
+ * This walks every node rather than going through the binder in
713
+ * scope.ts, so an import inside an `if` or `try` still counts as
714
+ * evidence even though the binder would not resolve a name through it.
715
+ */
716
+ interface PythonImportSite {
717
+ /** The name imported at this site, null for a bare `import module`, which binds the whole module rather than one name from it. */
718
+ name: string | null;
719
+ file: string;
720
+ line: number;
721
+ }
722
+ interface PythonImportEvidence {
723
+ /** The full dotted module text, exactly as a stub's `package` would spell it. */
724
+ module: string;
725
+ sites: PythonImportSite[];
726
+ }
727
+ interface PythonImportEvidenceOptions {
728
+ packageName: string;
729
+ directory: string;
730
+ }
731
+ /**
732
+ * Every import of `packageName`, or a submodule of it, across the
733
+ * project's own files, grouped by the exact module each was imported
734
+ * from.
735
+ */
736
+ declare function pythonImportEvidence(options: PythonImportEvidenceOptions): Promise<PythonImportEvidence[]>;
737
+
738
+ /**
739
+ * version.ts: this adapter's own half of the cache key.
740
+ *
741
+ * `ADAPTER_VERSION` is the hand-bumped semver. Bump it on any change
742
+ * that affects extraction output: IR shape, discovery semantics,
743
+ * terminal classification, anything that would invalidate previously
744
+ * cached summaries.
745
+ */
746
+ declare const ADAPTER_VERSION = "0.1.0";
747
+
748
+ export { ADAPTER_VERSION, type AnnotationContext, type Binding, type BoundPythonFile, type DecoratedClassRoute, type DecoratedFunctionRoute, type DecoratorArg, type DecoratorClassification, type DiscoveryOptions, type ExtractPythonOptions, type ExtractPythonResult, type ModuleBinding, type ModuleResolution, type ModuleResolverOptions, type MountObjectCarrier, type MountObjectPrefix, type MountPrefixEffect, type NoValuePrefix, type PathRepeatedSlashes, type PrefixTrailingSlash, type PythonDiscoveryPattern, type PythonImportEvidence, type PythonImportEvidenceOptions, type PythonImportSite, type PythonPack, type PythonValueHandle, PythonWhySession, type PythonWhySessionOptions, type RawSqlPattern, type RelativeModuleSpec, type RouteConventions, type RoutePrefixResolution, type RouterComposition, type RouterIndex, type Scope, type ScopeKind, type StoragePattern, annotationToShape, bindModule, buildRouterIndex, classifyDecorator, containedValues, discoverUnits, emitEntryFact, emitModuleImportFacts, emitValueFacts, extractPythonProject, findPythonFiles, nodeId, objectReturnedBy, parsePython, parsePythonSync, preloadPythonGrammar, pythonImportEvidence, readKey, resolveAbsoluteModule, resolveCalls, resolveModule, resolveName, resolveRelativeModule, shapeFromName, unitKey };
package/dist/index.d.ts CHANGED
@@ -2,7 +2,8 @@ import { TypeShape, BehavioralSummary } from '@suss/behavioral-ir';
2
2
  import { Tree, Node } from 'web-tree-sitter';
3
3
  export { Node as PyNode, Tree as PyTree } from 'web-tree-sitter';
4
4
  import { Database } from '@suss/datalog';
5
- import { ExtractorOptions, RawCodeStructure } from '@suss/extractor';
5
+ import { ExtractorOptions, RawCodeStructure, TimingReport, ExtractionReport, CacheDiagnostic } from '@suss/extractor';
6
+ import { WhyExplained } from '@suss/resolution';
6
7
 
7
8
  /**
8
9
  * A new `Parser` for every call, so that parses running at the same time do
@@ -10,6 +11,18 @@ import { ExtractorOptions, RawCodeStructure } from '@suss/extractor';
10
11
  * is loaded once per process and shared.
11
12
  */
12
13
  declare function parsePython(source: string): Promise<Tree>;
14
+ /**
15
+ * Load the grammar ahead of time, for a caller whose own entry point is
16
+ * async but whose parsing happens later through `parsePythonSync`. Loading
17
+ * the WASM grammar is the only async part; parsing a tree from it is not.
18
+ */
19
+ declare function preloadPythonGrammar(): Promise<void>;
20
+ /**
21
+ * `parsePython` without the await, for a caller that cannot itself be
22
+ * async. Throws if `preloadPythonGrammar` (or `parsePython`) has not
23
+ * already loaded the grammar in this process.
24
+ */
25
+ declare function parsePythonSync(source: string): Tree;
13
26
 
14
27
  /**
15
28
  * The lexical binder. It builds module, class, and function scopes over one
@@ -184,6 +197,22 @@ declare function classifyDecorator(decoratorNode: Node, scope: Scope): Decorator
184
197
  */
185
198
  interface PythonPack {
186
199
  name: string;
200
+ /**
201
+ * Pack version stamp, which feeds the cache invalidation key. Bump on
202
+ * any change that affects discovered units or extracted summaries.
203
+ * The CLI folds a hash of the loaded pack file and its config into
204
+ * this stamp on top, so a pack run through the CLI invalidates on an
205
+ * edit whether or not it declares a version of its own.
206
+ */
207
+ version?: string;
208
+ /**
209
+ * Files under the project this pack reads that are not among the
210
+ * `.py` files a run walks, given the files the run is about to walk.
211
+ * Their content feeds the same cache key the pack's own config does,
212
+ * so an edit to one of them re-extracts instead of handing back the
213
+ * previous answer.
214
+ */
215
+ discoveryInputs?: (files: readonly string[]) => string[];
187
216
  /** Wire protocol for the produced boundary bindings, e.g. "http". */
188
217
  protocol: string;
189
218
  discovery: PythonDiscoveryPattern[];
@@ -394,13 +423,16 @@ type NoValuePrefix = "unstated" | "unreadable";
394
423
  */
395
424
  type PathRepeatedSlashes = "kept" | "merged";
396
425
 
426
+ /**
427
+ * What discovery uses for one file. `factsPath` is the path the facts were
428
+ * keyed under, which is the absolute one, while a summary shows the short one.
429
+ */
397
430
  interface StorageLookup {
398
431
  readonly facts: Database;
399
432
  readonly factsPath: string;
400
433
  readonly patterns: readonly StoragePattern[];
401
434
  readonly definitionAt: (key: string) => Node | undefined;
402
435
  readonly couldMatch: ReadonlySet<string>;
403
- readonly leadsToStorage: ReadonlySet<string>;
404
436
  /** What a pack says about statements a project writes as SQL itself. */
405
437
  readonly rawSql?: readonly RawSqlPattern[];
406
438
  }
@@ -554,6 +586,12 @@ declare function objectReturnedBy(db: Database, callKey: string): string | null;
554
586
  * call and its callee start at the same offset.
555
587
  */
556
588
  declare function nodeId(filePath: string, node: Node): string;
589
+ /**
590
+ * The key a read of this expression joins on, for a caller that has an
591
+ * expression in hand and wants to ask the rules about it. `enclosing` is
592
+ * the function the expression is written in, or null at module level.
593
+ */
594
+ declare function readKey(filePath: string, node: Node, enclosing: Node | null): string;
557
595
  /**
558
596
  * Walk a module and emit the value facts. A nested function is walked in its
559
597
  * own right, so a body's returns and calls belong to the function that wrote
@@ -561,6 +599,59 @@ declare function nodeId(filePath: string, node: Node): string;
561
599
  */
562
600
  declare function emitValueFacts(db: Database, filePath: string, root: Node): void;
563
601
 
602
+ /**
603
+ * The session behind `suss ask why` on a Python project: a tree-sitter
604
+ * parse of the asked-about source, a way to point at the expression
605
+ * somebody spelled, and the witness proof of what it resolved to,
606
+ * rendered through `@suss/resolution`'s phrases.
607
+ *
608
+ * It parses every file under the root and emits the same value facts
609
+ * `extractPythonProject` does, keeping a location for every fact key so
610
+ * a proof's atoms can point back at source. A handle this session hands
611
+ * back pairs a tree-sitter node with the file it came from, since a
612
+ * node alone does not say which file parsed it.
613
+ */
614
+
615
+ interface PythonWhySessionOptions {
616
+ /** The project root, which paths in every answer come out relative to. */
617
+ dir: string;
618
+ }
619
+ /** A found node, paired with the file it was parsed from. */
620
+ interface PythonValueHandle {
621
+ file: string;
622
+ node: Node;
623
+ }
624
+ declare class PythonWhySession {
625
+ private readonly root;
626
+ private readonly db;
627
+ private readonly locations;
628
+ private readonly trees;
629
+ constructor(options: PythonWhySessionOptions);
630
+ /**
631
+ * The smallest expression on `line` of `file` whose text is exactly
632
+ * `text`, or null.
633
+ */
634
+ findExpression(file: string, line: number, text: string): PythonValueHandle | null;
635
+ /**
636
+ * The callee of the call written as `calleeText` between `startLine`
637
+ * and `endLine` of `file`, or null.
638
+ */
639
+ findCallee(file: string, startLine: number, endLine: number, calleeText: string): PythonValueHandle | null;
640
+ /**
641
+ * Why `value` resolves to what it does: the witness proof, flattened
642
+ * to the chain and rendered. Null when the value does not resolve,
643
+ * which the caller says in its own words.
644
+ */
645
+ explain(value: PythonValueHandle, options?: {
646
+ maxDepth?: number;
647
+ }): WhyExplained | null;
648
+ private locate;
649
+ private rootOf;
650
+ private pathOf;
651
+ /** A file path said relative to the root, or as given when it is outside the root. */
652
+ private displayPath;
653
+ }
654
+
564
655
  /**
565
656
  * The name is part of the key because the range is measured in lines, two
566
657
  * units can start on the same line, and `entry` is a set, so keying on the range
@@ -589,8 +680,18 @@ interface ExtractPythonOptions {
589
680
  roots: string[];
590
681
  /** When set, `location.file` on each summary is relativized against this. */
591
682
  workspaceRoot?: string;
683
+ /** The directory a summary's id measures its file from, when that differs from `workspaceRoot`. */
684
+ projectRoot?: string;
592
685
  /** As well as deciding how much of what nobody could read reaches a summary, "strict" lets a route that cannot be built stop the run. */
593
686
  gapHandling?: ExtractorOptions["gapHandling"];
687
+ /** Called once with the run's per-phase wall time, for `suss extract --timing`. */
688
+ onTiming?: (report: TimingReport) => void;
689
+ /** Called once with the file-by-file funnel, for `suss extract --explain`. */
690
+ onExtractionReport?: (report: ExtractionReport) => void;
691
+ /** Called once with what the cache decided, for `suss extract --timing`. */
692
+ onCacheDiagnostic?: (diagnostic: CacheDiagnostic) => void;
693
+ /** Absolute. `<projectRoot>/.suss/cache` by default; `null` turns it off. */
694
+ cacheDir?: string | null;
594
695
  }
595
696
  interface ExtractPythonResult {
596
697
  summaries: BehavioralSummary[];
@@ -600,4 +701,48 @@ declare function extractPythonProject(options: ExtractPythonOptions): Promise<Ex
600
701
  /** Every `.py` file under `root`, depth-first, skipping the usual non-source directories. */
601
702
  declare function findPythonFiles(root: string): string[];
602
703
 
603
- export { type AnnotationContext, type Binding, type BoundPythonFile, type DecoratedClassRoute, type DecoratedFunctionRoute, type DecoratorArg, type DecoratorClassification, type DiscoveryOptions, type ExtractPythonOptions, type ExtractPythonResult, type ModuleBinding, type ModuleResolution, type ModuleResolverOptions, type MountObjectCarrier, type MountObjectPrefix, type MountPrefixEffect, type NoValuePrefix, type PathRepeatedSlashes, type PrefixTrailingSlash, type PythonDiscoveryPattern, type PythonPack, type RawSqlPattern, type RelativeModuleSpec, type RouteConventions, type RoutePrefixResolution, type RouterComposition, type RouterIndex, type Scope, type ScopeKind, type StoragePattern, annotationToShape, bindModule, buildRouterIndex, classifyDecorator, containedValues, discoverUnits, emitEntryFact, emitModuleImportFacts, emitValueFacts, extractPythonProject, findPythonFiles, nodeId, objectReturnedBy, parsePython, resolveAbsoluteModule, resolveCalls, resolveModule, resolveName, resolveRelativeModule, shapeFromName, unitKey };
704
+ /**
705
+ * Evidence for drafting a project-wrapper dependency stub: every
706
+ * import, anywhere in the project, of the asked module or one of its
707
+ * submodules. A Python decorator pattern matches a wrapper's import
708
+ * module exactly (see discovery.ts's `importModule.includes`), so a
709
+ * stub covers one imported module at a time rather than one package,
710
+ * and this groups by the exact module text a project writes.
711
+ *
712
+ * This walks every node rather than going through the binder in
713
+ * scope.ts, so an import inside an `if` or `try` still counts as
714
+ * evidence even though the binder would not resolve a name through it.
715
+ */
716
+ interface PythonImportSite {
717
+ /** The name imported at this site, null for a bare `import module`, which binds the whole module rather than one name from it. */
718
+ name: string | null;
719
+ file: string;
720
+ line: number;
721
+ }
722
+ interface PythonImportEvidence {
723
+ /** The full dotted module text, exactly as a stub's `package` would spell it. */
724
+ module: string;
725
+ sites: PythonImportSite[];
726
+ }
727
+ interface PythonImportEvidenceOptions {
728
+ packageName: string;
729
+ directory: string;
730
+ }
731
+ /**
732
+ * Every import of `packageName`, or a submodule of it, across the
733
+ * project's own files, grouped by the exact module each was imported
734
+ * from.
735
+ */
736
+ declare function pythonImportEvidence(options: PythonImportEvidenceOptions): Promise<PythonImportEvidence[]>;
737
+
738
+ /**
739
+ * version.ts: this adapter's own half of the cache key.
740
+ *
741
+ * `ADAPTER_VERSION` is the hand-bumped semver. Bump it on any change
742
+ * that affects extraction output: IR shape, discovery semantics,
743
+ * terminal classification, anything that would invalidate previously
744
+ * cached summaries.
745
+ */
746
+ declare const ADAPTER_VERSION = "0.1.0";
747
+
748
+ export { ADAPTER_VERSION, type AnnotationContext, type Binding, type BoundPythonFile, type DecoratedClassRoute, type DecoratedFunctionRoute, type DecoratorArg, type DecoratorClassification, type DiscoveryOptions, type ExtractPythonOptions, type ExtractPythonResult, type ModuleBinding, type ModuleResolution, type ModuleResolverOptions, type MountObjectCarrier, type MountObjectPrefix, type MountPrefixEffect, type NoValuePrefix, type PathRepeatedSlashes, type PrefixTrailingSlash, type PythonDiscoveryPattern, type PythonImportEvidence, type PythonImportEvidenceOptions, type PythonImportSite, type PythonPack, type PythonValueHandle, PythonWhySession, type PythonWhySessionOptions, type RawSqlPattern, type RelativeModuleSpec, type RouteConventions, type RoutePrefixResolution, type RouterComposition, type RouterIndex, type Scope, type ScopeKind, type StoragePattern, annotationToShape, bindModule, buildRouterIndex, classifyDecorator, containedValues, discoverUnits, emitEntryFact, emitModuleImportFacts, emitValueFacts, extractPythonProject, findPythonFiles, nodeId, objectReturnedBy, parsePython, parsePythonSync, preloadPythonGrammar, pythonImportEvidence, readKey, resolveAbsoluteModule, resolveCalls, resolveModule, resolveName, resolveRelativeModule, shapeFromName, unitKey };