diff --git a/.cursorrules b/.cursorrules new file mode 100644 index 0000000..8194449 --- /dev/null +++ b/.cursorrules @@ -0,0 +1,30 @@ +# RoleFit Analyzer - Cursor Rules +# modified from https://github.com/PatrickJS/awesome-cursorrules/blob/main/rules/python-cursorrules-prompt-file-best-practices/.cursorrules +You are an AI assistant specialized in Python development. Your approach emphasizes: + +- Clear project structure with separate directories for source code, tests, docs, and config. +- Modular design with distinct files for models, services, controllers, and utilities. +- Configuration management using environment variables. +- Robust error handling and logging, including context capture. +- Comprehensive testing with pytest. +- Detailed documentation using docstrings and README files. +- Dependency management via https://github.com/astral-sh/uv and virtual environments. +- Code style consistency using Ruff for both formatting and linting. +- CI/CD implementation with GitHub Actions or GitLab CI. + +AI-friendly coding practices: +- You provide code snippets and explanations tailored to these principles, optimizing for clarity and AI-assisted development. + +Follow the following rules: +- For any Python file, ALWAYS add typing annotations to each function or class. Include explicit return types (including None where appropriate). Add descriptive docstrings to all Python functions and classes. +- Please follow PEP 257 docstring conventions. Update existing docstrings as needed. +- Make sure you keep any comments that exist in a file. +- When writing new features, always consider existing logic to minimize code duplication and propose simple call structures. +- When writing tests, ONLY use pytest or pytest plugins (not unittest). All tests should have typing annotations. Place all tests under ./tests. Create any necessary directories. If you create packages under ./tests or ./src/, be sure to add an __init__.py if one does not exist. + +All tests should be fully annotated and should contain docstrings. Be sure to import the following if TYPE_CHECKING: +from _pytest.capture import CaptureFixture +from _pytest.fixtures import FixtureRequest +from _pytest.logging import LogCaptureFixture +from _pytest.monkeypatch import MonkeyPatch +from pytest_mock.plugin import MockerFixture \ No newline at end of file diff --git a/.github/workflows/check-pr-title.yml b/.github/workflows/check-pr-title.yml index a7c21f6..d5efb0b 100644 --- a/.github/workflows/check-pr-title.yml +++ b/.github/workflows/check-pr-title.yml @@ -11,6 +11,6 @@ jobs: steps: - uses: deepakputhraya/action-pr-title@master with: - min_length: 6 # Min length of the title - max_length: 72 # Max length of the title + min_length: 6 # Min length of the title + max_length: 72 # Max length of the title github_token: ${{ github.token }} # Default: ${{ github.token }} diff --git a/.github/workflows/run-static-tests.yml b/.github/workflows/run-static-tests.yml new file mode 100644 index 0000000..d7734bf --- /dev/null +++ b/.github/workflows/run-static-tests.yml @@ -0,0 +1,22 @@ +name: Static Tests for Python Scripts + +on: + pull_request: + branches: [ main ] + +jobs: + format: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: jdx/mise-action@v3 + - run: mise exec -- make setup-dev + - run: mise exec -- make format + + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: jdx/mise-action@v3 + - run: mise exec -- make setup-dev + - run: mise exec -- make lint-no-fix \ No newline at end of file diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml deleted file mode 100644 index e98e868..0000000 --- a/.github/workflows/run-tests.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: Tests for Python Scripts - -on: - pull_request: - branches: [ main ] - -jobs: - format-lint: - runs-on: ubuntu-18.04 - defaults: - run: - shell: bash -l {0} - - steps: - - uses: actions/checkout@v2 - - uses: conda-incubator/setup-miniconda@v2 - with: - python-version: 3.8 - - - run: make setup - - run: conda info - - run: conda list - - run: make format - - run: make lint - - unit-test: - runs-on: ubuntu-18.04 - defaults: - run: - shell: bash -l {0} - - steps: - - uses: actions/checkout@v2 - - uses: conda-incubator/setup-miniconda@v2 - with: - python-version: 3.8 - - - run: make setup - - run: conda info - - run: conda list - - run: make utest diff --git a/.github/workflows/run-unit-tests.yml b/.github/workflows/run-unit-tests.yml new file mode 100644 index 0000000..e6b15ce --- /dev/null +++ b/.github/workflows/run-unit-tests.yml @@ -0,0 +1,14 @@ +name: Unit Tests for Python Scripts + +on: + pull_request: + branches: [ main ] + +jobs: + unit-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: jdx/mise-action@v3 + - run: mise exec -- make setup-dev + - run: mise exec -- make test \ No newline at end of file diff --git a/.mise.toml b/.mise.toml new file mode 100644 index 0000000..d2105ec --- /dev/null +++ b/.mise.toml @@ -0,0 +1,5 @@ +[tools] +python = "3.12" + +[env] +_.python.venv = { path = ".venv", create = true } # create the venv if it doesn't exist diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml deleted file mode 100644 index c595c78..0000000 --- a/.pre-commit-config.yaml +++ /dev/null @@ -1,13 +0,0 @@ -repos: -- repo: local - hooks: - - id: format - name: format - language: system - entry: make format - types: [python] - - id: lint - name: lint - language: system - entry: make lint - types: [python] diff --git a/Makefile b/Makefile index 524b864..765e366 100644 --- a/Makefile +++ b/Makefile @@ -1,23 +1,22 @@ -PYTHON=3.8 -BASENAME=$(shell basename $(CURDIR)) -CONDA_CH=conda-forge defaults - -env: - conda create -n $(BASENAME) python=$(PYTHON) +init: + # Trust mise configuration + # mise will install Python and uv automatically + mise trust setup: - conda install --file requirements.txt $(addprefix -c ,$(CONDA_CH)) - pre-commit install + uv pip install -e . + +setup-dev: + uv pip install -e ".[dev]" format: - black . - isort . + ruff format . lint: - pytest src --flake8 --pylint --mypy + ruff check --fix . -utest: - PYTHONPATH=src pytest test/utest --cov=src --cov-report=html --cov-report=term --cov-config=setup.cfg +lint-no-fix: + ruff check . -cov: - open htmlcov/index.html +test: + pytest \ No newline at end of file diff --git a/README.md b/README.md index 1cf3db4..ee84e54 100644 --- a/README.md +++ b/README.md @@ -1,36 +1,19 @@ # Python Project Template -This repository is a python template repo for internal uses of Annotation-AI. -## File Structure +### Commands for Setups ```bash -. -├── LICENSE -├── Makefile # commands -├── README.md -├── requirements.txt # package information -├── setup.cfg # configurations for formatting & linting & unit-test -├── src # source code location -└── test - └── utest # unit tests location +make init # Initialize the project +make setup # Install dependencies +make setup-dev # Install dependencies with development packages ``` -## Commands +## Commands for Development ```bash -$ make env # create anaconda environment -$ make setup # initial setup for the project $ make format # format python scripts $ make lint # lint python scripts -$ make utest # run unit tests -$ make cov # open coverage report (after `make utest`) +$ make test # run unit tests ``` -## Configurations -`setup.cfg` states all configurations for formatting & linting & unit-test. - -## Verifications -- per commit: pre-commit hook runs formatting and linting. -- per pull-request: GitHub Actions check formatting, linting, and unit-test results. - ## Recommended Repository Settings #### Restriction on multi-commit pushes `Settings` -> `General` -> `Merge botton` -> `Allow squash merging` ONLY @@ -41,4 +24,4 @@ $ make cov # open coverage report (after `make utest`) - Branch name pattern: `main` - Require a pull request before merging & Require approvals - Require status checks to pass before merging & Require branches to be up to date before merging -- Include administrators +- Include administrators \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..b32dd2e --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,55 @@ +[project] +name = "python-project-template" +version = "0.0.1" +readme = "README.md" +requires-python = ">=3.12" +authors = [ + { name = "Curt Park", email = "www.jwpark.co.kr@gmail.com" }, +] +keywords = ["python", "project_template"] +classifiers = [] + +dependencies = [] + +[project.optional-dependencies] +dev = [ + "ruff>=0.14.3", + "pytest>=8.4.2", + "pytest-cov>=7.0.0", +] + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.ruff] +line-length = 88 +target-version = "py312" + +[tool.hatch.build.targets.wheel] +packages = ["src"] + +[tool.ruff.lint] +select = [ + "E", # pycodestyle errors + "W", # pycodestyle warnings + "F", # Pyflakes + "I", # isort + "N", # pep8-naming + "UP", # pyupgrade + "B", # flake8-bugbear + "C4", # flake8-comprehensions + "PIE", # flake8-pie + "SIM", # flake8-simplify +] + +[tool.pytest.ini_options] +testpaths = ["tests"] +pythonpath = ["src"] +addopts = [ + "--strict-markers", + "--strict-config", + "--cov=src", + "--cov-report=term-missing", + "--cov-report=html", +] \ No newline at end of file diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 1f5911d..0000000 --- a/requirements.txt +++ /dev/null @@ -1,21 +0,0 @@ -pre-commit == 2.17.0 - -# formatter -isort == 5.10.1 # imports -black == 22.3.0 # coding style - -# linter -pylint == 2.12.2 # python static code analysis -mypy == 0.931 # type check -flake8 == 3.8.4 # PyFlakes + pycodestyle + Ned Batchelder’s McCabe script -flake8-docstrings == 1.6.0 # pydocstyle tool to flake8 -flake8-annotations == 2.7.0 # PEP 3107-style function annotations -flake8-builtins == 1.5.3 # check python builtins being used as variables or parameters -flake8-bugbear == 22.1.11 # find likely bugs and design problems - -# pytest for linting and unit test -pytest == 6.2.5 -pytest-pylint == 0.18.0 -pytest-flake8 == 1.0.7 -pytest-mypy == 0.8.0 -pytest-cov == 3.0.0 # coverage reports diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 76ee880..0000000 --- a/setup.cfg +++ /dev/null @@ -1,40 +0,0 @@ -# https://black.readthedocs.io/en/stable/guides/using_black_with_other_tools.html - -[isort] -line_length = 88 -profile = black - -[flake8] -max-line-length = 88 -extend-ignore = E203, ANN101 - -[pylint] -max-line-length = 88 -extension-pkg-whitelist=pydantic # need for fastapi - -[pylint.messages_control] -# https://vald-phoenix.github.io/pylint-errors/#list-of-errors -disable = - C0330, # bad-continuation - C0326, # bad-whitespace - C0411, # wrong-import-order - -[pylint.typecheck] -# List of members which are set dynamically and missed by Pylint inference -# system, and so shouldn't trigger E1101 when accessed. -generated-members=numpy.*, torch.* - -[mypy] -ignore_missing_imports = True - -[tool:pytest] -filterwarnings = ignore::DeprecationWarning - -[coverage:run] -# omit = file-path-to-omit -branch = true -parallel = true - -[coverage:report] -fail_under = 100.0 -show_missing = true diff --git a/test/utest/test_dummy.py b/tests/utest/test_dummy.py similarity index 100% rename from test/utest/test_dummy.py rename to tests/utest/test_dummy.py