py_launch_blueprint 1.1.3__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,187 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: py_launch_blueprint
|
|
3
|
+
Version: 1.1.3
|
|
4
|
+
Summary: CLI tools for interacting with Py, including project search functionality
|
|
5
|
+
Author: Steve Morin
|
|
6
|
+
Author-email: Steve Morin <steve.morin@gmail.com>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
15
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
16
|
+
Requires-Dist: click>=8.1.0
|
|
17
|
+
Requires-Dist: questionary>=2.0.0
|
|
18
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
19
|
+
Requires-Dist: thefuzz>=0.19.0
|
|
20
|
+
Requires-Dist: python-levenshtein>=0.21.0
|
|
21
|
+
Requires-Dist: pyperclip>=1.8.0
|
|
22
|
+
Requires-Dist: requests>=2.31.0
|
|
23
|
+
Requires-Dist: rich>=13.0.0
|
|
24
|
+
Requires-Python: >=3.12
|
|
25
|
+
Project-URL: Homepage, https://github.com/smorinlabs/py-launch-blueprint
|
|
26
|
+
Project-URL: Repository, https://github.com/smorinlabs/py-launch-blueprint
|
|
27
|
+
Project-URL: Documentation, https://py-launch-blueprint.readthedocs.io/en/latest/
|
|
28
|
+
Project-URL: Changelog, https://github.com/smorinlabs/py-launch-blueprint/blob/main/CHANGELOG.md
|
|
29
|
+
Project-URL: Issues, https://github.com/smorinlabs/py-launch-blueprint/issues
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
<!-- ITM-081 — badges. Single horizontal row (decided round 23). -->
|
|
33
|
+
[](https://pypi.org/project/py-launch-blueprint/)
|
|
34
|
+
[](https://pypi.org/project/py-launch-blueprint/)
|
|
35
|
+
[](https://github.com/smorinlabs/py-launch-blueprint/actions/workflows/ci.yml)
|
|
36
|
+
[](https://codecov.io/gh/smorinlabs/py-launch-blueprint)
|
|
37
|
+
[](LICENSE)
|
|
38
|
+
[](https://github.com/astral-sh/ruff)
|
|
39
|
+
[](https://github.com/astral-sh/uv)
|
|
40
|
+
[](https://www.conventionalcommits.org/)
|
|
41
|
+
|
|
42
|
+
# Py Launch Blueprint: A Production-Ready 🐍 Python Project Template with Integrated Best Practices
|
|
43
|
+
Py Launch Blueprint is a comprehensive Python project template that eliminates setup friction by providing a pre-configured development environment with carefully selected tools for linting, formatting, and type checking. It includes an annotated CLI example and detailed documentation explaining each tool choice and configuration decision, making it an ideal starting point for professional Python projects.
|
|
44
|
+
|
|
45
|
+

|
|
46
|
+
|
|
47
|
+
## Why Choose Py Launch Blueprint?
|
|
48
|
+
|
|
49
|
+
Py Launch Blueprint eliminates the setup friction in Python projects by providing a production-ready template with carefully curated tools and best practices.
|
|
50
|
+
|
|
51
|
+
## Full documentation on ReadTheDocs
|
|
52
|
+
- [py-launch-blueprint Docs](https://py-launch-blueprint.readthedocs.io/en/latest/)
|
|
53
|
+
|
|
54
|
+
### 🚀 Key Features
|
|
55
|
+
|
|
56
|
+
**Zero-config** development environment with **type safety** built in.
|
|
57
|
+
|
|
58
|
+
## ✨ Features TLDR
|
|
59
|
+
- 🛠️ **Dev Tools**: Ruff (linting/formatting), `ty` (type checking, Astral), lefthook (hooks), commitlint
|
|
60
|
+
- 🔒 **Security**: gitleaks (commit/push), TruffleHog (CI), bandit (pre-push + CI), CodeQL
|
|
61
|
+
- 🧠 **AI Ready**: AGENTS.md + CLAUDE.md, default configs for Cursor, Windsurf, Claude Code
|
|
62
|
+
- 💪 **Production**: Python 3.12+, uv + uv_build, PEP 735 dependency-groups, static version
|
|
63
|
+
- 🚀 **DX - Developer Experience**: VS Code DevContainer, sensible defaults, quality documentation
|
|
64
|
+
- 🔄 **CI/CD**: GitHub Actions workflows, release-please version bumps, OIDC trusted publishing
|
|
65
|
+
|
|
66
|
+
## Quick start
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
git clone https://github.com/smorinlabs/py-launch-blueprint.git
|
|
70
|
+
cd py-launch-blueprint
|
|
71
|
+
make hook-check # verify toolchain (lefthook/gitleaks/bun/uv/...)
|
|
72
|
+
scripts/install-bun.sh
|
|
73
|
+
scripts/install-lefthook.sh
|
|
74
|
+
scripts/install-gitleaks.sh
|
|
75
|
+
uv sync --group dev # PEP 735 dev tools
|
|
76
|
+
bun install # commitlint deps
|
|
77
|
+
just check # full quality pipeline
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Install as a tool: `uvx --from py-launch-blueprint py-projects` (uvx needs `--from` because the distribution name differs from the console-script name) or `pip install py-launch-blueprint && py-projects`.
|
|
81
|
+
|
|
82
|
+
See [AGENTS.md](AGENTS.md) for the canonical command set, [.github/CONTRIBUTING.md](.github/CONTRIBUTING.md) for the daily workflow, and [RELEASE.md](RELEASE.md) for the release flow.
|
|
83
|
+
|
|
84
|
+
**Starting a new project from this template?** If you use Claude Code or any agent that reads `AGENTS.md`, just say *"create a new Python project from py-launch-blueprint"* — the [`skill/`](skill/SKILL.md) skill will walk you through `gh repo create --template`, identity collection, `just init` rebrand with preview, and an optional handoff to `just post-init` for publishing/Codecov/ReadTheDocs setup. For humans without an agent: the skill is also a copy-pasteable runbook.
|
|
85
|
+
|
|
86
|
+
### 🎯 Perfect For
|
|
87
|
+
Teams and professionals needing maintainable, type-safe Python projects following best practices.
|
|
88
|
+
|
|
89
|
+
## Complete Feature List
|
|
90
|
+
|
|
91
|
+
### Development Tools
|
|
92
|
+
|
|
93
|
+
- **Bootstrap dependency check and install with `make`**: Execute common development tasks with simple commands, standardizing workflows across team members.
|
|
94
|
+
|
|
95
|
+
- **Command running with `just`**: Define and run project-specific commands with a modern Make alternative, simplifying complex operations with clear syntax.
|
|
96
|
+
|
|
97
|
+
- **Linting with `ruff`**: Catch errors and enforce code style at lightning speed (10-100x faster than traditional linters), reducing waiting time and improving developer productivity.
|
|
98
|
+
|
|
99
|
+
- **Type checking with `mypy`**: Prevent type-related bugs before they occur, making your codebase more robust and easier to maintain as it grows.
|
|
100
|
+
|
|
101
|
+
- **Formatting with `ruff`**: Ensure consistent code style across your project automatically, eliminating style debates and pull request revision cycles.
|
|
102
|
+
|
|
103
|
+
- **Pre-commit hooks with `pre-commit`**: Enforce quality standards before code enters your repository, preventing bad code from ever being committed and reducing technical debt.
|
|
104
|
+
|
|
105
|
+
- **TOML formatting and validation with `taplo`**: Verify Toml files for syntax correctness, maintain consistent configuration files, ensuring readability and avoiding syntax errors in critical project settings.
|
|
106
|
+
|
|
107
|
+
- **YAML validation with [yamllint](docs/source/tools/yaml_lint.md)**: Verify YAML files for syntax correctness, preventing configuration errors and deployment failures.
|
|
108
|
+
|
|
109
|
+
### Project Structure & Management
|
|
110
|
+
|
|
111
|
+
- **Project configuration with `pyproject.toml`**: Organize all project settings in one standardized location, simplifying maintenance and configuration.
|
|
112
|
+
|
|
113
|
+
- **Dependency groups separation**: Organize dependencies into main, dev, and doc categories, preventing bloated installations and clarifying requirements as part of `pyproject.toml` configuration.
|
|
114
|
+
|
|
115
|
+
- **Dependency management with [`uv`](https://docs.astral.sh/uv/)**: Install and manage packages at blazing speed (100x faster than pip/poetry), dramatically reducing environment setup time.
|
|
116
|
+
|
|
117
|
+
- **Build system with `uv_build`**: Build wheel and source distributions with uv's build backend and `uv build`.
|
|
118
|
+
|
|
119
|
+
- **Versioning with explicit project metadata**: Keep release tags aligned with the static version in `pyproject.toml` for predictable package metadata.
|
|
120
|
+
|
|
121
|
+
- **Copyright license automation**: Automatically add license headers to all files, ensuring legal compliance without manual effort.
|
|
122
|
+
|
|
123
|
+
### Documentation
|
|
124
|
+
|
|
125
|
+
- **Documentation with `sphinx + MyST`**: Generate comprehensive documentation that supports both reStructuredText and Markdown, improving contributor accessibility.
|
|
126
|
+
|
|
127
|
+
- **`Read the Docs` integration**: Deploy documentation automatically, providing instant hosting and versioning for your project's documentation.
|
|
128
|
+
|
|
129
|
+
- **Changelog management with `cog`**: Track and communicate changes effectively to users and team members, improving project transparency and adoption.
|
|
130
|
+
|
|
131
|
+
### Testing & Quality Assurance
|
|
132
|
+
|
|
133
|
+
- **Testing framework with `pytest`**: Write and run tests with a modern, powerful testing framework that supports fixtures and parameterization.
|
|
134
|
+
|
|
135
|
+
- **CI/CD with `GitHub Actions`**: Automatically test, build, and deploy your project on multiple Python versions, catching compatibility issues early.
|
|
136
|
+
|
|
137
|
+
- **Matrix testing with `GitHub Actions`**: Run tests across multiple Python versions and operating systems, ensuring broad compatibility.
|
|
138
|
+
|
|
139
|
+
- **Simplified debugging info with `just debug-info`**: Automatically collect and format essential system, tool, and dependency information for streamlined bug reporting via a simple command.
|
|
140
|
+
|
|
141
|
+
### GitHub Integration
|
|
142
|
+
|
|
143
|
+
- **Pull request template**: Guide contributors through the PR process with structured information requirements, improving submission quality.
|
|
144
|
+
|
|
145
|
+
- **Issue templates (Feature, Bug, Documentation)**: Standardize issue reporting with appropriate fields for each type, gathering all necessary information upfront.
|
|
146
|
+
|
|
147
|
+
- **Automated contributor recognition with `contributors-please`**: Automatically update contributor lists, acknowledging all project participants without manual tracking.
|
|
148
|
+
|
|
149
|
+
- **Conventional commits enforced with `commitlint`**: Enforce structured commit messages so `release-please` can automate changelog generation and version bumps.
|
|
150
|
+
|
|
151
|
+
- **Security policy**: Establish clear vulnerability reporting procedures, promoting responsible disclosure and faster security fixes.
|
|
152
|
+
|
|
153
|
+
- **Code of conduct**: Set community behavior expectations, fostering an inclusive and respectful project environment.
|
|
154
|
+
|
|
155
|
+
- **Contributing guidelines**: Provide clear instructions for contributors, reducing friction for new participants.
|
|
156
|
+
|
|
157
|
+
- **Automated dependency security scanning with `codeql`**: Detect vulnerable dependencies automatically, protecting your users from known security issues.
|
|
158
|
+
|
|
159
|
+
- **CLA (Contributor License Agreement) check via [`CLA Assistant`](docs/source/tools/cla-assistant.md)**: Ensure all contributors have signed appropriate licensing agreements, protecting the project legally.
|
|
160
|
+
|
|
161
|
+
### IDE Integration
|
|
162
|
+
|
|
163
|
+
- **VS Code integration**: Provide optimized settings and configurations for Visual Studio Code, enhancing developer productivity.
|
|
164
|
+
|
|
165
|
+
- **PyRight configuration**: Enable accurate, real-time type checking in the editor, catching errors before running tests.
|
|
166
|
+
|
|
167
|
+
- **Editor extensions recommendations**: Suggest optimal VS Code extensions automatically, standardizing the development environment.
|
|
168
|
+
|
|
169
|
+
### AI Integration
|
|
170
|
+
|
|
171
|
+
- **AI assistance with common agents `Cursor, Windsurf, Claude Code, Codex`**: Support popular AI coding assistants enabling AI-powered development.
|
|
172
|
+
|
|
173
|
+
- **Cursor Rules configuration**: Optimize Cursor AI assistant for your specific project structure, improving suggestion relevance.
|
|
174
|
+
|
|
175
|
+
- **Windsurf Rules configuration**: Configure Windsurf IDE to understand your project architecture, enhancing code generation quality.
|
|
176
|
+
|
|
177
|
+
### Communication & Notifications
|
|
178
|
+
|
|
179
|
+
- **Slack integration for PRs and issues**: Send automated notifications to Slack when PRs or issues are opened/closed, keeping the team informed.
|
|
180
|
+
|
|
181
|
+
- **PR reminder notifications**: Ping relevant team members on Slack for PR reviews, reducing review cycle times.
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
Start your next Python project with confidence, knowing you're building on a foundation of best practices and modern development tools.
|
|
185
|
+
|
|
186
|
+
## Full documentation on ReadTheDocs including how to run
|
|
187
|
+
- [py-launch-blueprint Docs](https://py-launch-blueprint.readthedocs.io/en/latest/)
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
<!-- ITM-081 — badges. Single horizontal row (decided round 23). -->
|
|
2
|
+
[](https://pypi.org/project/py-launch-blueprint/)
|
|
3
|
+
[](https://pypi.org/project/py-launch-blueprint/)
|
|
4
|
+
[](https://github.com/smorinlabs/py-launch-blueprint/actions/workflows/ci.yml)
|
|
5
|
+
[](https://codecov.io/gh/smorinlabs/py-launch-blueprint)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
[](https://github.com/astral-sh/ruff)
|
|
8
|
+
[](https://github.com/astral-sh/uv)
|
|
9
|
+
[](https://www.conventionalcommits.org/)
|
|
10
|
+
|
|
11
|
+
# Py Launch Blueprint: A Production-Ready 🐍 Python Project Template with Integrated Best Practices
|
|
12
|
+
Py Launch Blueprint is a comprehensive Python project template that eliminates setup friction by providing a pre-configured development environment with carefully selected tools for linting, formatting, and type checking. It includes an annotated CLI example and detailed documentation explaining each tool choice and configuration decision, making it an ideal starting point for professional Python projects.
|
|
13
|
+
|
|
14
|
+

|
|
15
|
+
|
|
16
|
+
## Why Choose Py Launch Blueprint?
|
|
17
|
+
|
|
18
|
+
Py Launch Blueprint eliminates the setup friction in Python projects by providing a production-ready template with carefully curated tools and best practices.
|
|
19
|
+
|
|
20
|
+
## Full documentation on ReadTheDocs
|
|
21
|
+
- [py-launch-blueprint Docs](https://py-launch-blueprint.readthedocs.io/en/latest/)
|
|
22
|
+
|
|
23
|
+
### 🚀 Key Features
|
|
24
|
+
|
|
25
|
+
**Zero-config** development environment with **type safety** built in.
|
|
26
|
+
|
|
27
|
+
## ✨ Features TLDR
|
|
28
|
+
- 🛠️ **Dev Tools**: Ruff (linting/formatting), `ty` (type checking, Astral), lefthook (hooks), commitlint
|
|
29
|
+
- 🔒 **Security**: gitleaks (commit/push), TruffleHog (CI), bandit (pre-push + CI), CodeQL
|
|
30
|
+
- 🧠 **AI Ready**: AGENTS.md + CLAUDE.md, default configs for Cursor, Windsurf, Claude Code
|
|
31
|
+
- 💪 **Production**: Python 3.12+, uv + uv_build, PEP 735 dependency-groups, static version
|
|
32
|
+
- 🚀 **DX - Developer Experience**: VS Code DevContainer, sensible defaults, quality documentation
|
|
33
|
+
- 🔄 **CI/CD**: GitHub Actions workflows, release-please version bumps, OIDC trusted publishing
|
|
34
|
+
|
|
35
|
+
## Quick start
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
git clone https://github.com/smorinlabs/py-launch-blueprint.git
|
|
39
|
+
cd py-launch-blueprint
|
|
40
|
+
make hook-check # verify toolchain (lefthook/gitleaks/bun/uv/...)
|
|
41
|
+
scripts/install-bun.sh
|
|
42
|
+
scripts/install-lefthook.sh
|
|
43
|
+
scripts/install-gitleaks.sh
|
|
44
|
+
uv sync --group dev # PEP 735 dev tools
|
|
45
|
+
bun install # commitlint deps
|
|
46
|
+
just check # full quality pipeline
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Install as a tool: `uvx --from py-launch-blueprint py-projects` (uvx needs `--from` because the distribution name differs from the console-script name) or `pip install py-launch-blueprint && py-projects`.
|
|
50
|
+
|
|
51
|
+
See [AGENTS.md](AGENTS.md) for the canonical command set, [.github/CONTRIBUTING.md](.github/CONTRIBUTING.md) for the daily workflow, and [RELEASE.md](RELEASE.md) for the release flow.
|
|
52
|
+
|
|
53
|
+
**Starting a new project from this template?** If you use Claude Code or any agent that reads `AGENTS.md`, just say *"create a new Python project from py-launch-blueprint"* — the [`skill/`](skill/SKILL.md) skill will walk you through `gh repo create --template`, identity collection, `just init` rebrand with preview, and an optional handoff to `just post-init` for publishing/Codecov/ReadTheDocs setup. For humans without an agent: the skill is also a copy-pasteable runbook.
|
|
54
|
+
|
|
55
|
+
### 🎯 Perfect For
|
|
56
|
+
Teams and professionals needing maintainable, type-safe Python projects following best practices.
|
|
57
|
+
|
|
58
|
+
## Complete Feature List
|
|
59
|
+
|
|
60
|
+
### Development Tools
|
|
61
|
+
|
|
62
|
+
- **Bootstrap dependency check and install with `make`**: Execute common development tasks with simple commands, standardizing workflows across team members.
|
|
63
|
+
|
|
64
|
+
- **Command running with `just`**: Define and run project-specific commands with a modern Make alternative, simplifying complex operations with clear syntax.
|
|
65
|
+
|
|
66
|
+
- **Linting with `ruff`**: Catch errors and enforce code style at lightning speed (10-100x faster than traditional linters), reducing waiting time and improving developer productivity.
|
|
67
|
+
|
|
68
|
+
- **Type checking with `mypy`**: Prevent type-related bugs before they occur, making your codebase more robust and easier to maintain as it grows.
|
|
69
|
+
|
|
70
|
+
- **Formatting with `ruff`**: Ensure consistent code style across your project automatically, eliminating style debates and pull request revision cycles.
|
|
71
|
+
|
|
72
|
+
- **Pre-commit hooks with `pre-commit`**: Enforce quality standards before code enters your repository, preventing bad code from ever being committed and reducing technical debt.
|
|
73
|
+
|
|
74
|
+
- **TOML formatting and validation with `taplo`**: Verify Toml files for syntax correctness, maintain consistent configuration files, ensuring readability and avoiding syntax errors in critical project settings.
|
|
75
|
+
|
|
76
|
+
- **YAML validation with [yamllint](docs/source/tools/yaml_lint.md)**: Verify YAML files for syntax correctness, preventing configuration errors and deployment failures.
|
|
77
|
+
|
|
78
|
+
### Project Structure & Management
|
|
79
|
+
|
|
80
|
+
- **Project configuration with `pyproject.toml`**: Organize all project settings in one standardized location, simplifying maintenance and configuration.
|
|
81
|
+
|
|
82
|
+
- **Dependency groups separation**: Organize dependencies into main, dev, and doc categories, preventing bloated installations and clarifying requirements as part of `pyproject.toml` configuration.
|
|
83
|
+
|
|
84
|
+
- **Dependency management with [`uv`](https://docs.astral.sh/uv/)**: Install and manage packages at blazing speed (100x faster than pip/poetry), dramatically reducing environment setup time.
|
|
85
|
+
|
|
86
|
+
- **Build system with `uv_build`**: Build wheel and source distributions with uv's build backend and `uv build`.
|
|
87
|
+
|
|
88
|
+
- **Versioning with explicit project metadata**: Keep release tags aligned with the static version in `pyproject.toml` for predictable package metadata.
|
|
89
|
+
|
|
90
|
+
- **Copyright license automation**: Automatically add license headers to all files, ensuring legal compliance without manual effort.
|
|
91
|
+
|
|
92
|
+
### Documentation
|
|
93
|
+
|
|
94
|
+
- **Documentation with `sphinx + MyST`**: Generate comprehensive documentation that supports both reStructuredText and Markdown, improving contributor accessibility.
|
|
95
|
+
|
|
96
|
+
- **`Read the Docs` integration**: Deploy documentation automatically, providing instant hosting and versioning for your project's documentation.
|
|
97
|
+
|
|
98
|
+
- **Changelog management with `cog`**: Track and communicate changes effectively to users and team members, improving project transparency and adoption.
|
|
99
|
+
|
|
100
|
+
### Testing & Quality Assurance
|
|
101
|
+
|
|
102
|
+
- **Testing framework with `pytest`**: Write and run tests with a modern, powerful testing framework that supports fixtures and parameterization.
|
|
103
|
+
|
|
104
|
+
- **CI/CD with `GitHub Actions`**: Automatically test, build, and deploy your project on multiple Python versions, catching compatibility issues early.
|
|
105
|
+
|
|
106
|
+
- **Matrix testing with `GitHub Actions`**: Run tests across multiple Python versions and operating systems, ensuring broad compatibility.
|
|
107
|
+
|
|
108
|
+
- **Simplified debugging info with `just debug-info`**: Automatically collect and format essential system, tool, and dependency information for streamlined bug reporting via a simple command.
|
|
109
|
+
|
|
110
|
+
### GitHub Integration
|
|
111
|
+
|
|
112
|
+
- **Pull request template**: Guide contributors through the PR process with structured information requirements, improving submission quality.
|
|
113
|
+
|
|
114
|
+
- **Issue templates (Feature, Bug, Documentation)**: Standardize issue reporting with appropriate fields for each type, gathering all necessary information upfront.
|
|
115
|
+
|
|
116
|
+
- **Automated contributor recognition with `contributors-please`**: Automatically update contributor lists, acknowledging all project participants without manual tracking.
|
|
117
|
+
|
|
118
|
+
- **Conventional commits enforced with `commitlint`**: Enforce structured commit messages so `release-please` can automate changelog generation and version bumps.
|
|
119
|
+
|
|
120
|
+
- **Security policy**: Establish clear vulnerability reporting procedures, promoting responsible disclosure and faster security fixes.
|
|
121
|
+
|
|
122
|
+
- **Code of conduct**: Set community behavior expectations, fostering an inclusive and respectful project environment.
|
|
123
|
+
|
|
124
|
+
- **Contributing guidelines**: Provide clear instructions for contributors, reducing friction for new participants.
|
|
125
|
+
|
|
126
|
+
- **Automated dependency security scanning with `codeql`**: Detect vulnerable dependencies automatically, protecting your users from known security issues.
|
|
127
|
+
|
|
128
|
+
- **CLA (Contributor License Agreement) check via [`CLA Assistant`](docs/source/tools/cla-assistant.md)**: Ensure all contributors have signed appropriate licensing agreements, protecting the project legally.
|
|
129
|
+
|
|
130
|
+
### IDE Integration
|
|
131
|
+
|
|
132
|
+
- **VS Code integration**: Provide optimized settings and configurations for Visual Studio Code, enhancing developer productivity.
|
|
133
|
+
|
|
134
|
+
- **PyRight configuration**: Enable accurate, real-time type checking in the editor, catching errors before running tests.
|
|
135
|
+
|
|
136
|
+
- **Editor extensions recommendations**: Suggest optimal VS Code extensions automatically, standardizing the development environment.
|
|
137
|
+
|
|
138
|
+
### AI Integration
|
|
139
|
+
|
|
140
|
+
- **AI assistance with common agents `Cursor, Windsurf, Claude Code, Codex`**: Support popular AI coding assistants enabling AI-powered development.
|
|
141
|
+
|
|
142
|
+
- **Cursor Rules configuration**: Optimize Cursor AI assistant for your specific project structure, improving suggestion relevance.
|
|
143
|
+
|
|
144
|
+
- **Windsurf Rules configuration**: Configure Windsurf IDE to understand your project architecture, enhancing code generation quality.
|
|
145
|
+
|
|
146
|
+
### Communication & Notifications
|
|
147
|
+
|
|
148
|
+
- **Slack integration for PRs and issues**: Send automated notifications to Slack when PRs or issues are opened/closed, keeping the team informed.
|
|
149
|
+
|
|
150
|
+
- **PR reminder notifications**: Ping relevant team members on Slack for PR reviews, reducing review cycle times.
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
Start your next Python project with confidence, knowing you're building on a foundation of best practices and modern development tools.
|
|
154
|
+
|
|
155
|
+
## Full documentation on ReadTheDocs including how to run
|
|
156
|
+
- [py-launch-blueprint Docs](https://py-launch-blueprint.readthedocs.io/en/latest/)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Copyright (c) 2025, Steve Morin
|
|
2
|
+
#
|
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
4
|
+
# this software and associated documentation files (the "Software"), to deal in
|
|
5
|
+
# the Software without restriction, including without limitation the rights to
|
|
6
|
+
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
7
|
+
# the Software, and to permit persons to whom the Software is furnished to do so,
|
|
8
|
+
# subject to the following conditions:
|
|
9
|
+
#
|
|
10
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
11
|
+
# copies or substantial portions of the Software.
|
|
12
|
+
#
|
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
15
|
+
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
16
|
+
# 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
|
|
18
|
+
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
19
|
+
|
|
20
|
+
"""Py utilities package."""
|
|
21
|
+
|
|
22
|
+
from importlib import metadata
|
|
23
|
+
|
|
24
|
+
__version__ = metadata.version("py_launch_blueprint")
|
|
25
|
+
|
|
26
|
+
from .projects import main as main # Re-export main function
|
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# Copyright (c) 2025, Steve Morin
|
|
3
|
+
#
|
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
5
|
+
# this software and associated documentation files (the "Software"), to deal in
|
|
6
|
+
# the Software without restriction, including without limitation the rights to
|
|
7
|
+
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
8
|
+
# the Software, and to permit persons to whom the Software is furnished to do so,
|
|
9
|
+
# subject to the following conditions:
|
|
10
|
+
#
|
|
11
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
# copies or substantial portions of the Software.
|
|
13
|
+
#
|
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
16
|
+
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
17
|
+
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
18
|
+
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
19
|
+
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
20
|
+
|
|
21
|
+
"""
|
|
22
|
+
Py Project Search CLI Tool.
|
|
23
|
+
|
|
24
|
+
A command-line interface for searching and selecting Py projects,
|
|
25
|
+
with support for fuzzy matching and various output formats.
|
|
26
|
+
"""
|
|
27
|
+
# TODO: remove mypy: ignore-errors and fix all type errors
|
|
28
|
+
# mypy: ignore-errors
|
|
29
|
+
|
|
30
|
+
import json
|
|
31
|
+
import os
|
|
32
|
+
import sys
|
|
33
|
+
from dataclasses import dataclass
|
|
34
|
+
from pathlib import Path
|
|
35
|
+
from typing import Any
|
|
36
|
+
|
|
37
|
+
import click
|
|
38
|
+
import pyperclip
|
|
39
|
+
import questionary
|
|
40
|
+
import requests
|
|
41
|
+
from dotenv import load_dotenv
|
|
42
|
+
from rich.console import Console
|
|
43
|
+
from rich.progress import Progress
|
|
44
|
+
from rich.table import Table
|
|
45
|
+
|
|
46
|
+
from py_launch_blueprint import __version__
|
|
47
|
+
|
|
48
|
+
# Initialize Rich console for pretty output
|
|
49
|
+
console = Console()
|
|
50
|
+
error_console = Console(stderr=True)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
# Custom Exceptions
|
|
54
|
+
class PyError(Exception):
|
|
55
|
+
"""Base exception for Py-related errors."""
|
|
56
|
+
|
|
57
|
+
pass
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class ConfigError(Exception):
|
|
61
|
+
"""Configuration-related errors."""
|
|
62
|
+
|
|
63
|
+
pass
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
# Configuration
|
|
67
|
+
@dataclass
|
|
68
|
+
class Config:
|
|
69
|
+
"""Configuration container."""
|
|
70
|
+
|
|
71
|
+
token: str | None = None
|
|
72
|
+
|
|
73
|
+
@classmethod
|
|
74
|
+
def from_env(cls, env_path: str | None = None) -> "Config":
|
|
75
|
+
"""
|
|
76
|
+
Create Config from environment variables or .env file.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
env_path: Optional path to .env file
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
Config object
|
|
83
|
+
"""
|
|
84
|
+
if env_path:
|
|
85
|
+
# Don't error if .env file is missing, just try to load if it exists
|
|
86
|
+
load_dotenv(env_path)
|
|
87
|
+
|
|
88
|
+
token = os.getenv("PY_TOKEN")
|
|
89
|
+
if token is None:
|
|
90
|
+
error_console.print(
|
|
91
|
+
"\n[yellow]No PY_TOKEN found in environment or config file.[/yellow]"
|
|
92
|
+
)
|
|
93
|
+
error_console.print("To set your Py token, you have three options:")
|
|
94
|
+
error_console.print("1. Set the PY_TOKEN environment variable:")
|
|
95
|
+
error_console.print(" export PY_TOKEN=your_token_here")
|
|
96
|
+
error_console.print(
|
|
97
|
+
"\n2. Create a .env file in ~/.config/py-cli/.env with:"
|
|
98
|
+
)
|
|
99
|
+
error_console.print(" PY_TOKEN=your_token_here")
|
|
100
|
+
error_console.print("\n3. Use the --token option when running the command:")
|
|
101
|
+
error_console.print(" py-cli --token your_token_here")
|
|
102
|
+
error_console.print(
|
|
103
|
+
"\nYou can get your token from: https://app.py.com/settings/tokens\n"
|
|
104
|
+
)
|
|
105
|
+
raise ConfigError("No PY_TOKEN found in environment or config file")
|
|
106
|
+
|
|
107
|
+
return cls(token=token)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def get_config_path() -> Path:
|
|
111
|
+
"""Get the path to the configuration directory."""
|
|
112
|
+
if os.name == "nt": # Windows
|
|
113
|
+
base_path = Path(os.environ["USERPROFILE"])
|
|
114
|
+
else: # Unix-like
|
|
115
|
+
base_path = Path.home()
|
|
116
|
+
|
|
117
|
+
return base_path / ".config" / "py-cli"
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def get_config(config_path: str | None = None) -> Config:
|
|
121
|
+
"""
|
|
122
|
+
Get configuration from various sources.
|
|
123
|
+
|
|
124
|
+
Priority (highest to lowest):
|
|
125
|
+
1. Environment variables
|
|
126
|
+
2. Configuration file
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
config_path: Optional path to config file
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
Config object with merged configuration
|
|
133
|
+
"""
|
|
134
|
+
config = Config()
|
|
135
|
+
|
|
136
|
+
# Load from file if specified
|
|
137
|
+
if config_path:
|
|
138
|
+
file_config = Config.from_env(config_path)
|
|
139
|
+
if file_config.token:
|
|
140
|
+
config.token = file_config.token
|
|
141
|
+
|
|
142
|
+
# Environment variables take precedence
|
|
143
|
+
env_token = os.getenv("PY_TOKEN")
|
|
144
|
+
if env_token:
|
|
145
|
+
config.token = env_token
|
|
146
|
+
|
|
147
|
+
return config
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
# API Client
|
|
151
|
+
class PyClient:
|
|
152
|
+
"""Client for interacting with the Py API."""
|
|
153
|
+
|
|
154
|
+
BASE_URL = "https://app.py.com/api/1.0"
|
|
155
|
+
|
|
156
|
+
def __init__(self, token: str):
|
|
157
|
+
"""
|
|
158
|
+
Initialize the Py API client.
|
|
159
|
+
|
|
160
|
+
Args:
|
|
161
|
+
token: Py Personal Access Token
|
|
162
|
+
"""
|
|
163
|
+
self.session = requests.Session()
|
|
164
|
+
self.session.headers.update(
|
|
165
|
+
{
|
|
166
|
+
"Authorization": f"Bearer {token}",
|
|
167
|
+
"Accept": "application/json",
|
|
168
|
+
}
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
def _request(self, method: str, path: str, **kwargs: Any) -> dict[str, Any]:
|
|
172
|
+
"""
|
|
173
|
+
Make a request to the Py API.
|
|
174
|
+
|
|
175
|
+
Args:
|
|
176
|
+
method: HTTP method
|
|
177
|
+
path: API endpoint path
|
|
178
|
+
**kwargs: Additional request parameters
|
|
179
|
+
|
|
180
|
+
Returns:
|
|
181
|
+
Response data
|
|
182
|
+
|
|
183
|
+
Raises:
|
|
184
|
+
PyError: If the request fails
|
|
185
|
+
"""
|
|
186
|
+
url = f"{self.BASE_URL}/{path.lstrip('/')}"
|
|
187
|
+
try:
|
|
188
|
+
response = self.session.request(method, url, **kwargs)
|
|
189
|
+
response.raise_for_status()
|
|
190
|
+
return response.json()
|
|
191
|
+
except requests.exceptions.RequestException as e:
|
|
192
|
+
if hasattr(e.response, "json"):
|
|
193
|
+
try:
|
|
194
|
+
if e.response is not None: # Check if response is not None
|
|
195
|
+
error_data = e.response.json()
|
|
196
|
+
error_msg = error_data.get("errors", [{}])[0].get(
|
|
197
|
+
"message", str(e)
|
|
198
|
+
)
|
|
199
|
+
else:
|
|
200
|
+
error_msg = str(e)
|
|
201
|
+
except ValueError:
|
|
202
|
+
error_msg = str(e)
|
|
203
|
+
else:
|
|
204
|
+
error_msg = str(e)
|
|
205
|
+
raise PyError(f"API request failed: {error_msg}") from e
|
|
206
|
+
|
|
207
|
+
def get_workspaces(self) -> list[dict[str, Any]]:
|
|
208
|
+
"""
|
|
209
|
+
Get all accessible workspaces.
|
|
210
|
+
|
|
211
|
+
Returns:
|
|
212
|
+
List of workspace dictionaries
|
|
213
|
+
"""
|
|
214
|
+
return self._request("GET", "/workspaces")["data"]
|
|
215
|
+
|
|
216
|
+
def get_projects(
|
|
217
|
+
self, workspace_name: str | None = None, limit: int = 200
|
|
218
|
+
) -> list[dict[str, Any]]:
|
|
219
|
+
"""
|
|
220
|
+
Get projects, optionally filtered by workspace.
|
|
221
|
+
|
|
222
|
+
Args:
|
|
223
|
+
workspace_name: Optional workspace name filter
|
|
224
|
+
limit: Maximum number of projects to return
|
|
225
|
+
|
|
226
|
+
Returns:
|
|
227
|
+
List of project dictionaries
|
|
228
|
+
"""
|
|
229
|
+
params = {
|
|
230
|
+
"limit": limit,
|
|
231
|
+
"opt_fields": "name,workspace.name",
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if workspace_name:
|
|
235
|
+
# First get workspaces and find the matching one
|
|
236
|
+
workspaces = self.get_workspaces()
|
|
237
|
+
workspace = next(
|
|
238
|
+
(w for w in workspaces if w["name"].lower() == workspace_name.lower()),
|
|
239
|
+
None,
|
|
240
|
+
)
|
|
241
|
+
if not workspace:
|
|
242
|
+
raise PyError(f"Workspace not found: {workspace_name}")
|
|
243
|
+
|
|
244
|
+
params["workspace"] = workspace["gid"]
|
|
245
|
+
|
|
246
|
+
response_data = self._request("GET", "/projects", params=params)
|
|
247
|
+
return response_data.get("data", [])
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
# CLI Functions
|
|
251
|
+
def setup_config(config_path: str | None = None) -> Config:
|
|
252
|
+
"""
|
|
253
|
+
Set up configuration from various sources.
|
|
254
|
+
|
|
255
|
+
Args:
|
|
256
|
+
config_path: Optional path to config file
|
|
257
|
+
|
|
258
|
+
Returns:
|
|
259
|
+
Config object with merged configuration
|
|
260
|
+
"""
|
|
261
|
+
# Load from default location if not specified
|
|
262
|
+
if not config_path:
|
|
263
|
+
config_dir = get_config_path()
|
|
264
|
+
config_path = str(config_dir / ".env")
|
|
265
|
+
|
|
266
|
+
try:
|
|
267
|
+
return get_config(config_path)
|
|
268
|
+
except ConfigError as e:
|
|
269
|
+
error_console.print(f"[red]Configuration error:[/red] {e}")
|
|
270
|
+
sys.exit(1)
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def format_output(projects: list[dict[str, Any]], format: str) -> str:
|
|
274
|
+
"""
|
|
275
|
+
Format projects list according to specified format.
|
|
276
|
+
|
|
277
|
+
Args:
|
|
278
|
+
projects: List of project dictionaries
|
|
279
|
+
format: Output format (text, json, or csv)
|
|
280
|
+
|
|
281
|
+
Returns:
|
|
282
|
+
Formatted string
|
|
283
|
+
"""
|
|
284
|
+
if format == "json":
|
|
285
|
+
return json.dumps({"projects": projects}, indent=2)
|
|
286
|
+
elif format == "csv":
|
|
287
|
+
header = "id,name\n"
|
|
288
|
+
rows = [f"{p['id']},{p['name']}" for p in projects]
|
|
289
|
+
return header + "\n".join(rows)
|
|
290
|
+
else: # text format
|
|
291
|
+
return "\n".join(p["id"] for p in projects)
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def display_projects(projects: list[dict[str, Any]], verbose: bool = False) -> None:
|
|
295
|
+
"""
|
|
296
|
+
Display projects in a rich table format.
|
|
297
|
+
|
|
298
|
+
Args:
|
|
299
|
+
projects: List of project dictionaries
|
|
300
|
+
verbose: Whether to show additional details
|
|
301
|
+
"""
|
|
302
|
+
table = Table(show_header=True)
|
|
303
|
+
table.add_column("Project Name", style="cyan")
|
|
304
|
+
table.add_column("Workspace", style="green")
|
|
305
|
+
if verbose:
|
|
306
|
+
table.add_column("ID", style="dim")
|
|
307
|
+
|
|
308
|
+
for project in projects:
|
|
309
|
+
row = [project["name"], project["workspace"]["name"]]
|
|
310
|
+
if verbose:
|
|
311
|
+
row.append(project["id"])
|
|
312
|
+
table.add_row(*row)
|
|
313
|
+
|
|
314
|
+
console.print(table)
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
@click.command()
|
|
318
|
+
@click.version_option(version=__version__)
|
|
319
|
+
@click.option("--token", help="Py Personal Access Token")
|
|
320
|
+
@click.option("--config", help="Path to config file", type=click.Path(exists=True))
|
|
321
|
+
@click.option("--workspace", help="Filter projects by workspace name")
|
|
322
|
+
@click.option("--limit", default=200, help="Maximum number of projects to retrieve")
|
|
323
|
+
@click.option(
|
|
324
|
+
"--format",
|
|
325
|
+
type=click.Choice(["text", "json", "csv"]),
|
|
326
|
+
default="text",
|
|
327
|
+
help="Output format",
|
|
328
|
+
)
|
|
329
|
+
@click.option("--copy", is_flag=True, help="Copy results to clipboard")
|
|
330
|
+
@click.option("--output", type=click.Path(), help="Write results to file")
|
|
331
|
+
@click.option("--no-color", is_flag=True, help="Disable colored output")
|
|
332
|
+
@click.option("--verbose", is_flag=True, help="Enable verbose output")
|
|
333
|
+
def main(
|
|
334
|
+
token: str | None,
|
|
335
|
+
config: str | None,
|
|
336
|
+
workspace: str | None,
|
|
337
|
+
limit: int,
|
|
338
|
+
format: str,
|
|
339
|
+
copy: bool,
|
|
340
|
+
output: str | None,
|
|
341
|
+
no_color: bool,
|
|
342
|
+
verbose: bool,
|
|
343
|
+
) -> None:
|
|
344
|
+
"""Search and select Py projects."""
|
|
345
|
+
try:
|
|
346
|
+
# Setup configuration
|
|
347
|
+
cfg = setup_config(config)
|
|
348
|
+
if token:
|
|
349
|
+
cfg.token = token
|
|
350
|
+
|
|
351
|
+
if not cfg.token:
|
|
352
|
+
error_console.print("[red]Error:[/red] No Py token provided")
|
|
353
|
+
sys.exit(1)
|
|
354
|
+
|
|
355
|
+
# Initialize API client
|
|
356
|
+
client = PyClient(cfg.token)
|
|
357
|
+
|
|
358
|
+
with Progress() as progress:
|
|
359
|
+
# Fetch projects
|
|
360
|
+
task = progress.add_task("Fetching projects...", total=None)
|
|
361
|
+
projects = client.get_projects(workspace_name=workspace, limit=limit)
|
|
362
|
+
progress.update(task, completed=True)
|
|
363
|
+
|
|
364
|
+
if not projects:
|
|
365
|
+
console.print("[yellow]No projects found.[/yellow]")
|
|
366
|
+
return
|
|
367
|
+
|
|
368
|
+
# Display projects and get selection
|
|
369
|
+
if format == "text":
|
|
370
|
+
display_projects(projects, verbose)
|
|
371
|
+
|
|
372
|
+
# Allow project selection
|
|
373
|
+
choices = [
|
|
374
|
+
questionary.Choice(title=f"{p['name']} ({p['workspace']['name']})", value=p)
|
|
375
|
+
for p in projects
|
|
376
|
+
]
|
|
377
|
+
|
|
378
|
+
selected = questionary.checkbox(
|
|
379
|
+
"Select projects:",
|
|
380
|
+
choices=choices,
|
|
381
|
+
).ask()
|
|
382
|
+
|
|
383
|
+
if not selected:
|
|
384
|
+
console.print("[yellow]No projects selected[/yellow]")
|
|
385
|
+
return
|
|
386
|
+
|
|
387
|
+
# Format output
|
|
388
|
+
result = format_output(selected, format)
|
|
389
|
+
|
|
390
|
+
# Handle output
|
|
391
|
+
if output:
|
|
392
|
+
Path(output).write_text(result)
|
|
393
|
+
console.print(f"[green]Results written to {output}[/green]")
|
|
394
|
+
else:
|
|
395
|
+
console.print(result)
|
|
396
|
+
|
|
397
|
+
if copy:
|
|
398
|
+
pyperclip.copy(result)
|
|
399
|
+
console.print("[green]Results copied to clipboard[/green]")
|
|
400
|
+
|
|
401
|
+
except PyError as e:
|
|
402
|
+
error_console.print(f"[red]Py API error:[/red] {e}")
|
|
403
|
+
sys.exit(3)
|
|
404
|
+
except Exception as e:
|
|
405
|
+
error_console.print(f"[red]Error:[/red] {e}")
|
|
406
|
+
if verbose:
|
|
407
|
+
error_console.print_exception()
|
|
408
|
+
sys.exit(4)
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
if __name__ == "__main__":
|
|
412
|
+
main()
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
# Copyright (c) 2025, Steve Morin
|
|
2
|
+
#
|
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
4
|
+
# this software and associated documentation files (the "Software"), to deal in
|
|
5
|
+
# the Software without restriction, including without limitation the rights to
|
|
6
|
+
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
7
|
+
# the Software, and to permit persons to whom the Software is furnished to do so,
|
|
8
|
+
# subject to the following conditions:
|
|
9
|
+
#
|
|
10
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
11
|
+
# copies or substantial portions of the Software.
|
|
12
|
+
#
|
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
15
|
+
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
16
|
+
# 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
|
|
18
|
+
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
19
|
+
|
|
20
|
+
[project]
|
|
21
|
+
name = "py_launch_blueprint"
|
|
22
|
+
# ITM-070 — static version (ADR-06 cutover). release-please bumps this.
|
|
23
|
+
version = "1.1.3"
|
|
24
|
+
description = "CLI tools for interacting with Py, including project search functionality"
|
|
25
|
+
readme = "README.md"
|
|
26
|
+
requires-python = ">=3.12"
|
|
27
|
+
license = "MIT" # PEP 639 license expression (ITM-070, round-19).
|
|
28
|
+
authors = [{ name = "Steve Morin", email = "steve.morin@gmail.com" }]
|
|
29
|
+
classifiers = [
|
|
30
|
+
# ITM-070 — round-19. py3.12+ only (per ITM-033 floor); MIT classifier
|
|
31
|
+
# intentionally omitted (PEP 639 license expression above is the single
|
|
32
|
+
# source of truth — duplication would drift).
|
|
33
|
+
"Development Status :: 4 - Beta",
|
|
34
|
+
"Intended Audience :: Developers",
|
|
35
|
+
"Operating System :: OS Independent",
|
|
36
|
+
"Programming Language :: Python :: 3",
|
|
37
|
+
"Programming Language :: Python :: 3.12",
|
|
38
|
+
"Programming Language :: Python :: 3.13",
|
|
39
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
40
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
41
|
+
]
|
|
42
|
+
dependencies = [
|
|
43
|
+
"click>=8.1.0",
|
|
44
|
+
"questionary>=2.0.0",
|
|
45
|
+
"python-dotenv>=1.0.0",
|
|
46
|
+
"thefuzz>=0.19.0",
|
|
47
|
+
"python-Levenshtein>=0.21.0", # For better performance with thefuzz
|
|
48
|
+
"pyperclip>=1.8.0",
|
|
49
|
+
"requests>=2.31.0",
|
|
50
|
+
"rich>=13.0.0",
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
# ITM-063 — PEP 735 dependency-groups (round-13 decision). Replaces
|
|
54
|
+
# [project.optional-dependencies] dev+docs. Install via `uv sync --group <name>`.
|
|
55
|
+
[dependency-groups]
|
|
56
|
+
dev = [
|
|
57
|
+
"pytest>=7.0.0",
|
|
58
|
+
"pytest-cov>=4.1.0",
|
|
59
|
+
"mypy>=1.0.0",
|
|
60
|
+
"ty>=0.0.1a16", # per ADR-03 (pre-1.0; bump as needed)
|
|
61
|
+
"ruff>=0.1.0",
|
|
62
|
+
"types-requests",
|
|
63
|
+
"types-Pygments",
|
|
64
|
+
"cogapp",
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
docs = [
|
|
68
|
+
"sphinx>=7.0.0",
|
|
69
|
+
"sphinx-rtd-theme",
|
|
70
|
+
"furo",
|
|
71
|
+
"myst-parser",
|
|
72
|
+
"sphinx-autodoc-typehints",
|
|
73
|
+
"cogapp",
|
|
74
|
+
"sphinx-copybutton",
|
|
75
|
+
"sphinx-autobuild",
|
|
76
|
+
"sphinxext-opengraph", # https://github.com/wpilibsuite/sphinxext-opengraph
|
|
77
|
+
]
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
[project.scripts]
|
|
81
|
+
py-projects = "py_launch_blueprint.projects:main"
|
|
82
|
+
|
|
83
|
+
# ITM-072 — package metadata URLs (round 19).
|
|
84
|
+
[project.urls]
|
|
85
|
+
Homepage = "https://github.com/smorinlabs/py-launch-blueprint"
|
|
86
|
+
Repository = "https://github.com/smorinlabs/py-launch-blueprint"
|
|
87
|
+
Documentation = "https://py-launch-blueprint.readthedocs.io/en/latest/"
|
|
88
|
+
Changelog = "https://github.com/smorinlabs/py-launch-blueprint/blob/main/CHANGELOG.md"
|
|
89
|
+
Issues = "https://github.com/smorinlabs/py-launch-blueprint/issues"
|
|
90
|
+
|
|
91
|
+
# ITM-073 — uv_build (ADR-06 cutover; replaces Hatchling + hatch-vcs).
|
|
92
|
+
[build-system]
|
|
93
|
+
requires = ["uv_build>=0.5,<1.0"]
|
|
94
|
+
build-backend = "uv_build"
|
|
95
|
+
|
|
96
|
+
# ITM-074 — uv_build module configuration.
|
|
97
|
+
# Template uses a flat layout (package at repo root, not src/) — must set
|
|
98
|
+
# module-root = "" so uv_build doesn't expect src/py_launch_blueprint/.
|
|
99
|
+
[tool.uv.build-backend]
|
|
100
|
+
module-name = "py_launch_blueprint"
|
|
101
|
+
module-root = ""
|
|
102
|
+
|
|
103
|
+
[tool.ruff]
|
|
104
|
+
# ITM-018 reconciled config (round-2). Merge: template's stricter rule
|
|
105
|
+
# selection + source's ignore rationale. target-version reflects ITM-033
|
|
106
|
+
# Python-floor bump.
|
|
107
|
+
target-version = "py312"
|
|
108
|
+
line-length = 88
|
|
109
|
+
|
|
110
|
+
lint.select = [
|
|
111
|
+
"E", # pycodestyle errors
|
|
112
|
+
"F", # pyflakes
|
|
113
|
+
"I", # isort
|
|
114
|
+
"B", # flake8-bugbear
|
|
115
|
+
"C4", # flake8-comprehensions
|
|
116
|
+
"UP", # pyupgrade
|
|
117
|
+
"N", # pep8-naming
|
|
118
|
+
"RUF", # Ruff-specific rules
|
|
119
|
+
"W", # pycodestyle warnings
|
|
120
|
+
"YTT", # flake8-2020
|
|
121
|
+
"S", # flake8-bandit
|
|
122
|
+
]
|
|
123
|
+
|
|
124
|
+
# Source's ignore rationale (round-2): line-length handled by formatter;
|
|
125
|
+
# template-applicable subset adopted (B904/B007 omitted — source-specific
|
|
126
|
+
# patterns that don't apply here).
|
|
127
|
+
lint.ignore = [
|
|
128
|
+
"E501", # line too long (formatter owns this)
|
|
129
|
+
"W293", # whitespace on blank line (formatter owns trim_trailing)
|
|
130
|
+
]
|
|
131
|
+
|
|
132
|
+
# Allow autofix behavior for specific rules
|
|
133
|
+
fix = true
|
|
134
|
+
lint.unfixable = [] # Rules that should not be fixed automatically
|
|
135
|
+
|
|
136
|
+
# Exclude files/folders
|
|
137
|
+
exclude = [
|
|
138
|
+
".git",
|
|
139
|
+
".venv",
|
|
140
|
+
"__pycache__",
|
|
141
|
+
"build",
|
|
142
|
+
"dist",
|
|
143
|
+
"docs/source/conf.py",
|
|
144
|
+
"py_launch_blueprint/_version.py",
|
|
145
|
+
]
|
|
146
|
+
# Per-file-ignores
|
|
147
|
+
[tool.ruff.lint.pycodestyle]
|
|
148
|
+
max-line-length = 88
|
|
149
|
+
[tool.ruff.lint.per-file-ignores]
|
|
150
|
+
"__init__.py" = ["F401"] # Ignore unused imports in __init__.py files
|
|
151
|
+
"tests/*" = ["S101", "S105", "S106"] # Ignore assert statements in tests
|
|
152
|
+
"init/tests/**" = ["S101", "S105", "S106"] # same exemption — pytest convention
|
|
153
|
+
"init/**" = ["S603", "S607"] # init/ wraps gh/just/uv via subprocess; that's the point
|
|
154
|
+
"skill/**" = ["S101"] # skill/ has illustrative example assertions in markdown
|
|
155
|
+
# S101: assert statements removed under -O — security risk if assert is the only gate.
|
|
156
|
+
# S105/S106: hardcoded password strings/variables in code.
|
|
157
|
+
# S603/S607: subprocess module use + partial-path executables — init/ tooling wraps gh/just/uv intentionally.
|
|
158
|
+
|
|
159
|
+
# ITM-018 — explicit format config (round-2; mirrors source). Values match Ruff
|
|
160
|
+
# defaults but being explicit prevents silent drift if defaults change.
|
|
161
|
+
[tool.ruff.format]
|
|
162
|
+
quote-style = "double"
|
|
163
|
+
indent-style = "space"
|
|
164
|
+
line-ending = "auto"
|
|
165
|
+
|
|
166
|
+
# ITM-027 — bandit config (round 3). Tests legitimately use `assert`
|
|
167
|
+
# (pytest convention) — exclude_dirs covers tests/.
|
|
168
|
+
[tool.bandit]
|
|
169
|
+
exclude_dirs = ["tests", "init/tests", ".venv", "build", "dist"]
|
|
170
|
+
skips = [] # No global skips; add with rationale only.
|
|
171
|
+
|
|
172
|
+
[tool.pytest.ini_options]
|
|
173
|
+
testpaths = ["tests"]
|
|
174
|
+
python_files = ["test_*.py"]
|
|
175
|
+
# Marker taxonomy (ITM-046, round-9 decision).
|
|
176
|
+
# `live` = requires external services; `slow` = takes >1s.
|
|
177
|
+
# Default `addopts` excludes both — run full suite with `pytest -m ""`.
|
|
178
|
+
markers = [
|
|
179
|
+
"live: requires external services",
|
|
180
|
+
"slow: takes >1s",
|
|
181
|
+
]
|
|
182
|
+
addopts = "-m 'not live and not slow'"
|
|
183
|
+
strict_markers = true
|
|
184
|
+
|
|
185
|
+
# ITM-015 — codespell. US English baseline (default builtin="clear,rare"); empty
|
|
186
|
+
# ignore list — add terms only when intentional. Decided round 9.
|
|
187
|
+
[tool.codespell]
|
|
188
|
+
skip = ".git,.venv,build,dist,node_modules,uv.lock,bun.lock,*.lock,docs/_build,*.svg,*.cast,.ruff_cache,.pytest_cache,.mypy_cache,.ty_cache,*.log,skill/optimization-workspace"
|
|
189
|
+
# *.log + skill/optimization-workspace: optimizer logs contain LLM-truncated
|
|
190
|
+
# text artifacts that aren't real typos; skip the whole tree.
|
|
191
|
+
ignore-words-list = "ans"
|
|
192
|
+
# ans: variable name used in prompt-handling code; codespell wants to "fix"
|
|
193
|
+
# it to "and". Whitelist to keep the short variable name.
|
|
194
|
+
check-filenames = true
|
|
195
|
+
check-hidden = false
|
|
196
|
+
|
|
197
|
+
[tool.mypy]
|
|
198
|
+
# Python version (ITM-033 — moves to 3.12; mypy block removed entirely
|
|
199
|
+
# once ITM-026 ty switch lands).
|
|
200
|
+
python_version = "3.12"
|
|
201
|
+
|
|
202
|
+
# Strict mode
|
|
203
|
+
strict = true
|
|
204
|
+
|
|
205
|
+
# Imports management
|
|
206
|
+
ignore_missing_imports = false
|
|
207
|
+
follow_imports = "normal"
|
|
208
|
+
follow_imports_for_stubs = true
|
|
209
|
+
|
|
210
|
+
# Disallow dynamic typing
|
|
211
|
+
disallow_any_generics = true
|
|
212
|
+
disallow_subclassing_any = true
|
|
213
|
+
disallow_untyped_calls = true
|
|
214
|
+
disallow_untyped_defs = true
|
|
215
|
+
disallow_incomplete_defs = true
|
|
216
|
+
disallow_untyped_decorators = true
|
|
217
|
+
|
|
218
|
+
# None and Optional handling
|
|
219
|
+
no_implicit_optional = true
|
|
220
|
+
strict_optional = true
|
|
221
|
+
|
|
222
|
+
# Warnings
|
|
223
|
+
warn_redundant_casts = true
|
|
224
|
+
warn_unused_ignores = true
|
|
225
|
+
warn_no_return = true
|
|
226
|
+
warn_return_any = true
|
|
227
|
+
warn_unreachable = true
|
|
228
|
+
|
|
229
|
+
# Error messages
|
|
230
|
+
pretty = true
|
|
231
|
+
show_error_codes = true
|
|
232
|
+
show_column_numbers = true
|
|
233
|
+
|
|
234
|
+
# Per-module settings example
|
|
235
|
+
[[tool.mypy.overrides]]
|
|
236
|
+
module = ["tests.*"]
|
|
237
|
+
disallow_untyped_defs = false
|