Skip to main content

py_extractor

Extract one self-contained Python file containing exactly the code a class or function needs — pulled from a GitHub/Hugging Face repository (or a local checkout).

Use it when you want to reuse a function or class from a package you don't fully trust, without importing the whole package and dragging in its dependencies.

How it works

  1. Acquire the tree once. The whole repository is downloaded as a tarball and materialised into an in-memory virtual filesystem, so imports are resolved against the real layout (no path guessing).
  2. Resolve imports properly. Relative imports (./..), src/ layouts, namespace packages and __init__.py re-exports are all handled.
  3. Compute the transitive closure. Free names are found with scope-aware AST analysis (locals, loop/comprehension variables, parameters and builtins are excluded; decorators, bases, annotations and defaults are included).
  4. Handle each dependency (first match wins):
    • Standard library → kept as an import (always, automatically).
    • Curated trusted package (torch, numpy, transformers, ...) → kept as an import.
    • In-repo module → recursed into and inlined.
    • Unknown third-party → looked up on PyPI, optionally inlined, otherwise flagged and kept as an import (warn, but still emit a runnable file).
  5. Emit a single file with a consolidated license attribution table, the kept imports, the inlined definitions in dependency order, and a resolution report listing provenance and warnings.

Install

pip install -e .            # runtime dep: requests
pip install -e '.[dev]'     # adds pytest, pytest-cov, ruff, yapf

CLI

py-extractor github:owner/repo SymbolName
py-extractor https://github.com/pallets/flask Flask --out flask_flask.py
python -m py_extractor github:owner/repo SymbolName --report json

Hugging Face models, datasets and spaces are all supported; the repo type selects the correct API and resolve URL prefixes::

py-extractor hf:owner/model-name SymbolName            # model  (default)
py-extractor hf:datasets/owner/dataset-name SymbolName # dataset
py-extractor hf:spaces/owner/space-name SymbolName     # space

The symbol is discovered automatically by scanning the whole repository. If the name is defined in more than one file, the CLI asks which one to use::

Symbol 'Upsample' is defined in multiple files:
  1) basicsr/archs/dat_arch.py  [default]
  2) basicsr/archs/arch_util.py
Which file is the reference? [1]:

For scripts/CI, pass --file PATH to select the reference file directly, or -y/--yes to fail fast (with the candidate list) instead of prompting. The prompt is only shown on an interactive terminal; when stdin is not a TTY the run errors out rather than hanging.

Key options:

Option Meaning
--file PATH Reference file; overrides the symbol search (scripts/CI)
--ref REF Git ref (branch/tag/commit). Default HEAD = the repo's default branch
--out FILE Write output to a file (default: stdout)
-y, --yes Never prompt; fail if the symbol is ambiguous
--trust a,b Extra trusted top-level module names
--no-trust a,b Revoke trusted names
--trust-file FILE Extra TOML registry ([packages] table)
--strict-trust Ignore the built-in registry (stdlib still trusted)
--[no-]third-party Inline third-party code when resolvable (default: on)
--offline Disallow network access
--report text|json|none Resolution report on stderr
--[no-]license-notice Emit the license attribution table (default: on)
--license-full-text Embed the full text of each license file

The default ref is HEAD, a symbolic ref that GitHub and Hugging Face both resolve to the repository's actual default branch. This means master-era repositories (e.g. google-research/bert, openai/gpt-2) work without knowing the branch name. Files are decoded as UTF-8 and a leading byte-order mark (BOM) is stripped, since ast.parse rejects a stray U+FEFF.

Verification

The generated file is always passed through the full Python compiler (compile()), which is stronger than ast.parse and catches errors such as a stray top-level return/break/yield or a duplicate argument that inlining could produce.

On top of that, two opt-in checks are available:

Flag What it does
--verify-compile Byte-compiles the written --out file (py_compile) and reports the result
--verify-import Runs the generated file in an isolated subprocess and confirms the target symbol is actually importable (executes module-level code, so it is opt-in)
--verify-timeout S Timeout for --verify-import (default 60s)

Both exit non-zero on failure. The import check is how you detect a file that compiles but would NameError/ImportError the moment it is used.

Licensing

Flattening code out of a repository produces a derivative work, so the generated file carries a consolidated license attribution table at the top. Each contributing repository (the target repo and any inlined third-party repos) gets a stable [L#] id, and each inlined definition references its source license by that id — so a notice is stated once instead of repeated above every definition.

# ====================================================================
# LICENSES
# ====================================================================
# [L1] MIT License (SPDX: MIT)
#      repo: owner/repo
#      source: github-api
#      Copyright (c) 2021 The Authors
# ====================================================================
...
# --- pkg.mod:Model  (from owner/repo:pkg/mod.py) ---  [L1]

License detection prefers authoritative metadata — a GitHub API SPDX id, PyPI License :: classifiers, or a Hugging Face model-card license field — and falls back to fingerprinting the text of a LICENSE/COPYING/NOTICE file found in the downloaded tree. Unrecognised licenses degrade to an Unknown license entry rather than failing the extraction. Metadata lookups are best-effort and never fatal (rate limits simply fall back to text detection).

The notice is on by default; disable it with --no-license-notice, or embed the full license bodies with --license-full-text.

Library

from py_extractor import extract_symbol

result = extract_symbol(
    "github:owner/repo",
    "MyClass",
    file_hint="pkg/module.py",   # optional override (skips discovery)
    trusted={"torch", "numpy"},
)
print(result.source)        # the generated file
for flag in result.closure.flags:
    print(flag.kind.value, flag.detail)

When the symbol is ambiguous and no file_hint is given, extract_symbol raises AmbiguousSymbolError (carrying the ranked candidates) unless you pass a choose callback:

from py_extractor import extract_symbol
from py_extractor.errors import AmbiguousSymbolError

try:
    result = extract_symbol("github:owner/repo", "Thing")
except AmbiguousSymbolError as exc:
    print(exc.candidates)               # ['pkg/one.py', 'pkg/two.py']

# ...or decide programmatically:
result = extract_symbol("github:owner/repo", "Thing",
                        choose=lambda symbol, candidates: candidates[1])

Verification is available from the library too:

from py_extractor import compile_file, compile_source, import_symbol

compile_file("extracted.py")                  # ValueError-free VerifyResult
compile_source(result.source)                 # raises SyntaxError if invalid
import_symbol("MyClass", source=result.source)  # runs in a subprocess

Trusted packages

The curated registry lives in src/py_extractor/data/trusted_packages.toml (import names, not distribution names). The Python standard library is always trusted automatically and never needs to be listed.

Tests

pytest                      # offline suite (network tests deselected)
pytest -m network           # real GitHub / Hugging Face integration tests

CI (.github/workflows/ci.yml) runs ruff, yapf --diff, and the offline suite with coverage on every push/PR. The network integration suite runs on demand (workflow_dispatch) and nightly.

Metadata

Release files for py-code-extractor 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for py-code-extractor 0.1.0
File Size Uploaded Provenance Actions
py_code_extractor-0.1.0.tar.gz 78.5 kB Without provenance Details for py_code_extractor-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for py-code-extractor 0.1.0
File Interpreter ABI Platform Actions
py_code_extractor-0.1.0-py3-none-any.whl Python 3 none any Details for py_code_extractor-0.1.0-py3-none-any.whl

Total release size: 139.3 kB

Release files / py_code_extractor-0.1.0.tar.gz

Download URL py_code_extractor-0.1.0.tar.gz
Size 78.5 kB
Tags Source
SHA-256 checksum
How to use checksums
782b5fadfef84a52a4586bd77586d4c6f8e39abef565913eb0a45ca8d940dac4
BLAKE2b-256 checksum
How to use checksums
0b5905134ab8b17342c40c1d7f3a5921bdb456239b73e8f219527e516ccc612b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.5

Release files / py_code_extractor-0.1.0-py3-none-any.whl

Download URL py_code_extractor-0.1.0-py3-none-any.whl
Size 60.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b6641b40cc29c3705d617a436999f4d4ee28c0df78aa2d621bed96d76f6b5d61
BLAKE2b-256 checksum
How to use checksums
9dd3fcf414db12268b2ed09f8cb772e748be03dd6cfa20562ad4c2faffc4294a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.5

Security for py-code-extractor 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page