diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index b65401ce7cb..9c3ed206289 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-24.04 strategy: matrix: - python-version: ["current", "previous"] + python-version: ["current", "previous", "next"] steps: - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" uses: actions/checkout@v4 diff --git a/.github/workflows/superset-python-integrationtest.yml b/.github/workflows/superset-python-integrationtest.yml index cd19ecb64c7..03da74abbfd 100644 --- a/.github/workflows/superset-python-integrationtest.yml +++ b/.github/workflows/superset-python-integrationtest.yml @@ -77,7 +77,7 @@ jobs: runs-on: ubuntu-24.04 strategy: matrix: - python-version: ["current", "previous"] + python-version: ["current", "previous", "next"] env: PYTHONPATH: ${{ github.workspace }} SUPERSET_CONFIG: tests.integration_tests.superset_test_config diff --git a/.github/workflows/superset-python-unittest.yml b/.github/workflows/superset-python-unittest.yml index a8feed453cd..208cf82421a 100644 --- a/.github/workflows/superset-python-unittest.yml +++ b/.github/workflows/superset-python-unittest.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-24.04 strategy: matrix: - python-version: ["previous", "current"] + python-version: ["previous", "current", "next"] env: PYTHONPATH: ${{ github.workspace }} steps: diff --git a/pyproject.toml b/pyproject.toml index c9ed5db5a83..b8cf768a22e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,6 +32,7 @@ authors = [ classifiers = [ "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", ] dependencies = [ "backoff>=1.8.0", @@ -66,7 +67,7 @@ dependencies = [ "markdown>=3.0", "msgpack>=1.0.0, <1.1", "nh3>=0.2.11, <0.3", - "numpy>1.23.5, <2", + "numpy>1.23.5, <2.3", "packaging", # -------------------------- # pandas and related (wanting pandas[performance] without numba as it's 100+MB and not needed) @@ -94,7 +95,8 @@ dependencies = [ "sqlalchemy-utils>=0.38.3, <0.39", "sqlglot>=26.1.3, <27", "sqlparse>=0.5.0", - "tabulate>=0.8.9, <0.9", + # newer pandas needs 0.9+ + "tabulate>=0.9.0, <1.0", "typing-extensions>=4, <5", "waitress; sys_platform == 'win32'", "wtforms>=2.3.3, <4", diff --git a/requirements/base.in b/requirements/base.in index f23e6ad1cad..e531ff644b2 100644 --- a/requirements/base.in +++ b/requirements/base.in @@ -33,3 +33,6 @@ apispec>=6.0.0,<6.7.0 # https://marshmallow-sqlalchemy.readthedocs.io/en/latest/changelog.html#id3 # Opened this issue https://github.com/marshmallow-code/marshmallow-sqlalchemy/issues/665 marshmallow-sqlalchemy>=1.3.0,<1.4.1 + +# needed for python 3.12 support +openapi-schema-validator>=0.6.3 diff --git a/requirements/base.txt b/requirements/base.txt index c887750e909..f9e20d836c7 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -11,9 +11,7 @@ apispec==6.6.1 apsw==3.49.2.0 # via shillelagh async-timeout==4.0.3 - # via - # -r requirements/base.in - # redis + # via -r requirements/base.in attrs==25.3.0 # via # cattrs @@ -99,11 +97,6 @@ email-validator==2.2.0 # via flask-appbuilder et-xmlfile==2.0.0 # via openpyxl -exceptiongroup==1.3.0 - # via - # cattrs - # trio - # trio-websocket flask==2.3.3 # via # apache-superset (pyproject.toml) @@ -189,9 +182,13 @@ jinja2==3.1.6 jsonpath-ng==1.7.0 # via apache-superset (pyproject.toml) jsonschema==4.23.0 - # via flask-appbuilder + # via + # flask-appbuilder + # openapi-schema-validator jsonschema-specifications==2025.4.1 - # via jsonschema + # via + # jsonschema + # openapi-schema-validator kombu==5.5.3 # via celery korean-lunar-calendar==0.3.1 @@ -238,6 +235,8 @@ numpy==1.26.4 # pandas odfpy==1.4.1 # via pandas +openapi-schema-validator==0.6.3 + # via -r requirements/base.in openpyxl==3.1.5 # via pandas ordered-set==4.1.0 @@ -336,6 +335,8 @@ requests==2.32.3 # shillelagh requests-cache==1.2.1 # via shillelagh +rfc3339-validator==0.1.4 + # via openapi-schema-validator rich==13.9.4 # via flask-limiter rpds-py==0.25.0 @@ -354,6 +355,8 @@ six==1.17.0 # via # prison # python-dateutil + # rfc3339-validator + # url-normalize # wtforms-json slack-sdk==3.35.0 # via apache-superset (pyproject.toml) @@ -380,7 +383,7 @@ sqlparse==0.5.3 # via apache-superset (pyproject.toml) sshtunnel==0.4.0 # via apache-superset (pyproject.toml) -tabulate==0.8.10 +tabulate==0.9.0 # via apache-superset (pyproject.toml) trio==0.30.0 # via @@ -392,12 +395,9 @@ typing-extensions==4.13.2 # via # apache-superset (pyproject.toml) # alembic - # cattrs - # exceptiongroup # limits # pyopenssl # referencing - # rich # selenium # shillelagh tzdata==2025.2 diff --git a/requirements/development.txt b/requirements/development.txt index 770406029b2..4a715b2a6ff 100644 --- a/requirements/development.txt +++ b/requirements/development.txt @@ -18,10 +18,6 @@ apsw==3.49.2.0 # via # -c requirements/base.txt # shillelagh -async-timeout==4.0.3 - # via - # -c requirements/base.txt - # redis attrs==25.3.0 # via # -c requirements/base.txt @@ -176,13 +172,6 @@ et-xmlfile==2.0.0 # via # -c requirements/base.txt # openpyxl -exceptiongroup==1.3.0 - # via - # -c requirements/base.txt - # cattrs - # pytest - # trio - # trio-websocket filelock==3.12.2 # via virtualenv flask==2.3.3 @@ -480,7 +469,9 @@ odfpy==1.4.1 # -c requirements/base.txt # pandas openapi-schema-validator==0.6.3 - # via openapi-spec-validator + # via + # -c requirements/base.txt + # openapi-spec-validator openapi-spec-validator==0.7.1 # via apache-superset openpyxl==3.1.5 @@ -727,7 +718,9 @@ requests-cache==1.2.1 requests-oauthlib==2.0.0 # via google-auth-oauthlib rfc3339-validator==0.1.4 - # via openapi-schema-validator + # via + # -c requirements/base.txt + # openapi-schema-validator rich==13.9.4 # via # -c requirements/base.txt @@ -815,14 +808,10 @@ sshtunnel==0.4.0 # apache-superset statsd==4.0.1 # via apache-superset -tabulate==0.8.10 +tabulate==0.9.0 # via # -c requirements/base.txt # apache-superset -tomli==2.2.1 - # via - # coverage - # pytest tqdm==4.67.1 # via # cmdstanpy @@ -843,12 +832,9 @@ typing-extensions==4.13.2 # -c requirements/base.txt # alembic # apache-superset - # cattrs - # exceptiongroup # limits # pyopenssl # referencing - # rich # selenium # shillelagh tzdata==2025.2 diff --git a/superset/connectors/sqla/models.py b/superset/connectors/sqla/models.py index 275cc0cdbf4..57952ef5ef7 100644 --- a/superset/connectors/sqla/models.py +++ b/superset/connectors/sqla/models.py @@ -794,7 +794,8 @@ class AnnotationDatasource(BaseDatasource): qry = qry.filter(Annotation.end_dttm <= query_obj["to_dttm"]) status = QueryStatus.SUCCESS try: - df = pd.read_sql_query(qry.statement, db.engine) + with db.engine.connect() as con: + df = pd.read_sql_query(qry.statement, con) except Exception as ex: # pylint: disable=broad-except df = pd.DataFrame() status = QueryStatus.FAILED diff --git a/superset/models/helpers.py b/superset/models/helpers.py index 341585e5da5..5647bc871bb 100644 --- a/superset/models/helpers.py +++ b/superset/models/helpers.py @@ -1375,10 +1375,11 @@ class ExploreMixin: # pylint: disable=too-many-public-methods if engine.dialect.identifier_preparer._double_percents: sql = sql.replace("%%", "%") - df = pd.read_sql_query(sql=self.text(sql), con=engine) - # replace NaN with None to ensure it can be serialized to JSON - df = df.replace({np.nan: None}) - return df["column_values"].to_list() + with engine.connect() as con: + df = pd.read_sql_query(sql=self.text(sql), con=con) + # replace NaN with None to ensure it can be serialized to JSON + df = df.replace({np.nan: None}) + return df["column_values"].to_list() def get_timestamp_expression( self, diff --git a/tests/integration_tests/reports/commands_tests.py b/tests/integration_tests/reports/commands_tests.py index d3798d05ec8..30a9d174c5b 100644 --- a/tests/integration_tests/reports/commands_tests.py +++ b/tests/integration_tests/reports/commands_tests.py @@ -1978,7 +1978,7 @@ def test_slack_token_callable_chart_report( TEST_ID, create_report_slack_chart.id, datetime.utcnow() ).run() app.config["SLACK_API_TOKEN"].assert_called() - assert slack_client_mock_class.called_with(token="cool_code", proxy="") # noqa: S106 + slack_client_mock_class.assert_called_with(token="cool_code", proxy=None) # noqa: S106 assert_log(ReportState.SUCCESS) diff --git a/tests/unit_tests/models/helpers_test.py b/tests/unit_tests/models/helpers_test.py index 4e8aa493be3..d0dfef43b86 100644 --- a/tests/unit_tests/models/helpers_test.py +++ b/tests/unit_tests/models/helpers_test.py @@ -209,4 +209,4 @@ def test_values_for_column_double_percents( called_conn = pd.read_sql_query.call_args.kwargs["con"] assert called_sql.compare(expected_sql) is True - assert called_conn == engine + assert called_conn.engine == engine