diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index 4bf6421c16..833fd7ffd4 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -16,6 +16,7 @@ jobs: disable-sudo: true egress-policy: block allowed-endpoints: > + api.deps.dev api.github.com:443 api.securityscorecards.dev:443 github.com:443 @@ -23,5 +24,3 @@ jobs: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - uses: actions/dependency-review-action@3c4e3dcb1aa7874d2c16be7d79418e9b7efd6261 - with: - allow-ghsas: GHSA-pq67-6m6q-mj2v # urllib3 diff --git a/.github/workflows/python-checks.yml b/.github/workflows/python-checks.yml index e6ae1338d7..f80799fc00 100644 --- a/.github/workflows/python-checks.yml +++ b/.github/workflows/python-checks.yml @@ -52,13 +52,11 @@ jobs: - uses: install-pinned/uv@259f91feb61b6e94766d7a1dbcd5f17335370e64 - if: matrix.resolution != 'limited-dependencies' - continue-on-error: ${{ contains(matrix.python-version, '3.14') }} run: | uv pip install --system --resolution ${{ matrix.resolution }} -e .[all] uv pip install --system --resolution ${{ matrix.resolution }} -r requirements-dev.txt - if: matrix.resolution == 'limited-dependencies' - continue-on-error: ${{ contains(matrix.python-version, '3.14') }} env: PARSONS_LIMITED_DEPENDENCIES: 'TRUE' run: | @@ -72,12 +70,10 @@ jobs: key: pytest-${{ matrix.python-version }}-${{ matrix.os }}-${{ matrix.resolution }}-${{ hashFiles('pyproject.toml') }} - run: pytest - continue-on-error: ${{ contains(matrix.python-version, '3.14') }} env: COVERAGE_FILE: ".coverage.${{ matrix.os }}.${{ matrix.python-version }}.${{ matrix.resolution }}" - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f - if: ${{ !contains(matrix.python-version, '3.14') }} with: name: coverage-${{ matrix.os }}-${{ matrix.python-version }}-${{ matrix.resolution }} path: .coverage.${{ matrix.os }}.${{ matrix.python-version }}.${{ matrix.resolution }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index fcc5538640..3a56d84a3d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -59,6 +59,7 @@ jobs: - '3.11' - '3.12' - '3.13' + - '3.14' os: - ubuntu-latest - windows-latest diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8c1a1b7391..333cb27dfb 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,12 +1,12 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.13.0 + rev: v0.14.14 hooks: - - id: ruff + - id: ruff-check args: ['--fix'] - id: ruff-format - repo: https://github.com/PyCQA/bandit - rev: 1.8.6 + rev: 1.9.3 hooks: - id: bandit args: ['--confidence-level', 'medium', '--severity-level', 'medium', '--exclude', '**/vendor/*'] diff --git a/README.md b/README.md index c738427f93..fce9c8787e 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ This project is maintained by [The Movement Cooperative](https://movementcoopera after [Lucy Parsons](https://en.wikipedia.org/wiki/Lucy_Parsons). The Movement Cooperative is a member-led organization focused on providing data, tools, and strategic support for the progressive community. -Parsons is only supported for Python 3.10-13. +Parsons is only supported for Python 3.10 - 3.14. ## Table of Contents diff --git a/pyproject.toml b/pyproject.toml index f18a4d9438..430447366d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,6 +23,7 @@ classifiers = [ "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", ] dynamic = [ "dependencies", diff --git a/requirements-dev.txt b/requirements-dev.txt index 6675d34268..bc94466957 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,26 +1,25 @@ # Testing Requirements -bandit[sarif]==1.8.6 -coverage==7.10.7 -pre-commit==4.3.0 -pytest-cov==7.0.0 -pytest-datadir==1.8.0 -pytest-mock==3.15.1 -pytest-xdist==3.8.0 -pytest==8.4.2 -requests-mock==1.12.1 -ruff==0.13.0 -testfixtures==8.3.0;python_version<'3.11' -testfixtures==9.1.0;python_version>='3.11' +bandit[sarif]==1.9.3 +pre-commit~=4.5 +pytest-cov~=7.0 +pytest-datadir~=1.8 +pytest-mock~=3.15 +pytest-xdist~=3.8 +pytest~=9.0 +requests-mock~=1.12 +ruff==0.14.14 +testfixtures~=8.3.0;python_version<'3.11' +testfixtures~=10.0.0;python_version>='3.11' # Build and publish requirements -twine==6.2.0 +twine~=6.2 build - # Docs Requirements -myst-parser==4.0.1 -sphinxcontrib-googleanalytics==0.5 -sphinx-multiversion==0.2.4 -sphinx-rtd-theme==3.0.2 -Sphinx==7.4.7;python_version<'3.11' -Sphinx==8.2.3;python_version>='3.11' +myst-parser~=4.0;python_version<'3.11' +myst-parser~=5.0;python_version>='3.11' +sphinxcontrib-googleanalytics~=0.5 +sphinx-multiversion~=0.2 +sphinx-rtd-theme~=3.1 +Sphinx~=7.4;python_version<'3.11' +Sphinx~=8.2;python_version>='3.11' diff --git a/requirements.txt b/requirements.txt index 898c37aac3..0ae89c618b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,31 +1,35 @@ azure-storage-blob==12.27.1 -boto3>=1.17.98 +boto3>=1.42.0 boxsdk==4.1.0 braintree==4.41.0 -bs4==0.0.2 +beautifulsoup4>=4.10.0 civis==2.4.3 curlify==3.0.0 -dbt-core>=1.5.0 +dbt-core>=1.9.0 +dbt-bigquery>=1.9.0 +dbt-postgres>=1.9.0 +dbt-redshift>=1.9.0 +dbt-snowflake>=1.9.0 defusedxml>=0.7.1, <=0.8.0 facebook-business==24.0.1 -fastavro==1.10.0 +fastavro==1.12.1 google-api-core==2.28.1 google-api-python-client==2.187.0 google-auth==2.40.3 google-cloud-bigquery==3.40.0 google-cloud-storage-transfer==1.18.0 -google-cloud-storage==3.7.0 +google-cloud-storage>=3.1,<3.8 grpcio==1.76.0 gspread==6.2.1 -httplib2==0.30.0 +httplib2==0.31.2 joblib==1.4.2 +lxml>=6.0.2 mysql-connector-python==9.4.0 newmode==0.1.6 oauth2client==4.1.3 paramiko==4.0.0 petl==1.7.17 -psycopg2-binary==2.9.9;python_version<"3.13" -psycopg2-binary==2.9.10;python_version>="3.13" +psycopg2-binary>=2.9.11 pyairtable==3.2.0 PyGitHub==2.8.1 python-dateutil==2.9.0.post0 @@ -36,12 +40,12 @@ setuptools==80.9.0 simple-salesforce==1.12.9 simplejson==3.20.1 slack-sdk==3.38.0 -sqlalchemy >= 1.4.22, != 1.4.33, < 3.0.0 # Prefect does not work with 1.4.33 and >=2.0.0 has breaking changes +sqlalchemy>=1.4.54 sshtunnel==0.4.0 suds-py3==1.4.5.0 surveygizmo==1.2.3 twilio==9.9.0 -urllib3==2.6.0 +urllib3==2.6.3 validate-email==1.3 xmltodict==1.0.2 diff --git a/setup.py b/setup.py index 33f9effe7d..ea14f87a31 100644 --- a/setup.py +++ b/setup.py @@ -33,10 +33,15 @@ "braintree": ["braintree"], "catalist": ["paramiko"], "civis": ["civis"], - "dbt-redshift": ["dbt-redshift >= 1.5.0"], - "dbt-bigquery": ["dbt-bigquery >= 1.5.0"], - "dbt-postgres": ["dbt-postgres >= 1.5.0"], - "dbt-snowflake": ["dbt-snowflake >= 1.5.0"], + "dbt-redshift": [ + "dbt-redshift >= 1.5.0", + "dbt-core >= 1.5.0", + "lxml;python_version < '3.14'", + "lxml>=5.5.0;python_version >= '3.14'", + ], + "dbt-bigquery": ["dbt-bigquery >= 1.5.0", "dbt-core >= 1.5.0"], + "dbt-postgres": ["dbt-postgres >= 1.5.0", "dbt-core >= 1.5.0"], + "dbt-snowflake": ["dbt-snowflake >= 1.5.0", "dbt-core >= 1.5.0"], "facebook": ["joblib", "facebook-business"], "geocode": [ "requests >= 2.27.0", @@ -57,19 +62,19 @@ ], "mysql": [ "mysql-connector-python", - "sqlalchemy >= 1.4.22", + "sqlalchemy >= 1.4.54", ], "newmode": ["newmode"], "ngpvan": ["suds-py3"], "mobilecommons": ["beautifulsoup4"], "postgres": [ - "psycopg2-binary >= 2.0.0", - "sqlalchemy >= 1.4.22", + "psycopg2-binary >= 2.9.11", + "sqlalchemy >= 1.4.54", ], "redshift": [ "boto3", - "psycopg2-binary >= 2.0.0", - "sqlalchemy >= 1.4.22", + "psycopg2-binary >= 2.9.11", + "sqlalchemy >= 1.4.54", ], "s3": ["boto3"], "salesforce": ["simple-salesforce"], @@ -81,8 +86,8 @@ "twilio": ["twilio"], "ssh": [ "sshtunnel", - "psycopg2-binary >= 2.0.0", - "sqlalchemy >= 1.4.22", + "psycopg2-binary >= 2.9.11", + "sqlalchemy >= 1.4.54", ], } diff --git a/test/test_databases/test_dbsync.py b/test/test_databases/test_dbsync.py index 5852464494..ff9cd8bca0 100644 --- a/test/test_databases/test_dbsync.py +++ b/test/test_databases/test_dbsync.py @@ -26,7 +26,7 @@ class TestDBSync(ABC, unittest.TestCase): def setUpClass(cls): # Skip tests on this abstract base class if cls is TestDBSync: - raise unittest.SkipTest(f"{cls.__name__} is an abstract base class") + raise pytest.skip(f"{cls.__name__} is an abstract base class") else: super().setUpClass()