@suss/adapter-python 0.3.2-0 → 0.4.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/README.md +89 -0
- package/dist/index.cjs +16771 -191
- package/dist/index.d.cts +70 -13
- package/dist/index.d.ts +70 -13
- package/dist/index.js +16772 -190
- package/package.json +5 -4
package/dist/index.d.cts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
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
|
-
import { ExtractorOptions, RawCodeStructure } from '@suss/extractor';
|
|
5
4
|
import { Database } from '@suss/datalog';
|
|
5
|
+
import { ExtractorOptions, RawCodeStructure } from '@suss/extractor';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* A new `Parser` for every call, so that parses running at the same time do
|
|
@@ -107,15 +107,6 @@ declare function annotationToShape(typeNode: Node, scope: Scope, ctx: Annotation
|
|
|
107
107
|
/** Exported so a decorator keyword that gives a class name reads the same way as that name written in annotation position. */
|
|
108
108
|
declare function shapeFromName(name: string, scope: Scope, ctx: AnnotationContext): TypeShape;
|
|
109
109
|
|
|
110
|
-
/**
|
|
111
|
-
* Small helpers for reading a tree-sitter-python parse tree.
|
|
112
|
-
*
|
|
113
|
-
* The node-type strings here come from tree-sitter-python's grammar, at the
|
|
114
|
-
* version the grammar README gives. Read a node through these helpers rather
|
|
115
|
-
* than calling `childForFieldName` or `.type` inline, so that a grammar upgrade
|
|
116
|
-
* that renames a field only has to be fixed in one place.
|
|
117
|
-
*/
|
|
118
|
-
|
|
119
110
|
interface Range {
|
|
120
111
|
start: number;
|
|
121
112
|
end: number;
|
|
@@ -175,6 +166,24 @@ interface PythonPack {
|
|
|
175
166
|
/** Wire protocol for the produced boundary bindings, e.g. "http". */
|
|
176
167
|
protocol: string;
|
|
177
168
|
discovery: PythonDiscoveryPattern[];
|
|
169
|
+
/** What the library's own database queries look like. The README says how one is matched. */
|
|
170
|
+
storage?: StoragePattern[];
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* A call talks to the database when the method behind it says it returns one
|
|
174
|
+
* of the library's query types. Matching on the return rather than on the
|
|
175
|
+
* import is what reads a project base class that wraps the library, which is
|
|
176
|
+
* how the measured corpus writes every one of its queries.
|
|
177
|
+
*/
|
|
178
|
+
interface StoragePattern {
|
|
179
|
+
/** The module a query type is imported from, `sqlalchemy.orm` for a Session. */
|
|
180
|
+
module: string;
|
|
181
|
+
/** Type names that mean the value is a query against the database. */
|
|
182
|
+
queryTypes: string[];
|
|
183
|
+
/** Chain-ending methods that change what is stored. Anything else reads. */
|
|
184
|
+
writes: string[];
|
|
185
|
+
/** Which database the library is talking to, for the boundary binding. */
|
|
186
|
+
storageSystem: "postgres" | "mysql" | "sqlite";
|
|
178
187
|
}
|
|
179
188
|
type PythonDiscoveryPattern = DecoratedClassRoute | DecoratedFunctionRoute;
|
|
180
189
|
/** Conventions both kinds of route share. Each one describes what the library does, never a project's choice. */
|
|
@@ -327,6 +336,18 @@ type NoValuePrefix = "unstated" | "unreadable";
|
|
|
327
336
|
*/
|
|
328
337
|
type PathRepeatedSlashes = "kept" | "merged";
|
|
329
338
|
|
|
339
|
+
/**
|
|
340
|
+
* What discovery uses for one file. `factsPath` is the path the facts were
|
|
341
|
+
* keyed under, which is the absolute one, while a summary shows the short one.
|
|
342
|
+
*/
|
|
343
|
+
interface StorageLookup {
|
|
344
|
+
readonly facts: Database;
|
|
345
|
+
readonly factsPath: string;
|
|
346
|
+
readonly patterns: readonly StoragePattern[];
|
|
347
|
+
readonly definitionAt: (key: string) => Node | undefined;
|
|
348
|
+
readonly couldMatch: ReadonlySet<string>;
|
|
349
|
+
}
|
|
350
|
+
|
|
330
351
|
/**
|
|
331
352
|
* Maps a dotted import onto the file in the repo it refers to.
|
|
332
353
|
*
|
|
@@ -394,7 +415,11 @@ type RoutePrefixResolution = {
|
|
|
394
415
|
interface RouterIndex {
|
|
395
416
|
resolve(pattern: PythonDiscoveryPattern, module: ModuleBinding, objectName: string): RoutePrefixResolution;
|
|
396
417
|
}
|
|
397
|
-
|
|
418
|
+
interface RouterIndexOptions extends ModuleResolverOptions {
|
|
419
|
+
/** The project's facts, so a loop over a call can be settled by the rules. */
|
|
420
|
+
facts?: Database;
|
|
421
|
+
}
|
|
422
|
+
declare function buildRouterIndex(files: BoundPythonFile[], packs: PythonPack[], resolverOptions: RouterIndexOptions): RouterIndex;
|
|
398
423
|
|
|
399
424
|
/**
|
|
400
425
|
* Finds decorated routes and turns each one into a `RawCodeStructure`.
|
|
@@ -418,9 +443,37 @@ interface DiscoveryOptions {
|
|
|
418
443
|
routerIndex?: RouterIndex;
|
|
419
444
|
/** Under "strict" a route whose unit cannot be built stops the run instead of abstaining. */
|
|
420
445
|
gapHandling?: ExtractorOptions["gapHandling"];
|
|
446
|
+
/** What a pack needs to say a call talks to the database. Absent when no pack does. */
|
|
447
|
+
storage?: StorageLookup | undefined;
|
|
421
448
|
}
|
|
422
449
|
declare function discoverUnits(root: Node, module: ModuleBinding, options: DiscoveryOptions): RawCodeStructure[];
|
|
423
450
|
|
|
451
|
+
/**
|
|
452
|
+
* Ask what these calls come down to, then derive. Asking about every call in
|
|
453
|
+
* a project costs seconds on a large one and answers questions nobody has,
|
|
454
|
+
* so a caller names the handful it needs.
|
|
455
|
+
*/
|
|
456
|
+
declare function resolveCalls(db: Database, callKeys: readonly string[]): void;
|
|
457
|
+
/**
|
|
458
|
+
* The values an object contains under its own keys, in the order the source
|
|
459
|
+
* writes them. Empty when nothing said what the object contains.
|
|
460
|
+
*/
|
|
461
|
+
declare function containedValues(db: Database, objectKey: string): string[];
|
|
462
|
+
/** What a call comes down to, when the rules settled it on an object. */
|
|
463
|
+
declare function objectReturnedBy(db: Database, callKey: string): string | null;
|
|
464
|
+
|
|
465
|
+
/**
|
|
466
|
+
* A node's identity across the whole run. The end is part of it because a
|
|
467
|
+
* call and its callee start at the same offset.
|
|
468
|
+
*/
|
|
469
|
+
declare function nodeId(filePath: string, node: Node): string;
|
|
470
|
+
/**
|
|
471
|
+
* Walk a module and emit the value facts. A nested function is walked in its
|
|
472
|
+
* own right, so a body's returns and calls belong to the function that wrote
|
|
473
|
+
* them.
|
|
474
|
+
*/
|
|
475
|
+
declare function emitValueFacts(db: Database, filePath: string, root: Node): void;
|
|
476
|
+
|
|
424
477
|
/**
|
|
425
478
|
* The name is part of the key because the range is measured in lines, two
|
|
426
479
|
* units can start on the same line, and `entry` is a set, so keying on the range
|
|
@@ -434,7 +487,11 @@ declare function emitEntryFact(db: Database, filePath: string, range: {
|
|
|
434
487
|
start: number;
|
|
435
488
|
end: number;
|
|
436
489
|
}, name: string): void;
|
|
437
|
-
/**
|
|
490
|
+
/**
|
|
491
|
+
* Every import in the file, wherever it is written. Python code puts an import
|
|
492
|
+
* inside a function to break a cycle between two modules, and a chain through
|
|
493
|
+
* one of those functions stops dead without it.
|
|
494
|
+
*/
|
|
438
495
|
declare function emitModuleImportFacts(db: Database, filePath: string, module: ModuleBinding, resolverOptions: ModuleResolverOptions): void;
|
|
439
496
|
|
|
440
497
|
interface ExtractPythonOptions {
|
|
@@ -456,4 +513,4 @@ declare function extractPythonProject(options: ExtractPythonOptions): Promise<Ex
|
|
|
456
513
|
/** Every `.py` file under `root`, depth-first, skipping the usual non-source directories. */
|
|
457
514
|
declare function findPythonFiles(root: string): string[];
|
|
458
515
|
|
|
459
|
-
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 RelativeModuleSpec, type RouteConventions, type RoutePrefixResolution, type RouterComposition, type RouterIndex, type Scope, type ScopeKind, annotationToShape, bindModule, buildRouterIndex, classifyDecorator, discoverUnits, emitEntryFact, emitModuleImportFacts, extractPythonProject, findPythonFiles, parsePython, resolveAbsoluteModule, resolveModule, resolveName, resolveRelativeModule, shapeFromName, unitKey };
|
|
516
|
+
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 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 };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
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
|
-
import { ExtractorOptions, RawCodeStructure } from '@suss/extractor';
|
|
5
4
|
import { Database } from '@suss/datalog';
|
|
5
|
+
import { ExtractorOptions, RawCodeStructure } from '@suss/extractor';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* A new `Parser` for every call, so that parses running at the same time do
|
|
@@ -107,15 +107,6 @@ declare function annotationToShape(typeNode: Node, scope: Scope, ctx: Annotation
|
|
|
107
107
|
/** Exported so a decorator keyword that gives a class name reads the same way as that name written in annotation position. */
|
|
108
108
|
declare function shapeFromName(name: string, scope: Scope, ctx: AnnotationContext): TypeShape;
|
|
109
109
|
|
|
110
|
-
/**
|
|
111
|
-
* Small helpers for reading a tree-sitter-python parse tree.
|
|
112
|
-
*
|
|
113
|
-
* The node-type strings here come from tree-sitter-python's grammar, at the
|
|
114
|
-
* version the grammar README gives. Read a node through these helpers rather
|
|
115
|
-
* than calling `childForFieldName` or `.type` inline, so that a grammar upgrade
|
|
116
|
-
* that renames a field only has to be fixed in one place.
|
|
117
|
-
*/
|
|
118
|
-
|
|
119
110
|
interface Range {
|
|
120
111
|
start: number;
|
|
121
112
|
end: number;
|
|
@@ -175,6 +166,24 @@ interface PythonPack {
|
|
|
175
166
|
/** Wire protocol for the produced boundary bindings, e.g. "http". */
|
|
176
167
|
protocol: string;
|
|
177
168
|
discovery: PythonDiscoveryPattern[];
|
|
169
|
+
/** What the library's own database queries look like. The README says how one is matched. */
|
|
170
|
+
storage?: StoragePattern[];
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* A call talks to the database when the method behind it says it returns one
|
|
174
|
+
* of the library's query types. Matching on the return rather than on the
|
|
175
|
+
* import is what reads a project base class that wraps the library, which is
|
|
176
|
+
* how the measured corpus writes every one of its queries.
|
|
177
|
+
*/
|
|
178
|
+
interface StoragePattern {
|
|
179
|
+
/** The module a query type is imported from, `sqlalchemy.orm` for a Session. */
|
|
180
|
+
module: string;
|
|
181
|
+
/** Type names that mean the value is a query against the database. */
|
|
182
|
+
queryTypes: string[];
|
|
183
|
+
/** Chain-ending methods that change what is stored. Anything else reads. */
|
|
184
|
+
writes: string[];
|
|
185
|
+
/** Which database the library is talking to, for the boundary binding. */
|
|
186
|
+
storageSystem: "postgres" | "mysql" | "sqlite";
|
|
178
187
|
}
|
|
179
188
|
type PythonDiscoveryPattern = DecoratedClassRoute | DecoratedFunctionRoute;
|
|
180
189
|
/** Conventions both kinds of route share. Each one describes what the library does, never a project's choice. */
|
|
@@ -327,6 +336,18 @@ type NoValuePrefix = "unstated" | "unreadable";
|
|
|
327
336
|
*/
|
|
328
337
|
type PathRepeatedSlashes = "kept" | "merged";
|
|
329
338
|
|
|
339
|
+
/**
|
|
340
|
+
* What discovery uses for one file. `factsPath` is the path the facts were
|
|
341
|
+
* keyed under, which is the absolute one, while a summary shows the short one.
|
|
342
|
+
*/
|
|
343
|
+
interface StorageLookup {
|
|
344
|
+
readonly facts: Database;
|
|
345
|
+
readonly factsPath: string;
|
|
346
|
+
readonly patterns: readonly StoragePattern[];
|
|
347
|
+
readonly definitionAt: (key: string) => Node | undefined;
|
|
348
|
+
readonly couldMatch: ReadonlySet<string>;
|
|
349
|
+
}
|
|
350
|
+
|
|
330
351
|
/**
|
|
331
352
|
* Maps a dotted import onto the file in the repo it refers to.
|
|
332
353
|
*
|
|
@@ -394,7 +415,11 @@ type RoutePrefixResolution = {
|
|
|
394
415
|
interface RouterIndex {
|
|
395
416
|
resolve(pattern: PythonDiscoveryPattern, module: ModuleBinding, objectName: string): RoutePrefixResolution;
|
|
396
417
|
}
|
|
397
|
-
|
|
418
|
+
interface RouterIndexOptions extends ModuleResolverOptions {
|
|
419
|
+
/** The project's facts, so a loop over a call can be settled by the rules. */
|
|
420
|
+
facts?: Database;
|
|
421
|
+
}
|
|
422
|
+
declare function buildRouterIndex(files: BoundPythonFile[], packs: PythonPack[], resolverOptions: RouterIndexOptions): RouterIndex;
|
|
398
423
|
|
|
399
424
|
/**
|
|
400
425
|
* Finds decorated routes and turns each one into a `RawCodeStructure`.
|
|
@@ -418,9 +443,37 @@ interface DiscoveryOptions {
|
|
|
418
443
|
routerIndex?: RouterIndex;
|
|
419
444
|
/** Under "strict" a route whose unit cannot be built stops the run instead of abstaining. */
|
|
420
445
|
gapHandling?: ExtractorOptions["gapHandling"];
|
|
446
|
+
/** What a pack needs to say a call talks to the database. Absent when no pack does. */
|
|
447
|
+
storage?: StorageLookup | undefined;
|
|
421
448
|
}
|
|
422
449
|
declare function discoverUnits(root: Node, module: ModuleBinding, options: DiscoveryOptions): RawCodeStructure[];
|
|
423
450
|
|
|
451
|
+
/**
|
|
452
|
+
* Ask what these calls come down to, then derive. Asking about every call in
|
|
453
|
+
* a project costs seconds on a large one and answers questions nobody has,
|
|
454
|
+
* so a caller names the handful it needs.
|
|
455
|
+
*/
|
|
456
|
+
declare function resolveCalls(db: Database, callKeys: readonly string[]): void;
|
|
457
|
+
/**
|
|
458
|
+
* The values an object contains under its own keys, in the order the source
|
|
459
|
+
* writes them. Empty when nothing said what the object contains.
|
|
460
|
+
*/
|
|
461
|
+
declare function containedValues(db: Database, objectKey: string): string[];
|
|
462
|
+
/** What a call comes down to, when the rules settled it on an object. */
|
|
463
|
+
declare function objectReturnedBy(db: Database, callKey: string): string | null;
|
|
464
|
+
|
|
465
|
+
/**
|
|
466
|
+
* A node's identity across the whole run. The end is part of it because a
|
|
467
|
+
* call and its callee start at the same offset.
|
|
468
|
+
*/
|
|
469
|
+
declare function nodeId(filePath: string, node: Node): string;
|
|
470
|
+
/**
|
|
471
|
+
* Walk a module and emit the value facts. A nested function is walked in its
|
|
472
|
+
* own right, so a body's returns and calls belong to the function that wrote
|
|
473
|
+
* them.
|
|
474
|
+
*/
|
|
475
|
+
declare function emitValueFacts(db: Database, filePath: string, root: Node): void;
|
|
476
|
+
|
|
424
477
|
/**
|
|
425
478
|
* The name is part of the key because the range is measured in lines, two
|
|
426
479
|
* units can start on the same line, and `entry` is a set, so keying on the range
|
|
@@ -434,7 +487,11 @@ declare function emitEntryFact(db: Database, filePath: string, range: {
|
|
|
434
487
|
start: number;
|
|
435
488
|
end: number;
|
|
436
489
|
}, name: string): void;
|
|
437
|
-
/**
|
|
490
|
+
/**
|
|
491
|
+
* Every import in the file, wherever it is written. Python code puts an import
|
|
492
|
+
* inside a function to break a cycle between two modules, and a chain through
|
|
493
|
+
* one of those functions stops dead without it.
|
|
494
|
+
*/
|
|
438
495
|
declare function emitModuleImportFacts(db: Database, filePath: string, module: ModuleBinding, resolverOptions: ModuleResolverOptions): void;
|
|
439
496
|
|
|
440
497
|
interface ExtractPythonOptions {
|
|
@@ -456,4 +513,4 @@ declare function extractPythonProject(options: ExtractPythonOptions): Promise<Ex
|
|
|
456
513
|
/** Every `.py` file under `root`, depth-first, skipping the usual non-source directories. */
|
|
457
514
|
declare function findPythonFiles(root: string): string[];
|
|
458
515
|
|
|
459
|
-
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 RelativeModuleSpec, type RouteConventions, type RoutePrefixResolution, type RouterComposition, type RouterIndex, type Scope, type ScopeKind, annotationToShape, bindModule, buildRouterIndex, classifyDecorator, discoverUnits, emitEntryFact, emitModuleImportFacts, extractPythonProject, findPythonFiles, parsePython, resolveAbsoluteModule, resolveModule, resolveName, resolveRelativeModule, shapeFromName, unitKey };
|
|
516
|
+
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 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 };
|