diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fecd97885..b83380aec 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -59,7 +59,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ['3.10', '3.11', '3.12', '3.13', '3.14'] + python-version: ['3.11', '3.12', '3.13', '3.14', '3.15'] steps: - uses: actions/checkout@v7 - uses: actions/setup-python@v7 diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml index 46742cbae..8d16f9979 100644 --- a/.github/workflows/e2e-test.yml +++ b/.github/workflows/e2e-test.yml @@ -41,14 +41,6 @@ on: python-version: description: 'Specify the Python version to use for running tests. Leave empty to use the default Python version configured in the environment' required: false - run-eol-python-version: - description: 'Indicates whether to run tests using an End-of-Life (EOL) Python version. Defaults to "false". Choose "true" to include tests for deprecated Python versions' - required: false - default: 'false' - type: choice - options: - - 'true' - - 'false' test_report_upload: description: 'Indicates whether to upload the test report to object storage. Defaults to "false"' type: choice @@ -63,8 +55,7 @@ on: - dev env: - DEFAULT_PYTHON_VERSION: "3.13" - EOL_PYTHON_VERSION: "3.10" + DEFAULT_PYTHON_VERSION: "3.11" EXIT_STATUS: 0 jobs: @@ -89,7 +80,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v7 with: - python-version: ${{ inputs.run-eol-python-version == 'true' && env.EOL_PYTHON_VERSION || inputs.python-version || env.DEFAULT_PYTHON_VERSION }} + python-version: ${{ inputs.python-version || env.DEFAULT_PYTHON_VERSION }} - name: Install Python deps run: pip install -U setuptools wheel boto3 certifi diff --git a/.github/workflows/release-cross-repo-test.yml b/.github/workflows/release-cross-repo-test.yml index be2eaba68..8a57205bb 100644 --- a/.github/workflows/release-cross-repo-test.yml +++ b/.github/workflows/release-cross-repo-test.yml @@ -27,7 +27,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v7 with: - python-version: '3.10' + python-version: '3.13' - name: Checkout ansible repo uses: actions/checkout@v7 diff --git a/AGENTS.md b/AGENTS.md index 20f924d80..e9192dc6e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -3,7 +3,7 @@ ## Source of Truth - This is the official synchronous Python SDK for the Linode API. Supported - Python versions come from [pyproject.toml](pyproject.toml) (`>=3.10`). + Python versions come from [pyproject.toml](pyproject.toml) (`>=3.11`). - Make changes only in canonical source trees such as `linode_api4/`, `test/`, `docs/`, `examples/`, and `.github/`. Do not edit generated copies or output in `build/`, `dist/`, `docs/build/`, `docs/_build/`, or `linode_api4.egg-info/`. diff --git a/linode_api4/groups/linode.py b/linode_api4/groups/linode.py index 07254fb3d..1b4060931 100644 --- a/linode_api4/groups/linode.py +++ b/linode_api4/groups/linode.py @@ -97,7 +97,6 @@ def stackscripts(self, *filters, **kwargs): :returns: A list of StackScripts matching the query. :rtype: PaginatedList of StackScript """ - # python2 can't handle *args and a single keyword argument, so this is a workaround if "mine_only" in kwargs: if kwargs["mine_only"]: new_filter = Filter({"mine": True}) diff --git a/linode_api4/login_client.py b/linode_api4/login_client.py index 8b8fe69c3..b671d1724 100644 --- a/linode_api4/login_client.py +++ b/linode_api4/login_client.py @@ -1,18 +1,12 @@ import re from datetime import datetime, timedelta from enum import Enum +from urllib.parse import urlencode, urlparse, urlunparse import requests from linode_api4.errors import ApiError -try: - from urllib.parse import urlencode, urlparse, urlunparse -except ImportError: - from urllib import urlencode - - from urlparse import urlparse, urlunparse - class AllWrapper: def __repr__(self): diff --git a/linode_api4/objects/account.py b/linode_api4/objects/account.py index a4aca1848..9b61b448b 100644 --- a/linode_api4/objects/account.py +++ b/linode_api4/objects/account.py @@ -494,7 +494,6 @@ def set_thumbnail(self, thumbnail): "Content-type": "image/png", } - # TODO this check needs to be smarter - python2 doesn't do it right if not isinstance(thumbnail, bytes): with open(thumbnail, "rb") as f: thumbnail = f.read() diff --git a/linode_api4/objects/linode.py b/linode_api4/objects/linode.py index 78bc0710a..f2249213e 100644 --- a/linode_api4/objects/linode.py +++ b/linode_api4/objects/linode.py @@ -2,7 +2,6 @@ import copy import string -import sys import warnings from dataclasses import dataclass, field from datetime import datetime @@ -1292,15 +1291,10 @@ def resize( @staticmethod def generate_root_password(): - def _func(value): - if sys.version_info[0] < 3: - value = int(value.encode("hex"), 16) - return value - password = "".join( [ - PASSWORD_CHARS[_func(c) % len(PASSWORD_CHARS)] - for c in urandom(randint(50, 110)) + PASSWORD_CHARS[value % len(PASSWORD_CHARS)] + for value in urandom(randint(50, 110)) ] ) diff --git a/linode_api4/objects/serializable.py b/linode_api4/objects/serializable.py index c1f59f6d4..55a2d6fba 100644 --- a/linode_api4/objects/serializable.py +++ b/linode_api4/objects/serializable.py @@ -272,9 +272,6 @@ class StrEnum(str, Enum): """ Used for enums that are of type string, which is necessary for implicit JSON serialization. - - NOTE: Replace this with StrEnum once Python 3.10 has been EOL'd. - See: https://docs.python.org/3/library/enum.html#enum.StrEnum """ def __new__(cls, *values): diff --git a/pyproject.toml b/pyproject.toml index e4e641aa7..a7008fea0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ name = "linode_api4" authors = [{ name = "Linode", email = "devs@linode.com" }] description = "The official Python SDK for Linode API v4" readme = "README.rst" -requires-python = ">=3.10" +requires-python = ">=3.11" keywords = [ "akamai", "Akamai Connected Cloud", @@ -25,11 +25,11 @@ classifiers = [ "License :: OSI Approved :: BSD License", "Programming Language :: Python", "Programming Language :: Python :: 3", - "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", + "Programming Language :: Python :: 3.15", ] dependencies = ["requests", "polling", "deprecated"] dynamic = ["version"] @@ -49,7 +49,7 @@ int-test = [ "cryptography", ] lint = [ - "black>=23.1.0", + "black>=26.10.1", "isort>=5.12.0", "autoflake>=2.0.1", "pylint", @@ -85,7 +85,7 @@ line_length = 80 [tool.black] line-length = 80 -target-version = ["py310", "py311", "py312", "py313", "py314"] +target-version = ["py311", "py312", "py313", "py314", "py315"] [tool.autoflake] expand-star-imports = true