splatfold 0.2.0__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.
@@ -0,0 +1,70 @@
1
+ # Changelog
2
+
3
+ All notable changes to Splatfold will be documented here.
4
+
5
+ The project follows Semantic Versioning once its public API is released.
6
+
7
+ ## Unreleased
8
+
9
+ ### Changed
10
+
11
+ - Renamed the project from Obtuse/preprocessor to Splatfold.
12
+ - Added a side-effect-free Python build API and `BuildResult.write()`.
13
+ - Added conventional `__version__` metadata and explicit public exports.
14
+ - Added positional CLI input while retaining `-i` and `--input`.
15
+ - Matched Python's package-before-module import resolution precedence.
16
+ - Kept output writing compatible with Python 3.9.
17
+ - Made output replacement atomic, synchronized file contents before replacement,
18
+ and preserved existing or input-file permissions.
19
+ - Added Python 3.9-3.14 CI, 90% branch-coverage enforcement, distribution package
20
+ checks, and a Trusted Publishing release workflow with commit-pinned actions.
21
+ - Added focused macOS and Windows CI jobs to verify the package's
22
+ operating-system-independent claim.
23
+ - Added Dependabot maintenance for Python tooling and GitHub Actions.
24
+ - Made the wheel smoke test install outside the source checkout so local build
25
+ metadata cannot masquerade as an installed distribution.
26
+ - Added release-tag/version validation, serialized publishing, artifact
27
+ presence checks, and an isolated smoke test of the exact release wheel.
28
+ - The release workflow now reruns lint, formatting, tests, and branch coverage
29
+ against the exact release commit before building publishable artifacts.
30
+ - Checkout credentials are not persisted into CI or release workspaces; the
31
+ workflows pass a dedicated GitHub Actions security audit.
32
+ - Added a required CI job that continuously enforces the GitHub Actions
33
+ security audit instead of relying only on manual release review.
34
+ - Documented the Python API result contract, exception hierarchy, filesystem
35
+ mutation boundary, CLI streams, and exit statuses.
36
+ - Added strict static type checking for the standalone implementation to local,
37
+ CI, and release quality gates, using the newest mypy line that still models
38
+ the supported Python 3.9 syntax target.
39
+ - Added full `pyproject.toml` schema, dependency-version, and SPDX license
40
+ validation to package and release gates.
41
+ - Added wheel-layout validation to local, CI, and release gates.
42
+ - Added an Obtuse-to-Splatfold migration guide covering compatible commands,
43
+ renamed surfaces, corrected prototype behavior, and the new release model.
44
+ - Defined the supported security release line and explicitly retired copied
45
+ Obtuse/preprocessor scripts from security support.
46
+
47
+ ### Fixed
48
+
49
+ - Dependency `__main__` guards with `else` clauses now fail safely instead of
50
+ silently discarding code that normal imports would execute.
51
+ - Encoding-cookie removal no longer mistakes ordinary first-line source text
52
+ containing `coding:` for a declaration.
53
+ - Standalone `BuildResult` values now use safe default permissions when no
54
+ included source path is available.
55
+ - Rewritten wildcard and future imports now reject physical lines shared with
56
+ other statements instead of silently discarding neighboring code.
57
+ - Future-import hoisting now rejects root docstrings that share their final
58
+ physical line with another statement.
59
+ - Included files without a final newline no longer join their last statement
60
+ to the importing file's following source line.
61
+ - Indented comments beginning with `#!` are preserved instead of being
62
+ mistaken for executable shebang lines.
63
+ - Future features are deduplicated individually even when source files group
64
+ them into different multi-feature import statements.
65
+ - User-path expansion and resolution failures now use the stable public error
66
+ hierarchy instead of leaking raw filesystem exceptions.
67
+ - `BuildResult.write()` now revalidates its current source immediately before
68
+ filesystem mutation, including for directly constructed or modified results.
69
+ - Output protection now detects existing filesystem aliases of included source
70
+ files instead of relying only on textual path equality.
@@ -0,0 +1,32 @@
1
+ # Contributing
2
+
3
+ Splatfold keeps its complete runtime implementation in `splatfold.py` so the
4
+ tool itself remains easy to copy and run as one file. Tests, documentation,
5
+ packaging metadata, and automation live beside it.
6
+
7
+ ## Development checks
8
+
9
+ From this directory, run:
10
+
11
+ ```zsh
12
+ python3 -m pip install -e ".[dev,release]"
13
+ ruff check splatfold.py tests
14
+ ruff format --check splatfold.py tests
15
+ mypy splatfold.py
16
+ python3 -m coverage run -m pytest
17
+ python3 -m coverage report
18
+ uvx zizmor .github/workflows
19
+ python3 -m compileall -q splatfold.py
20
+ validate-pyproject pyproject.toml
21
+ python3 -m build
22
+ python3 -m twine check dist/*
23
+ check-wheel-contents dist/*.whl
24
+ ```
25
+
26
+ Changes to resolution or rendering semantics must include a focused regression
27
+ test. Tests should compare generated behavior with normal Python behavior when
28
+ Splatfold claims equivalence, and should make intentional differences explicit.
29
+
30
+ Before a release, install the built wheel into a clean virtual environment and
31
+ use that installed CLI—not the source checkout—to fold and run the Acute
32
+ integration fixture.
@@ -0,0 +1,58 @@
1
+ # Splatfold design contract
2
+
3
+ Splatfold is a source preprocessor, not an import-system emulator. It gives a
4
+ restricted set of valid Python wildcard imports an additional build-time
5
+ meaning: include the referenced local source once at the import location.
6
+
7
+ ## Invariants
8
+
9
+ 1. Development sources remain valid Python and continue to work without
10
+ Splatfold when their ordinary imports are valid.
11
+ 2. Project source is read and parsed, never imported or executed during a
12
+ build.
13
+ 3. Only module-level `from ... import *` statements are candidates for local
14
+ inclusion. Every other import is preserved.
15
+ 4. A source file is emitted at most once. Active recursion edges are reported
16
+ as cycles and omitted from the generated module.
17
+ 5. The generated source is UTF-8 and is compiled for syntax validity both when
18
+ built and immediately before it can be written.
19
+ 6. Writing is explicit in the Python API and atomic with respect to the final
20
+ destination path.
21
+ 7. The input and every included source path are protected from accidental
22
+ output overwrite, including filesystem aliases of the same file.
23
+ 8. The implementation remains a standalone standard-library-only Python file.
24
+
25
+ ## Resolution
26
+
27
+ Absolute imports are searched in `root` followed by each configured search
28
+ path. Relative imports are resolved from the importing file. On each path
29
+ entry, `name/__init__.py` takes precedence over `name.py`, matching Python.
30
+
31
+ An unresolved wildcard import is preserved by default because it may refer to
32
+ the standard library or an installed dependency. Strict mode rejects it.
33
+
34
+ ## Rendering
35
+
36
+ Inclusion is depth-first at the original import location. Dependency shebangs
37
+ and encoding cookies are removed. The root shebang is retained and the output
38
+ declares UTF-8. Future imports are deduplicated and hoisted after the root
39
+ module docstring.
40
+
41
+ Conventional dependency `if __name__ == "__main__":` blocks without `else`
42
+ are removed by default. A guard with `else` is rejected because deleting the
43
+ whole statement would discard code that normal importing executes.
44
+
45
+ Statements that Splatfold removes or replaces must occupy their own physical
46
+ lines. A trailing comment is allowed. Sharing such a line with another Python
47
+ statement is rejected explicitly rather than risking silent loss of code.
48
+
49
+ ## Intentional limits
50
+
51
+ All included definitions share one global namespace. Per-module values of
52
+ `__name__`, `__package__`, `__file__`, module dictionaries, `sys.modules`
53
+ entries, import hooks, and initialization isolation are not reproduced.
54
+ `__all__` remains ordinary source metadata but does not hide code that has been
55
+ physically included.
56
+
57
+ These limits are fundamental to source folding and must remain visible in user
58
+ documentation and tests.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 WithoutSophie
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.
@@ -0,0 +1,9 @@
1
+ include CHANGELOG.md
2
+ include CONTRIBUTING.md
3
+ include DESIGN.md
4
+ include LICENSE
5
+ include MIGRATING.md
6
+ include RELEASING.md
7
+ include SECURITY.md
8
+ include readme.md
9
+ recursive-include tests *.py
@@ -0,0 +1,66 @@
1
+ # Migrating from Obtuse
2
+
3
+ Splatfold is the production continuation of the project previously published
4
+ on GitHub as **Obtuse**. It keeps the wildcard-include model while replacing
5
+ the prototype's script-only release process with a tested Python distribution.
6
+
7
+ ## Source compatibility
8
+
9
+ Existing module-level directives remain valid:
10
+
11
+ ```python
12
+ from module import *
13
+ from package.module import *
14
+ from .local import *
15
+ ```
16
+
17
+ The original `-i` and `--input` CLI forms remain supported, along with the
18
+ output, root, search-path, strictness, marker, tracing, dependency-listing, and
19
+ check-only behavior. The preferred form now uses a positional input:
20
+
21
+ ```zsh
22
+ splatfold main.py -o dist/app.py
23
+ ```
24
+
25
+ ## Names that changed
26
+
27
+ - The command and standalone implementation are now named `splatfold` and
28
+ `splatfold.py`; no `preprocessor` or `obtuse` package is installed.
29
+ - Generated comments identify `splatfold` instead of the prototype script.
30
+ - The importable API is `splatfold.build(...)`, returning a `BuildResult` whose
31
+ `write()` method performs the explicit filesystem mutation.
32
+
33
+ Code that invokes an old checkout as `python3 preprocessor.py ...` should
34
+ install Splatfold and invoke the `splatfold` console command instead. Existing
35
+ automation may keep `-i/--input` while migrating.
36
+
37
+ ## Intentional safety changes
38
+
39
+ Several prototype behaviors were bugs and are not preserved:
40
+
41
+ - When `name.py` and `name/__init__.py` coexist on one search entry, the
42
+ package now wins, matching Python's import system.
43
+ - A dependency `if __name__ == "__main__": ... else: ...` is rejected unless
44
+ `--keep-main-guards` is requested; the prototype silently discarded the
45
+ import-time `else` branch.
46
+ - Wildcard and future imports that share a physical line with another Python
47
+ statement are rejected instead of silently deleting neighboring code.
48
+ - Output writes work on Python 3.9, are atomic, preserve appropriate file
49
+ permissions, and refuse to overwrite any included source.
50
+ - Future features are deduplicated individually and included files missing a
51
+ final newline cannot merge with the importing file's next statement.
52
+
53
+ These changes favor explicit failure over generating code with altered
54
+ semantics. Projects relying on a rejected edge case should first rewrite the
55
+ source into ordinary multi-line Python; `--keep-main-guards` is available only
56
+ when literal guard inclusion is genuinely intended.
57
+
58
+ ## Release and packaging changes
59
+
60
+ Splatfold requires Python 3.9 or newer and has no runtime dependencies outside
61
+ the standard library. Releases provide both a universal wheel and source
62
+ distribution. The version is available as `splatfold.__version__`, and the CLI
63
+ reports the same value with `splatfold --version`.
64
+
65
+ PyPI publication uses GitHub OIDC Trusted Publishing. The obsolete Obtuse
66
+ workflow and long-lived upload tokens must not be reused.