exportify 0.1.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.
Files changed (50) hide show
  1. exportify-0.1.0/.gitignore +232 -0
  2. exportify-0.1.0/LICENSE-Apache-2.0 +1 -0
  3. exportify-0.1.0/LICENSE-MIT +1 -0
  4. exportify-0.1.0/LICENSES/Apache-2.0.txt +73 -0
  5. exportify-0.1.0/LICENSES/MIT.txt +18 -0
  6. exportify-0.1.0/PKG-INFO +32 -0
  7. exportify-0.1.0/README.md +233 -0
  8. exportify-0.1.0/pyproject.toml +201 -0
  9. exportify-0.1.0/src/exportify/__init__.py +80 -0
  10. exportify-0.1.0/src/exportify/_version.py +9 -0
  11. exportify-0.1.0/src/exportify/analysis/__init__.py +10 -0
  12. exportify-0.1.0/src/exportify/analysis/ast_parser.py +389 -0
  13. exportify-0.1.0/src/exportify/analysis/ast_parser_overload.py +113 -0
  14. exportify-0.1.0/src/exportify/cli.py +54 -0
  15. exportify-0.1.0/src/exportify/commands/__init__.py +53 -0
  16. exportify-0.1.0/src/exportify/commands/check.py +355 -0
  17. exportify-0.1.0/src/exportify/commands/clear_cache.py +47 -0
  18. exportify-0.1.0/src/exportify/commands/doctor.py +79 -0
  19. exportify-0.1.0/src/exportify/commands/fix.py +220 -0
  20. exportify-0.1.0/src/exportify/commands/generate.py +177 -0
  21. exportify-0.1.0/src/exportify/commands/init.py +98 -0
  22. exportify-0.1.0/src/exportify/commands/status.py +78 -0
  23. exportify-0.1.0/src/exportify/commands/utils.py +261 -0
  24. exportify-0.1.0/src/exportify/common/__init__.py +7 -0
  25. exportify-0.1.0/src/exportify/common/cache.py +422 -0
  26. exportify-0.1.0/src/exportify/common/config.py +218 -0
  27. exportify-0.1.0/src/exportify/common/types.py +500 -0
  28. exportify-0.1.0/src/exportify/discovery/__init__.py +10 -0
  29. exportify-0.1.0/src/exportify/discovery/file_discovery.py +158 -0
  30. exportify-0.1.0/src/exportify/export_manager/__init__.py +44 -0
  31. exportify-0.1.0/src/exportify/export_manager/file_writer.py +325 -0
  32. exportify-0.1.0/src/exportify/export_manager/generator.py +531 -0
  33. exportify-0.1.0/src/exportify/export_manager/graph.py +360 -0
  34. exportify-0.1.0/src/exportify/export_manager/module_all.py +500 -0
  35. exportify-0.1.0/src/exportify/export_manager/rules.py +260 -0
  36. exportify-0.1.0/src/exportify/export_manager/section_parser.py +406 -0
  37. exportify-0.1.0/src/exportify/migration.py +486 -0
  38. exportify-0.1.0/src/exportify/pipeline.py +287 -0
  39. exportify-0.1.0/src/exportify/py.typed +0 -0
  40. exportify-0.1.0/src/exportify/rules/README.md +437 -0
  41. exportify-0.1.0/src/exportify/rules/default_rules.yaml +248 -0
  42. exportify-0.1.0/src/exportify/schemas/exportify-config.schema.json +148 -0
  43. exportify-0.1.0/src/exportify/types.py +37 -0
  44. exportify-0.1.0/src/exportify/utils.py +128 -0
  45. exportify-0.1.0/src/exportify/validator/__init__.py +20 -0
  46. exportify-0.1.0/src/exportify/validator/consistency.py +187 -0
  47. exportify-0.1.0/src/exportify/validator/resolver.py +118 -0
  48. exportify-0.1.0/src/exportify/validator/validator.py +531 -0
  49. exportify-0.1.0/src/exportify/verify.sh +75 -0
  50. exportify-0.1.0/tests/README.md +80 -0
@@ -0,0 +1,232 @@
1
+ # SPDX-FileCopyrightText: 2025 Knitli Inc.
2
+ # SPDX-FileContributor: Adam Poulemanos <adam@knit.li>
3
+ #
4
+ # SPDX-License-Identifier: MIT OR Apache-2.0
5
+
6
+ # local configs
7
+ .claude/*.local.*
8
+ **/*.local.*
9
+ **/*.local.*.license
10
+ mise.local.toml
11
+ mise.*.local.toml
12
+ mise.local.toml.license
13
+ mise.*.local.toml.license
14
+ hk.local.pkl.license
15
+ .ruff_cache
16
+ .roo/mcp.json
17
+ # local terminal zsh config -- can contain sensitive info
18
+ .vscode/terminal.local.zsh
19
+ *mcp*.backup*
20
+
21
+ # CLAUDE.md -- we symlink this file from AGENTS.md in the setup script
22
+ CLAUDE.md
23
+ GEMINI.md
24
+
25
+ # non-public working files
26
+ .workbench/
27
+ .devenv/
28
+ .testbuild/
29
+ .history
30
+ .temp/
31
+
32
+ # Workspace files
33
+ *.code-workspace
34
+ *.code-workspace.license
35
+
36
+ # mkdocs
37
+ .cache
38
+
39
+ # Playwright
40
+ logs
41
+ _.log
42
+ report.[0-9]_[0-9]_[0-9]_[0-9]_.json
43
+ out
44
+ dist/
45
+ *.tgz
46
+ coverage
47
+ *.lcov
48
+ .env
49
+ *.local.*
50
+ *.local
51
+ .eslintcache
52
+ .cache
53
+ !.cache/uv/
54
+ *.tsbuildinfo
55
+ **/dist/
56
+
57
+ # venv
58
+ **/.venv
59
+ .venv/
60
+
61
+ # node and docs-site
62
+ node_modules/
63
+ **/node_modules/
64
+ docs-site/dist/
65
+ docs-site/.cache/
66
+ docs-site/.astro/
67
+
68
+ # Cache files
69
+ **/__pycache__/
70
+ **/.pytest_cache/
71
+ __pycache__/
72
+ .pytest_cache/
73
+ .eslintcache
74
+ # Visual Studio cache files
75
+ # files ending in .cache can be ignored
76
+ *.[Cc]ache
77
+ .pytest_cache
78
+
79
+ dist/
80
+ site/
81
+ *.tar
82
+ *.tar.*
83
+ *.jar
84
+ *.exe
85
+ *.msi
86
+ *.zip
87
+ *.tgz
88
+ *.log
89
+ *.log.*
90
+ *.sig
91
+
92
+ .DS_Store
93
+ *.swp
94
+
95
+ # Installer logs
96
+ pip-log.txt
97
+ pip-delete-this-directory.txt
98
+
99
+ # Local config
100
+ ipython_config.py
101
+
102
+ # Environments
103
+ .env
104
+ .venv
105
+ env/
106
+ venv/
107
+ ENV/
108
+ env.bak/
109
+ venv.bak/
110
+
111
+ # Build results
112
+ [Dd]ebug/
113
+ [Dd]ebugPublic/
114
+ [Rr]elease/
115
+ [Rr]eleases/
116
+ x64/
117
+ x86/
118
+ [Ww][Ii][Nn]32/
119
+ [Aa][Rr][Mm]/
120
+ [Aa][Rr][Mm]64/
121
+ bld/
122
+ [Oo]bj/
123
+ [Ll]og/
124
+ [Ll]ogs/
125
+
126
+ # Files built by Visual Studio
127
+ *_i.c
128
+ *_p.c
129
+ *_h.h
130
+ *.ilk
131
+ *.meta
132
+ *.obj
133
+ *.iobj
134
+ *.pch
135
+ *.pdb
136
+ *.ipdb
137
+ *.pgc
138
+ *.pgd
139
+ *.rsp
140
+ *.sbr
141
+ *.tlb
142
+ *.tli
143
+ *.tlh
144
+ *.tmp
145
+ *.tmp_proj
146
+ *_wpftmp.csproj
147
+ *.log
148
+ *.tlog
149
+ *.vspscc
150
+ *.vssscc
151
+ .builds
152
+ *.pidb
153
+ *.svclog
154
+ *.scc
155
+
156
+ # Including strong name files can present a security risk
157
+ # (https://github.com/github/gitignore/pull/2483#issue-259490424)
158
+ *.snk
159
+
160
+ # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
161
+ bower_components/
162
+
163
+ # Local History for Visual Studio Code
164
+ .history/
165
+ lib64/
166
+ remote-debug-profile/
167
+
168
+ # zcomp and zhistory files
169
+ .vscode/zsh/.zcompdump
170
+ .vscode/zsh/.zcompdump-*
171
+ .vscode/zsh/.zsh_history
172
+
173
+ __pycache__/
174
+ **/.pytest_cache/
175
+ .pytest_cache/
176
+ # //!SECTION EXCEPTIONS -- Put all inverted ("!") rules at the end of the file!
177
+
178
+ # but keep track of directories ending in .cache
179
+ !?*.[Cc]ache/
180
+
181
+ # Leave launch.json public
182
+ !.vscode/launch.json
183
+ !.vscode/launch.json.license
184
+
185
+ # Leave settings.json and workspace zshrc/init public
186
+ !.vscode/tasks.json
187
+ !.vscode/tasks.json.license
188
+ !.vscode/extensions.json
189
+ !.vscode/extensions.json.license
190
+ !.vscode/mcp.json
191
+ !.vscode/mcp.json.license
192
+ !.vscode/settings.json
193
+ !.vscode/settings.json.license
194
+ !.vscode/terminal.extra.zsh
195
+ !.vscode/terminal.extra.zsh.example
196
+ !.vscode/zsh/.zshrc
197
+
198
+ # project-level git files that should be public and easily get caught in ignores
199
+ !.gitattributes
200
+ !.gitconfig.license
201
+ !.gitignore
202
+ !.gitconfig
203
+ !.mailmap
204
+
205
+ !.cache/uv/
206
+
207
+ # Generated Files
208
+ **/htmlcov/
209
+ .coverage
210
+ .coveragexml
211
+ .vscode/.history/
212
+ coverage.xml
213
+ docs-site/dist/
214
+ htmlcov/
215
+ lcov-report/
216
+ server.json
217
+ server.json.license
218
+ server.yaml
219
+ server.yaml.license
220
+ test-results.xml
221
+
222
+ .jj/
223
+
224
+ # Finally, stuff we *really* don't want to let leak
225
+ .local.env
226
+ mise.local.toml
227
+ mise.local.env
228
+
229
+ .gemini/
230
+ gha-creds-*.json
231
+
232
+ src/exportify/_version.py
@@ -0,0 +1 @@
1
+ ./LICENSES/Apache-2.0.txt
@@ -0,0 +1 @@
1
+ ./LICENSES/MIT.txt
@@ -0,0 +1,73 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
10
+
11
+ "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
12
+
13
+ "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
14
+
15
+ "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
16
+
17
+ "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
18
+
19
+ "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
20
+
21
+ "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
22
+
23
+ "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
24
+
25
+ "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
26
+
27
+ "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
28
+
29
+ 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
30
+
31
+ 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
32
+
33
+ 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
34
+
35
+ (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
36
+
37
+ (b) You must cause any modified files to carry prominent notices stating that You changed the files; and
38
+
39
+ (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
40
+
41
+ (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
42
+
43
+ You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
44
+
45
+ 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
46
+
47
+ 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
48
+
49
+ 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
50
+
51
+ 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
52
+
53
+ 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
54
+
55
+ END OF TERMS AND CONDITIONS
56
+
57
+ APPENDIX: How to apply the Apache License to your work.
58
+
59
+ To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
60
+
61
+ Copyright 2026 Knitli Inc.
62
+
63
+ Licensed under the Apache License, Version 2.0 (the "License");
64
+ you may not use this file except in compliance with the License.
65
+ You may obtain a copy of the License at
66
+
67
+ http://www.apache.org/licenses/LICENSE-2.0
68
+
69
+ Unless required by applicable law or agreed to in writing, software
70
+ distributed under the License is distributed on an "AS IS" BASIS,
71
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
72
+ See the License for the specific language governing permissions and
73
+ limitations under the License.
@@ -0,0 +1,18 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Knitli Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
6
+ associated documentation files (the "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
9
+ following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all copies or substantial
12
+ portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
15
+ LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
16
+ EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
18
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,32 @@
1
+ Metadata-Version: 2.4
2
+ Name: exportify
3
+ Version: 0.1.0
4
+ Summary: Export, __all__, and lazy import management for Python projects.
5
+ Project-URL: Homepage, https://github.com/knitli/exportify
6
+ Project-URL: Issues, https://github.com/knitli/exportify/issues
7
+ Project-URL: Repository, https://github.com/knitli/exportify
8
+ Author: Knitli Inc.
9
+ Author-email: Adam Poulemanos <adam@knit.li>
10
+ License-File: LICENSE-Apache-2.0
11
+ License-File: LICENSE-MIT
12
+ License-File: LICENSES/Apache-2.0.txt
13
+ License-File: LICENSES/MIT.txt
14
+ Keywords: __all__,__init__,code-generation,exports,lazy-imports,package-management
15
+ Classifier: Development Status :: 3 - Alpha
16
+ Classifier: Environment :: Console
17
+ Classifier: Intended Audience :: Developers
18
+ Classifier: License :: OSI Approved :: Apache Software License
19
+ Classifier: License :: OSI Approved :: MIT License
20
+ Classifier: Operating System :: OS Independent
21
+ Classifier: Programming Language :: Python :: 3
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Topic :: Software Development :: Code Generators
25
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
26
+ Classifier: Typing :: Typed
27
+ Requires-Python: >=3.12
28
+ Requires-Dist: cyclopts>=4.5.0
29
+ Requires-Dist: lateimport>=0.1.0
30
+ Requires-Dist: pyyaml>=6.0.3
31
+ Requires-Dist: rich>=14.3.0
32
+ Requires-Dist: textcase>=0.4.5
@@ -0,0 +1,233 @@
1
+ <!--
2
+ SPDX-FileCopyrightText: 2026 Knitli Inc.
3
+
4
+ SPDX-License-Identifier: MIT OR Apache-2.0
5
+ -->
6
+
7
+ # exportify
8
+
9
+ **exportify** is a CLI tool and library for managing Python package exports: generating `__init__.py` files with lazy imports (using [`lateimport`](https://github.com/knitli/lateimport)), managing `__all__` declarations, and validating import consistency.
10
+
11
+ Exportify was previously developed as an internal dev tool to assist with our [CodeWeaver](https://github.com/knitli/codeweaver) project; it slowly grew in function until it didn't make sense to keep it as part of that project. Here it is for anyone to use.
12
+
13
+ ## What it Does
14
+
15
+ Exportify **solves the problem of managing consistency and updates in export patterns across a codebase.** It ensures module and package-level `__all__` exports are consistent, accurate, and complete. It can also validate
16
+
17
+ Exportify offers a simple rule-based system for enforcing `__all__` and `__init__` patterns across a codebase with optional per-file overrides. Comes with sane defaults.
18
+
19
+ ## Features
20
+
21
+ - **Lazy `__init__.py` generation** — generates `__init__.py` files using a lazy `__getattr__` pattern powered by [`lateimport`](https://pypi.org/project/lateimport/), keeping package imports fast and circular-import-free
22
+ - **YAML-driven rule engine** — declarative rules control which symbols are exported, with priority ordering and pattern matching
23
+ - **Export propagation** — symbols exported from submodules automatically propagate up the package hierarchy
24
+ - **Code preservation** — manually written code above the `# === MANAGED EXPORTS ===` sentinel is preserved across regeneration
25
+ - **Validation** — checks that lazy import calls are well-formed and that `__all__` declarations are consistent
26
+ - **Cache** — SHA-256-based analysis cache for fast incremental updates
27
+
28
+ ## Installation
29
+
30
+ Easiest to install with [`uv`](https://docs.astral.sh/uv/getting-started/installation/):
31
+
32
+ ```bash
33
+ uv tool install exportify
34
+ ```
35
+
36
+ or `pipx`:
37
+
38
+ ```bash
39
+ pipx install exportify
40
+ ```
41
+
42
+ Python 3.12+ required.
43
+
44
+ ## Quick Start
45
+
46
+ ```bash
47
+ # Create a default config file (.exportify/config.yaml)
48
+ exportify init
49
+
50
+ # Check current state — runs all checks by default
51
+ exportify check
52
+
53
+ # Bootstrap __init__.py files for packages that don't have one
54
+ exportify generate
55
+
56
+ # Preview what fix would change without writing anything
57
+ exportify fix --dry-run
58
+
59
+ # Sync exports and __all__ to match rules
60
+ exportify fix
61
+
62
+ # Show overall export/import health
63
+ exportify status
64
+ ```
65
+
66
+ ## Documentation
67
+
68
+ ### For new users
69
+
70
+ | Document | Description |
71
+ |----------|-------------|
72
+ | [Getting Started](docs/getting-started.md) | Step-by-step tutorial for new projects |
73
+
74
+ ### Reference
75
+
76
+ | Document | Description |
77
+ |----------|-------------|
78
+ | [CLI Reference](docs/cli-reference.md) | Complete command reference with all flags |
79
+ | [Rule Engine](src/exportify/rules/README.md) | Rule syntax, priorities, match criteria, provenance |
80
+ | [Configuration](docs/init.md) | Initializing and configuring exportify |
81
+
82
+ ### Guides
83
+
84
+ | Document | Description |
85
+ |----------|-------------|
86
+ | [Troubleshooting & FAQ](docs/troubleshooting.md) | Common issues and answers |
87
+ | [Contributing](docs/contributing.md) | Development setup and how to contribute |
88
+
89
+ ### Internals (for contributors)
90
+
91
+ | Document | Description |
92
+ |----------|-------------|
93
+ | [Caching](docs/caching.md) | Cache implementation and API |
94
+ | [Overload Handling](docs/overload-handling.md) | `@overload` decorator support |
95
+ | [Provenance Support](docs/provenance.md) | Symbol provenance in rules |
96
+ | [Schema Versioning](docs/schema-versioning.md) | Config schema version management |
97
+
98
+ ## Configuration
99
+
100
+ Rules live in `.exportify/config.yaml` (created by `exportify init` or written manually). Exportify searches for the config file in this order:
101
+
102
+ 1. `EXPORTIFY_CONFIG` environment variable (any path)
103
+ 2. `.exportify/config.yaml`
104
+ 3. `.exportify/config.yml`
105
+ 4. `.exportify.yaml` in the current working directory
106
+ 5. `.exportify.yml`
107
+ 6. `exportify.yaml`
108
+ 7. `exportify.yml`
109
+
110
+ ```yaml
111
+ schema_version: "1.0"
112
+
113
+ rules:
114
+ - name: "exclude-private"
115
+ priority: 1000
116
+ match:
117
+ name_pattern: "^_"
118
+ action: exclude
119
+
120
+ - name: "include-public-classes"
121
+ priority: 700
122
+ match:
123
+ name_pattern: "^[A-Z]"
124
+ member_types: [class]
125
+ action: include
126
+ propagate: root
127
+
128
+ - name: "include-public-functions"
129
+ priority: 700
130
+ match:
131
+ name_pattern: "^[a-z]"
132
+ member_types: [function]
133
+ action: include
134
+ propagate: parent
135
+ ```
136
+
137
+ ### Rule Priority Bands
138
+
139
+ | Priority | Purpose |
140
+ |----------|---------|
141
+ | 1000 | Absolute exclusions (private, dunders) |
142
+ | 900–800 | Infrastructure/framework exclusions |
143
+ | 700 | Primary export rules (classes, functions) |
144
+ | 600–500 | Import handling |
145
+ | 300–400 | Special cases |
146
+ | 0–200 | Defaults/fallbacks |
147
+
148
+ See the [Rule Engine docs](src/exportify/rules/README.md) for the full rule syntax including logical combinations, match criteria, and advanced propagation options.
149
+
150
+ ### Propagation Levels
151
+
152
+ - `none` — export only in the defining module
153
+ - `parent` — export in the defining module and its direct parent
154
+ - `root` — export all the way to the package root
155
+ - `custom` — specify explicit target module
156
+
157
+ ## Generated Output
158
+
159
+ Exportify generates `__init__.py` files using the lazy `__getattr__` pattern from `lateimport`:
160
+
161
+ ```python
162
+ # SPDX-FileCopyrightText: 2026 Your Name
163
+ #
164
+ # SPDX-License-Identifier: MIT
165
+
166
+ # === MANAGED EXPORTS ===
167
+ # This section is automatically generated. Manual edits below this line will be overwritten.
168
+
169
+ from __future__ import annotations
170
+
171
+ from typing import TYPE_CHECKING
172
+ from types import MappingProxyType
173
+
174
+ from lateimport import create_late_getattr
175
+
176
+ if TYPE_CHECKING:
177
+ from mypackage.core import MyClass
178
+ from mypackage.utils import helper_function
179
+
180
+ _dynamic_imports: MappingProxyType[str, tuple[str, str]] = MappingProxyType({
181
+ "MyClass": (__spec__.parent, "core"),
182
+ "helper_function": (__spec__.parent, "utils"),
183
+ })
184
+
185
+ __getattr__ = create_late_getattr(_dynamic_imports, globals(), __name__)
186
+
187
+ __all__ = ("MyClass", "helper_function")
188
+
189
+ def __dir__() -> list[str]:
190
+ """List available attributes for the package."""
191
+ return list(__all__)
192
+ ```
193
+
194
+ > [!IMPORTANT]
195
+ > To use exportify for lazy `__init__` management, you must add `lateimport` as a runtime dependency.
196
+
197
+ ## Code Preservation
198
+
199
+ Add a `# === MANAGED EXPORTS ===` sentinel to an existing `__init__.py` to protect manually written code above it:
200
+
201
+ ```python
202
+ """My package."""
203
+
204
+ from .compat import legacy_function # kept across regeneration
205
+
206
+ # === MANAGED EXPORTS ===
207
+ # ... generated section below (managed by exportify)
208
+ ```
209
+
210
+ Everything above the sentinel is left untouched on every `fix` or `generate` run.
211
+
212
+ ## CLI Reference
213
+
214
+ | Command | Description |
215
+ |---------|-------------|
216
+ | `exportify check` | Check exports and `__all__` declarations for consistency |
217
+ | `exportify fix` | Sync exports and `__all__` to match rules |
218
+ | `exportify generate` | Bootstrap new `__init__.py` files for packages missing one |
219
+ | `exportify status` | Show current export/import health status |
220
+ | `exportify doctor` | Run health checks and provide actionable advice |
221
+ | `exportify init` | Initialize exportify with a default config file |
222
+ | `exportify clear-cache` | Clear the analysis cache |
223
+
224
+ See the [full CLI reference](docs/cli-reference.md) for all flags and options.
225
+
226
+ ## Requirements
227
+
228
+ - Python 3.12+
229
+ - [`lateimport`](https://pypi.org/project/lateimport/) (installed automatically)
230
+
231
+ ## License
232
+
233
+ Dual-licensed under MIT and Apache 2.0. See [LICENSE-MIT](LICENSE-MIT) and [LICENSE-Apache-2.0](LICENSE-Apache-2.0).