fantasm 0.1.2__tar.gz
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.
- fantasm-0.1.2/.github/workflows/ci.yml +16 -0
- fantasm-0.1.2/.github/workflows/readme-check.yml +28 -0
- fantasm-0.1.2/.github/workflows/release.yml +64 -0
- fantasm-0.1.2/.github/workflows/test.yml +90 -0
- fantasm-0.1.2/.gitignore +59 -0
- fantasm-0.1.2/.pre-commit-config.yaml +15 -0
- fantasm-0.1.2/CLAUDE.md +138 -0
- fantasm-0.1.2/LICENSE +21 -0
- fantasm-0.1.2/PKG-INFO +201 -0
- fantasm-0.1.2/README.md +178 -0
- fantasm-0.1.2/docs/configuration.md +289 -0
- fantasm-0.1.2/docs/index.md +17 -0
- fantasm-0.1.2/docs/inventory.md +106 -0
- fantasm-0.1.2/docs/migration_readiness.md +164 -0
- fantasm-0.1.2/docs/testing.md +63 -0
- fantasm-0.1.2/pyproject.toml +90 -0
- fantasm-0.1.2/scripts/generate_readme.py +125 -0
- fantasm-0.1.2/scripts/readme_template.md.j2 +108 -0
- fantasm-0.1.2/src/fantasm/__init__.py +5 -0
- fantasm-0.1.2/src/fantasm/api/__init__.py +240 -0
- fantasm-0.1.2/src/fantasm/api/asm_extract.py +183 -0
- fantasm-0.1.2/src/fantasm/api/audit.py +486 -0
- fantasm-0.1.2/src/fantasm/api/backfill.py +742 -0
- fantasm-0.1.2/src/fantasm/api/blockmatch.py +259 -0
- fantasm-0.1.2/src/fantasm/api/cfg.py +358 -0
- fantasm-0.1.2/src/fantasm/api/comment_check.py +588 -0
- fantasm-0.1.2/src/fantasm/api/compare.py +423 -0
- fantasm-0.1.2/src/fantasm/api/context.py +315 -0
- fantasm-0.1.2/src/fantasm/api/find_shared.py +164 -0
- fantasm-0.1.2/src/fantasm/api/fingerprint.py +92 -0
- fantasm-0.1.2/src/fantasm/api/insert_point.py +194 -0
- fantasm-0.1.2/src/fantasm/api/labels.py +228 -0
- fantasm-0.1.2/src/fantasm/api/lint.py +301 -0
- fantasm-0.1.2/src/fantasm/api/mos6502.py +221 -0
- fantasm-0.1.2/src/fantasm/api/paths.py +220 -0
- fantasm-0.1.2/src/fantasm/api/project.py +197 -0
- fantasm-0.1.2/src/fantasm/api/promote.py +174 -0
- fantasm-0.1.2/src/fantasm/api/rename_labels.py +139 -0
- fantasm-0.1.2/src/fantasm/api/suggest.py +175 -0
- fantasm-0.1.2/src/fantasm/api/verify.py +140 -0
- fantasm-0.1.2/src/fantasm/api/version_graph.py +477 -0
- fantasm-0.1.2/src/fantasm/cli.py +2556 -0
- fantasm-0.1.2/src/fantasm/cli_helpers.py +179 -0
- fantasm-0.1.2/src/fantasm/config.py +65 -0
- fantasm-0.1.2/tests/api/__init__.py +0 -0
- fantasm-0.1.2/tests/api/test_asm_extract.py +199 -0
- fantasm-0.1.2/tests/api/test_audit.py +317 -0
- fantasm-0.1.2/tests/api/test_backfill.py +475 -0
- fantasm-0.1.2/tests/api/test_blockmatch_fingerprint.py +174 -0
- fantasm-0.1.2/tests/api/test_comment_check.py +392 -0
- fantasm-0.1.2/tests/api/test_compare.py +230 -0
- fantasm-0.1.2/tests/api/test_insert_point_cfg_context.py +545 -0
- fantasm-0.1.2/tests/api/test_labels.py +253 -0
- fantasm-0.1.2/tests/api/test_lint.py +248 -0
- fantasm-0.1.2/tests/api/test_mos6502.py +165 -0
- fantasm-0.1.2/tests/api/test_paths.py +187 -0
- fantasm-0.1.2/tests/api/test_project.py +194 -0
- fantasm-0.1.2/tests/api/test_promote_findshared.py +238 -0
- fantasm-0.1.2/tests/api/test_suggest.py +162 -0
- fantasm-0.1.2/tests/api/test_verify_rename.py +186 -0
- fantasm-0.1.2/tests/api/test_version_graph.py +556 -0
- fantasm-0.1.2/tests/conftest.py +28 -0
- fantasm-0.1.2/tests/test_cli.py +89 -0
- fantasm-0.1.2/tests/test_cli_commands.py +893 -0
- fantasm-0.1.2/tests/test_cli_project.py +229 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [master]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [master]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
uses: ./.github/workflows/test.yml
|
|
12
|
+
|
|
13
|
+
readme-check:
|
|
14
|
+
# Belt-and-braces against contributors who bypass the pre-commit
|
|
15
|
+
# hook. Same job is reused by release.yml as a publication gate.
|
|
16
|
+
uses: ./.github/workflows/readme-check.yml
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
name: README check
|
|
2
|
+
|
|
3
|
+
# Reusable workflow: verifies that README.md is in sync with the
|
|
4
|
+
# generator (scripts/generate_readme.py). Called by ci.yml on push/PR
|
|
5
|
+
# and by release.yml as a publication gate so a v-tag with a stale
|
|
6
|
+
# README is held back from PyPI.
|
|
7
|
+
|
|
8
|
+
on:
|
|
9
|
+
workflow_call:
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
check:
|
|
13
|
+
name: README.md is in sync with the generator
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
- name: Install uv
|
|
19
|
+
uses: astral-sh/setup-uv@v6
|
|
20
|
+
with:
|
|
21
|
+
python-version: "3.13"
|
|
22
|
+
cache-dependency-glob: pyproject.toml
|
|
23
|
+
|
|
24
|
+
- name: Install dev dependencies
|
|
25
|
+
run: uv sync
|
|
26
|
+
|
|
27
|
+
- name: Verify README.md matches the generator's output
|
|
28
|
+
run: uv run python scripts/generate_readme.py --check
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# Atomic release workflow: on a `v*` tag produced by bump-my-version,
|
|
4
|
+
# runs the full test matrix and the README sync check in parallel as
|
|
5
|
+
# two gates. Only when BOTH gates are green does publish-pypi run.
|
|
6
|
+
#
|
|
7
|
+
# `workflow_dispatch` is enabled so a release can be re-attempted
|
|
8
|
+
# manually if the publish step fails transiently after the gates
|
|
9
|
+
# pass. Individual failed jobs can also be re-run from the Actions UI.
|
|
10
|
+
|
|
11
|
+
on:
|
|
12
|
+
push:
|
|
13
|
+
tags: ["v*"]
|
|
14
|
+
workflow_dispatch:
|
|
15
|
+
|
|
16
|
+
# Default read-only permissions for the workflow; the publishing job
|
|
17
|
+
# narrows its own permissions to what it actually needs.
|
|
18
|
+
permissions:
|
|
19
|
+
contents: read
|
|
20
|
+
|
|
21
|
+
jobs:
|
|
22
|
+
test:
|
|
23
|
+
# Reuses the matrix defined in test.yml so CI and Release exercise
|
|
24
|
+
# the exact same test surface against the built wheel.
|
|
25
|
+
uses: ./.github/workflows/test.yml
|
|
26
|
+
|
|
27
|
+
readme-check:
|
|
28
|
+
# Same gate ci.yml runs on every push.
|
|
29
|
+
uses: ./.github/workflows/readme-check.yml
|
|
30
|
+
|
|
31
|
+
publish-pypi:
|
|
32
|
+
name: Publish to PyPI
|
|
33
|
+
# Both gates must pass before publication. If either fails, this
|
|
34
|
+
# job does not run.
|
|
35
|
+
needs: [test, readme-check]
|
|
36
|
+
runs-on: ubuntu-latest
|
|
37
|
+
# The `pypi` GitHub deployment environment is the gate for the
|
|
38
|
+
# PYPI_TOKEN secret (and/or trusted-publishing OIDC config).
|
|
39
|
+
environment:
|
|
40
|
+
name: pypi
|
|
41
|
+
url: https://pypi.org/project/fantasm/
|
|
42
|
+
permissions:
|
|
43
|
+
# Required if/when the project opts into PyPI trusted publishing
|
|
44
|
+
# via OIDC. Harmless when using a token instead.
|
|
45
|
+
id-token: write
|
|
46
|
+
steps:
|
|
47
|
+
- uses: actions/checkout@v4
|
|
48
|
+
|
|
49
|
+
- name: Install uv
|
|
50
|
+
uses: astral-sh/setup-uv@v6
|
|
51
|
+
with:
|
|
52
|
+
python-version: "3.13"
|
|
53
|
+
|
|
54
|
+
- name: Build distributions
|
|
55
|
+
run: uv build
|
|
56
|
+
|
|
57
|
+
- name: Publish to PyPI
|
|
58
|
+
# Uses UV_PUBLISH_TOKEN if set; otherwise uv falls back to
|
|
59
|
+
# PyPI trusted publishing via the OIDC token minted by
|
|
60
|
+
# GitHub (works when the project is registered as a trusted
|
|
61
|
+
# publisher under the `pypi` environment).
|
|
62
|
+
run: uv publish
|
|
63
|
+
env:
|
|
64
|
+
UV_PUBLISH_TOKEN: ${{ secrets.PYPI_TOKEN }}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
name: Test
|
|
2
|
+
|
|
3
|
+
# Reusable workflow: builds a wheel and runs the test suite against the
|
|
4
|
+
# installed wheel (not the source tree) on a matrix of OS x Python
|
|
5
|
+
# version. Called by ci.yml on push/PR so verification always exercises
|
|
6
|
+
# the exact artefact shape users will install -- catching packaging
|
|
7
|
+
# regressions like missing package data, omitted entry points, or an
|
|
8
|
+
# unshipped py.typed marker that an editable install would hide.
|
|
9
|
+
|
|
10
|
+
on:
|
|
11
|
+
workflow_call:
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
resolve-python-versions:
|
|
15
|
+
name: Resolve supported Python versions from pyproject classifiers
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
outputs:
|
|
18
|
+
versions: ${{ steps.extract.outputs.versions }}
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v4
|
|
21
|
+
- id: extract
|
|
22
|
+
name: Pick earliest + latest declared Python version
|
|
23
|
+
# Reading the supported versions from the classifiers keeps the CI
|
|
24
|
+
# matrix in sync with the published metadata. ubuntu-latest ships
|
|
25
|
+
# a stdlib tomllib-capable Python (>=3.11).
|
|
26
|
+
run: |
|
|
27
|
+
versions=$(python - <<'PY'
|
|
28
|
+
import json
|
|
29
|
+
import re
|
|
30
|
+
import tomllib
|
|
31
|
+
from pathlib import Path
|
|
32
|
+
|
|
33
|
+
data = tomllib.loads(Path("pyproject.toml").read_text())
|
|
34
|
+
declared = sorted(
|
|
35
|
+
(
|
|
36
|
+
c.rsplit(" :: ", 1)[-1]
|
|
37
|
+
for c in data["project"]["classifiers"]
|
|
38
|
+
if re.match(r"^Programming Language :: Python :: 3\.\d+$", c)
|
|
39
|
+
),
|
|
40
|
+
key=lambda v: tuple(map(int, v.split("."))),
|
|
41
|
+
)
|
|
42
|
+
if not declared:
|
|
43
|
+
raise SystemExit("No 'Programming Language :: Python :: 3.x' classifiers found")
|
|
44
|
+
selected = [declared[0], declared[-1]] if len(declared) >= 2 else declared
|
|
45
|
+
print(json.dumps(selected))
|
|
46
|
+
PY
|
|
47
|
+
)
|
|
48
|
+
echo "versions=$versions" >> "$GITHUB_OUTPUT"
|
|
49
|
+
|
|
50
|
+
test:
|
|
51
|
+
name: Test on ${{ matrix.os }} / Python ${{ matrix.python-version }}
|
|
52
|
+
needs: resolve-python-versions
|
|
53
|
+
runs-on: ${{ matrix.os }}
|
|
54
|
+
strategy:
|
|
55
|
+
fail-fast: false
|
|
56
|
+
matrix:
|
|
57
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
58
|
+
python-version: ${{ fromJson(needs.resolve-python-versions.outputs.versions) }}
|
|
59
|
+
steps:
|
|
60
|
+
- uses: actions/checkout@v4
|
|
61
|
+
|
|
62
|
+
- name: Install uv
|
|
63
|
+
uses: astral-sh/setup-uv@v6
|
|
64
|
+
with:
|
|
65
|
+
python-version: ${{ matrix.python-version }}
|
|
66
|
+
cache-dependency-glob: pyproject.toml
|
|
67
|
+
|
|
68
|
+
- name: Install dependency environment (without fantasm itself)
|
|
69
|
+
# Sync all dev/test deps into the venv but skip installing the
|
|
70
|
+
# fantasm project. We install it from a freshly built wheel below
|
|
71
|
+
# so tests exercise the distribution artefact rather than the
|
|
72
|
+
# source tree.
|
|
73
|
+
run: uv sync --no-install-project
|
|
74
|
+
|
|
75
|
+
- name: Build wheel
|
|
76
|
+
run: uv build
|
|
77
|
+
|
|
78
|
+
- name: Install the built wheel into the test environment
|
|
79
|
+
# Force bash so dist/*.whl globs on Windows runners too (default
|
|
80
|
+
# pwsh does not glob the same way).
|
|
81
|
+
shell: bash
|
|
82
|
+
run: uv pip install dist/*.whl
|
|
83
|
+
|
|
84
|
+
- name: Run tests against the installed wheel
|
|
85
|
+
# --no-sync keeps the existing venv (with the wheel-installed
|
|
86
|
+
# fantasm) intact; without it `uv run` would re-sync and
|
|
87
|
+
# reinstate an editable install of the source tree, defeating
|
|
88
|
+
# the point. Confirmed locally that the test process imports
|
|
89
|
+
# fantasm from site-packages.
|
|
90
|
+
run: uv run --no-sync pytest -v
|
fantasm-0.1.2/.gitignore
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.Python
|
|
7
|
+
|
|
8
|
+
# Distribution / packaging
|
|
9
|
+
build/
|
|
10
|
+
dist/
|
|
11
|
+
*.egg-info/
|
|
12
|
+
*.egg
|
|
13
|
+
.eggs/
|
|
14
|
+
wheels/
|
|
15
|
+
share/python-wheels/
|
|
16
|
+
|
|
17
|
+
# Installer logs
|
|
18
|
+
pip-log.txt
|
|
19
|
+
pip-delete-this-directory.txt
|
|
20
|
+
|
|
21
|
+
# Unit test / coverage
|
|
22
|
+
.tox/
|
|
23
|
+
.nox/
|
|
24
|
+
.coverage
|
|
25
|
+
.coverage.*
|
|
26
|
+
.cache
|
|
27
|
+
htmlcov/
|
|
28
|
+
.pytest_cache/
|
|
29
|
+
.ruff_cache/
|
|
30
|
+
.mypy_cache/
|
|
31
|
+
.dmypy.json
|
|
32
|
+
dmypy.json
|
|
33
|
+
|
|
34
|
+
# Virtual environments
|
|
35
|
+
.venv/
|
|
36
|
+
venv/
|
|
37
|
+
env/
|
|
38
|
+
ENV/
|
|
39
|
+
|
|
40
|
+
# uv
|
|
41
|
+
.uv/
|
|
42
|
+
# Fantasm is a library as much as an application; consumers resolve
|
|
43
|
+
# their own dependency versions, so uv.lock stays out of git.
|
|
44
|
+
uv.lock
|
|
45
|
+
|
|
46
|
+
# Environments / secrets
|
|
47
|
+
.env
|
|
48
|
+
.env.*
|
|
49
|
+
|
|
50
|
+
# IDEs / editors
|
|
51
|
+
.idea/
|
|
52
|
+
.vscode/
|
|
53
|
+
*.swp
|
|
54
|
+
*.swo
|
|
55
|
+
.DS_Store
|
|
56
|
+
|
|
57
|
+
# Project-local scratch
|
|
58
|
+
scratch/
|
|
59
|
+
tmp/
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
- repo: local
|
|
3
|
+
hooks:
|
|
4
|
+
- id: generate-readme-check
|
|
5
|
+
name: README.md is in sync with the generator
|
|
6
|
+
entry: uv run python scripts/generate_readme.py --check
|
|
7
|
+
language: system
|
|
8
|
+
pass_filenames: false
|
|
9
|
+
files: |
|
|
10
|
+
(?x)^(
|
|
11
|
+
README\.md
|
|
12
|
+
| scripts/generate_readme\.py
|
|
13
|
+
| scripts/readme_template\.md\.j2
|
|
14
|
+
| src/fantasm/.*\.py
|
|
15
|
+
)$
|
fantasm-0.1.2/CLAUDE.md
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# Fantasm — guidance for AI assistants
|
|
2
|
+
|
|
3
|
+
Project goal: consolidate 6502 disassembly tooling from four sibling
|
|
4
|
+
acornaeology repositories (`acorn-6502-tube-client`, `acorn-adfs`,
|
|
5
|
+
`acorn-econet-bridge`, `acorn-nfs`) into a single `fantasm` package with a
|
|
6
|
+
Click CLI and a programmatic `fantasm.api` package.
|
|
7
|
+
|
|
8
|
+
## Layout
|
|
9
|
+
|
|
10
|
+
- `src/fantasm/` — package
|
|
11
|
+
- `src/fantasm/cli.py` — Click entrypoint, hierarchical sub-command groups
|
|
12
|
+
- `src/fantasm/api/` — programmatic API; flat re-exports from `__init__.py`
|
|
13
|
+
- `src/fantasm/config.py` — project-root resolution and `fantasm.toml` loading
|
|
14
|
+
- `tests/` — pytest suite with shared fixtures in `conftest.py`
|
|
15
|
+
- `docs/` — user/developer docs
|
|
16
|
+
|
|
17
|
+
## Testing strategy
|
|
18
|
+
|
|
19
|
+
The original code being consolidated has **no tests**. As code is ported in
|
|
20
|
+
we add tests, but the approach is constrained by the recovery context:
|
|
21
|
+
|
|
22
|
+
- We cannot TDD pre-existing behaviour. Instead, write **characterisation
|
|
23
|
+
tests** that pin down current observable behaviour on representative
|
|
24
|
+
inputs. These are the safety net that lets us merge the four divergent
|
|
25
|
+
forks and refactor afterwards.
|
|
26
|
+
- Prefer small hand-crafted fixtures (a few bytes, a tiny `.asm` file) over
|
|
27
|
+
full ROM dumps — fast, reviewable, and easy to reason about.
|
|
28
|
+
- For modules that emit assembly source, write **round-trip tests** that
|
|
29
|
+
assemble the output with `beebasm` and compare the resulting bytes to the
|
|
30
|
+
original input.
|
|
31
|
+
|
|
32
|
+
See `docs/testing.md` for a fuller treatment.
|
|
33
|
+
|
|
34
|
+
## README is generated, not hand-written
|
|
35
|
+
|
|
36
|
+
`README.md` is produced by `scripts/generate_readme.py` from a Jinja2
|
|
37
|
+
template at `scripts/readme_template.md.j2`. The generator imports
|
|
38
|
+
`fantasm.cli.main` and runs it via `click.testing.CliRunner` (inside
|
|
39
|
+
`isolated_filesystem`, with `COLUMNS=80` / `NO_COLOR=1` and
|
|
40
|
+
`FANTASM_PROJECT_ROOT` cleared) to capture deterministic `--help` text
|
|
41
|
+
and a sample `info` table.
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
uv run python scripts/generate_readme.py # regenerate README.md
|
|
45
|
+
uv run python scripts/generate_readme.py --check # verify; prints diff + exits 1 on drift
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
A pre-commit hook (`.pre-commit-config.yaml`) runs the `--check`
|
|
49
|
+
variant whenever `README.md`, the generator, the template, or any
|
|
50
|
+
`src/fantasm/*.py` changes — so editing the public CLI surface forces
|
|
51
|
+
a README regeneration before the commit lands. First-time setup in a
|
|
52
|
+
fresh clone:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
uv run pre-commit install
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
A `readme-check` job in `.github/workflows/ci.yml` runs the same
|
|
59
|
+
`--check` on every push and PR as a safety net for contributors who
|
|
60
|
+
bypass the local hook. **Never hand-edit `README.md`** — edit the
|
|
61
|
+
template (or the generator, or the CLI source) and re-run the
|
|
62
|
+
generator.
|
|
63
|
+
|
|
64
|
+
## External tooling assumed available
|
|
65
|
+
|
|
66
|
+
- **py8dis** (the disassembler that produces the JSON / ASM /
|
|
67
|
+
driver-script artefacts fantasm operates on) — a workflow
|
|
68
|
+
prerequisite, **not** a runtime dependency of fantasm. Users are
|
|
69
|
+
expected to have it installed in their development environment to
|
|
70
|
+
generate disassembly output; fantasm consumes the artefacts and
|
|
71
|
+
never imports the package. Currently a private fork at
|
|
72
|
+
https://github.com/acornaeology/py8dis; will eventually be
|
|
73
|
+
published on PyPI as `msabeeb`. Don't list it in `[project]
|
|
74
|
+
dependencies` — PyPI rejects direct git-URL deps and fantasm
|
|
75
|
+
doesn't actually link against it.
|
|
76
|
+
- **beebasm** (the BBC Micro 6502 cross-assembler) — assumed on `PATH`.
|
|
77
|
+
Tests obtain its location via the `beebasm_filepath` fixture in
|
|
78
|
+
`tests/conftest.py` and skip cleanly when it is absent.
|
|
79
|
+
- **uv** for dependency management. Use `uv sync` and `uv run`.
|
|
80
|
+
|
|
81
|
+
## Project-root resolution
|
|
82
|
+
|
|
83
|
+
Three-step lookup, highest priority first:
|
|
84
|
+
|
|
85
|
+
1. `--project-root` on the top-level `fantasm` group
|
|
86
|
+
2. `FANTASM_PROJECT_ROOT` environment variable
|
|
87
|
+
3. Walk upwards from cwd looking for `fantasm.toml`
|
|
88
|
+
|
|
89
|
+
Commands that need a project root should check `ctx.obj["project"].has_root`
|
|
90
|
+
and fail with a clear message if unresolved.
|
|
91
|
+
|
|
92
|
+
## Output formatting
|
|
93
|
+
|
|
94
|
+
Commands that produce structured results use `asyoulikeit.report_output`,
|
|
95
|
+
which gives them a uniform `--as display|tsv|json` story. See
|
|
96
|
+
`src/fantasm/cli.py::info` for the canonical pattern. When a command needs
|
|
97
|
+
the Click context, use `click.get_current_context()` inside the body
|
|
98
|
+
rather than mixing `@click.pass_context` with `@report_output`.
|
|
99
|
+
|
|
100
|
+
## Versioning and releases
|
|
101
|
+
|
|
102
|
+
Version is managed via `bump-my-version` (configured in `pyproject.toml`
|
|
103
|
+
under `[tool.bumpversion]`). The single source of truth is `__version__`
|
|
104
|
+
in `src/fantasm/__init__.py`; hatchling reads it dynamically via
|
|
105
|
+
`[tool.hatch.version]` and exposes it as the wheel's installed version.
|
|
106
|
+
Do not edit the version by hand in more than one place — let
|
|
107
|
+
`bump-my-version` update both the module and the
|
|
108
|
+
`[tool.bumpversion] current_version` copy in lock-step.
|
|
109
|
+
|
|
110
|
+
Release flow (on a clean working tree, from `master`):
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
uv run bump-my-version bump --dry-run --verbose patch # preview
|
|
114
|
+
uv run bump-my-version bump patch # or `minor` / `major`
|
|
115
|
+
git push --follow-tags # publish commit + v<X.Y.Z> tag
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Each real bump produces one commit (`Bump version: X.Y.Z → X.Y.Z+1`) and
|
|
119
|
+
one annotated tag (`vX.Y.Z+1`). bump-my-version refuses to run with a
|
|
120
|
+
dirty tree — that is the intended safety net.
|
|
121
|
+
|
|
122
|
+
A `release.yml` workflow triggers on `v*` tags (the ones
|
|
123
|
+
`bump-my-version` produces) plus manual `workflow_dispatch`. Two
|
|
124
|
+
parallel gates — the full test matrix from `test.yml` and the
|
|
125
|
+
README-sync check from `readme-check.yml` — feed a single
|
|
126
|
+
`publish-pypi` job. Nothing is published unless **both** gates are
|
|
127
|
+
green. PyPI publication uses `uv publish` with `UV_PUBLISH_TOKEN`
|
|
128
|
+
from the `PYPI_TOKEN` repo secret, scoped to the `pypi` GitHub
|
|
129
|
+
deployment environment. To release: bump the version, push the
|
|
130
|
+
`v<X.Y.Z>` tag, watch the Actions UI. A failed publish can be
|
|
131
|
+
re-attempted via the **Run workflow** button.
|
|
132
|
+
|
|
133
|
+
## Naming conventions
|
|
134
|
+
|
|
135
|
+
- Use `_filename`, `_filepath`, `_dirpath`, `_dirname` suffixes; avoid the
|
|
136
|
+
ambiguous `_dir` / `_file` suffixes.
|
|
137
|
+
- Keep code comments and commit messages free of references to specific AI
|
|
138
|
+
tools or model providers.
|
fantasm-0.1.2/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Robert Smallshire
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
fantasm-0.1.2/PKG-INFO
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: fantasm
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: Fantasm — the Fantastic (dis-/re-)Assembly tools for 6502 code
|
|
5
|
+
Author: Robert Smallshire
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: MacOS
|
|
12
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
13
|
+
Classifier: Operating System :: POSIX
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Topic :: Software Development :: Disassemblers
|
|
18
|
+
Requires-Python: >=3.12
|
|
19
|
+
Requires-Dist: asyoulikeit>=0.1
|
|
20
|
+
Requires-Dist: click>=8.1
|
|
21
|
+
Requires-Dist: networkx>=3.0
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
24
|
+
# Fantasm
|
|
25
|
+
|
|
26
|
+
The Fantastic (dis-/re-)Assembly tools for 6502 code, version `0.1.2`.
|
|
27
|
+
|
|
28
|
+
Fantasm is a consolidated suite of tools for working on annotated
|
|
29
|
+
disassemblies of 6502-based ROMs (originally those from the Acorn / BBC
|
|
30
|
+
Microcomputer family). It brings together capabilities that previously
|
|
31
|
+
lived in per-project forks under the `acornaeology` umbrella, behind a
|
|
32
|
+
single `fantasm` command and a programmatic `fantasm.api` package.
|
|
33
|
+
|
|
34
|
+
## Status
|
|
35
|
+
|
|
36
|
+
Early scaffolding. The CLI shell is in place; the consolidation of
|
|
37
|
+
per-project tools into `fantasm` is in progress.
|
|
38
|
+
|
|
39
|
+
## Install (development)
|
|
40
|
+
|
|
41
|
+
```sh
|
|
42
|
+
uv sync
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## CLI
|
|
46
|
+
|
|
47
|
+
```console
|
|
48
|
+
$ fantasm --help
|
|
49
|
+
Usage: fantasm [OPTIONS] COMMAND [ARGS]...
|
|
50
|
+
|
|
51
|
+
Fantasm — the Fantastic (dis-/re-)Assembly tools for 6502 code.
|
|
52
|
+
|
|
53
|
+
Options:
|
|
54
|
+
--version Show the version and exit.
|
|
55
|
+
--project-root DIRECTORY Project root directory. Overrides
|
|
56
|
+
FANTASM_PROJECT_ROOT. If neither is given, fantasm
|
|
57
|
+
searches upwards from the current directory for a
|
|
58
|
+
fantasm.toml.
|
|
59
|
+
-h, --help Show this message and exit.
|
|
60
|
+
|
|
61
|
+
Commands:
|
|
62
|
+
addresses Address translation across ROM versions.
|
|
63
|
+
annotations Cross-version annotation diff and management.
|
|
64
|
+
asm Assembly-source extraction and inspection.
|
|
65
|
+
audit Subroutine annotation audit.
|
|
66
|
+
backfill Propose annotation propagations from SOURCE_VERSION to...
|
|
67
|
+
cfg Inter-procedural call-graph queries.
|
|
68
|
+
comments Comment / annotation consistency checks.
|
|
69
|
+
compare Compare two ROM versions at byte / opcode / full-instruction...
|
|
70
|
+
context Code context queries (depth, sub-context, uncommented gaps).
|
|
71
|
+
fingerprint Fingerprint each block of a ROM version's bytes and report...
|
|
72
|
+
info Show the resolved project context.
|
|
73
|
+
labels Auto-generated label classification and renaming.
|
|
74
|
+
lint Validate that a driver script's annotation addresses...
|
|
75
|
+
project Initialise and manage fantasm projects.
|
|
76
|
+
promote Score labelled code items as candidates for promotion to...
|
|
77
|
+
shared Find shared 6502 code fragments between a primary ROM and...
|
|
78
|
+
sub Subroutine workflow helpers.
|
|
79
|
+
verify Verify a disassembly round-trips: assemble its .asm with...
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
The top-level `fantasm` command accepts a `--project-root` option and
|
|
83
|
+
also reads `FANTASM_PROJECT_ROOT` from the environment. When neither is
|
|
84
|
+
given, fantasm walks upwards from the current working directory looking
|
|
85
|
+
for a `fantasm.toml` to identify the project root.
|
|
86
|
+
|
|
87
|
+
### `fantasm info`
|
|
88
|
+
|
|
89
|
+
The `info` sub-command shows the resolved project context for the
|
|
90
|
+
current invocation. Like every fantasm command that produces structured
|
|
91
|
+
output, it inherits a uniform `--as display | tsv | json` story (and
|
|
92
|
+
friends) from
|
|
93
|
+
[asyoulikeit](https://github.com/sixty-north/asyoulikeit):
|
|
94
|
+
|
|
95
|
+
```console
|
|
96
|
+
$ fantasm info --help
|
|
97
|
+
Usage: fantasm info [OPTIONS]
|
|
98
|
+
|
|
99
|
+
Show the resolved project context.
|
|
100
|
+
|
|
101
|
+
Options:
|
|
102
|
+
Report Output Options:
|
|
103
|
+
--no-reports Suppress all report output. The handler still runs
|
|
104
|
+
(useful for action commands whose reports are
|
|
105
|
+
incidental); only rendering is skipped. Mutually
|
|
106
|
+
exclusive with --report and --all-reports.
|
|
107
|
+
--all-reports Render every report the handler returns,
|
|
108
|
+
regardless of the command's default_reports.
|
|
109
|
+
Useful for commands whose default is a subset (or
|
|
110
|
+
silent) but where you want the full picture this
|
|
111
|
+
time. Mutually exclusive with --report and --no-
|
|
112
|
+
reports.
|
|
113
|
+
--report [project] Report name(s) to display (can be specified
|
|
114
|
+
multiple times). Shows all if omitted. Valid
|
|
115
|
+
values: project.
|
|
116
|
+
--header / --no-header Include column headers in output. Overrides each
|
|
117
|
+
report's default. Format-specific: TSV prefixes
|
|
118
|
+
first cell with '#', display omits
|
|
119
|
+
headers/title/caption, JSON ignores this flag.
|
|
120
|
+
--detailed / --essential Include detailed columns or only essential
|
|
121
|
+
columns. Auto-detects based on output format if
|
|
122
|
+
not specified.
|
|
123
|
+
--as [display|json|tsv] Output format for tabular data. Defaults to
|
|
124
|
+
'display' for terminals, 'tsv' for pipes.
|
|
125
|
+
-h, --help Show this message and exit.
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Sample output (an explicit project root that does not contain a
|
|
129
|
+
`fantasm.toml`):
|
|
130
|
+
|
|
131
|
+
```console
|
|
132
|
+
$ fantasm --project-root /path/to/your/project info
|
|
133
|
+
Fantasm project
|
|
134
|
+
┏━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
135
|
+
┃ Key ┃ Value ┃
|
|
136
|
+
┡━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩
|
|
137
|
+
│ project_root │ /path/to/your/project │
|
|
138
|
+
│ config_filepath │ (none) │
|
|
139
|
+
│ config_keys │ (empty) │
|
|
140
|
+
└─────────────────┴───────────────────────┘
|
|
141
|
+
Resolved project context for the current
|
|
142
|
+
invocation.
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
The same invocation through a pipe (or with `--as tsv`) emits
|
|
146
|
+
tab-separated output suitable for downstream tooling:
|
|
147
|
+
|
|
148
|
+
```console
|
|
149
|
+
$ fantasm --project-root /path/to/your/project info --as tsv
|
|
150
|
+
# Key Value
|
|
151
|
+
project_root /path/to/your/project
|
|
152
|
+
config_filepath (none)
|
|
153
|
+
config_keys (empty)
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Programmatic API
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
from fantasm.api import ... # surface filled in as modules are ported
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Testing
|
|
163
|
+
|
|
164
|
+
The codebase fantasm consolidates is untested. As modules are ported in,
|
|
165
|
+
fantasm adds **characterisation tests** that pin down observable
|
|
166
|
+
behaviour on representative inputs — these are the safety net for
|
|
167
|
+
merging the four upstream forks. Modules that emit 6502 assembly source
|
|
168
|
+
are exercised with **round-trip tests** that re-assemble the output with
|
|
169
|
+
`beebasm` and compare bytes; the `beebasm_filepath` pytest fixture skips
|
|
170
|
+
such tests when the assembler is not on `PATH`. See `docs/testing.md`
|
|
171
|
+
for the patterns and `CLAUDE.md` for the project-level guidance.
|
|
172
|
+
|
|
173
|
+
## Layout
|
|
174
|
+
|
|
175
|
+
```
|
|
176
|
+
src/fantasm/ the package
|
|
177
|
+
src/fantasm/cli.py Click entrypoint
|
|
178
|
+
src/fantasm/api/ programmatic API (re-exports the public surface)
|
|
179
|
+
src/fantasm/config.py project-root resolution + fantasm.toml loading
|
|
180
|
+
tests/ pytest suite (with shared fixtures in conftest.py)
|
|
181
|
+
docs/ user and developer documentation
|
|
182
|
+
scripts/ README generator + Jinja2 template
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Related projects
|
|
186
|
+
|
|
187
|
+
- [py8dis (fork)](https://github.com/acornaeology/py8dis) — the tracing
|
|
188
|
+
disassembler fantasm builds on top of (will eventually become
|
|
189
|
+
`msabeeb`).
|
|
190
|
+
- The four sibling repositories under `acornaeology` from which fantasm
|
|
191
|
+
draws its initial tooling: `acorn-6502-tube-client`, `acorn-adfs`,
|
|
192
|
+
`acorn-econet-bridge`, `acorn-nfs`.
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
This README is generated from `scripts/readme_template.md.j2` by
|
|
197
|
+
`scripts/generate_readme.py`. **Do not edit it directly** — edit the
|
|
198
|
+
template (or the generator, or the source files whose output it
|
|
199
|
+
captures) and re-run `uv run python scripts/generate_readme.py`. The
|
|
200
|
+
pre-commit hook and the `readme-check` CI job both run the
|
|
201
|
+
generator's `--check` mode and will refuse stale READMEs.
|