diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..9045fa850 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,35 @@ +# http://editorconfig.org +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.{py,rst,ini,json,sh}] +indent_style = space +indent_size = 4 + +[*.py] +line_length=120 +known_first_party=cover_agent,tests_integration +multi_line_output=3 +default_section=THIRDPARTY + +[*.{html,css,scss,js}] +indent_style = space +indent_size = 2 + +[*.yml] +indent_style = space +indent_size = 2 + +[*.md] +trim_trailing_whitespace = false + +[Makefile] +indent_style = tab + +[makefile-local] +indent_style = tab diff --git a/.github/workflows/ci_pipeline.yml b/.github/workflows/ci_pipeline.yml index 850b7cddf..2d6b1e986 100644 --- a/.github/workflows/ci_pipeline.yml +++ b/.github/workflows/ci_pipeline.yml @@ -8,6 +8,11 @@ on: branches: - main +env: + PYTHON_VERSION: '3.12' + POETRY_VERSION: '2.1.3' + FAKE_OPENAI_API_KEY: "sk-fake-key-for-testing-only" + jobs: # Checks for changes in version.txt (used for release job) changes: @@ -16,8 +21,8 @@ jobs: version_changed: ${{ steps.filter.outputs.version_changed }} relevant_changes: ${{ steps.filter.outputs.relevant_changes }} steps: - - uses: actions/checkout@v3 - - uses: dorny/paths-filter@v2 + - uses: actions/checkout@v4 + - uses: dorny/paths-filter@v3 id: filter with: filters: | @@ -26,21 +31,30 @@ jobs: relevant_changes: - '!README.md' - '!docs/**' + - '!*.md' test: needs: [changes] if: needs.changes.outputs.relevant_changes == 'true' runs-on: ubuntu-latest + timeout-minutes: 30 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: fetch-depth: 0 # Ensures we fetch all history for all branches + - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 + with: + python-version: ${{ env.PYTHON_VERSION }} + + - name: Install Poetry + uses: snok/install-poetry@v1 with: - python-version: '3.12' - - # Step to cache Poetry dependencies + version: ${{ env.POETRY_VERSION }} + virtualenvs-create: true + virtualenvs-in-project: false + - name: Cache Poetry dependencies uses: actions/cache@v4 with: @@ -51,41 +65,63 @@ jobs: restore-keys: | ${{ runner.os }}-poetry- - - name: Install Poetry - run: pip install poetry - - name: Install dependencies using Poetry - run: poetry install + - name: Install dependencies + run: poetry install --no-interaction + + - name: Run code linters + run: make lint-check + - name: Run tests and generate reports env: - OPENAI_API_KEY: "This_is_a_fake_API_key" + OPENAI_API_KEY: ${{ env.FAKE_OPENAI_API_KEY }} run: make test - - name: Upload test report + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v4 + with: + files: cobertura.xml + + - name: Upload test results uses: actions/upload-artifact@v4 if: always() with: name: test-reports path: testLog.xml + retention-days: 30 + - name: Upload coverage report uses: actions/upload-artifact@v4 if: always() with: name: coverage-reports path: cobertura.xml - env: - pythonLocation: /opt/hostedtoolcache/Python/3.12.2/x64 - LD_LIBRARY_PATH: /opt/hostedtoolcache/Python/3.12.2/x64/lib + retention-days: 30 + + - name: Publish test results + uses: EnricoMi/publish-unit-test-result-action@v2 + if: always() + with: + files: testLog.xml package-test: needs: test runs-on: ubuntu-latest + timeout-minutes: 15 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 + - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 + with: + python-version: ${{ env.PYTHON_VERSION }} + + - name: Install Poetry + uses: snok/install-poetry@v1 with: - python-version: '3.12' - - # Step to cache Poetry dependencies + version: ${{ env.POETRY_VERSION }} + virtualenvs-create: true + virtualenvs-in-project: true + - name: Cache Poetry dependencies uses: actions/cache@v4 with: @@ -93,89 +129,110 @@ jobs: ~/.cache/pypoetry ~/.cache/pip key: ${{ runner.os }}-poetry-${{ hashFiles('**/poetry.lock') }} - restore-keys: | - ${{ runner.os }}-poetry- - - name: Install Poetry - run: pip install poetry - - name: Install dependencies using Poetry - run: poetry install - - name: Build, Install and Test Package from Different Location + - name: Install dependencies + run: poetry install --no-interaction + + - name: Build package + run: poetry build + + - name: Test package installation run: | - poetry build pip install dist/*.whl cd /tmp - cover-agent --help + cover-agent --help build: needs: [test, changes] if: needs.changes.outputs.relevant_changes == 'true' strategy: + fail-fast: false matrix: - os: [ubuntu-22.04, windows-latest, macos-latest] + os: [ubuntu-22.04, windows-latest, macos-latest] + include: + - os: ubuntu-22.04 + executable: cover-agent + - os: windows-latest + executable: cover-agent.exe + - os: macos-latest + executable: cover-agent runs-on: ${{ matrix.os }} + timeout-minutes: 30 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 + - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: - python-version: '3.12' - - # Step to cache Poetry dependencies + python-version: ${{ env.PYTHON_VERSION }} + + - name: Install Poetry + uses: snok/install-poetry@v1 + with: + version: ${{ env.POETRY_VERSION }} + virtualenvs-create: true + virtualenvs-in-project: true + - name: Cache Poetry dependencies uses: actions/cache@v4 with: - path: | - ~/.cache/pypoetry - ~/.cache/pip - key: ${{ runner.os }}-poetry-${{ hashFiles('**/poetry.lock') }} - restore-keys: | - ${{ runner.os }}-poetry- + path: .venv + key: venv-${{ runner.os }}-${{ env.PYTHON_VERSION }}-${{ hashFiles('**/poetry.lock') }} - name: Install Dependencies run: | make setup-installer - poetry install + poetry install --no-interaction + - name: Build Executable run: make installer - - name: Test Executable (Windows) - if: ${{ matrix.os == 'windows-latest' }} - run: .\dist\cover-agent.exe --help - shell: pwsh - - name: Test Executable (Unix) - if: ${{ matrix.os != 'windows-latest' }} - run: ./dist/cover-agent --help + + - name: Test Executable + run: | + if [ "${{ runner.os }}" = "Windows" ]; then + ./dist/${{ matrix.executable }} --help + else + ./dist/${{ matrix.executable }} --help + fi shell: bash + - name: Upload Executable uses: actions/upload-artifact@v4 with: name: cover-agent-${{ matrix.os }} - path: dist/cover-agent* + path: dist/${{ matrix.executable }} + retention-days: 30 e2e-test: # This job will run after building binary because it needs the binary to run the E2E tests in Docker needs: build runs-on: ubuntu-latest + timeout-minutes: 45 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 + - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: - python-version: '3.12' + python-version: ${{ env.PYTHON_VERSION }} - # Download the Ubuntu binary - name: Download Ubuntu executable uses: actions/download-artifact@v4 with: name: cover-agent-ubuntu-22.04 path: dist - # Make the binary executable - name: Make binary executable run: chmod +x dist/cover-agent - # Cache and install dependencies + - name: Install Poetry + uses: snok/install-poetry@v1 + with: + version: ${{ env.POETRY_VERSION }} + virtualenvs-create: true + virtualenvs-in-project: true + - name: Cache Poetry dependencies uses: actions/cache@v4 with: @@ -183,22 +240,16 @@ jobs: ~/.cache/pypoetry ~/.cache/pip key: ${{ runner.os }}-poetry-${{ hashFiles('**/poetry.lock') }} - restore-keys: | - ${{ runner.os }}-poetry- - - name: Install Poetry - run: pip install poetry - - name: Install dependencies using Poetry - run: poetry install + - name: Install dependencies + run: poetry install --no-interaction - # Run the E2E Docker tests using the Makefile target `e2e-test` - name: Run E2E Docker tests env: - OPENAI_API_KEY: "This_is_a_fake_API_key" + OPENAI_API_KEY: ${{ env.FAKE_OPENAI_API_KEY }} run: | make e2e-test 2>&1 | tee e2e_test_full.log - # Upload E2E test reports - name: Upload E2E Docker test report uses: actions/upload-artifact@v4 if: always() @@ -207,6 +258,13 @@ jobs: path: | testLog_e2e.xml e2e_test_full.log + retention-days: 30 + + - name: Publish e2e test results + uses: EnricoMi/publish-unit-test-result-action@v2 + if: always() + with: + files: testLog_e2e.xml release: # This job will run only if the following conditions are met: @@ -215,63 +273,50 @@ jobs: # - There are relevant changes outside 'README.md' and the 'docs/' folder needs: [build, changes, e2e-test] if: > - github.event_name == 'push' && + github.event_name == 'push' && github.ref == 'refs/heads/main' && needs.changes.outputs.version_changed == 'true' && needs.changes.outputs.relevant_changes == 'true' runs-on: ubuntu-latest + permissions: + contents: write + timeout-minutes: 15 steps: - - uses: actions/checkout@v2 - - name: Download executables (Ubuntu) + - uses: actions/checkout@v4 + + - name: Download all executables uses: actions/download-artifact@v4 with: - name: cover-agent-ubuntu-22.04 - path: dist/ubuntu-22.04 - - uses: actions/download-artifact@v4 - with: - name: cover-agent-windows-latest - path: dist/windows-latest - - uses: actions/download-artifact@v4 - with: - name: cover-agent-macos-latest - path: dist/macos-latest + pattern: cover-agent-* + path: dist + merge-multiple: false + - name: Extract version + id: version run: | - echo "VERSION=$(cat cover_agent/version.txt)" >> $GITHUB_ENV + VERSION=$(cat cover_agent/version.txt) + echo "VERSION=$VERSION" >> $GITHUB_ENV + echo "version=$VERSION" >> $GITHUB_OUTPUT + - name: Create Release - id: create_release - uses: actions/create-release@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + uses: softprops/action-gh-release@v2 with: tag_name: ${{ env.VERSION }} - release_name: Release ${{ env.VERSION }} + name: Release ${{ env.VERSION }} draft: false prerelease: false - - name: Upload Release Asset (Ubuntu) - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: dist/ubuntu-22.04/cover-agent - asset_name: cover-agent-ubuntu - asset_content_type: application/octet-stream - - name: Upload Release Asset (Windows) - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: dist/windows-latest/cover-agent.exe - asset_name: cover-agent-windows.exe - asset_content_type: application/octet-stream - - name: Upload Release Asset (macOS) - uses: actions/upload-release-asset@v1 + files: | + dist/cover-agent-ubuntu-22.04/cover-agent + dist/cover-agent-windows-latest/cover-agent.exe + dist/cover-agent-macos-latest/cover-agent + body: | + ## Release ${{ env.VERSION }} + + ### Downloads + - **Ubuntu/Linux**: cover-agent + - **Windows**: cover-agent.exe + - **macOS**: cover-agent + + Built from commit: ${{ github.sha }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: dist/macos-latest/cover-agent - asset_name: cover-agent-macos - asset_content_type: application/octet-stream diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 000000000..3bc8aa047 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,15 @@ +repos: +- repo: https://github.com/psf/black + rev: 25.1.0 + hooks: + - id: black + language_version: python3.12 + args: ["--check"] + exclude: ^(templated_tests|cover_agent/lsp_logic)/ + +- repo: https://github.com/pycqa/isort + rev: 6.0.1 + hooks: + - id: isort + args: ["--check-only", "--diff"] + exclude: ^(templated_tests|cover_agent/lsp_logic)/ diff --git a/Makefile b/Makefile index ebff23a1f..bb8dd7599 100644 --- a/Makefile +++ b/Makefile @@ -23,9 +23,18 @@ e2e-test: --junitxml=testLog_e2e.xml \ --log-cli-level=INFO -# Use Python Black to format python files -format: - black . +# Use black to format Python files +format-black: + poetry run black . + +# Use isort to format Python files +format-isort: + poetry run isort . + +# Run code linters +lint-check: + poetry run black --check . + poetry run isort --check-only --diff . # Generate wheel file using poetry build command build: @@ -51,4 +60,3 @@ installer: --onefile \ --name cover-agent \ cover_agent/main.py - diff --git a/docs/pre_commit_hook.md b/docs/pre_commit_hook.md new file mode 100644 index 000000000..bf3a8e3e1 --- /dev/null +++ b/docs/pre_commit_hook.md @@ -0,0 +1,36 @@ +## qodo-cover: Pre-commit hooks # + +To run additional checks before making commit we use [Pre-commit](https://pre-commit.com/) hooks. + +`pre-commit` package is installed with backend requirements, so there is no need of [manual installation](https://pre-commit.com/#install). +But you need to generate the actual git pre-commit hook. It should be done only once during the project setup: + +```bash +poetry run pre-commit install +``` + +Keep in mind, code formatters are configured separately for the pre-commit hook in the `.pre-commit-config.yaml` file. Pre-commit runs tools on staged files, not as part of your project that's why it requires a separate configuration. However it should be synced with those settings in `pyproject.toml` file. + + +### Usage +To run pre-commit hooks manually: + +```bash +poetry run pre-commit run --all-files +``` + +Check staged files only: +```bash +poetry run pre-commit run +``` + +To run specific hook: + +```bash +poetry run pre-commit run +``` + +See more info in official documentation: + +* [Usage](https://pre-commit.com/#usage) +* [Adding new hooks](https://pre-commit.com/#plugins) diff --git a/poetry.lock b/poetry.lock index a7991eb32..8d8de5b84 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.1.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.1.3 and should not be changed by hand. [[package]] name = "aiohappyeyeballs" @@ -234,6 +234,53 @@ charset-normalizer = ["charset-normalizer"] html5lib = ["html5lib"] lxml = ["lxml"] +[[package]] +name = "black" +version = "25.1.0" +description = "The uncompromising code formatter." +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "black-25.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:759e7ec1e050a15f89b770cefbf91ebee8917aac5c20483bc2d80a6c3a04df32"}, + {file = "black-25.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e519ecf93120f34243e6b0054db49c00a35f84f195d5bce7e9f5cfc578fc2da"}, + {file = "black-25.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:055e59b198df7ac0b7efca5ad7ff2516bca343276c466be72eb04a3bcc1f82d7"}, + {file = "black-25.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:db8ea9917d6f8fc62abd90d944920d95e73c83a5ee3383493e35d271aca872e9"}, + {file = "black-25.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a39337598244de4bae26475f77dda852ea00a93bd4c728e09eacd827ec929df0"}, + {file = "black-25.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:96c1c7cd856bba8e20094e36e0f948718dc688dba4a9d78c3adde52b9e6c2299"}, + {file = "black-25.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bce2e264d59c91e52d8000d507eb20a9aca4a778731a08cfff7e5ac4a4bb7096"}, + {file = "black-25.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:172b1dbff09f86ce6f4eb8edf9dede08b1fce58ba194c87d7a4f1a5aa2f5b3c2"}, + {file = "black-25.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4b60580e829091e6f9238c848ea6750efed72140b91b048770b64e74fe04908b"}, + {file = "black-25.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1e2978f6df243b155ef5fa7e558a43037c3079093ed5d10fd84c43900f2d8ecc"}, + {file = "black-25.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b48735872ec535027d979e8dcb20bf4f70b5ac75a8ea99f127c106a7d7aba9f"}, + {file = "black-25.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:ea0213189960bda9cf99be5b8c8ce66bb054af5e9e861249cd23471bd7b0b3ba"}, + {file = "black-25.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8f0b18a02996a836cc9c9c78e5babec10930862827b1b724ddfe98ccf2f2fe4f"}, + {file = "black-25.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:afebb7098bfbc70037a053b91ae8437c3857482d3a690fefc03e9ff7aa9a5fd3"}, + {file = "black-25.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:030b9759066a4ee5e5aca28c3c77f9c64789cdd4de8ac1df642c40b708be6171"}, + {file = "black-25.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:a22f402b410566e2d1c950708c77ebf5ebd5d0d88a6a2e87c86d9fb48afa0d18"}, + {file = "black-25.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a1ee0a0c330f7b5130ce0caed9936a904793576ef4d2b98c40835d6a65afa6a0"}, + {file = "black-25.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f3df5f1bf91d36002b0a75389ca8663510cf0531cca8aa5c1ef695b46d98655f"}, + {file = "black-25.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d9e6827d563a2c820772b32ce8a42828dc6790f095f441beef18f96aa6f8294e"}, + {file = "black-25.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:bacabb307dca5ebaf9c118d2d2f6903da0d62c9faa82bd21a33eecc319559355"}, + {file = "black-25.1.0-py3-none-any.whl", hash = "sha256:95e8176dae143ba9097f351d174fdaf0ccd29efb414b362ae3fd72bf0f710717"}, + {file = "black-25.1.0.tar.gz", hash = "sha256:33496d5cd1222ad73391352b4ae8da15253c5de89b93a80b3e2c8d9a19ec2666"}, +] + +[package.dependencies] +click = ">=8.0.0" +mypy-extensions = ">=0.4.3" +packaging = ">=22.0" +pathspec = ">=0.9.0" +platformdirs = ">=2" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.10)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +uvloop = ["uvloop (>=0.15.2)"] + [[package]] name = "boto3" version = "1.36.25" @@ -328,6 +375,18 @@ files = [ {file = "certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651"}, ] +[[package]] +name = "cfgv" +version = "3.4.0" +description = "Validate configuration and produce human readable error messages." +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, + {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, +] + [[package]] name = "chardet" version = "5.2.0" @@ -570,6 +629,18 @@ Pygments = ">=2.19.1,<3.0.0" [package.extras] toml = ["tomli (>=1.2.1)"] +[[package]] +name = "distlib" +version = "0.3.9" +description = "Distribution utilities" +optional = false +python-versions = "*" +groups = ["dev"] +files = [ + {file = "distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87"}, + {file = "distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403"}, +] + [[package]] name = "distro" version = "1.9.0" @@ -786,7 +857,7 @@ version = "3.17.0" description = "A platform independent file lock." optional = false python-versions = ">=3.9" -groups = ["main"] +groups = ["main", "dev"] files = [ {file = "filelock-3.17.0-py3-none-any.whl", hash = "sha256:533dc2f7ba78dc2f0f531fc6c4940addf7b70a481e269a5a3b93be94ffbe8338"}, {file = "filelock-3.17.0.tar.gz", hash = "sha256:ee4e77401ef576ebb38cd7f13b9b28893194acc20a8e68e18730ba9c0e54660e"}, @@ -1629,6 +1700,21 @@ testing = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "fastapi", "gr torch = ["safetensors[torch]", "torch"] typing = ["types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)"] +[[package]] +name = "identify" +version = "2.6.10" +description = "File identification library for Python" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "identify-2.6.10-py2.py3-none-any.whl", hash = "sha256:5f34248f54136beed1a7ba6a6b5c4b6cf21ff495aac7c359e1ef831ae3b8ab25"}, + {file = "identify-2.6.10.tar.gz", hash = "sha256:45e92fd704f3da71cc3880036633f48b4b7265fd4de2b57627cb157216eb7eb8"}, +] + +[package.extras] +license = ["ukkonen"] + [[package]] name = "idna" version = "3.10" @@ -1681,6 +1767,22 @@ files = [ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] +[[package]] +name = "isort" +version = "6.0.1" +description = "A Python utility / library to sort Python imports." +optional = false +python-versions = ">=3.9.0" +groups = ["dev"] +files = [ + {file = "isort-6.0.1-py3-none-any.whl", hash = "sha256:2dc5d7f65c9678d94c88dfc29161a320eec67328bc97aad576874cb4be1e9615"}, + {file = "isort-6.0.1.tar.gz", hash = "sha256:1cb5df28dfbc742e490c5e41bad6da41b805b0a8be7bc93cd0fb2a8a890ac450"}, +] + +[package.extras] +colors = ["colorama"] +plugins = ["setuptools"] + [[package]] name = "jedi" version = "0.19.2" @@ -2255,6 +2357,30 @@ files = [ [package.dependencies] typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.11\""} +[[package]] +name = "mypy-extensions" +version = "1.1.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505"}, + {file = "mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558"}, +] + +[[package]] +name = "nodeenv" +version = "1.9.1" +description = "Node.js virtual environment builder" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["dev"] +files = [ + {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, + {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, +] + [[package]] name = "numpy" version = "1.26.4" @@ -2361,7 +2487,7 @@ version = "0.12.1" description = "Utility library for gitignore style pattern matching of file paths." optional = false python-versions = ">=3.8" -groups = ["main"] +groups = ["main", "dev"] files = [ {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, @@ -2386,7 +2512,7 @@ version = "4.3.6" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.8" -groups = ["main"] +groups = ["main", "dev"] files = [ {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, @@ -2433,6 +2559,25 @@ tomlkit = ">=0.4" [package.extras] plugin = ["poetry (>=1.2.0)"] +[[package]] +name = "pre-commit" +version = "4.2.0" +description = "A framework for managing and maintaining multi-language pre-commit hooks." +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "pre_commit-4.2.0-py2.py3-none-any.whl", hash = "sha256:a009ca7205f1eb497d10b845e52c838a98b6cdd2102a6c8e4540e94ee75c58bd"}, + {file = "pre_commit-4.2.0.tar.gz", hash = "sha256:601283b9757afd87d40c4c4a9b2b5de9637a8ea02eaff7adc2d0fb4e04841146"}, +] + +[package.dependencies] +cfgv = ">=2.0.0" +identify = ">=1.0.0" +nodeenv = ">=0.11.1" +pyyaml = ">=5.1" +virtualenv = ">=20.10.0" + [[package]] name = "propcache" version = "0.3.0" @@ -4388,6 +4533,27 @@ dev = ["Cython (>=3.0,<4.0)", "setuptools (>=60)"] docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] test = ["aiohttp (>=3.10.5)", "flake8 (>=5.0,<6.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=23.0.0,<23.1.0)", "pycodestyle (>=2.9.0,<2.10.0)"] +[[package]] +name = "virtualenv" +version = "20.31.2" +description = "Virtual Python Environment builder" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "virtualenv-20.31.2-py3-none-any.whl", hash = "sha256:36efd0d9650ee985f0cad72065001e66d49a6f24eb44d98980f630686243cf11"}, + {file = "virtualenv-20.31.2.tar.gz", hash = "sha256:e10c0a9d02835e592521be48b332b6caee6887f332c111aa79a09b9e79efc2af"}, +] + +[package.dependencies] +distlib = ">=0.3.7,<1" +filelock = ">=3.12.2,<4" +platformdirs = ">=3.9.1,<5" + +[package.extras] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8) ; platform_python_implementation == \"PyPy\" or platform_python_implementation == \"GraalVM\" or platform_python_implementation == \"CPython\" and sys_platform == \"win32\" and python_version >= \"3.13\"", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10) ; platform_python_implementation == \"CPython\""] + [[package]] name = "wandb" version = "0.17.9" @@ -4720,4 +4886,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = ">=3.9.17,<3.14" -content-hash = "b513b23e6dc996003137b6056d05ceb2c3271c2faae7123f9b485d712250ee99" +content-hash = "493b754b9c9f99e64bc4d7caa14db1627016193651ccdb5035ebead0c3c07136" diff --git a/pyproject.toml b/pyproject.toml index 18d2cb455..2dc931ada 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -51,6 +51,11 @@ pytest-asyncio = "^0.23.8" pytest-timeout = "^2.3.1" fastapi = "^0.111.1" +# Code formatters +pre-commit = "^4.2.0" +isort = "^6.0.1" +black = "^25.1.0" + [build-system] requires = ["poetry-core>=1.0.0", "poetry-dynamic-versioning>=1.0.0,<2.0.0"] build-backend = "poetry_dynamic_versioning.backend" @@ -65,3 +70,42 @@ enable = true [tool.poetry-dynamic-versioning.from-file] source = "cover_agent/version.txt" + +[tool.black] +line-length = 120 +skip-string-normalization = false +target-version = ["py310", "py311", "py312"] +# `templated_tests` and `cover_agent/lsp_logic` folders are excluded for now +exclude = ''' +/( + templated_tests + | cover_agent/lsp_logic + | \.eggs + | \.git + | \.hg + | \.mypy_cache + | \.tox + | \.venv + | _build + | build + | dist + | node_modules +)/ +''' + +[tool.isort] +profile = "black" +line_length = 120 +skip = ["templated_tests", "cover_agent/lsp_logic"] # Folders are excluded for now +length_sort = false +multi_line_output = 3 +indent = " " +lines_between_types = 1 +lines_after_imports = 2 +known_first_party = ["cover_agent", "tests_integration"] +sections = ["FUTURE", "STDLIB", "THIRDPARTY", "FIRSTPARTY", "LOCALFOLDER"] +default_section = "THIRDPARTY" +combine_star = true +include_trailing_comma = true +use_parentheses = true +from_first = false