diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f134759d9..c9d385318 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -55,7 +55,7 @@ jobs: # if changing the below change the run-integration-tests versions and the check-deploy versions # Make sure that we are running the integration tests on the first and last versions of the matrix - python: ['3.11', '3.12', '3.13', '3.14'] + python: ['3.11', '3.12', '3.13', '3.14', '3.15'] runs-on: ${{ matrix.os }} @@ -109,7 +109,7 @@ jobs: pytest -sv --cov-append --cov=. --cov-report xml tests/unit - name: Check for Secret availability id: secret-check - if: ${{ contains(fromJSON('["3.11"]'), matrix.python) || contains(fromJSON('["3.14"]'), matrix.python) }} + if: ${{ contains(fromJSON('["3.11"]'), matrix.python) || contains(fromJSON('["3.15"]'), matrix.python) }} # perform secret check & put boolean result as an output shell: bash run: | @@ -126,7 +126,7 @@ jobs: fi - name: Download Failed Tests from Previous Attempt - if: ${{ github.run_attempt > 1 && (contains(fromJSON('["3.11"]'), matrix.python) || contains(fromJSON('["3.14"]'), matrix.python)) && steps.secret-check.outputs.secrets_available == 'true'}} + if: ${{ github.run_attempt > 1 && (contains(fromJSON('["3.11"]'), matrix.python) || contains(fromJSON('["3.15"]'), matrix.python)) && steps.secret-check.outputs.secrets_available == 'true'}} uses: actions/download-artifact@v4 with: name: failed-tests-${{ matrix.os }}-${{ matrix.python }} @@ -142,25 +142,25 @@ jobs: shell: bash # keep versions consistent with the first and last from the strategy matrix - if: ${{ (contains(fromJSON('["3.11"]'), matrix.python) || contains(fromJSON('["3.14"]'), matrix.python)) && steps.secret-check.outputs.secrets_available == 'true' && github.event_name != 'release'}} + if: ${{ (contains(fromJSON('["3.11"]'), matrix.python) || contains(fromJSON('["3.15"]'), matrix.python)) && steps.secret-check.outputs.secrets_available == 'true' && github.event_name != 'release'}} run: | # Set SYNAPSE_PROFILE based on OS and Python version if [ "${{ startsWith(matrix.os, 'ubuntu') }}" == "true" ]; then if [ "${{ matrix.python }}" == "3.11" ]; then export SYNAPSE_PROFILE="TestUbuntuMinimumPython" - elif [ "${{ matrix.python }}" == "3.14" ]; then + elif [ "${{ matrix.python }}" == "3.15" ]; then export SYNAPSE_PROFILE="TestUbuntuMaximumPython" fi elif [ "${{ startsWith(matrix.os, 'windows') }}" == "true" ]; then if [ "${{ matrix.python }}" == "3.11" ]; then export SYNAPSE_PROFILE="TestWindowsMinimumPython" - elif [ "${{ matrix.python }}" == "3.14" ]; then + elif [ "${{ matrix.python }}" == "3.15" ]; then export SYNAPSE_PROFILE="TestWindowsMaximumPython" fi elif [ "${{ startsWith(matrix.os, 'macos') }}" == "true" ]; then if [ "${{ matrix.python }}" == "3.11" ]; then export SYNAPSE_PROFILE="TestMacosMinimumPython" - elif [ "${{ matrix.python }}" == "3.14" ]; then + elif [ "${{ matrix.python }}" == "3.15" ]; then export SYNAPSE_PROFILE="TestMacosMaximumPython" fi fi @@ -547,7 +547,7 @@ jobs: os: [ubuntu-24.04, macos-15-intel, windows-2022] # python versions should be consistent with the strategy matrix and the runs-integration-tests versions - python: ['3.11', '3.12', '3.13', '3.14'] + python: ['3.11', '3.12', '3.13', '3.14', '3.15'] runs-on: ${{ matrix.os }} diff --git a/.github/workflows/validate-release.yml b/.github/workflows/validate-release.yml index 04f4492d2..2d6bc1a31 100644 --- a/.github/workflows/validate-release.yml +++ b/.github/workflows/validate-release.yml @@ -16,7 +16,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: - python-version: '3.14' + python-version: '3.15' - name: Install dependencies run: | python -m pip install --upgrade pip diff --git a/CLAUDE.md b/CLAUDE.md index a19452b19..4b1560669 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -6,7 +6,7 @@ Synapse Python Client — official Python SDK and CLI for Synapse (synapse.org), ## Stack -- Python 3.11–3.14 (`setup.cfg`: `python_requires = >=3.11, <3.15`) +- Python 3.11–3.15 (`setup.cfg`: `python_requires = >=3.11, <3.16`) - HTTP: httpx (async), requests (sync/legacy) - Models: stdlib dataclasses (NOT Pydantic) - pandas (optional): `pandas>=1.5,<4.0` (`setup.cfg`, 4 places) @@ -132,7 +132,7 @@ Code must work on every pandas version from 1.5 to 3.x. Use one code path that w - Integration tests use `--reruns 3` for flaky retries and `-n 4 --dist loadscope` for parallelism - Integration fixtures create per-worker Synapse projects; use `schedule_for_cleanup()` for teardown - Auth env vars: `SYNAPSE_AUTH_TOKEN` (bearer token), `SYNAPSE_PROFILE` (config file profile, default: `"default"`), `SYNAPSE_TOKEN_AWS_SSM_PARAMETER_NAME` (AWS SSM path) -- CI runs integration tests only on Python 3.11 and 3.14 (oldest + newest) to limit Synapse server load +- CI runs integration tests only on Python 3.11 and 3.15 (oldest + newest) to limit Synapse server load - CI job `test-pandas-versions` (`.github/workflows/build.yml`) runs the unit tests on older pandas versions: 1.5.3 on Python 3.11, 2.1.4 on Python 3.12, 2.2.3 on Python 3.13 (ubuntu only). The `package` job needs it. pandas < 2.2.2 requires `numpy<2`, so each matrix entry pins its own numpy version (1.26.4, 1.26.4, 2.5.4). ## Maintenance diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 06ecb2736..a16981469 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -93,7 +93,7 @@ copied to forks). #### Installing the Python Client in a virtual environment with pipenv Perform the following one-time steps to set up your local environment. -1. This package uses Python, if you have not already, please install [pyenv](https://github.com/pyenv/pyenv#installation) to manage your Python versions. Versions supported by this package are all versions >=3.11 and <=3.14. If you do not install `pyenv` make sure that Python and `pip` are installed correctly and have been added to your PATH by running `python3 --version` and `pip3 --version`. If your installation was successful, your terminal will return the versions of Python and `pip` that you installed. **Note**: If you have `pyenv` it will install a specific version of Python for you. +1. This package uses Python, if you have not already, please install [pyenv](https://github.com/pyenv/pyenv#installation) to manage your Python versions. Versions supported by this package are all versions >=3.11 and <=3.15. If you do not install `pyenv` make sure that Python and `pip` are installed correctly and have been added to your PATH by running `python3 --version` and `pip3 --version`. If your installation was successful, your terminal will return the versions of Python and `pip` that you installed. **Note**: If you have `pyenv` it will install a specific version of Python for you. 2. Install `pipenv` by running `pip install pipenv`. - If you already have `pipenv` installed, ensure that the version is >=2023.9.8 to avoid compatibility issues. @@ -271,18 +271,18 @@ When adding support for a new Python version or dropping support for an old vers #### Adding a new Python version -When adding support for a new Python version (e.g., adding Python 3.15), update the following: +When adding support for a new Python version (e.g., adding Python 3.16), update the following: **Code configuration files:** 1. **`setup.cfg`**: - - Add the new version to the `classifiers` list under `[metadata]` (e.g., `Programming Language :: Python :: 3.15`) - - Update the `python_requires` constraint under `[options]` to include the new version (e.g., `>=3.11, <3.16`) + - Add the new version to the `classifiers` list under `[metadata]` (e.g., `Programming Language :: Python :: 3.16`) + - Update the `python_requires` constraint under `[options]` to include the new version (e.g., `>=3.11, <3.17`) 2. **`pyproject.toml`**: - Update the `target-version` list in the `[tool.black]` section to include the new version if needed 3. **`Dockerfile`**: - - Update the base image to use the new Python version (e.g., `FROM python:3.15-slim`) + - Update the base image to use the new Python version (e.g., `FROM python:3.16-slim`) **CI/CD configuration files:** 1. **`.github/workflows/build.yml`**: @@ -301,7 +301,7 @@ When dropping support for an old Python version (e.g., removing Python 3.11), up **Code configuration files:** 1. **`setup.cfg`**: - Remove the old version from the `classifiers` list under `[metadata]` - - Update the `python_requires` constraint under `[options]` to reflect the new minimum version (e.g., `>=3.12, <3.15`) + - Update the `python_requires` constraint under `[options]` to reflect the new minimum version (e.g., `>=3.12, <3.16`) 2. **`pyproject.toml`**: - Update the `target-version` list in the `[tool.black]` section to remove the old version diff --git a/Dockerfile b/Dockerfile index 99b8ffdaa..19d51d148 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.14-slim +FROM python:3.15-slim RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections RUN apt-get update \ diff --git a/README.md b/README.md index de9d91023..443392b97 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ flowchart TD Installation ------------ -We test the client on Python 3.11, 3.12, 3.13, and 3.14. It runs on Mac OS X, Linux, and Windows. +We test the client on Python 3.11, 3.12, 3.13, 3.14, and 3.15. It runs on Mac OS X, Linux, and Windows. **Version 3.0 and later needs Python 3.10 or higher. Version 4.15.0 and later needs Python 3.11 or higher.** diff --git a/docs/tutorials/installation.md b/docs/tutorials/installation.md index ca4f2e932..2581f9978 100644 --- a/docs/tutorials/installation.md +++ b/docs/tutorials/installation.md @@ -21,7 +21,7 @@ The [synapseclient](https://pypi.python.org/pypi/synapseclient/) package is avai - conda: Please follow instructions [here](https://docs.conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html) to manage environments: ```bash -conda create -n synapseclient python=3.14 +conda create -n synapseclient python=3.15 conda activate synapseclient # Here are a few ways to install the client. Choose the one that fits your use-case @@ -43,8 +43,8 @@ to the `/usr/local/lib` directory. [See here](https://github.com/conda/conda/iss - pyenv: Use [virtualenv](https://virtualenv.pypa.io/en/latest/) to manage your python environment: ```bash -pyenv install -v 3.14.0 -pyenv global 3.14.0 +pyenv install -v 3.15.0 +pyenv global 3.15.0 python -m venv env source env/bin/activate diff --git a/setup.cfg b/setup.cfg index 3e9085626..4cc209800 100644 --- a/setup.cfg +++ b/setup.cfg @@ -26,6 +26,7 @@ classifiers = Programming Language :: Python :: 3.12 Programming Language :: Python :: 3.13 Programming Language :: Python :: 3.14 + Programming Language :: Python :: 3.15 Operating System :: MacOS Operating System :: Microsoft :: Windows Operating System :: Unix @@ -41,7 +42,7 @@ classifiers = zip_safe = False include_package_data = True packages = find: -python_requires = >=3.11, <3.15 +python_requires = >=3.11, <3.16 install_requires = requests>=2.34.0,<3.0 urllib3>=2.8.0 diff --git a/synapseclient/core/download/download_functions.py b/synapseclient/core/download/download_functions.py index 14d211f99..71d83d54f 100644 --- a/synapseclient/core/download/download_functions.py +++ b/synapseclient/core/download/download_functions.py @@ -973,7 +973,7 @@ def _ftp_report_hook( destination=destination, file_handle_id=file_handle_id ) range_header = ( - {"Range": f"bytes={os.path.getsize(filename=temp_destination)}-"} + {"Range": f"bytes={os.path.getsize(temp_destination)}-"} if os.path.exists(temp_destination) else {} ) @@ -1103,7 +1103,7 @@ def _ftp_report_hook( # Servers that respect the Range header return 206 Partial Content if response.status_code == 206: mode = "ab" - previously_transferred = os.path.getsize(filename=temp_destination) + previously_transferred = os.path.getsize(temp_destination) to_be_transferred += previously_transferred transferred += previously_transferred increment_progress_bar_total( diff --git a/tests/unit/synapseclient/core/unit_test_download.py b/tests/unit/synapseclient/core/unit_test_download.py index 826a3c8dc..8b18a1798 100644 --- a/tests/unit/synapseclient/core/unit_test_download.py +++ b/tests/unit/synapseclient/core/unit_test_download.py @@ -986,9 +986,7 @@ async def test_download_end_early_retry(self, syn: Synapse) -> None: # assert getsize() called 2 times # once because exists()=True and another time because response status code = 206 - assert [ - call(filename=temp_destination) - ] * 2 == mocked_getsize.call_args_list + assert [call(temp_destination)] * 2 == mocked_getsize.call_args_list # assert shutil.move() called 1 time mocked_move.assert_called_once_with(temp_destination, destination)