├── nox_actions ├── __init__.py ├── utils.py ├── codetest.py ├── lint.py ├── docs.py └── release.py ├── tests ├── __init__.py ├── test_version.py └── test_cli.py ├── src └── your_project_name │ ├── __version__.py │ ├── __init__.py │ ├── cli.py │ └── config.py ├── docs ├── source │ ├── changelog.rst │ ├── contributing.rst │ ├── index.rst │ ├── api.rst │ ├── usage.rst │ ├── installation.rst │ └── conf.py ├── Makefile ├── index.md └── make.bat ├── .hound.yml ├── renovate.json ├── codecov.yml ├── requirements-dev.txt ├── CHANGELOG.md ├── .pylintrc ├── docker-compose.yml ├── .coveragerc ├── .github ├── workflows │ ├── dependency-review.yml │ ├── release-drafter.yml │ ├── label-sync.yml │ ├── semantic-release.yml │ ├── bumpversion.yml │ ├── issue-translator.yml │ ├── codeql-analysis.yml │ ├── codeql.yml │ ├── stale.yml │ ├── codecov.yml │ ├── docs.yml │ ├── build-exe.yml │ ├── docker-publish.yml │ ├── scorecards.yml │ ├── python-publish.yml │ ├── mr-test.yml │ └── release.yml ├── CODEOWNERS ├── SECURITY.md ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── FUNDING.yml ├── dependabot.yml ├── release-drafter-config.yml ├── pull_request_template.md ├── release-template.md ├── labels.yml └── CODE_OF_CONDUCT.md ├── examples ├── config.json ├── basic_usage.py ├── cli_example.py └── config_example.py ├── Dockerfile ├── .editorconfig ├── .gitignore ├── .pre-commit-config.yaml ├── noxfile.py ├── .readthedocs.yaml ├── .flake8 ├── LICENSE ├── .dockerignore ├── CONTRIBUTING.md ├── README_zh.md ├── README.md └── pyproject.toml /nox_actions/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/your_project_name/__version__.py: -------------------------------------------------------------------------------- 1 | """Version information.""" 2 | 3 | __version__ = "0.0.1" 4 | -------------------------------------------------------------------------------- /docs/source/changelog.rst: -------------------------------------------------------------------------------- 1 | Changelog 2 | ========= 3 | 4 | .. include:: ../../CHANGELOG.md 5 | :parser: myst_parser 6 | -------------------------------------------------------------------------------- /docs/source/contributing.rst: -------------------------------------------------------------------------------- 1 | Contributing 2 | ============ 3 | 4 | .. include:: ../../CONTRIBUTING.md 5 | :parser: myst_parser 6 | -------------------------------------------------------------------------------- /.hound.yml: -------------------------------------------------------------------------------- 1 | python: 2 | enabled: true 3 | 4 | flake8: 5 | enabled: true 6 | config_file: .flake8 7 | 8 | fail_on_violations: true 9 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:recommended" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | status: 3 | project: off 4 | 5 | github_checks: 6 | annotations: false 7 | 8 | ignore: 9 | - "noxfile.py" 10 | -------------------------------------------------------------------------------- /src/your_project_name/__init__.py: -------------------------------------------------------------------------------- 1 | """Your project description.""" 2 | 3 | # Import local modules 4 | from .__version__ import __version__ 5 | 6 | __all__ = ["__version__"] 7 | -------------------------------------------------------------------------------- /requirements-dev.txt: -------------------------------------------------------------------------------- 1 | poetry>=1.7.0 2 | nox>=2023.4.22 3 | pytest>=7.4.0 4 | pytest-cov>=6.0.0 5 | ruff>=0.9.0 6 | mypy>=1.5.1 7 | isort>=5.13.2 8 | pre-commit>=3.5.0 9 | uv>=0.1.0 10 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG 2 | 3 | 4 | 5 | ## v0.0.0 (2025-03-19) 6 | 7 | ### Unknown 8 | 9 | * Initial commit ([`b5ec414`](https://github.com/loonghao/dcc-mcp/commit/b5ec414afdfd58333fdf1869d245acfbcd69db89)) 10 | -------------------------------------------------------------------------------- /.pylintrc: -------------------------------------------------------------------------------- 1 | # Generated Pylint configuration file that disables default output tables. 2 | 3 | [MESSAGES CONTROL] 4 | disable=RP0001,RP0002,RP0003,RP0101,RP0401,RP0402,RP0701,RP0801,C0103,R0903 5 | 6 | [REPORTS] 7 | output-format=text 8 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | 3 | services: 4 | app: 5 | build: . 6 | volumes: 7 | - ./data:/app/data 8 | environment: 9 | - PYTHONUNBUFFERED=1 10 | - LOG_LEVEL=INFO 11 | command: python -m your_project_name 12 | -------------------------------------------------------------------------------- /tests/test_version.py: -------------------------------------------------------------------------------- 1 | """Test version information.""" 2 | 3 | # Import local modules 4 | from your_project_name import __version__ 5 | 6 | 7 | def test_version(): 8 | """Test that version is a string.""" 9 | assert isinstance(__version__, str) 10 | -------------------------------------------------------------------------------- /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | branch = True 3 | source = your_project_name 4 | 5 | [report] 6 | exclude_lines = 7 | if self.debug: 8 | pragma: no cover 9 | raise NotImplementedError 10 | if __name__ == .__main__.: 11 | if TYPE_CHECKING: 12 | ignore_errors = True 13 | omit = 14 | tests/* 15 | -------------------------------------------------------------------------------- /.github/workflows/dependency-review.yml: -------------------------------------------------------------------------------- 1 | name: 'Dependency Review' 2 | on: [pull_request] 3 | 4 | permissions: 5 | contents: read 6 | 7 | jobs: 8 | dependency-review: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: 'Checkout Repository' 12 | uses: actions/checkout@v4 13 | - name: 'Dependency Review' 14 | uses: actions/dependency-review-action@v3 15 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | Welcome to your-project-name's documentation! 2 | ====================================== 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | :caption: Contents: 7 | 8 | installation 9 | usage 10 | api 11 | contributing 12 | changelog 13 | 14 | Indices and tables 15 | ================== 16 | 17 | * :ref:`genindex` 18 | * :ref:`modindex` 19 | * :ref:`search` 20 | -------------------------------------------------------------------------------- /.github/workflows/release-drafter.yml: -------------------------------------------------------------------------------- 1 | name: Release Drafter 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | update_release_draft: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: release-drafter/release-drafter@v5 13 | with: 14 | config-name: release-drafter-config.yml 15 | env: 16 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 17 | -------------------------------------------------------------------------------- /examples/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "settings": { 3 | "debug": false, 4 | "log_level": "INFO", 5 | "timeout": 30 6 | }, 7 | "api": { 8 | "url": "https://api.example.com", 9 | "key": "YOUR_API_KEY_HERE" 10 | }, 11 | "features": { 12 | "feature1": true, 13 | "feature2": false, 14 | "feature3": { 15 | "enabled": true, 16 | "options": ["option1", "option2"] 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.github/workflows/label-sync.yml: -------------------------------------------------------------------------------- 1 | name: Sync labels 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | - .github/labels.yml 9 | workflow_dispatch: 10 | 11 | jobs: 12 | sync: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v4 16 | - uses: micnncim/action-label-syncer@v1 17 | env: 18 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 19 | with: 20 | manifest: .github/labels.yml 21 | -------------------------------------------------------------------------------- /docs/source/api.rst: -------------------------------------------------------------------------------- 1 | API Reference 2 | ============= 3 | 4 | This part of the documentation covers all the interfaces of your-project-name. 5 | 6 | your_project_name 7 | ---------------- 8 | 9 | .. automodule:: your_project_name 10 | :members: 11 | 12 | your_project_name.cli 13 | -------------------- 14 | 15 | .. automodule:: your_project_name.cli 16 | :members: 17 | 18 | your_project_name.config 19 | ----------------------- 20 | 21 | .. automodule:: your_project_name.config 22 | :members: 23 | -------------------------------------------------------------------------------- /nox_actions/utils.py: -------------------------------------------------------------------------------- 1 | # Import built-in modules 2 | from pathlib import Path 3 | 4 | 5 | PACKAGE_NAME = "your_project_name" 6 | THIS_ROOT = Path(__file__).parent.parent 7 | PROJECT_ROOT = THIS_ROOT.parent 8 | 9 | 10 | def _assemble_env_paths(*paths): 11 | """Assemble environment paths separated by a semicolon. 12 | 13 | Args: 14 | *paths: Paths to be assembled. 15 | 16 | Returns: 17 | str: Assembled paths separated by a semicolon. 18 | """ 19 | return ";".join(paths) 20 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # These owners will be the default owners for everything in the repo. 2 | # Unless a later match takes precedence, they will be requested for 3 | # review when someone opens a pull request. 4 | * @yourusername 5 | 6 | # Order is important; the last matching pattern takes the most precedence. 7 | 8 | # Core code 9 | /src/ @yourusername 10 | 11 | # Tests 12 | /tests/ @yourusername 13 | 14 | # Documentation 15 | /docs/ @yourusername 16 | 17 | # CI/CD workflows 18 | /.github/workflows/ @yourusername 19 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9-slim 2 | 3 | WORKDIR /app 4 | 5 | # Install Poetry 6 | RUN pip install --no-cache-dir poetry==1.7.1 7 | 8 | # Copy only requirements to cache them in docker layer 9 | COPY pyproject.toml poetry.lock* /app/ 10 | 11 | # Configure poetry to not use a virtual environment 12 | RUN poetry config virtualenvs.create false 13 | 14 | # Install dependencies 15 | RUN poetry install --no-dev --no-interaction --no-ansi 16 | 17 | # Copy project 18 | COPY . /app/ 19 | 20 | # Run the application 21 | CMD ["python", "-m", "your_project_name"] 22 | -------------------------------------------------------------------------------- /.github/workflows/semantic-release.yml: -------------------------------------------------------------------------------- 1 | name: Semantic Release 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | release: 10 | runs-on: ubuntu-latest 11 | concurrency: release 12 | permissions: 13 | id-token: write 14 | contents: write 15 | 16 | steps: 17 | - uses: actions/checkout@v4 18 | with: 19 | fetch-depth: 0 20 | 21 | - name: Python Semantic Release 22 | uses: python-semantic-release/python-semantic-release@v8.5.1 23 | with: 24 | github_token: ${{ secrets.GITHUB_TOKEN }} 25 | -------------------------------------------------------------------------------- /.github/SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Use this section to tell people about which versions of your project are 6 | currently being supported with security updates. 7 | 8 | | Version | Supported | 9 | | ------- | ------------------ | 10 | | 0.0.1 | :white_check_mark: | 11 | 12 | ## Reporting a Vulnerability 13 | 14 | Use this section to tell people how to report a vulnerability. 15 | 16 | Tell them where to go, how often they can expect to get an update on a 17 | reported vulnerability, what to expect if the vulnerability is accepted or 18 | declined, etc. 19 | -------------------------------------------------------------------------------- /nox_actions/codetest.py: -------------------------------------------------------------------------------- 1 | # Import built-in modules 2 | import os 3 | 4 | # Import third-party modules 5 | import nox 6 | from nox_actions.utils import PACKAGE_NAME 7 | from nox_actions.utils import THIS_ROOT 8 | 9 | 10 | def pytest(session: nox.Session) -> None: 11 | session.install(".") 12 | session.install("pytest", "pytest_cov", "pytest_mock") 13 | test_root = os.path.join(THIS_ROOT, "tests") 14 | session.run("pytest", f"--cov={PACKAGE_NAME}", 15 | "--cov-report=xml:coverage.xml", 16 | f"--rootdir={test_root}", 17 | env={"PYTHONPATH": THIS_ROOT.as_posix()}) 18 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | insert_final_newline = true 10 | charset = utf-8 11 | trim_trailing_whitespace = true 12 | 13 | # 4 space indentation for Python files 14 | [*.py] 15 | indent_style = space 16 | indent_size = 4 17 | 18 | # 2 space indentation for YAML, JSON, and markdown files 19 | [*.{yml,yaml,json,md,rst}] 20 | indent_style = space 21 | indent_size = 2 22 | 23 | # Tab indentation for Makefile 24 | [Makefile] 25 | indent_style = tab 26 | -------------------------------------------------------------------------------- /nox_actions/lint.py: -------------------------------------------------------------------------------- 1 | # Import third-party modules 2 | import nox 3 | from nox_actions.utils import PACKAGE_NAME 4 | 5 | 6 | def lint(session: nox.Session) -> None: 7 | session.install("isort", "ruff") 8 | session.run("isort", "--check-only", PACKAGE_NAME) 9 | session.run("ruff", "check") 10 | 11 | 12 | def lint_fix(session: nox.Session) -> None: 13 | session.install("isort", "ruff", "pre-commit", "autoflake") 14 | session.run("ruff", "check", "--fix") 15 | session.run("isort", ".") 16 | session.run("pre-commit", "run", "--all-files") 17 | session.run("autoflake", "--in-place", "--remove-all-unused-imports", "--remove-unused-variables") 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # Distribution / packaging 7 | dist/ 8 | build/ 9 | *.egg-info/ 10 | 11 | # Unit test / coverage reports 12 | .coverage 13 | .coverage.* 14 | coverage.xml 15 | htmlcov/ 16 | .pytest_cache/ 17 | 18 | # Environments 19 | .env 20 | .venv 21 | env/ 22 | venv/ 23 | ENV/ 24 | env.bak/ 25 | venv.bak/ 26 | 27 | # mypy 28 | .mypy_cache/ 29 | 30 | # ruff 31 | .ruff_cache/ 32 | 33 | # nox 34 | .nox/ 35 | 36 | # Poetry 37 | poetry.lock 38 | 39 | # IDE files 40 | .idea/ 41 | .vscode/ 42 | *.swp 43 | *~ 44 | 45 | # Jupyter Notebook 46 | .ipynb_checkpoints 47 | 48 | # macOS 49 | .DS_Store 50 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature Request 3 | about: Suggest an idea for this project 4 | title: '[FEATURE] ' 5 | labels: enhancement 6 | assignees: '' 7 | --- 8 | 9 | ## Is your feature request related to a problem? Please describe. 10 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 11 | 12 | ## Describe the solution you'd like 13 | A clear and concise description of what you want to happen. 14 | 15 | ## Describe alternatives you've considered 16 | A clear and concise description of any alternative solutions or features you've considered. 17 | 18 | ## Additional context 19 | Add any other context or screenshots about the feature request here. 20 | -------------------------------------------------------------------------------- /examples/basic_usage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Basic usage example for your-project-name.""" 3 | 4 | # Import built-in modules 5 | import sys 6 | import os 7 | 8 | # Add the parent directory to sys.path to import the package 9 | sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) 10 | 11 | # Import the package 12 | from your_project_name import __version__ 13 | 14 | 15 | def main(): 16 | """Main function to demonstrate basic usage.""" 17 | print(f"Using your-project-name version {__version__}") 18 | 19 | # Add your example code here 20 | print("This is a basic usage example.") 21 | 22 | return 0 23 | 24 | 25 | if __name__ == "__main__": 26 | sys.exit(main()) 27 | -------------------------------------------------------------------------------- /.github/workflows/bumpversion.yml: -------------------------------------------------------------------------------- 1 | name: Bump version 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | bump-version: 10 | if: "!startsWith(github.event.head_commit.message, 'bump:')" 11 | runs-on: ubuntu-latest 12 | name: "Bump version and create changelog with commitizen" 13 | steps: 14 | - name: Check out 15 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 16 | with: 17 | fetch-depth: 0 18 | token: '${{ secrets.PERSONAL_ACCESS_TOKEN }}' 19 | - name: Create bump and changelog 20 | uses: commitizen-tools/commitizen-action@master 21 | with: 22 | github_token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} 23 | branch: main 24 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | default_language_version: 2 | python: python3.10 3 | repos: 4 | - repo: https://github.com/pre-commit/pre-commit-hooks 5 | rev: v4.5.0 6 | hooks: 7 | - id: check-toml 8 | - id: check-yaml 9 | args: ["--unsafe"] 10 | - id: end-of-file-fixer 11 | - id: no-commit-to-branch # prevent direct commits to main branch 12 | - id: trailing-whitespace 13 | 14 | - repo: https://github.com/charliermarsh/ruff-pre-commit 15 | rev: v0.3.0 16 | hooks: 17 | - id: ruff 18 | args: [--fix, --exit-non-zero-on-fix] 19 | - id: ruff-format 20 | 21 | - repo: https://github.com/pycqa/isort 22 | rev: 5.13.2 23 | hooks: 24 | - id: isort 25 | name: isort (python) 26 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug Report 3 | about: Create a report to help us improve 4 | title: '[BUG] ' 5 | labels: bug 6 | assignees: '' 7 | --- 8 | 9 | ## Bug Description 10 | A clear and concise description of what the bug is. 11 | 12 | ## Steps To Reproduce 13 | 1. Go to '...' 14 | 2. Click on '...' 15 | 3. Scroll down to '...' 16 | 4. See error 17 | 18 | ## Expected Behavior 19 | A clear and concise description of what you expected to happen. 20 | 21 | ## Screenshots 22 | If applicable, add screenshots to help explain your problem. 23 | 24 | ## Environment 25 | - OS: [e.g. Windows, macOS, Linux] 26 | - Python Version: [e.g. 3.7, 3.8] 27 | - Package Version: [e.g. 0.1.0] 28 | 29 | ## Additional Context 30 | Add any other context about the problem here. 31 | -------------------------------------------------------------------------------- /docs/source/usage.rst: -------------------------------------------------------------------------------- 1 | Usage 2 | ===== 3 | 4 | To use your-project-name in a project:: 5 | 6 | import your_project_name 7 | 8 | Basic Example 9 | ------------ 10 | 11 | Here's a basic example of how to use your-project-name:: 12 | 13 | from your_project_name import some_function 14 | 15 | # Add your example code here 16 | result = some_function() 17 | print(result) 18 | 19 | Command Line Interface 20 | --------------------- 21 | 22 | your-project-name also comes with a command-line interface:: 23 | 24 | $ your-project-name --help 25 | Usage: your-project-name [OPTIONS] 26 | 27 | Options: 28 | -v, --version Show version and exit 29 | -c, --config Path to configuration file 30 | --help Show this message and exit. 31 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | .PHONY: help Makefile 13 | 14 | help: 15 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 16 | 17 | .PHONY: clean 18 | clean: 19 | rm -rf $(BUILDDIR)/* 20 | 21 | # Catch-all target: route all unknown targets to Sphinx using the new 22 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 23 | %: Makefile 24 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 25 | -------------------------------------------------------------------------------- /noxfile.py: -------------------------------------------------------------------------------- 1 | # Import built-in modules 2 | import os 3 | import sys 4 | 5 | # Import third-party modules 6 | import nox 7 | 8 | 9 | ROOT = os.path.dirname(__file__) 10 | 11 | # Ensure maya_umbrella is importable. 12 | if ROOT not in sys.path: 13 | sys.path.append(ROOT) 14 | 15 | # Import third-party modules 16 | from nox_actions import codetest # noqa: E402 17 | from nox_actions import docs # noqa: E402 18 | from nox_actions import lint # noqa: E402 19 | from nox_actions import release # noqa: E402 20 | 21 | 22 | nox.session(lint.lint, name="lint") 23 | nox.session(lint.lint_fix, name="lint-fix") 24 | nox.session(codetest.pytest, name="pytest") 25 | nox.session(release.build_exe, name="build-exe") 26 | nox.session(docs.docs, name="docs") 27 | nox.session(docs.docs_serve, name="docs-serve") 28 | -------------------------------------------------------------------------------- /.github/workflows/issue-translator.yml: -------------------------------------------------------------------------------- 1 | name: 'issue-translator' 2 | on: 3 | issue_comment: 4 | types: [created] 5 | issues: 6 | types: [opened] 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: usthe/issues-translate-action@v2.7 13 | with: 14 | IS_MODIFY_TITLE: false 15 | # not require, default false, . Decide whether to modify the issue title 16 | # if true, the robot account @Issues-translate-bot must have modification permissions, invite @Issues-translate-bot to your project or use your custom bot. 17 | CUSTOM_BOT_NOTE: Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑‍🤝‍🧑👫🧑🏿‍🤝‍🧑🏻👩🏾‍🤝‍👨🏿👬🏿 18 | # not require. Customize the translation robot prefix message. 19 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | schedule: 9 | - cron: '0 0 * * 0' 10 | 11 | jobs: 12 | analyze: 13 | name: Analyze 14 | runs-on: ubuntu-latest 15 | permissions: 16 | actions: read 17 | contents: read 18 | security-events: write 19 | 20 | strategy: 21 | fail-fast: false 22 | matrix: 23 | language: [ 'python' ] 24 | 25 | steps: 26 | - name: Checkout repository 27 | uses: actions/checkout@v4 28 | 29 | - name: Initialize CodeQL 30 | uses: github/codeql-action/init@v3 31 | with: 32 | languages: ${{ matrix.language }} 33 | 34 | - name: Perform CodeQL Analysis 35 | uses: github/codeql-action/analyze@v3 36 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # Your Project Name 2 | 3 | Welcome to the documentation for Your Project Name. 4 | 5 | ## Overview 6 | 7 | Your Project Name is a Python library that [brief description of what your project does]. 8 | 9 | ## Installation 10 | 11 | ```bash 12 | pip install your-project-name 13 | ``` 14 | 15 | Or with Poetry: 16 | 17 | ```bash 18 | poetry add your-project-name 19 | ``` 20 | 21 | ## Quick Start 22 | 23 | ```python 24 | import your_project_name 25 | 26 | # Add usage examples here 27 | ``` 28 | 29 | ## Features 30 | 31 | - Feature 1: Description of feature 1 32 | - Feature 2: Description of feature 2 33 | - Feature 3: Description of feature 3 34 | 35 | ## License 36 | 37 | This project is licensed under the MIT License - see the [LICENSE](https://github.com/yourusername/your-project-name/blob/main/LICENSE) file for details. 38 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yaml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | # Set the OS, Python version and other tools you might need 9 | build: 10 | os: ubuntu-22.04 11 | tools: 12 | python: "3.9" 13 | # You can also specify other tool versions: 14 | # nodejs: "19" 15 | 16 | # Build documentation in the docs/ directory with Sphinx 17 | sphinx: 18 | configuration: docs/source/conf.py 19 | 20 | # Optionally build your docs in additional formats such as PDF and ePub 21 | formats: 22 | - pdf 23 | - epub 24 | 25 | # Optionally declare the Python requirements required to build your docs 26 | python: 27 | install: 28 | - method: pip 29 | path: . 30 | extra_requirements: 31 | - docs 32 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "pip" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | open-pull-requests-limit: 10 8 | target-branch: "main" 9 | labels: 10 | - "dependencies" 11 | - "python" 12 | assignees: 13 | - "yourusername" 14 | reviewers: 15 | - "yourusername" 16 | commit-message: 17 | prefix: "deps" 18 | include: "scope" 19 | 20 | - package-ecosystem: "github-actions" 21 | directory: "/" 22 | schedule: 23 | interval: "weekly" 24 | open-pull-requests-limit: 10 25 | target-branch: "main" 26 | labels: 27 | - "dependencies" 28 | - "github-actions" 29 | assignees: 30 | - "yourusername" 31 | reviewers: 32 | - "yourusername" 33 | commit-message: 34 | prefix: "ci" 35 | include: "scope" 36 | -------------------------------------------------------------------------------- /tests/test_cli.py: -------------------------------------------------------------------------------- 1 | """Tests for the CLI module.""" 2 | 3 | # Import built-in modules 4 | from unittest import mock 5 | 6 | # Import local modules 7 | from your_project_name.cli import main 8 | 9 | 10 | def test_main_returns_zero(): 11 | """Test that the main function returns zero.""" 12 | result = main(["--help"]) 13 | assert result == 0 14 | 15 | 16 | def test_version_flag(): 17 | """Test that the version flag works.""" 18 | with mock.patch("sys.stdout") as mock_stdout: 19 | with mock.patch("sys.exit") as mock_exit: 20 | main(["--version"]) 21 | mock_exit.assert_called_once() 22 | 23 | 24 | def test_config_flag(): 25 | """Test that the config flag works.""" 26 | with mock.patch("builtins.print") as mock_print: 27 | main(["--config", "test_config.json"]) 28 | mock_print.assert_any_call("Using configuration file: test_config.json") 29 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | schedule: 9 | - cron: '30 1 * * 0' 10 | 11 | jobs: 12 | analyze: 13 | name: Analyze 14 | runs-on: ubuntu-latest 15 | permissions: 16 | actions: read 17 | contents: read 18 | security-events: write 19 | 20 | strategy: 21 | fail-fast: false 22 | matrix: 23 | language: [ 'python' ] 24 | 25 | steps: 26 | - name: Checkout repository 27 | uses: actions/checkout@v4 28 | 29 | - name: Initialize CodeQL 30 | uses: github/codeql-action/init@v3 31 | with: 32 | languages: ${{ matrix.language }} 33 | 34 | - name: Autobuild 35 | uses: github/codeql-action/autobuild@v3 36 | 37 | - name: Perform CodeQL Analysis 38 | uses: github/codeql-action/analyze@v3 39 | with: 40 | category: "/language:${{matrix.language}}" 41 | -------------------------------------------------------------------------------- /examples/cli_example.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Example of using the CLI functionality of your-project-name.""" 3 | 4 | # Import built-in modules 5 | import subprocess 6 | import sys 7 | 8 | 9 | def main(): 10 | """Main function to demonstrate CLI usage.""" 11 | print("Running CLI with --help flag:") 12 | result = subprocess.run( 13 | [sys.executable, "-m", "your_project_name", "--help"], 14 | capture_output=True, 15 | text=True, 16 | check=True, 17 | ) 18 | print(result.stdout) 19 | 20 | print("\nRunning CLI with --version flag:") 21 | result = subprocess.run( 22 | [sys.executable, "-m", "your_project_name", "--version"], 23 | capture_output=True, 24 | text=True, 25 | check=False, # Version flag exits with code 0, but subprocess might see it as an error 26 | ) 27 | print(result.stdout) 28 | 29 | return 0 30 | 31 | 32 | if __name__ == "__main__": 33 | sys.exit(main()) 34 | -------------------------------------------------------------------------------- /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | ignore = BLK100 3 | 4 | # flake8-quotes: 5 | # Use double quotes as our default to comply with black, we like it and 6 | # don't want to use single quotes anymore. 7 | # We would love to configure this via our pyproject.toml but flake8-3.8 does 8 | # not support it yet. 9 | inline-quotes = double 10 | multiline-quotes = double 11 | docstring-quotes = double 12 | avoid-escape = True 13 | 14 | # flake8-docstrings 15 | # Use the Google Python Styleguide Docstring format. 16 | docstring-convention=google 17 | 18 | exclude = 19 | # No need to traverse our git directory 20 | .git, 21 | # There's no value in checking cache directories 22 | __pycache__, 23 | # The conf file is mostly autogenerated, ignore it 24 | docs/source/conf.py, 25 | # The old directory contains Flake8 2.0 26 | old, 27 | # This contains our built documentation 28 | build, 29 | # This contains builds of flake8 that we don't want to check 30 | dist, 31 | venv, 32 | docs 33 | 34 | max-line-length = 120 35 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: Mark stale issues and pull requests 2 | 3 | on: 4 | schedule: 5 | - cron: "30 1 * * *" 6 | 7 | jobs: 8 | stale: 9 | runs-on: ubuntu-latest 10 | permissions: 11 | issues: write 12 | pull-requests: write 13 | 14 | steps: 15 | - uses: actions/stale@v9 16 | with: 17 | repo-token: ${{ secrets.GITHUB_TOKEN }} 18 | stale-issue-message: 'This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.' 19 | stale-pr-message: 'This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.' 20 | stale-issue-label: 'stale' 21 | stale-pr-label: 'stale' 22 | days-before-stale: 60 23 | days-before-close: 7 24 | exempt-issue-labels: 'pinned,security,enhancement,bug' 25 | exempt-pr-labels: 'pinned,security,work-in-progress' 26 | -------------------------------------------------------------------------------- /.github/release-drafter-config.yml: -------------------------------------------------------------------------------- 1 | name-template: 'v$RESOLVED_VERSION 🌈' 2 | name-prefix: 'v' 3 | tag-template: 'v$RESOLVED_VERSION' 4 | categories: 5 | - title: '🚀 Features' 6 | labels: 7 | - 'feature' 8 | - 'enhancement' 9 | - title: '🐛 Bug Fixes' 10 | labels: 11 | - 'fix' 12 | - 'bugfix' 13 | - 'bug' 14 | - title: '🧰 Maintenance' 15 | labels: 16 | - 'chore' 17 | - 'maintenance' 18 | - title: '📚 Documentation' 19 | labels: 20 | - 'documentation' 21 | - 'docs' 22 | - title: '⬆️ Dependencies' 23 | labels: 24 | - 'dependencies' 25 | change-template: '- $TITLE @$AUTHOR (#$NUMBER)' 26 | change-title-escapes: '\<*_&' # You can add # and @ to disable mentions, and add ` to disable code blocks. 27 | version-resolver: 28 | major: 29 | labels: 30 | - 'major' 31 | minor: 32 | labels: 33 | - 'minor' 34 | patch: 35 | labels: 36 | - 'patch' 37 | default: patch 38 | template: | 39 | ## Changes 40 | 41 | $CHANGES 42 | 43 | ## Contributors 44 | 45 | $CONTRIBUTORS 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Hal 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. 22 | -------------------------------------------------------------------------------- /.github/workflows/codecov.yml: -------------------------------------------------------------------------------- 1 | name: Codecov 2 | on: [push, pull_request] 3 | jobs: 4 | run: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - name: Checkout 8 | uses: actions/checkout@v4 9 | with: 10 | fetch-depth: 0 11 | - name: Get repository name 12 | id: repo-name 13 | uses: MariachiBear/get-repo-name-action@v1.3.0 14 | with: 15 | with-owner: 'true' 16 | string-case: 'uppercase' 17 | - name: Set up Python 3.10 18 | uses: actions/setup-python@v5 19 | with: 20 | python-version: '3.10' 21 | - name: Install dependencies 22 | run: | 23 | python -m pip install -r requirements-dev.txt 24 | poetry --version 25 | - name: Run tests and collect coverage 26 | run: | 27 | nox -s pytest 28 | - name: Upload coverage reports to Codecov 29 | uses: codecov/codecov-action@v5 30 | with: 31 | slug: loonghao/${{ steps.repo-name.outputs.repository-name }} 32 | files: 'coverage.xml' 33 | env: 34 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} 35 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. 3 | 4 | Fixes # (issue) 5 | 6 | ## Type of change 7 | Please delete options that are not relevant. 8 | 9 | - [ ] Bug fix (non-breaking change which fixes an issue) 10 | - [ ] New feature (non-breaking change which adds functionality) 11 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) 12 | - [ ] Documentation update 13 | 14 | ## How Has This Been Tested? 15 | Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. 16 | 17 | ## Checklist: 18 | - [ ] My code follows the style guidelines of this project 19 | - [ ] I have performed a self-review of my own code 20 | - [ ] I have commented my code, particularly in hard-to-understand areas 21 | - [ ] I have made corresponding changes to the documentation 22 | - [ ] My changes generate no new warnings 23 | - [ ] I have added tests that prove my fix is effective or that my feature works 24 | - [ ] New and existing unit tests pass locally with my changes 25 | -------------------------------------------------------------------------------- /docs/source/installation.rst: -------------------------------------------------------------------------------- 1 | Installation 2 | ============ 3 | 4 | Stable release 5 | ------------- 6 | 7 | To install your-project-name, run this command in your terminal: 8 | 9 | .. code-block:: console 10 | 11 | $ pip install your-project-name 12 | 13 | Or with Poetry: 14 | 15 | .. code-block:: console 16 | 17 | $ poetry add your-project-name 18 | 19 | This is the preferred method to install your-project-name, as it will always install the most recent stable release. 20 | 21 | From sources 22 | ----------- 23 | 24 | The sources for your-project-name can be downloaded from the `Github repo`_. 25 | 26 | You can either clone the public repository: 27 | 28 | .. code-block:: console 29 | 30 | $ git clone git://github.com/yourusername/your-project-name 31 | 32 | Or download the `tarball`_: 33 | 34 | .. code-block:: console 35 | 36 | $ curl -OJL https://github.com/yourusername/your-project-name/tarball/main 37 | 38 | Once you have a copy of the source, you can install it with: 39 | 40 | .. code-block:: console 41 | 42 | $ poetry install 43 | 44 | 45 | .. _Github repo: https://github.com/yourusername/your-project-name 46 | .. _tarball: https://github.com/yourusername/your-project-name/tarball/main 47 | -------------------------------------------------------------------------------- /.github/workflows/docs.yml: -------------------------------------------------------------------------------- 1 | name: Build and Deploy Docs 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | paths: 7 | - 'docs/**' 8 | - 'src/**' 9 | - '.github/workflows/docs.yml' 10 | pull_request: 11 | branches: [main] 12 | paths: 13 | - 'docs/**' 14 | - 'src/**' 15 | - '.github/workflows/docs.yml' 16 | release: 17 | types: [published] 18 | workflow_dispatch: 19 | 20 | jobs: 21 | docs: 22 | runs-on: ubuntu-latest 23 | steps: 24 | - uses: actions/checkout@v4 25 | with: 26 | fetch-depth: 0 27 | 28 | - name: Set up Python 29 | uses: actions/setup-python@v5 30 | with: 31 | python-version: '3.9' 32 | 33 | - name: Install dependencies 34 | run: | 35 | python -m pip install --upgrade pip 36 | pip install poetry 37 | poetry install --with docs 38 | 39 | - name: Build docs 40 | run: | 41 | cd docs 42 | make html 43 | 44 | - name: Deploy to GitHub Pages 45 | uses: peaceiris/actions-gh-pages@v3 46 | if: github.event_name == 'push' && github.ref == 'refs/heads/main' || github.event_name == 'release' || github.event_name == 'workflow_dispatch' 47 | with: 48 | github_token: ${{ secrets.GITHUB_TOKEN }} 49 | publish_dir: ./docs/build/html 50 | -------------------------------------------------------------------------------- /nox_actions/docs.py: -------------------------------------------------------------------------------- 1 | """Nox sessions for building documentation.""" 2 | 3 | # Import built-in modules 4 | import os 5 | import shutil 6 | from pathlib import Path 7 | 8 | # Import third-party modules 9 | import nox 10 | 11 | # Import local modules 12 | from nox_actions.utils import PACKAGE_NAME, THIS_ROOT 13 | 14 | 15 | @nox.session 16 | def docs(session): 17 | """Build the documentation.""" 18 | output_dir = os.path.join(THIS_ROOT, "docs", "build", "html") 19 | if os.path.exists(output_dir): 20 | shutil.rmtree(output_dir) 21 | session.install("-e", ".") 22 | session.install("sphinx", "sphinx-rtd-theme", "myst-parser") 23 | session.chdir(os.path.join(THIS_ROOT, "docs")) 24 | session.run( 25 | "sphinx-build", 26 | "-b", 27 | "html", 28 | "source", 29 | "build/html", 30 | "-W", 31 | ) 32 | 33 | 34 | @nox.session 35 | def docs_serve(session): 36 | """Build and serve the documentation with live reloading on file changes.""" 37 | session.install("-e", ".") 38 | session.install("sphinx", "sphinx-rtd-theme", "sphinx-autobuild", "myst-parser") 39 | session.chdir(os.path.join(THIS_ROOT, "docs")) 40 | session.run( 41 | "sphinx-autobuild", 42 | "--watch", f"../src/{PACKAGE_NAME}", 43 | "--re-ignore", r"_build/.*", 44 | "--open-browser", 45 | "source", 46 | "build/html", 47 | ) 48 | -------------------------------------------------------------------------------- /examples/config_example.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Example of using configuration in your-project-name.""" 3 | 4 | # Import built-in modules 5 | import json 6 | import os 7 | import sys 8 | 9 | # Add the parent directory to sys.path to import the package 10 | sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) 11 | 12 | # Import the package 13 | from your_project_name.config import get_config, save_config 14 | 15 | 16 | def main(): 17 | """Main function to demonstrate configuration usage.""" 18 | # Load example config 19 | config_path = os.path.join(os.path.dirname(__file__), 'config.json') 20 | 21 | with open(config_path, 'r') as f: 22 | example_config = json.load(f) 23 | 24 | print("Example configuration:") 25 | print(json.dumps(example_config, indent=2)) 26 | 27 | # Modify configuration 28 | example_config['settings']['debug'] = True 29 | example_config['settings']['log_level'] = 'DEBUG' 30 | 31 | # Save modified configuration 32 | modified_path = os.path.join(os.path.dirname(__file__), 'modified_config.json') 33 | save_config(example_config, modified_path) 34 | 35 | # Load the modified configuration 36 | loaded_config = get_config(modified_path) 37 | 38 | print("\nModified configuration:") 39 | print(json.dumps(loaded_config, indent=2)) 40 | 41 | return 0 42 | 43 | 44 | if __name__ == "__main__": 45 | sys.exit(main()) 46 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | # Git 2 | .git 3 | .gitignore 4 | .github 5 | 6 | # CI 7 | .codeclimate.yml 8 | .travis.yml 9 | .taskcluster.yml 10 | 11 | # Docker 12 | docker-compose.yml 13 | Dockerfile 14 | .docker 15 | .dockerignore 16 | 17 | # Byte-compiled / optimized / DLL files 18 | __pycache__/ 19 | **/__pycache__/ 20 | *.py[cod] 21 | *$py.class 22 | *.so 23 | .Python 24 | build/ 25 | develop-eggs/ 26 | dist/ 27 | downloads/ 28 | eggs/ 29 | .eggs/ 30 | lib/ 31 | lib64/ 32 | parts/ 33 | sdist/ 34 | var/ 35 | wheels/ 36 | *.egg-info/ 37 | .installed.cfg 38 | *.egg 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | .hypothesis/ 51 | 52 | # Translations 53 | *.mo 54 | *.pot 55 | 56 | # PyBuilder 57 | target/ 58 | 59 | # Jupyter Notebook 60 | .ipynb_checkpoints 61 | 62 | # IPython 63 | profile_default/ 64 | ipython_config.py 65 | 66 | # pyenv 67 | .python-version 68 | 69 | # celery beat schedule file 70 | celerybeat-schedule 71 | 72 | # SageMath parsed files 73 | *.sage.py 74 | 75 | # Environments 76 | .env 77 | .venv 78 | env/ 79 | venv/ 80 | ENV/ 81 | env.bak/ 82 | venv.bak/ 83 | 84 | # Spyder project settings 85 | .spyderproject 86 | .spyproject 87 | 88 | # Rope project settings 89 | .ropeproject 90 | 91 | # mypy 92 | .mypy_cache/ 93 | 94 | # ruff 95 | .ruff_cache/ 96 | 97 | # IDE settings 98 | .vscode/ 99 | .idea/ 100 | *.swp 101 | *~ 102 | 103 | # macOS 104 | .DS_Store 105 | -------------------------------------------------------------------------------- /.github/workflows/build-exe.yml: -------------------------------------------------------------------------------- 1 | name: Build Executable 2 | 3 | on: 4 | workflow_run: 5 | workflows: ["Python Package"] 6 | types: 7 | - completed 8 | branches: 9 | - "main" 10 | 11 | jobs: 12 | build: 13 | # Only run if the python-publish workflow succeeded 14 | if: ${{ github.event.workflow_run.conclusion == 'success' }} 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | target: 19 | - os: windows-2022 20 | triple: x86_64-pc-windows-msvc 21 | - os: ubuntu-22.04 22 | triple: x86_64-unknown-linux-gnu 23 | - os: macos-12 24 | triple: x86_64-apple-darwin 25 | runs-on: ${{ matrix.target.os }} 26 | permissions: 27 | contents: write 28 | 29 | steps: 30 | - uses: actions/checkout@v4 31 | with: 32 | fetch-depth: 0 33 | 34 | - uses: olegtarasov/get-tag@v2.1.4 35 | id: get_tag_name 36 | with: 37 | tagRegex: "v(?.*)" 38 | 39 | - name: Set up Python 40 | uses: actions/setup-python@v5 41 | with: 42 | python-version: "3.10" 43 | cache: pip 44 | 45 | - name: Install dependencies 46 | run: | 47 | python -m pip install --upgrade pip 48 | pip install nox 49 | 50 | - name: Build exe 51 | run: | 52 | nox -s build-exe -- --release --version ${{ steps.get_tag_name.outputs.version }} 53 | 54 | - uses: ncipollo/release-action@v1 55 | with: 56 | allowUpdates: true 57 | updateOnlyUnreleased: false 58 | omitBody: true 59 | artifacts: ".zip/*.zip" 60 | token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} 61 | -------------------------------------------------------------------------------- /src/your_project_name/cli.py: -------------------------------------------------------------------------------- 1 | """Command-line interface for the project.""" 2 | 3 | # Import built-in modules 4 | import argparse 5 | import sys 6 | from typing import List, Optional 7 | 8 | # Import local modules 9 | from .__version__ import __version__ 10 | 11 | 12 | def parse_args(args: Optional[List[str]] = None) -> argparse.Namespace: 13 | """Parse command line arguments. 14 | 15 | Args: 16 | args: Command line arguments. If None, uses sys.argv. 17 | 18 | Returns: 19 | Parsed arguments. 20 | """ 21 | parser = argparse.ArgumentParser( 22 | description="Your project description", 23 | formatter_class=argparse.ArgumentDefaultsHelpFormatter, 24 | ) 25 | 26 | parser.add_argument( 27 | "-v", "--version", 28 | action="version", 29 | version=f"%(prog)s {__version__}", 30 | help="Show version and exit", 31 | ) 32 | 33 | # Add your arguments here 34 | parser.add_argument( 35 | "-c", "--config", 36 | help="Path to configuration file", 37 | ) 38 | 39 | return parser.parse_args(args) 40 | 41 | 42 | def main(args: Optional[List[str]] = None) -> int: 43 | """Main entry point for the application. 44 | 45 | Args: 46 | args: Command line arguments. If None, uses sys.argv. 47 | 48 | Returns: 49 | Exit code. 50 | """ 51 | parsed_args = parse_args(args) 52 | 53 | # Your application logic here 54 | print(f"Running your_project_name version {__version__}") 55 | 56 | if parsed_args.config: 57 | print(f"Using configuration file: {parsed_args.config}") 58 | 59 | return 0 60 | 61 | 62 | if __name__ == "__main__": 63 | sys.exit(main()) 64 | -------------------------------------------------------------------------------- /.github/workflows/docker-publish.yml: -------------------------------------------------------------------------------- 1 | name: Docker 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | tags: [ 'v*.*.*' ] 7 | pull_request: 8 | branches: [ "main" ] 9 | 10 | env: 11 | REGISTRY: ghcr.io 12 | IMAGE_NAME: ${{ github.repository }} 13 | 14 | jobs: 15 | build: 16 | runs-on: ubuntu-latest 17 | permissions: 18 | contents: read 19 | packages: write 20 | id-token: write 21 | 22 | steps: 23 | - name: Checkout repository 24 | uses: actions/checkout@v4 25 | 26 | - name: Setup Docker buildx 27 | uses: docker/setup-buildx-action@v3 28 | 29 | - name: Log into registry ${{ env.REGISTRY }} 30 | if: github.event_name != 'pull_request' 31 | uses: docker/login-action@v3 32 | with: 33 | registry: ${{ env.REGISTRY }} 34 | username: ${{ github.actor }} 35 | password: ${{ secrets.GITHUB_TOKEN }} 36 | 37 | - name: Extract Docker metadata 38 | id: meta 39 | uses: docker/metadata-action@v5 40 | with: 41 | images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} 42 | tags: | 43 | type=semver,pattern={{version}} 44 | type=semver,pattern={{major}}.{{minor}} 45 | type=semver,pattern={{major}} 46 | type=ref,event=branch 47 | type=ref,event=pr 48 | type=sha 49 | 50 | - name: Build and push Docker image 51 | id: build-and-push 52 | uses: docker/build-push-action@v5 53 | with: 54 | context: . 55 | push: ${{ github.event_name != 'pull_request' }} 56 | tags: ${{ steps.meta.outputs.tags }} 57 | labels: ${{ steps.meta.outputs.labels }} 58 | cache-from: type=gha 59 | cache-to: type=gha,mode=max 60 | -------------------------------------------------------------------------------- /src/your_project_name/config.py: -------------------------------------------------------------------------------- 1 | """Configuration handling for the project.""" 2 | 3 | # Import built-in modules 4 | from pathlib import Path 5 | from typing import Dict, Optional, Union 6 | 7 | # Import third-party modules 8 | from platformdirs import user_config_dir 9 | 10 | # Constants 11 | APP_NAME = "your_project_name" 12 | CONFIG_DIR = Path(user_config_dir(APP_NAME)) 13 | DEFAULT_CONFIG_PATH = CONFIG_DIR / "config.json" 14 | 15 | 16 | def ensure_config_dir() -> None: 17 | """Ensure the configuration directory exists.""" 18 | CONFIG_DIR.mkdir(parents=True, exist_ok=True) 19 | 20 | 21 | def get_config(config_path: Optional[Union[str, Path]] = None) -> Dict: 22 | """Get configuration from file. 23 | 24 | Args: 25 | config_path: Path to configuration file. If None, uses default path. 26 | 27 | Returns: 28 | Configuration dictionary. 29 | """ 30 | import json 31 | 32 | if config_path is None: 33 | config_path = DEFAULT_CONFIG_PATH 34 | else: 35 | config_path = Path(config_path) 36 | 37 | if not config_path.exists(): 38 | return {} 39 | 40 | with open(config_path, "r") as f: 41 | return json.load(f) 42 | 43 | 44 | def save_config(config: Dict, config_path: Optional[Union[str, Path]] = None) -> None: 45 | """Save configuration to file. 46 | 47 | Args: 48 | config: Configuration dictionary to save. 49 | config_path: Path to save configuration to. If None, uses default path. 50 | """ 51 | import json 52 | 53 | if config_path is None: 54 | config_path = DEFAULT_CONFIG_PATH 55 | else: 56 | config_path = Path(config_path) 57 | 58 | ensure_config_dir() 59 | 60 | with open(config_path, "w") as f: 61 | json.dump(config, f, indent=2) 62 | -------------------------------------------------------------------------------- /.github/workflows/scorecards.yml: -------------------------------------------------------------------------------- 1 | name: Scorecards supply-chain security 2 | on: 3 | # Only the default branch is supported. 4 | branch_protection_rule: 5 | schedule: 6 | - cron: '30 1 * * 6' 7 | push: 8 | branches: [ "main" ] 9 | 10 | # Declare default permissions as read only. 11 | permissions: read-all 12 | 13 | jobs: 14 | analysis: 15 | name: Scorecards analysis 16 | runs-on: ubuntu-latest 17 | permissions: 18 | # Needed to upload the results to code-scanning dashboard. 19 | security-events: write 20 | # Used to receive a badge. 21 | id-token: write 22 | # Needs for private repositories. 23 | contents: read 24 | actions: read 25 | 26 | steps: 27 | - name: "Checkout code" 28 | uses: actions/checkout@v4 29 | with: 30 | persist-credentials: false 31 | 32 | - name: "Run analysis" 33 | uses: ossf/scorecard-action@v2.3.1 34 | with: 35 | results_file: results.sarif 36 | results_format: sarif 37 | # (Optional) Read-only PAT token. Uncomment the line below if you want to enable the Branch-Protection check on a private repository. 38 | # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat. 39 | # repo_token: ${{ secrets.SCORECARD_READ_TOKEN }} 40 | # Publish the results for public repositories to enable scorecard badges. For more details, see 41 | # https://github.com/ossf/scorecard-action#publishing-results. 42 | publish_results: true 43 | 44 | # Upload the results as artifacts (optional). 45 | - name: "Upload artifact" 46 | uses: actions/upload-artifact@v4 47 | with: 48 | name: SARIF file 49 | path: results.sarif 50 | retention-days: 5 51 | 52 | # Upload the results to GitHub's code scanning dashboard. 53 | - name: "Upload to code-scanning" 54 | uses: github/codeql-action/upload-sarif@v3 55 | with: 56 | sarif_file: results.sarif 57 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Your Project Name 2 | 3 | Thank you for your interest in contributing to this project! Here are some guidelines to help you get started. 4 | 5 | ## Development Setup 6 | 7 | 1. Clone the repository: 8 | ```bash 9 | git clone https://github.com/yourusername/your-project-name.git 10 | cd your-project-name 11 | ``` 12 | 13 | 2. Install development dependencies with Poetry: 14 | ```bash 15 | poetry install 16 | ``` 17 | 18 | 3. Install pre-commit hooks: 19 | ```bash 20 | pre-commit install 21 | ``` 22 | 23 | ## Code Style 24 | 25 | This project uses: 26 | - [Ruff](https://github.com/charliermarsh/ruff) for linting and formatting 27 | - [isort](https://pycqa.github.io/isort/) for import sorting 28 | - [mypy](https://mypy.readthedocs.io/) for type checking 29 | 30 | You can run the linters with: 31 | ```bash 32 | nox -s lint 33 | ``` 34 | 35 | And fix formatting issues with: 36 | ```bash 37 | nox -s lint_fix 38 | ``` 39 | 40 | ## Testing 41 | 42 | Write tests for all new features and bug fixes. Run the test suite with: 43 | ```bash 44 | nox -s pytest 45 | ``` 46 | 47 | ## Pull Request Process 48 | 49 | 1. Fork the repository and create your branch from `main`. 50 | 2. Make your changes and add tests if applicable. 51 | 3. Ensure all tests pass and code style checks pass. 52 | 4. Update documentation if needed. 53 | 5. Submit a pull request. 54 | 55 | ## Commit Messages 56 | 57 | This project follows [Conventional Commits](https://www.conventionalcommits.org/) for commit messages: 58 | 59 | ``` 60 | [optional scope]: 61 | 62 | [optional body] 63 | 64 | [optional footer(s)] 65 | ``` 66 | 67 | Types include: 68 | - `feat`: A new feature 69 | - `fix`: A bug fix 70 | - `docs`: Documentation changes 71 | - `style`: Code style changes (formatting, etc.) 72 | - `refactor`: Code refactoring 73 | - `test`: Adding or updating tests 74 | - `chore`: Maintenance tasks 75 | 76 | ## License 77 | 78 | By contributing to this project, you agree that your contributions will be licensed under the project's [MIT License](LICENSE). 79 | -------------------------------------------------------------------------------- /.github/workflows/python-publish.yml: -------------------------------------------------------------------------------- 1 | name: Upload Python Package 2 | 3 | on: 4 | push: 5 | tags: 6 | - "v*" 7 | 8 | jobs: 9 | deploy: 10 | runs-on: ubuntu-latest 11 | permissions: 12 | # IMPORTANT: this permission is mandatory for trusted publishing 13 | id-token: write 14 | contents: write 15 | 16 | steps: 17 | - uses: actions/checkout@v4 18 | with: 19 | token: "${{ secrets.GITHUB_TOKEN }}" 20 | fetch-depth: 0 21 | ref: main 22 | - uses: olegtarasov/get-tag@v2.1.4 23 | id: get_tag_name 24 | with: 25 | tagRegex: "v(?.*)" 26 | - name: Set up Python 27 | uses: actions/setup-python@v5 28 | with: 29 | python-version: '3.x' 30 | - name: Install dependencies 31 | run: | 32 | python -m pip install --upgrade pip 33 | python -m pip install poetry build twine 34 | poetry build 35 | # Note that we don't need credentials. 36 | # We rely on https://docs.pypi.org/trusted-publishers/. 37 | - name: Upload to PyPI 38 | uses: pypa/gh-action-pypi-publish@release/v1 39 | with: 40 | packages-dir: dist 41 | - name: Generate changelog 42 | id: changelog 43 | uses: jaywcjlove/changelog-generator@main 44 | with: 45 | token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} 46 | filter-author: (|dependabot|renovate\[bot\]|dependabot\[bot\]|Renovate Bot) 47 | filter: '[R|r]elease[d]\s+[v|V]\d(\.\d+){0,2}' 48 | template: | 49 | ## Bugs 50 | {{fix}} 51 | ## Feature 52 | {{feat}} 53 | ## Improve 54 | {{refactor,perf,clean}} 55 | ## Misc 56 | {{chore,style,ci||🔶 Nothing change}} 57 | ## Unknown 58 | {{__unknown__}} 59 | - uses: ncipollo/release-action@v1 60 | with: 61 | artifacts: "dist/*" 62 | token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} 63 | body: | 64 | Comparing Changes: ${{ steps.changelog.outputs.compareurl }} 65 | 66 | ${{ steps.changelog.outputs.changelog }} 67 | -------------------------------------------------------------------------------- /nox_actions/release.py: -------------------------------------------------------------------------------- 1 | # Import built-in modules 2 | import argparse 3 | import os 4 | import shutil 5 | import zipfile 6 | 7 | # Import third-party modules 8 | import nox 9 | from nox_actions.utils import PACKAGE_NAME 10 | from nox_actions.utils import THIS_ROOT 11 | 12 | 13 | @nox.session(name="build-exe", reuse_venv=True) 14 | def build_exe(session: nox.Session) -> None: 15 | parser = argparse.ArgumentParser(prog="nox -s build-exe --release") 16 | parser.add_argument("--release", action="store_true") 17 | parser.add_argument("--version", default="0.5.0", help="Version to use for the zip file") 18 | parser.add_argument("--test", action="store_true") 19 | args = parser.parse_args(session.posargs) 20 | build_root = THIS_ROOT / "build" 21 | session.install("pyoxidizer") 22 | session.run("pyoxidizer", "build", "install", "--path", THIS_ROOT, "--release") 23 | for platform_name in os.listdir(build_root): 24 | platform_dir = build_root / platform_name / "release" / "install" 25 | print(os.listdir(platform_dir)) 26 | print(f"build {platform_name} -> {platform_dir}") 27 | 28 | if args.test: 29 | print("run tests") 30 | vexcle_exe = shutil.which("vexcle", path=platform_dir) 31 | assert os.path.exists(vexcle_exe) 32 | 33 | if args.release: 34 | temp_dir = os.path.join(THIS_ROOT, ".zip") 35 | version = str(args.version) 36 | print(f"make zip to current version: {version}") 37 | os.makedirs(temp_dir, exist_ok=True) 38 | zip_file = os.path.join(temp_dir, f"{PACKAGE_NAME}-{version}-{platform_name}.zip") 39 | with zipfile.ZipFile(zip_file, "w") as zip_obj: 40 | for root, _, files in os.walk(platform_dir): 41 | for file in files: 42 | zip_obj.write(os.path.join(root, file), 43 | os.path.relpath(os.path.join(root, file), 44 | os.path.join(platform_dir, "."))) 45 | print("Saving to {zipfile}".format(zipfile=zip_file)) 46 | -------------------------------------------------------------------------------- /.github/release-template.md: -------------------------------------------------------------------------------- 1 | # Your Project Name $RELEASE_VERSION 2 | 3 |
4 | 5 | [![PyPI version](https://badge.fury.io/py/your-project-name.svg)](https://badge.fury.io/py/your-project-name) 6 | [![Build Status](https://github.com/username/your-project-name/workflows/Build%20and%20Release/badge.svg)](https://github.com/username/your-project-name/actions) 7 | [![Documentation Status](https://readthedocs.org/projects/your-project-name/badge/?version=latest)](https://your-project-name.readthedocs.io/en/latest/?badge=latest) 8 | [![Python Version](https://img.shields.io/pypi/pyversions/your-project-name.svg)](https://pypi.org/project/your-project-name/) 9 | [![License](https://img.shields.io/github/license/username/your-project-name.svg)](https://github.com/username/your-project-name/blob/main/LICENSE) 10 | [![Downloads](https://static.pepy.tech/badge/your-project-name)](https://pepy.tech/project/your-project-name) 11 | [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) 12 | [![Ruff](https://img.shields.io/badge/ruff-enabled-brightgreen)](https://github.com/astral-sh/ruff) 13 | 14 |
15 | 16 | ## 🚀 What's New 17 | 18 | $CHANGES 19 | 20 | For detailed release notes, see the [CHANGELOG.md](https://github.com/username/your-project-name/blob/main/CHANGELOG.md). 21 | 22 | ## 📦 Installation 23 | 24 | ### Using pip 25 | 26 | ```bash 27 | pip install your-project-name==$RELEASE_VERSION 28 | ``` 29 | 30 | ### Using Poetry 31 | 32 | ```bash 33 | poetry add your-project-name==$RELEASE_VERSION 34 | ``` 35 | 36 | ### From source 37 | 38 | ```bash 39 | git clone https://github.com/username/your-project-name.git 40 | cd your-project-name 41 | git checkout $RELEASE_VERSION # Checkout the specific version 42 | pip install -e . 43 | ``` 44 | 45 | ## 💻 Supported Platforms 46 | 47 | - Windows 48 | - Linux 49 | - macOS 50 | 51 | ## 🐍 Python Compatibility 52 | 53 | - Python 3.7+ 54 | 55 | ## ✨ Key Features 56 | 57 | - Feature 1 58 | - Feature 2 59 | - Feature 3 60 | 61 | ## 📚 Documentation 62 | 63 | For detailed documentation, visit [https://your-project-name.readthedocs.io/](https://your-project-name.readthedocs.io/) 64 | -------------------------------------------------------------------------------- /.github/labels.yml: -------------------------------------------------------------------------------- 1 | - name: "bug" 2 | color: "d73a4a" 3 | description: "Something isn't working" 4 | 5 | - name: "documentation" 6 | color: "0075ca" 7 | description: "Improvements or additions to documentation" 8 | 9 | - name: "duplicate" 10 | color: "cfd3d7" 11 | description: "This issue or pull request already exists" 12 | 13 | - name: "enhancement" 14 | color: "a2eeef" 15 | description: "New feature or request" 16 | 17 | - name: "good first issue" 18 | color: "7057ff" 19 | description: "Good for newcomers" 20 | 21 | - name: "help wanted" 22 | color: "008672" 23 | description: "Extra attention is needed" 24 | 25 | - name: "invalid" 26 | color: "e4e669" 27 | description: "This doesn't seem right" 28 | 29 | - name: "question" 30 | color: "d876e3" 31 | description: "Further information is requested" 32 | 33 | - name: "wontfix" 34 | color: "ffffff" 35 | description: "This will not be worked on" 36 | 37 | - name: "dependencies" 38 | color: "0366d6" 39 | description: "Pull requests that update a dependency file" 40 | 41 | - name: "python" 42 | color: "2b67c6" 43 | description: "Pull requests that update Python code" 44 | 45 | - name: "github-actions" 46 | color: "000000" 47 | description: "Pull requests that update GitHub Actions code" 48 | 49 | - name: "security" 50 | color: "ee0701" 51 | description: "Security related issues or changes" 52 | 53 | - name: "performance" 54 | color: "16c60c" 55 | description: "Performance improvements" 56 | 57 | - name: "testing" 58 | color: "fbca04" 59 | description: "Testing related changes" 60 | 61 | - name: "ci" 62 | color: "0e8a16" 63 | description: "Changes to CI configuration files and scripts" 64 | 65 | - name: "feature" 66 | color: "a2eeef" 67 | description: "New feature or request" 68 | 69 | - name: "fix" 70 | color: "d73a4a" 71 | description: "Bug fix" 72 | 73 | - name: "maintenance" 74 | color: "c5def5" 75 | description: "Repository maintenance" 76 | 77 | - name: "docs" 78 | color: "0075ca" 79 | description: "Documentation only changes" 80 | 81 | - name: "major" 82 | color: "b60205" 83 | description: "Major version bump" 84 | 85 | - name: "minor" 86 | color: "fbca04" 87 | description: "Minor version bump" 88 | 89 | - name: "patch" 90 | color: "0e8a16" 91 | description: "Patch version bump" 92 | 93 | - name: "pinned" 94 | color: "c2e0c6" 95 | description: "Pinned for later review" 96 | 97 | - name: "work-in-progress" 98 | color: "c5def5" 99 | description: "Work in progress" 100 | -------------------------------------------------------------------------------- /.github/workflows/mr-test.yml: -------------------------------------------------------------------------------- 1 | name: MR Checks 2 | on: [ pull_request ] 3 | 4 | jobs: 5 | python-check: 6 | strategy: 7 | max-parallel: 3 8 | matrix: 9 | os: [ubuntu-latest, windows-latest, macos-latest] 10 | python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"] 11 | include: 12 | - os: ubuntu-latest 13 | python-version: "3.7" 14 | fail-fast: false 15 | runs-on: ${{ matrix.os }} 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v4 19 | with: 20 | fetch-depth: 0 21 | 22 | - name: Set up Python ${{ matrix.python-version }} 23 | uses: actions/setup-python@v5 24 | with: 25 | python-version: ${{ matrix.python-version }} 26 | cache: 'pip' 27 | cache-dependency-path: '**/pyproject.toml' 28 | 29 | # 缓存 Poetry 依赖 30 | - name: Cache Poetry dependencies 31 | uses: actions/cache@v4 32 | with: 33 | path: ~/.cache/pypoetry 34 | key: ${{ runner.os }}-poetry-${{ matrix.python-version }}-${{ hashFiles('**/poetry.lock') }} 35 | restore-keys: | 36 | ${{ runner.os }}-poetry-${{ matrix.python-version }}- 37 | 38 | # 缓存 nox 环境 39 | - name: Cache nox environments 40 | uses: actions/cache@v4 41 | with: 42 | path: .nox 43 | key: ${{ runner.os }}-nox-${{ matrix.python-version }}-${{ hashFiles('**/noxfile.py') }} 44 | restore-keys: | 45 | ${{ runner.os }}-nox-${{ matrix.python-version }}- 46 | 47 | # 安装依赖 48 | - name: Install dependencies (Python >= 3.8) 49 | if: matrix.python-version != '3.7' 50 | run: | 51 | python -m pip install --upgrade pip 52 | python -m pip install uv 53 | uvx poetry lock 54 | uvx poetry install 55 | 56 | # 为 Python 3.7 特殊处理 57 | - name: Install dependencies (Python 3.7) 58 | if: matrix.python-version == '3.7' 59 | run: | 60 | python -m pip install --upgrade pip 61 | python -m pip install poetry 62 | poetry lock 63 | poetry install 64 | 65 | # 运行 lint 66 | - name: Lint (Python >= 3.8) 67 | if: matrix.python-version != '3.7' 68 | run: | 69 | uvx nox -s lint 70 | 71 | # 为 Python 3.7 特殊处理 72 | - name: Lint (Python 3.7) 73 | if: matrix.python-version == '3.7' 74 | run: | 75 | python -m pip install nox 76 | nox -s lint 77 | 78 | # 运行测试 79 | - name: Test (Python >= 3.8) 80 | if: matrix.python-version != '3.7' 81 | run: | 82 | uvx nox -s pytest 83 | 84 | # 为 Python 3.7 特殊处理 85 | - name: Test (Python 3.7) 86 | if: matrix.python-version == '3.7' 87 | run: | 88 | nox -s pytest 89 | -------------------------------------------------------------------------------- /README_zh.md: -------------------------------------------------------------------------------- 1 | # DCC-MCP 2 | 3 |
4 | 5 | [![PyPI version](https://badge.fury.io/py/dcc-mcp.svg)](https://badge.fury.io/py/dcc-mcp) 6 | [![Build Status](https://github.com/loonghao/dcc-mcp/workflows/Build%20and%20Release/badge.svg)](https://github.com/loonghao/dcc-mcp/actions) 7 | [![Documentation Status](https://readthedocs.org/projects/dcc-mcp/badge/?version=latest)](https://dcc-mcp.readthedocs.io/en/latest/?badge=latest) 8 | [![Python Version](https://img.shields.io/pypi/pyversions/dcc-mcp.svg)](https://pypi.org/project/dcc-mcp/) 9 | [![License](https://img.shields.io/github/license/loonghao/dcc-mcp.svg)](https://github.com/loonghao/dcc-mcp/blob/main/LICENSE) 10 | [![Downloads](https://static.pepy.tech/badge/dcc-mcp)](https://pepy.tech/project/dcc-mcp) 11 | [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) 12 | [![Ruff](https://img.shields.io/badge/ruff-enabled-brightgreen)](https://github.com/astral-sh/ruff) 13 | 14 |
15 | 16 | DCC-MCP 是基于模型-上下文-协议(MCP)在数字内容创作(DCC)软件中的统一实现方案,旨在为VFX和动画行业的各种DCC应用程序提供一致的接口。 17 | 18 | > **注意:** 前置API目前正在开发中,敬请期待! 19 | > 20 | > 相关组件 (dcc-mcp-core, dcc-mcp-maya, dcc-mcp-rpyc) 也正在积极开发中。 21 | 22 | ## 特性 23 | 24 | - 针对DCC应用程序的MCP标准化实现 25 | - 跨不同DCC软件的一致性API(Maya、Houdini、Nuke等) 26 | - 跨平台兼容性(Windows、Linux、macOS) 27 | - 可扩展的架构,支持自定义集成 28 | 29 | ## 安装 30 | 31 | ```bash 32 | pip install dcc-mcp 33 | ``` 34 | 35 | 或者使用 Poetry: 36 | 37 | ```bash 38 | poetry add dcc-mcp 39 | ``` 40 | 41 | ## 使用方法 42 | 43 | ```python 44 | import dcc_mcp 45 | 46 | # API最终确定后将提供使用示例 47 | ``` 48 | 49 | ## 开发 50 | 51 | ### 环境设置 52 | 53 | ```bash 54 | # 克隆仓库 55 | git clone https://github.com/loonghao/dcc-mcp.git 56 | cd dcc-mcp 57 | 58 | # 使用 Poetry 安装依赖 59 | poetry install 60 | ``` 61 | 62 | ### 测试 63 | 64 | ```bash 65 | # 使用 nox 运行测试 66 | nox -s pytest 67 | 68 | # 运行代码检查 69 | nox -s lint 70 | 71 | # 修复代码风格问题 72 | nox -s lint_fix 73 | ``` 74 | 75 | ### 文档 76 | 77 | ```bash 78 | # 构建文档 79 | nox -s docs 80 | 81 | # 启动带有实时重载功能的文档服务器 82 | nox -s docs-serve 83 | ``` 84 | 85 | ## 许可证 86 | 87 | MIT 88 | 89 | ## GitHub Actions 配置 90 | 91 | 本项目使用 GitHub Actions 进行 CI/CD。包含以下工作流: 92 | 93 | - **构建和发布**:在多个 Python 版本和操作系统上测试包,并在创建新版本时发布到 PyPI。 94 | - **文档**:构建文档并部署到 GitHub Pages。 95 | - **依赖审查**:扫描依赖项中的安全漏洞。 96 | - **Scorecards**:分析项目的安全健康状况。 97 | 98 | 发布工作流使用 PyPI 的可信发布(trusted publishing)功能,这意味着您不需要设置任何 PyPI API 令牌。相反,您需要在创建包后在 PyPI 项目设置中配置可信发布。有关更多信息,请参阅 [PyPI 关于可信发布的文档](https://docs.pypi.org/trusted-publishers/)。 99 | 100 | ### 发布流程 101 | 102 | 创建新版本的步骤: 103 | 104 | 1. 更新 `pyproject.toml` 中的版本号 105 | 2. 更新 `CHANGELOG.md`,添加新版本和变更内容 106 | 3. 提交并推送更改 107 | 4. 创建一个带有版本号的新标签(例如 `1.0.0`) 108 | 5. 将标签推送到 GitHub 109 | 110 | ```bash 111 | # 发布流程示例 112 | git add pyproject.toml CHANGELOG.md 113 | git commit -m "Release 1.0.0" 114 | git tag 1.0.0 115 | git push && git push --tags 116 | ``` 117 | 118 | GitHub Actions 工作流将自动构建包并发布到 PyPI。 119 | -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | # 13 | import os 14 | import sys 15 | import datetime 16 | 17 | sys.path.insert(0, os.path.abspath('../..')) 18 | 19 | # -- Project information ----------------------------------------------------- 20 | 21 | project = 'your-project-name' 22 | copyright = f'{datetime.datetime.now().year}, Your Name' 23 | author = 'Your Name' 24 | 25 | # The full version, including alpha/beta/rc tags 26 | from your_project_name.__version__ import __version__ 27 | release = __version__ 28 | version = '.'.join(release.split('.')[:2]) 29 | 30 | # -- General configuration --------------------------------------------------- 31 | 32 | # Add any Sphinx extension module names here, as strings. They can be 33 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 34 | # ones. 35 | extensions = [ 36 | 'sphinx.ext.autodoc', 37 | 'sphinx.ext.viewcode', 38 | 'sphinx.ext.napoleon', 39 | 'sphinx.ext.intersphinx', 40 | 'sphinx.ext.autosummary', 41 | 'sphinx_rtd_theme', 42 | ] 43 | 44 | # Add any paths that contain templates here, relative to this directory. 45 | templates_path = ['_templates'] 46 | 47 | # List of patterns, relative to source directory, that match files and 48 | # directories to ignore when looking for source files. 49 | # This pattern also affects html_static_path and html_extra_path. 50 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 51 | 52 | # -- Options for HTML output ------------------------------------------------- 53 | 54 | # The theme to use for HTML and HTML Help pages. See the documentation for 55 | # a list of builtin themes. 56 | # 57 | html_theme = 'sphinx_rtd_theme' 58 | 59 | # Add any paths that contain custom static files (such as style sheets) here, 60 | # relative to this directory. They are copied after the builtin static files, 61 | # so a file named "default.css" will overwrite the builtin "default.css". 62 | html_static_path = ['_static'] 63 | 64 | # -- Extension configuration ------------------------------------------------- 65 | 66 | # Napoleon settings 67 | napoleon_google_docstring = True 68 | napoleon_numpy_docstring = False 69 | napoleon_include_init_with_doc = True 70 | napoleon_include_private_with_doc = True 71 | napoleon_include_special_with_doc = True 72 | napoleon_use_admonition_for_examples = True 73 | napoleon_use_admonition_for_notes = True 74 | napoleon_use_admonition_for_references = True 75 | napoleon_use_ivar = True 76 | napoleon_use_param = True 77 | napoleon_use_rtype = True 78 | napoleon_use_keyword = True 79 | napoleon_custom_sections = None 80 | 81 | # Intersphinx settings 82 | intersphinx_mapping = { 83 | 'python': ('https://docs.python.org/3', None), 84 | 'numpy': ('https://numpy.org/doc/stable', None), 85 | 'pandas': ('https://pandas.pydata.org/pandas-docs/stable', None), 86 | } 87 | 88 | # Autodoc settings 89 | autodoc_member_order = 'bysource' 90 | autodoc_default_options = { 91 | 'members': True, 92 | 'show-inheritance': True, 93 | 'undoc-members': True, 94 | 'inherited-members': True 95 | } 96 | 97 | # Autosummary settings 98 | autosummary_generate = True 99 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DCC-MCP 2 | 3 |
4 | 5 | [![PyPI version](https://badge.fury.io/py/dcc-mcp.svg)](https://badge.fury.io/py/dcc-mcp) 6 | [![Build Status](https://github.com/loonghao/dcc-mcp/workflows/Build%20and%20Release/badge.svg)](https://github.com/loonghao/dcc-mcp/actions) 7 | [![Documentation Status](https://readthedocs.org/projects/dcc-mcp/badge/?version=latest)](https://dcc-mcp.readthedocs.io/en/latest/?badge=latest) 8 | [![Python Version](https://img.shields.io/pypi/pyversions/dcc-mcp.svg)](https://pypi.org/project/dcc-mcp/) 9 | [![License](https://img.shields.io/github/license/loonghao/dcc-mcp.svg)](https://github.com/loonghao/dcc-mcp/blob/main/LICENSE) 10 | [![Downloads](https://static.pepy.tech/badge/dcc-mcp)](https://pepy.tech/project/dcc-mcp) 11 | [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) 12 | [![Ruff](https://img.shields.io/badge/ruff-enabled-brightgreen)](https://github.com/astral-sh/ruff) 13 | 14 |
15 | 16 | DCC-MCP is a unified implementation of the Model-Context-Protocol (MCP) for Digital Content Creation (DCC) software, designed to provide a consistent interface for various DCC applications used in the VFX and animation industry. 17 | 18 | > **Note:** Frontend API is currently under development. Stay tuned for updates! 19 | > 20 | > Related components (dcc-mcp-core, dcc-mcp-maya, dcc-mcp-rpyc) are also under active development. 21 | 22 | ## Features 23 | 24 | - Standardized implementation of MCP for DCC applications 25 | - Consistent API across different DCC software (Maya, Houdini, Nuke, etc.) 26 | - Cross-platform compatibility (Windows, Linux, macOS) 27 | - Extensible architecture for custom integrations 28 | 29 | ## Installation 30 | 31 | ```bash 32 | pip install dcc-mcp 33 | ``` 34 | 35 | Or with Poetry: 36 | 37 | ```bash 38 | poetry add dcc-mcp 39 | ``` 40 | 41 | ## Usage 42 | 43 | ```python 44 | import dcc_mcp 45 | 46 | # Example usage will be available once the API is finalized 47 | ``` 48 | 49 | ## Development 50 | 51 | ### Setup 52 | 53 | ```bash 54 | # Clone the repository 55 | git clone https://github.com/loonghao/dcc-mcp.git 56 | cd dcc-mcp 57 | 58 | # Install dependencies with Poetry 59 | poetry install 60 | ``` 61 | 62 | ### Testing 63 | 64 | ```bash 65 | # Run tests with nox 66 | nox -s pytest 67 | 68 | # Run linting 69 | nox -s lint 70 | 71 | # Fix linting issues 72 | nox -s lint_fix 73 | ``` 74 | 75 | ### Documentation 76 | 77 | ```bash 78 | # Build documentation 79 | nox -s docs 80 | 81 | # Serve documentation with live reloading 82 | nox -s docs-serve 83 | ``` 84 | 85 | ## License 86 | 87 | MIT 88 | 89 | ## GitHub Actions Configuration 90 | 91 | This project uses GitHub Actions for CI/CD. The following workflows are included: 92 | 93 | - **Build and Release**: Tests the package on multiple Python versions and operating systems, and publishes to PyPI when a new release is created. 94 | - **Documentation**: Builds and deploys documentation to GitHub Pages. 95 | - **Dependency Review**: Scans dependencies for security vulnerabilities. 96 | - **Scorecards**: Analyzes the security health of the project. 97 | 98 | The release workflow uses PyPI's trusted publishing, which means you don't need to set up any PyPI API tokens. Instead, you'll need to configure trusted publishing in your PyPI project settings once you've created your package. See [PyPI's documentation on trusted publishing](https://docs.pypi.org/trusted-publishers/) for more information. 99 | 100 | ### Release Process 101 | 102 | To create a new release: 103 | 104 | 1. Update the version in `pyproject.toml` 105 | 2. Update the `CHANGELOG.md` with the new version and changes 106 | 3. Commit and push the changes 107 | 4. Create a new tag with the version number (e.g., `1.0.0`) 108 | 5. Push the tag to GitHub 109 | 110 | ```bash 111 | # Example release process 112 | git add pyproject.toml CHANGELOG.md 113 | git commit -m "Release 1.0.0" 114 | git tag 1.0.0 115 | git push && git push --tags 116 | ``` 117 | 118 | The GitHub Actions workflow will automatically build and publish the package to PyPI. 119 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["poetry-core>=1.0.0"] 3 | build-backend = "poetry.core.masonry.api" 4 | 5 | [tool.poetry] 6 | name = "your-project-name" 7 | version = "0.0.1" 8 | description = "Your project description" 9 | authors = ["Your Name "] 10 | readme = "README.md" 11 | packages = [{include = "your_project_name", from = "src"}] 12 | license = "MIT" 13 | classifiers = [ 14 | "Development Status :: 3 - Alpha", 15 | "Intended Audience :: Developers", 16 | "License :: OSI Approved :: MIT License", 17 | "Programming Language :: Python :: 3", 18 | "Programming Language :: Python :: 3.7", 19 | "Programming Language :: Python :: 3.8", 20 | "Programming Language :: Python :: 3.9", 21 | "Programming Language :: Python :: 3.10", 22 | "Programming Language :: Python :: 3.11", 23 | "Programming Language :: Python :: 3.12", 24 | "Programming Language :: Python :: 3.13", 25 | ] 26 | 27 | [tool.poetry.dependencies] 28 | python = ">=3.7,<4.0" 29 | loguru = ">=0.7.3,<0.8.0" 30 | platformdirs = ">=3,<4.0.0" 31 | pydantic = ">=1.10.0,<2.0.0" 32 | 33 | [tool.poetry.group.dev.dependencies] 34 | pytest = "^7.4.0" 35 | pytest-cov = "^4.1.0" 36 | commitizen = "^3.12.0" 37 | ruff = "^0.9.0" 38 | pyfakefs = "^5.8.0" 39 | python-semantic-release = "^8.5.1" 40 | 41 | [tool.poetry.group.docs] 42 | optional = true 43 | 44 | [tool.poetry.group.docs.dependencies] 45 | sphinx = "^7.2.6" 46 | sphinx-rtd-theme = "^2.0.0" 47 | myst-parser = "^2.0.0" 48 | 49 | [tool.poetry.urls] 50 | Homepage = "https://github.com/yourusername/your-project-name" 51 | Issues = "https://github.com/yourusername/your-project-name/issues" 52 | 53 | [tool.poetry.scripts] 54 | your-project-name = "your_project_name.cli:main" 55 | 56 | [tool.commitizen] 57 | name = "cz_conventional_commits" 58 | version = "0.0.1" 59 | tag_format = "$version" 60 | version_files = [ 61 | "pyproject.toml:version", 62 | "src/your_project_name/__version__.py", 63 | ] 64 | 65 | [tool.pytest.ini_options] 66 | testpaths = ["tests"] 67 | python_files = ["test_*.py"] 68 | python_classes = ["Test*"] 69 | python_functions = ["test_*"] 70 | 71 | [tool.coverage.run] 72 | source = ["your_project_name"] 73 | branch = true 74 | 75 | [tool.coverage.report] 76 | exclude_lines = [ 77 | "pragma: no cover", 78 | "def __repr__", 79 | "if __name__ == .__main__.:", 80 | "raise NotImplementedError", 81 | "if TYPE_CHECKING:", 82 | ] 83 | 84 | [tool.mypy] 85 | python_version = "3.7" 86 | strict = true 87 | warn_return_any = true 88 | warn_unused_configs = true 89 | disallow_untyped_defs = true 90 | disallow_incomplete_defs = true 91 | check_untyped_defs = true 92 | disallow_untyped_decorators = true 93 | no_implicit_optional = true 94 | warn_redundant_casts = true 95 | warn_unused_ignores = true 96 | warn_no_return = true 97 | warn_unreachable = true 98 | ignore_missing_imports = true 99 | disable_error_code = ["type-arg", "misc", "no-any-return"] 100 | 101 | [tool.ruff] 102 | line-length = 120 103 | target-version = "py37" 104 | src = ["src", "tests"] 105 | 106 | [tool.ruff.lint] 107 | select = [ 108 | "E", # pycodestyle 109 | "F", # pyflakes 110 | "D", # pydocstyle 111 | "UP", # pyupgrade 112 | "RUF", # ruff-specific rules 113 | ] 114 | ignore = ["D203", "D213", "ARG001", "D107", "D105", "D102", "F811", "I001"] 115 | 116 | [tool.ruff.lint.per-file-ignores] 117 | "__init__.py" = ["F401"] 118 | "tests/*.py" = ["ARG001", "F401", "F811", "D107", "D105", "D102", "E501", "I001"] 119 | "nox_actions/*.py" = ["D100", "D103", "D104", "E402"] 120 | "noxfile.py" = ["D100", "E402", "D401", "D400"] 121 | "examples/*.py" = ["D401", "D415", "RUF013", "E722", "D400"] 122 | 123 | [tool.ruff.format] 124 | quote-style = "double" 125 | indent-style = "space" 126 | skip-magic-trailing-comma = false 127 | line-ending = "auto" 128 | 129 | [tool.isort] 130 | # Enforce import section headers. 131 | import_heading_future = "Import future modules" 132 | import_heading_stdlib = "Import built-in modules" 133 | import_heading_thirdparty = "Import third-party modules" 134 | import_heading_firstparty = "Import local modules" 135 | 136 | profile = "black" 137 | line_length = 120 138 | force_sort_within_sections = true 139 | force_single_line = true 140 | sections = ["FUTURE", "STDLIB", "THIRDPARTY", "FIRSTPARTY", "LOCALFOLDER"] 141 | known_first_party = ["your_project_name"] 142 | 143 | [tool.nox] 144 | sessions = ["lint", "pytest"] 145 | python = ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"] 146 | reuse_venv = true 147 | 148 | [tool.nox.session.lint] 149 | deps = ["ruff", "mypy", "isort"] 150 | commands = [ 151 | "mypy --install-types --non-interactive", 152 | "ruff check .", 153 | "ruff format --check .", 154 | "isort --check-only .", 155 | "mypy src/your_project_name --strict" 156 | ] 157 | 158 | [tool.nox.session.lint_fix] 159 | deps = ["ruff", "mypy", "isort"] 160 | commands = [ 161 | "ruff check --fix .", 162 | "ruff format .", 163 | "isort ." 164 | ] 165 | 166 | [tool.nox.session.pytest] 167 | deps = ["pytest", "pytest-cov"] 168 | commands = [ 169 | "pytest tests/ --cov=your_project_name --cov-report=xml:coverage.xml --cov-report=term-missing" 170 | ] 171 | 172 | [tool.semantic_release] 173 | version_variable = [ 174 | "src/your_project_name/__version__.py:__version__", 175 | "pyproject.toml:version" 176 | ] 177 | branch = "main" 178 | upload_to_pypi = false 179 | upload_to_release = true 180 | build_command = "pip install poetry && poetry build" 181 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | [INSERT CONTACT METHOD]. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Build and Release 2 | 3 | # Permissions needed for this workflow 4 | permissions: 5 | contents: write # For creating releases 6 | pull-requests: write # For commenting on PRs 7 | id-token: write # For PyPI trusted publishing 8 | 9 | on: 10 | push: 11 | tags: 12 | - '[0-9]+.[0-9]+.[0-9]+*' 13 | branches: [ main ] 14 | paths-ignore: 15 | - '**.md' 16 | - 'docs/**' 17 | - '.github/*.md' 18 | - '.github/ISSUE_TEMPLATE/**' 19 | - 'LICENSE*' 20 | - '.readthedocs.yml' 21 | - 'CITATION.cff' 22 | - 'CODE_OF_CONDUCT.md' 23 | - 'CONTRIBUTING.md' 24 | - '**.rst' 25 | - '.hound.yml' 26 | - '.gitignore' 27 | - '.gitmodules' 28 | - '.coveragerc' 29 | - 'codecov.yml' 30 | - '.flake8' 31 | - '.pylintrc' 32 | - 'renovate.json' 33 | release: 34 | types: [published] 35 | pull_request: 36 | branches: [ main ] 37 | paths-ignore: 38 | - '**.md' 39 | - 'docs/**' 40 | - '.github/*.md' 41 | - '.github/ISSUE_TEMPLATE/**' 42 | - 'LICENSE*' 43 | - '.readthedocs.yml' 44 | - 'CITATION.cff' 45 | - 'CODE_OF_CONDUCT.md' 46 | - 'CONTRIBUTING.md' 47 | - '**.rst' 48 | - '.hound.yml' 49 | - '.gitignore' 50 | - '.gitmodules' 51 | - '.coveragerc' 52 | - 'codecov.yml' 53 | - '.flake8' 54 | - '.pylintrc' 55 | - 'renovate.json' 56 | workflow_dispatch: 57 | inputs: 58 | fast-mode: 59 | description: 'Skip building wheels and only run tests' 60 | required: false 61 | default: false 62 | type: boolean 63 | python-version: 64 | description: 'Python version to use for testing' 65 | required: false 66 | default: '3.10' 67 | type: string 68 | os: 69 | description: 'OS to run tests on' 70 | required: false 71 | default: 'ubuntu-latest' 72 | type: choice 73 | options: 74 | - ubuntu-latest 75 | - windows-latest 76 | - macos-latest 77 | 78 | jobs: 79 | # Build and test the package 80 | build-and-test: 81 | name: Build and test on ${{ matrix.os }} with Python ${{ matrix.python-version }} 82 | runs-on: ${{ matrix.os }} 83 | strategy: 84 | fail-fast: false 85 | matrix: 86 | os: [ubuntu-latest, windows-latest, macos-latest] 87 | python-version: ['3.7', '3.9', '3.11'] 88 | 89 | steps: 90 | - uses: actions/checkout@v4 91 | with: 92 | fetch-depth: 0 93 | 94 | - name: Set up Python ${{ matrix.python-version }} 95 | uses: actions/setup-python@v5 96 | with: 97 | python-version: ${{ matrix.python-version }} 98 | cache: 'pip' 99 | cache-dependency-path: | 100 | **/pyproject.toml 101 | **/requirements*.txt 102 | 103 | - name: Install dependencies 104 | run: | 105 | python -m pip install --upgrade pip 106 | pip install poetry build 107 | poetry install --with dev 108 | 109 | - name: Lint with ruff 110 | run: | 111 | poetry run ruff check . 112 | 113 | - name: Test with pytest 114 | run: | 115 | poetry run pytest tests/ 116 | 117 | - name: Build package 118 | run: | 119 | poetry build 120 | 121 | - name: Upload artifacts 122 | uses: actions/upload-artifact@v4 123 | with: 124 | name: dist-${{ matrix.os }}-${{ matrix.python-version }} 125 | path: dist/ 126 | if-no-files-found: error 127 | 128 | # Release to PyPI 129 | release-to-pypi: 130 | name: Release 131 | needs: [build-and-test] 132 | if: github.event_name == 'release' || (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')) 133 | runs-on: ubuntu-latest 134 | permissions: 135 | contents: write 136 | id-token: write 137 | 138 | steps: 139 | - uses: actions/checkout@v4 140 | with: 141 | fetch-depth: 0 142 | 143 | - name: Set up Python 144 | uses: actions/setup-python@v5 145 | with: 146 | python-version: '3.9' 147 | 148 | # Download all artifacts 149 | - name: Download all artifacts 150 | uses: actions/download-artifact@v4 151 | with: 152 | path: dist 153 | merge-multiple: true 154 | 155 | # List all artifacts 156 | - name: List all artifacts 157 | run: find dist -type f | sort 158 | 159 | # Generate release notes from changelog 160 | - name: Generate Release Notes 161 | if: startsWith(github.ref, 'refs/tags/') 162 | id: release-notes 163 | run: | 164 | VERSION=${GITHUB_REF#refs/tags/} 165 | # No need to remove 'v' prefix as we're using numeric versioning 166 | 167 | # Try to find the version in CHANGELOG.md 168 | if [ -f CHANGELOG.md ]; then 169 | CHANGES=$(grep -A 100 "## \[$VERSION\]" CHANGELOG.md | grep -B 100 -m 2 "^## " | grep -v "^## \[$VERSION\]" | grep -v "^## " | sed '/^$/d') 170 | else 171 | CHANGES="No changelog found for version $VERSION" 172 | fi 173 | 174 | # Load template and replace variables 175 | TEMPLATE=$(cat .github/release-template.md) 176 | TEMPLATE="${TEMPLATE//\$RELEASE_VERSION/$VERSION}" 177 | TEMPLATE="${TEMPLATE//\$CHANGES/$CHANGES}" 178 | 179 | # Create a temporary file for the release notes 180 | echo "$TEMPLATE" > release-notes.md 181 | shell: bash 182 | 183 | # Update release notes 184 | - name: Update Release Notes 185 | if: startsWith(github.ref, 'refs/tags/') 186 | uses: softprops/action-gh-release@v2 187 | with: 188 | body_path: release-notes.md 189 | files: dist/* 190 | fail_on_unmatched_files: true 191 | env: 192 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 193 | 194 | # Publish to PyPI 195 | - name: Publish to PyPI 196 | uses: pypa/gh-action-pypi-publish@release/v1 197 | --------------------------------------------------------------------------------