diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 0310222..2d8ac20 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -40,11 +40,11 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v7 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v4 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -58,7 +58,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v2 + uses: github/codeql-action/autobuild@v4 # â„šī¸ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -71,6 +71,6 @@ jobs: # ./location_of_script_within_repo/buildscript.sh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v4 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/debian_package.yml b/.github/workflows/debian_package.yml index 6fc3151..51591c6 100644 --- a/.github/workflows/debian_package.yml +++ b/.github/workflows/debian_package.yml @@ -7,7 +7,7 @@ jobs: if: "!contains(github.event.head_commit.message, '[skip ci]')" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v7 - name: Install dependencies run: | sudo apt-get install -yq --no-install-suggests --no-install-recommends devscripts fakeroot equivs dh-python python3-all python3-dateutil python3-requests python3-six diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 701b10e..eb0fbb0 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -8,26 +8,26 @@ jobs: if: "!contains(github.event.head_commit.message, '[skip ci]')" strategy: matrix: - python-version: ["3.11.x"] + python-version: ["3.14.x"] toxenv: [ruff, isort, black, pypi-description, docs, towncrier] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v7 with: repository: ${{ github.event.pull_request.head.repo.full_name }} ref: ${{ github.event.pull_request.head.ref }} - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v7 with: python-version: ${{ matrix.python-version }} - name: Cache pip - uses: actions/cache@v3 + uses: actions/cache@v6 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ matrix.toxenv }} restore-keys: | ${{ runner.os }}-pip-${{ matrix.toxenv }} - name: Cache tox - uses: actions/cache@v3 + uses: actions/cache@v6 with: path: .tox key: ${{ runner.os }}-lint-${{ matrix.toxenv }}-${{ hashFiles('setup.cfg') }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 641c0a7..57f5d9a 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -8,20 +8,20 @@ jobs: deploy: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v7 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v7 with: python-version: '3.x' - name: Cache pip - uses: actions/cache@v3 + uses: actions/cache@v6 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ matrix.toxenv }} restore-keys: | ${{ runner.os }}-pip-${{ matrix.toxenv }} - name: Cache tox - uses: actions/cache@v3 + uses: actions/cache@v6 with: path: .tox key: ${{ runner.os }}-tox-release-${{ hashFiles('setup.cfg') }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 74694c0..fdd0373 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,22 +8,22 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.11", "3.10", "3.9"] + python-version: ["3.14", "3.13", "3.12", "3.11"] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v7 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v7 with: python-version: ${{ matrix.python-version }} - name: Cache pip - uses: actions/cache@v3 + uses: actions/cache@v6 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ matrix.toxenv }} restore-keys: | ${{ runner.os }}-pip-${{ matrix.toxenv }} - name: Cache tox - uses: actions/cache@v3 + uses: actions/cache@v6 with: path: .tox key: ${{ runner.os }}-tox-${{ format('{{py{0}}}', matrix.python-version) }}-${{ hashFiles('setup.cfg') }} @@ -47,7 +47,7 @@ jobs: with: github-token: ${{ secrets.GITHUB_TOKEN }} parallel: true - - uses: codecov/codecov-action@v3 + - uses: codecov/codecov-action@v7 with: token: ${{ secrets.CODECOV_TOKEN }} flags: unittests diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 078edf5..be51919 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -31,16 +31,7 @@ repos: hooks: - id: pyupgrade args: - - --py3-plus - - repo: https://github.com/adamchainz/django-upgrade - rev: "1.31.1" - hooks: - - id: django-upgrade - args: [--target-version, "3.2"] - - repo: https://github.com/asottile/pyupgrade - rev: v3.21.2 - hooks: - - id: pyupgrade + - --py311-plus - repo: local hooks: - id: towncrier diff --git a/.readthedocs.yml b/.readthedocs.yml index a076dba..182f769 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -1,9 +1,9 @@ version: 2 build: - os: ubuntu-22.04 + os: ubuntu-24.04 tools: - python: "3.10" + python: "3.13" sphinx: configuration: docs/conf.py diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 3321ceb..a182ca3 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -114,7 +114,7 @@ Testing tips ------------ You can test your project using any specific version of python. -For example ``tox -epy37`` runs the tests on python 3.7. +For example ``tox -epy311`` runs the tests on python 3.11. Pull Request Guidelines ======================= diff --git a/changes/265.chore b/changes/265.chore new file mode 100644 index 0000000..68094d9 --- /dev/null +++ b/changes/265.chore @@ -0,0 +1 @@ +Add support for Python 3.12, 3.13 and 3.14 diff --git a/pyproject.toml b/pyproject.toml index feca7bc..e81f1d1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [tool.black] line-length = 119 -target-version = ["py310"] +target-version = ["py311"] [tool.towncrier] package = "taiga" @@ -40,11 +40,13 @@ multi_line_output = 3 use_parentheses = true [tool.ruff] -ignore = [] line-length = 119 -target-version = "py310" +target-version = "py311" + +[tool.ruff.lint] +ignore = [] -[tool.ruff.mccabe] +[tool.ruff.lint.mccabe] max-complexity = 10 [tool.bumpversion] diff --git a/setup.cfg b/setup.cfg index 4da9c36..c85baca 100644 --- a/setup.cfg +++ b/setup.cfg @@ -17,21 +17,19 @@ classifiers = Development Status :: 5 - Production/Stable Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.7 - Programming Language :: Python :: 3.8 - Programming Language :: Python :: 3.9 - Programming Language :: Python :: 3.10 Programming Language :: Python :: 3.11 + Programming Language :: Python :: 3.12 + Programming Language :: Python :: 3.13 + Programming Language :: Python :: 3.14 [options] include_package_data = True install_requires = requests>2.11 - six>=1.9 python-dateutil>=2.4 pyjwkest>=1.0 packages = taiga -python_requires = >=3.7 +python_requires = >=3.11 setup_requires = setuptools zip_safe = False diff --git a/taiga/exceptions.py b/taiga/exceptions.py index f4a1a21..04a1a24 100644 --- a/taiga/exceptions.py +++ b/taiga/exceptions.py @@ -17,5 +17,5 @@ def __init__(self, uri, status_code, message="", method="GET"): except ValueError: pass if not message: - message = "Status: {} on URI: {}".format(status_code, uri) + message = f"Status: {status_code} on URI: {uri}" super().__init__(message) diff --git a/taiga/models/base.py b/taiga/models/base.py index 3ec60b1..5aa9b59 100644 --- a/taiga/models/base.py +++ b/taiga/models/base.py @@ -203,9 +203,9 @@ def parse(cls, requester, entry): def __repr__(self): try: - return "{}({})".format(self.__class__.__name__, self.id) + return f"{self.__class__.__name__}({self.id})" except AttributeError: - return "{}({})".format(self.__class__.__name__, id(self)) + return f"{self.__class__.__name__}({id(self)})" def __str__(self): return self._rp() @@ -213,6 +213,6 @@ def __str__(self): def _rp(self): attr = getattr(self, self.repr_attribute, None) if attr: - return "{}".format(attr) + return f"{attr}" else: return repr(self) diff --git a/taiga/models/models.py b/taiga/models/models.py index 76bfc26..884477e 100644 --- a/taiga/models/models.py +++ b/taiga/models/models.py @@ -52,7 +52,7 @@ def set_attribute(self, id, value, version=1): # noqa: A002 :param version: version of the attribute (default = 1) """ attributes = self._get_attributes(cache=True) - formatted_id = "{}".format(id) + formatted_id = f"{id}" attributes["attributes_values"][formatted_id] = value response = self.requester.patch( "/{endpoint}/custom-attributes-values/{id}", @@ -1746,14 +1746,14 @@ def add_tag(self, tag, color=None): attrs = {"tag": tag} if color: attrs["color"] = color - response = self.requester.post("/{}/{}/create_tag".format(self.endpoint, self.id), payload=attrs) + response = self.requester.post(f"/{self.endpoint}/{self.id}/create_tag", payload=attrs) return response def list_tags(self): """ Get the list of tags for the project. """ - response = self.requester.get("/{}/{}/tags_colors".format(self.endpoint, self.id)) + response = self.requester.get(f"/{self.endpoint}/{self.id}/tags_colors") return response.json() def duplicate(self, name, description, is_private=False, users=[], **attrs): diff --git a/taiga/requestmaker.py b/taiga/requestmaker.py index 5d41a9f..c48cb4b 100644 --- a/taiga/requestmaker.py +++ b/taiga/requestmaker.py @@ -73,7 +73,7 @@ def is_bad_response(self, response): def headers(self, paginate=True): headers = { "Content-type": "application/json", - "Authorization": "{} {}".format(self.token_type, self.token), + "Authorization": f"{self.token_type} {self.token}", } if self.enable_pagination and paginate: headers["x-lazy-pagination"] = "True" @@ -120,7 +120,7 @@ def get(self, uri, query=None, cache=False, paginate=True, **parameters): def post(self, uri, payload=None, query=None, files=None, **parameters): if files: headers = { - "Authorization": "{} {}".format(self.token_type, self.token), + "Authorization": f"{self.token_type} {self.token}", "x-disable-pagination": "True", } data = payload diff --git a/tasks.py b/tasks.py index d8c0510..c297cfe 100644 --- a/tasks.py +++ b/tasks.py @@ -20,7 +20,7 @@ def clean(c): patterns.append("docs/_build") patterns.append("**/*.pyc") for pattern in patterns: - c.run("rm -rf {}".format(pattern)) + c.run(f"rm -rf {pattern}") @task diff --git a/tests/test_model_base.py b/tests/test_model_base.py index 5d44462..c7ba69c 100644 --- a/tests/test_model_base.py +++ b/tests/test_model_base.py @@ -339,4 +339,4 @@ def test_repr(self): self.assertEqual(fake._rp(), str(fake)) fake.repr_attribute = "notexisting" rep = fake._rp() - self.assertEqual(rep, "{}({})".format(fake.__class__.__name__, fake.id)) + self.assertEqual(rep, f"{fake.__class__.__name__}({fake.id})") diff --git a/tox.ini b/tox.ini index 34e715e..9b31b0a 100644 --- a/tox.ini +++ b/tox.ini @@ -8,7 +8,7 @@ envlist = ruff pypi-description towncrier - py{311,310,39} + py{314,313,312,311} [testenv] commands = {env:COMMAND:python} -m pytest {posargs}