Skip to content

flashkit 1.2.0: coordinated public-API polish#2

Merged
bitalizer merged 13 commits intomainfrom
v1.2.0
Apr 15, 2026
Merged

flashkit 1.2.0: coordinated public-API polish#2
bitalizer merged 13 commits intomainfrom
v1.2.0

Conversation

@bitalizer
Copy link
Copy Markdown
Owner

Summary

Coordinated pass over the public API surface. Version bump 1.1.0 → 1.2.0. Breaking changes are allowed in the 1.x line while the API stabilizes; no deprecation wrappers are shipped.

Added

  • Workspace.class_graph — lazily-built, cached ClassGraph.
  • InheritanceGraph.from_workspace(ws) classmethod (existing .from_classes(classes) preserved).
  • ClassInfo.workspace — public back-reference to the owning Workspace.
  • ClassInfo.fingerprints — lazy cached list[MethodFingerprint].
  • MethodInfoResolved.fingerprint — lazy cached MethodFingerprint | None.
  • Return-type annotations on every Workspace analysis property.
  • Top-level re-exports: from flashkit import Workspace, ClassInfo.

Changed (breaking)

  • build_class_graph(ws) removed — use ws.class_graph or ClassGraph.from_workspace(ws).
  • ClassInfo._abc / _workspace are no longer intended for external reads — use cls.abc / cls.workspace.
  • CallGraph/ReferenceIndex/StringIndex/FieldAccessIndex.from_workspace and build_all_indexes now declare workspace: Workspace (was workspace: object).
  • ClassInfo.references_to / references_from annotated list[Reference].
  • ClassInfo.field_access_summary annotated dict[str, dict[str, list[str]]].
  • Empty flashkit.search subpackage removed.

Migration

# before
from flashkit.analysis import build_class_graph
g = build_class_graph(ws)

# after — cached (recommended)
g = ws.class_graph

# after — uncached
from flashkit.analysis import ClassGraph
g = ClassGraph.from_workspace(ws)
# before
abc = cls._abc
fps = extract_all_fingerprints(cls, abc)
fp  = extract_fingerprint(cls, method, abc)

# after
abc = cls.abc
fps = cls.fingerprints
fp  = method.fingerprint

Test plan

  • Full pytest sweep green (323 passed)
  • Smoke: from flashkit import Workspace, ClassInfo works, __version__ == "1.2.0"
  • from flashkit.analysis import build_class_graph now raises ImportError
  • Every __all__ entry resolves (tests/test_public_api.py)
  • ClassGraph.from_workspace(ws) / ws.class_graph identity-cached
  • cls.fingerprints / method.fingerprint cached and slots-safe
  • External bh-deobfuscator callsites of cls._abc migrated to cls.abc

Introduces a readable disassembly output: resolve_instructions() converts
raw Instruction operands (pool indices) to human-readable strings —
multinames become names, string indices become quoted literals, int/uint/
double indices become literal values. Exposed via Workspace.disassemble_method()
for quick per-method inspection.

Baseline commit carried over from prior work.
Adds two new analysis modules carried over from prior session work:

- method_fingerprint: structural features of method bodies (param count,
  builtin-only types, opcode counts, constants, sequence bigrams).
  Suitable for cross-SWF method comparison that is robust to identifier
  renaming.
- class_graph: per-class node structure with typed edges (extends,
  implements, field_type, param_type, return_type, call, instantiation,
  class_ref, coerce). Wraps ReferenceIndex into adjacency form and
  attaches method fingerprints to each node.

ClassInfo gains a public 'abc' property and a '_abc' back-reference field
so downstream analyses can reach the defining AbcFile without a Workspace
round-trip. constructor_params moves from computed-each-time to the
ClassInfo API surface.

Baseline commit; API polish (1.2.0) builds on top of this.
…orkspace

Use TYPE_CHECKING guard to avoid circular imports. Restores IDE
autocomplete and static type-checking for the public .from_workspace
classmethods. Runtime behavior unchanged.
Shared fixture used by upcoming Workspace-property and ClassInfo
tests so each spec isn't re-building a mini SWF.
Convenience wrapper around from_classes(ws.classes). Establishes the
consistent .from_workspace(ws) pattern across all analysis classes.
…workspace()

BREAKING: build_class_graph is removed. Users call ClassGraph.from_workspace(ws)
or the cached ws.class_graph property (added in a follow-up task).
Establishes the consistent .from_workspace(ws) pattern across all analysis
classes.
Workspace.class_graph lazily builds a ClassGraph on first access, matching
the existing call_graph/inheritance/etc. pattern. All analysis properties
now declare their return type via TYPE_CHECKING imports, restoring IDE
autocomplete.
- ClassInfo.workspace public property (was accessible only via _workspace).
- references_to/from typed as list[Reference].
- field_access_summary typed as dict[str, dict[str, list[str]]].
Wraps extract_all_fingerprints(cls, cls.abc). Cached in a private slot
field (_fingerprints_cache) because ClassInfo is slots=True and
functools.cached_property doesn't work with slots.
Returns MethodFingerprint or None (None is a valid result when the
method has no decodable body). Uses a separate _fingerprint_computed
flag because None can't also mean "not yet computed". Slots-compatible.
Ensure every __all__ entry actually exists in its module, and that
the 1.2.0 additions (Workspace, ClassInfo) and removals (build_class_graph)
are in the expected state.
Final reviewer caught two spots where flashkit itself was still reading
cls._abc, the exact anti-pattern 1.2.0 tells users to migrate away from.
Use the public cls.abc accessor (try/except RuntimeError for the
optional-abc skip case in ClassGraph.from_workspace).
@bitalizer bitalizer self-assigned this Apr 15, 2026
@bitalizer bitalizer merged commit 8713b33 into main Apr 15, 2026
3 checks passed
@bitalizer bitalizer deleted the v1.2.0 branch April 15, 2026 02:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant