From ff98491247c8cb13479b8a23c805020cb2c61c8d Mon Sep 17 00:00:00 2001 From: Thomas Li <47963215+lithomas1@users.noreply.github.com> Date: Tue, 20 Jun 2023 11:02:55 -0700 Subject: [PATCH 01/23] CI: Test Python 3.12 --- .circleci/config.yml | 6 +++--- .github/workflows/unit-tests.yml | 4 ++-- .github/workflows/wheels.yml | 3 ++- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index dfaade1d69c75..41f22d63f0c54 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -47,8 +47,8 @@ jobs: - run: name: Build aarch64 wheels command: | - pip3 install cibuildwheel==2.12.1 - cibuildwheel --output-dir wheelhouse + pip3 install cibuildwheel==2.11.1 + cibuildwheel --prerelease-pythons --output-dir wheelhouse environment: CIBW_BUILD: << parameters.cibw-build >> @@ -91,4 +91,4 @@ workflows: only: /^v.*/ matrix: parameters: - cibw-build: ["cp39-manylinux_aarch64", "cp310-manylinux_aarch64", "cp311-manylinux_aarch64"] + cibw-build: ["cp39-manylinux_aarch64", "cp310-manylinux_aarch64", "cp311-manylinux_aarch64", "cp312-manylinux_aarch64"] diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 541b36d9b4c1d..71abe2a18559a 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -302,7 +302,7 @@ jobs: # To freeze this file, uncomment out the ``if: false`` condition, and migrate the jobs # to the corresponding posix/windows-macos/sdist etc. workflows. # Feel free to modify this comment as necessary. - if: false # Uncomment this to freeze the workflow, comment it to unfreeze + #if: false # Uncomment this to freeze the workflow, comment it to unfreeze runs-on: ${{ matrix.os }} strategy: fail-fast: false @@ -331,7 +331,7 @@ jobs: - name: Set up Python Dev Version uses: actions/setup-python@v4 with: - python-version: '3.11-dev' + python-version: '3.12-dev' - name: Install dependencies run: | diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index eae2949594bcc..43fc068f98cce 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -93,7 +93,7 @@ jobs: - [macos-12, macosx_*] - [windows-2022, win_amd64] # TODO: support PyPy? - python: [["cp39", "3.9"], ["cp310", "3.10"], ["cp311", "3.11"]] + python: [["cp39", "3.9"], ["cp310", "3.10"], ["cp311", "3.11"], ["cp312", "3.12"]] env: IS_PUSH: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') }} IS_SCHEDULE_DISPATCH: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} @@ -117,6 +117,7 @@ jobs: #with: # package-dir: ./dist/${{ needs.build_sdist.outputs.sdist_file }} env: + CIBW_PRERELEASE_PYTHONS: True CIBW_BUILD: ${{ matrix.python[0] }}-${{ matrix.buildplat[1] }} - name: Set up Python From fcbe1ed77a3de46c13436a88932c5b74e4aea2a6 Mon Sep 17 00:00:00 2001 From: Thomas Li <47963215+lithomas1@users.noreply.github.com> Date: Tue, 20 Jun 2023 12:23:29 -0700 Subject: [PATCH 02/23] Update unit-tests.yml --- .github/workflows/unit-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 71abe2a18559a..0a6bc1beac62e 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -336,7 +336,7 @@ jobs: - name: Install dependencies run: | python --version - python -m pip install --upgrade pip setuptools wheel + python -m pip install --upgrade pip setuptools wheel meson[ninja]==1.0.1 meson-python==0.13.1 python -m pip install --pre --extra-index-url https://pypi.anaconda.org/scientific-python-nightly-wheels/simple numpy python -m pip install git+https://github.com/nedbat/coveragepy.git python -m pip install versioneer[toml] From dd4a4885ba5ed706d98d219267bac3d37efdafeb Mon Sep 17 00:00:00 2001 From: Thomas Li <47963215+lithomas1@users.noreply.github.com> Date: Tue, 20 Jun 2023 12:24:29 -0700 Subject: [PATCH 03/23] Update config.yml --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 41f22d63f0c54..59f84b2139513 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -47,7 +47,7 @@ jobs: - run: name: Build aarch64 wheels command: | - pip3 install cibuildwheel==2.11.1 + pip3 install cibuildwheel==2.13.1 cibuildwheel --prerelease-pythons --output-dir wheelhouse environment: CIBW_BUILD: << parameters.cibw-build >> From c809bcd9e87f5cbd826361d6eab1e42b2ff7efcb Mon Sep 17 00:00:00 2001 From: Thomas Li <47963215+lithomas1@users.noreply.github.com> Date: Tue, 20 Jun 2023 13:47:51 -0700 Subject: [PATCH 04/23] update --- .github/workflows/unit-tests.yml | 4 ++-- meson.build | 7 +++++++ pyproject.toml | 6 +++++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 0a6bc1beac62e..17f5b2d3f9e62 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -340,12 +340,12 @@ jobs: python -m pip install --pre --extra-index-url https://pypi.anaconda.org/scientific-python-nightly-wheels/simple numpy python -m pip install git+https://github.com/nedbat/coveragepy.git python -m pip install versioneer[toml] - python -m pip install python-dateutil pytz cython hypothesis>=6.46.1 pytest>=7.0.0 pytest-xdist>=2.2.0 pytest-cov pytest-asyncio>=0.17 + python -m pip install python-dateutil pytz tzdata cython hypothesis>=6.46.1 pytest>=7.0.0 pytest-xdist>=2.2.0 pytest-cov pytest-asyncio>=0.17 python -m pip list - name: Build Pandas run: | - python -m pip install -e . --no-build-isolation --no-index + python -m pip install -ve . --no-build-isolation --no-index - name: Build Version run: | diff --git a/meson.build b/meson.build index adbf87f8e3390..a927b59abeaf9 100644 --- a/meson.build +++ b/meson.build @@ -27,6 +27,13 @@ versioneer = files('generate_version.py') add_project_arguments('-DNPY_NO_DEPRECATED_API=0', language : 'c') add_project_arguments('-DNPY_NO_DEPRECATED_API=0', language : 'cpp') +# Allow supporting older numpys than the version compiled against +# Set the define to the min supported version of numpy for pandas +# e.g. right now this is targeting numpy 1.21+ +add_project_arguments('-DNPY_TARGET_VERSION=NPY_1_21_API_VERSION', language : 'c') +add_project_arguments('-DNPY_TARGET_VERSION=NPY_1_21_API_VERSION', language : 'cpp') + + if fs.exists('_version_meson.py') py.install_sources('_version_meson.py', pure: false, subdir: 'pandas') else diff --git a/pyproject.toml b/pyproject.toml index 6f91aa2360406..5ecfd0862aea0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,11 @@ requires = [ "meson[ninja]==1.0.1", "wheel", "Cython>=0.29.33,<3", # Note: sync with setup.py, environment.yml and asv.conf.json - "oldest-supported-numpy>=2022.8.16", + # Note: numpy 1.25 has a backwards compatible C API by default + # we don't want to force users to compile with 1.25 though + # (Ideally, in the future, though, oldest-supported-numpy can be dropped when our min numpy is 1.25.x) + "oldest-supported-numpy>=2022.8.16; python_version<'3.12'", + "numpy>=1.21.6; python_version>'3.12'", "versioneer[toml]" ] From 8c7aea2f63a7e04bbf4657d448eda70f85590791 Mon Sep 17 00:00:00 2001 From: Thomas Li <47963215+lithomas1@users.noreply.github.com> Date: Tue, 20 Jun 2023 14:26:18 -0700 Subject: [PATCH 05/23] fix condition --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index a78124b818426..0b447f1b4926f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,7 +10,7 @@ requires = [ # we don't want to force users to compile with 1.25 though # (Ideally, in the future, though, oldest-supported-numpy can be dropped when our min numpy is 1.25.x) "oldest-supported-numpy>=2022.8.16; python_version<'3.12'", - "numpy>=1.21.6; python_version>'3.12'", + "numpy>=1.21.6; python_version>='3.12'", "versioneer[toml]" ] From d2b38681f9ab9caf462958113670341ca4a1f7dc Mon Sep 17 00:00:00 2001 From: Thomas Li <47963215+lithomas1@users.noreply.github.com> Date: Sun, 25 Jun 2023 15:08:48 -0700 Subject: [PATCH 06/23] fix some tests --- pandas/core/computation/expr.py | 7 +++++-- pandas/io/xml.py | 2 +- pandas/tests/computation/test_eval.py | 6 +----- pandas/tests/io/parser/test_quoting.py | 2 +- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/pandas/core/computation/expr.py b/pandas/core/computation/expr.py index f8c8e6d87ff13..d00890dea5011 100644 --- a/pandas/core/computation/expr.py +++ b/pandas/core/computation/expr.py @@ -543,15 +543,18 @@ def visit_UnaryOp(self, node, **kwargs): def visit_Name(self, node, **kwargs): return self.term_type(node.id, self.env, **kwargs) + # TODO: deprecated since Python 3.8. Remove after Python 3.14 is min def visit_NameConstant(self, node, **kwargs) -> Term: return self.const_type(node.value, self.env) + # TODO: deprecated since Python 3.8. Remove after Python 3.14 is min def visit_Num(self, node, **kwargs) -> Term: - return self.const_type(node.n, self.env) + return self.const_type(node.value, self.env) def visit_Constant(self, node, **kwargs) -> Term: - return self.const_type(node.n, self.env) + return self.const_type(node.value, self.env) + # TODO: deprecated since Python 3.8. Remove after Python 3.14 is min def visit_Str(self, node, **kwargs): name = self.env.add_tmp(node.s) return self.term_type(name, self.env) diff --git a/pandas/io/xml.py b/pandas/io/xml.py index 2aec361d46b99..0b4e86d92f078 100644 --- a/pandas/io/xml.py +++ b/pandas/io/xml.py @@ -513,7 +513,7 @@ def _validate_names(self) -> None: children = self.iterparse[next(iter(self.iterparse))] else: parent = self.xml_doc.find(self.xpath, namespaces=self.namespaces) - children = parent.findall("*") if parent else [] + children = parent.findall("*") if parent is not None else [] if is_list_like(self.names): if len(self.names) < len(children): diff --git a/pandas/tests/computation/test_eval.py b/pandas/tests/computation/test_eval.py index 35960c707d3bd..0c91da6977cde 100644 --- a/pandas/tests/computation/test_eval.py +++ b/pandas/tests/computation/test_eval.py @@ -561,11 +561,7 @@ def test_unary_in_array(self): # TODO: 2022-01-29: result return list with numexpr 2.7.3 in CI # but cannot reproduce locally result = np.array( - pd.eval( - "[-True, True, ~True, +True," - "-False, False, ~False, +False," - "-37, 37, ~37, +37]" - ), + pd.eval("[-True, True, +True, -False, False, +False, -37, 37, ~37, +37]"), dtype=np.object_, ) expected = np.array( diff --git a/pandas/tests/io/parser/test_quoting.py b/pandas/tests/io/parser/test_quoting.py index 025a612dc47d2..b8b05af609aa2 100644 --- a/pandas/tests/io/parser/test_quoting.py +++ b/pandas/tests/io/parser/test_quoting.py @@ -40,7 +40,7 @@ def test_bad_quote_char(all_parsers, kwargs, msg): "quoting,msg", [ ("foo", '"quoting" must be an integer|Argument'), - (5, 'bad "quoting" value'), # quoting must be in the range [0, 3] + (10, 'bad "quoting" value'), # quoting must be in the range [0, 3] ], ) def test_bad_quoting(all_parsers, quoting, msg): From 5814bcc9d507bb75fbc96117c9434a8b800ad1f2 Mon Sep 17 00:00:00 2001 From: Thomas Li <47963215+lithomas1@users.noreply.github.com> Date: Sun, 25 Jun 2023 15:10:55 -0700 Subject: [PATCH 07/23] Remove wheel building for Python 3.12 --- .circleci/config.yml | 3 ++- .github/workflows/wheels.yml | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 59f84b2139513..fdcd5a205922a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -91,4 +91,5 @@ workflows: only: /^v.*/ matrix: parameters: - cibw-build: ["cp39-manylinux_aarch64", "cp310-manylinux_aarch64", "cp311-manylinux_aarch64", "cp312-manylinux_aarch64"] + # TODO: Enable Python 3.12 wheels when numpy releases a version that supports Python 3.12 + cibw-build: ["cp39-manylinux_aarch64", "cp310-manylinux_aarch64", "cp311-manylinux_aarch64"]#, "cp312-manylinux_aarch64"] diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index a878c709edca7..4e1d3b0897266 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -93,7 +93,8 @@ jobs: - [macos-12, macosx_*] - [windows-2022, win_amd64] # TODO: support PyPy? - python: [["cp39", "3.9"], ["cp310", "3.10"], ["cp311", "3.11"], ["cp312", "3.12"]] + # TODO: Enable Python 3.12 wheels when numpy releases a version that supports Python 3.12 + python: [["cp39", "3.9"], ["cp310", "3.10"], ["cp311", "3.11"]]#, ["cp312", "3.12"]] env: IS_PUSH: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') }} IS_SCHEDULE_DISPATCH: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} From 7be7ea9e03444456056af9e112eba1dfc11d98bc Mon Sep 17 00:00:00 2001 From: Thomas Li <47963215+lithomas1@users.noreply.github.com> Date: Sun, 25 Jun 2023 20:50:54 -0700 Subject: [PATCH 08/23] fix more --- pandas/io/sql.py | 26 ++++++++++++++++++- pandas/tests/computation/test_eval.py | 2 -- .../tests/scalar/timestamp/test_arithmetic.py | 3 ++- .../tests/scalar/timestamp/test_timestamp.py | 9 ++++--- 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/pandas/io/sql.py b/pandas/io/sql.py index 51cc3eacae284..592427e104b8a 100644 --- a/pandas/io/sql.py +++ b/pandas/io/sql.py @@ -2048,6 +2048,11 @@ class SQLiteTable(SQLTable): """ def __init__(self, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + + self._register_date_adapters() + + def _register_date_adapters(self): # GH 8341 # register an adapter callable for datetime.time object import sqlite3 @@ -2058,8 +2063,27 @@ def _adapt_time(t) -> str: # This is faster than strftime return f"{t.hour:02d}:{t.minute:02d}:{t.second:02d}.{t.microsecond:06d}" + # Also register adapters for date/datetime and co + # xref https://docs.python.org/3.12/library/sqlite3.html#adapter-and-converter-recipes + # Python 3.12+ doesn't auto-register adapters for us anymore + + adapt_date_iso = lambda val: val.isoformat() + adapt_datetime_iso = lambda val: val.isoformat() + adapt_datetime_epoch = lambda val: int(val.timestamp()) + sqlite3.register_adapter(time, _adapt_time) - super().__init__(*args, **kwargs) + + sqlite3.register_adapter(date, adapt_date_iso) + sqlite3.register_adapter(datetime, adapt_datetime_iso) + sqlite3.register_adapter(datetime, adapt_datetime_epoch) + + convert_date = lambda val: date.fromisoformat(val.decode()) + convert_datetime = lambda val: datetime.fromisoformat(val.decode()) + convert_timestamp = lambda val: datetime.fromtimestamp(int(val)) + + sqlite3.register_converter("date", convert_date) + sqlite3.register_converter("datetime", convert_datetime) + sqlite3.register_converter("timestamp", convert_timestamp) def sql_schema(self) -> str: return str(";\n".join(self.table)) diff --git a/pandas/tests/computation/test_eval.py b/pandas/tests/computation/test_eval.py index 0c91da6977cde..b39fc37e71ecd 100644 --- a/pandas/tests/computation/test_eval.py +++ b/pandas/tests/computation/test_eval.py @@ -568,11 +568,9 @@ def test_unary_in_array(self): [ -True, True, - ~True, +True, -False, False, - ~False, +False, -37, 37, diff --git a/pandas/tests/scalar/timestamp/test_arithmetic.py b/pandas/tests/scalar/timestamp/test_arithmetic.py index 2dac346bc54d5..d8e0337cb5d8d 100644 --- a/pandas/tests/scalar/timestamp/test_arithmetic.py +++ b/pandas/tests/scalar/timestamp/test_arithmetic.py @@ -1,4 +1,5 @@ from datetime import ( + UTC, datetime, timedelta, timezone, @@ -197,7 +198,7 @@ def test_radd_tdscalar(self, td, fixed_now_ts): ], ) def test_timestamp_add_timedelta64_unit(self, other, expected_difference): - now = datetime.utcnow() + now = datetime.now(UTC) ts = Timestamp(now).as_unit("ns") result = ts + other valdiff = result._value - ts._value diff --git a/pandas/tests/scalar/timestamp/test_timestamp.py b/pandas/tests/scalar/timestamp/test_timestamp.py index aa326f3a43bd5..690599eb9e197 100644 --- a/pandas/tests/scalar/timestamp/test_timestamp.py +++ b/pandas/tests/scalar/timestamp/test_timestamp.py @@ -2,6 +2,7 @@ import calendar from datetime import ( + UTC, datetime, timedelta, timezone, @@ -269,7 +270,7 @@ def compare(x, y): compare(Timestamp.now(), datetime.now()) compare(Timestamp.now("UTC"), datetime.now(pytz.timezone("UTC"))) - compare(Timestamp.utcnow(), datetime.utcnow()) + compare(Timestamp.utcnow(), datetime.now(UTC)) compare(Timestamp.today(), datetime.today()) current_time = calendar.timegm(datetime.now().utctimetuple()) @@ -289,7 +290,7 @@ def compare(x, y): datetime.fromtimestamp(current_time, utc), ) - date_component = datetime.utcnow() + date_component = datetime.now(UTC) time_component = (date_component + timedelta(minutes=10)).time() compare( Timestamp.combine(date_component, time_component), @@ -308,7 +309,7 @@ def compare(x, y): compare(Timestamp.now(), datetime.now()) compare(Timestamp.now("UTC"), datetime.now(tzutc())) - compare(Timestamp.utcnow(), datetime.utcnow()) + compare(Timestamp.utcnow(), datetime.now(UTC)) compare(Timestamp.today(), datetime.today()) current_time = calendar.timegm(datetime.now().utctimetuple()) @@ -319,7 +320,7 @@ def compare(x, y): Timestamp.fromtimestamp(current_time), datetime.fromtimestamp(current_time) ) - date_component = datetime.utcnow() + date_component = datetime.now(UTC) time_component = (date_component + timedelta(minutes=10)).time() compare( Timestamp.combine(date_component, time_component), From e9c0ed4caab62b02045332bbf899963c46b8af5c Mon Sep 17 00:00:00 2001 From: Matthew Roeschke <10647082+mroeschke@users.noreply.github.com> Date: Thu, 29 Jun 2023 15:34:26 -0700 Subject: [PATCH 09/23] Use timezone.utc --- pandas/tests/scalar/timestamp/test_arithmetic.py | 3 +-- pandas/tests/scalar/timestamp/test_timestamp.py | 9 ++++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/pandas/tests/scalar/timestamp/test_arithmetic.py b/pandas/tests/scalar/timestamp/test_arithmetic.py index d8e0337cb5d8d..f5c9c576abc24 100644 --- a/pandas/tests/scalar/timestamp/test_arithmetic.py +++ b/pandas/tests/scalar/timestamp/test_arithmetic.py @@ -1,5 +1,4 @@ from datetime import ( - UTC, datetime, timedelta, timezone, @@ -198,7 +197,7 @@ def test_radd_tdscalar(self, td, fixed_now_ts): ], ) def test_timestamp_add_timedelta64_unit(self, other, expected_difference): - now = datetime.now(UTC) + now = datetime.now(timezone.utc) ts = Timestamp(now).as_unit("ns") result = ts + other valdiff = result._value - ts._value diff --git a/pandas/tests/scalar/timestamp/test_timestamp.py b/pandas/tests/scalar/timestamp/test_timestamp.py index 690599eb9e197..78b08fd5ca702 100644 --- a/pandas/tests/scalar/timestamp/test_timestamp.py +++ b/pandas/tests/scalar/timestamp/test_timestamp.py @@ -2,7 +2,6 @@ import calendar from datetime import ( - UTC, datetime, timedelta, timezone, @@ -270,7 +269,7 @@ def compare(x, y): compare(Timestamp.now(), datetime.now()) compare(Timestamp.now("UTC"), datetime.now(pytz.timezone("UTC"))) - compare(Timestamp.utcnow(), datetime.now(UTC)) + compare(Timestamp.utcnow(), datetime.now(timezone.utc)) compare(Timestamp.today(), datetime.today()) current_time = calendar.timegm(datetime.now().utctimetuple()) @@ -290,7 +289,7 @@ def compare(x, y): datetime.fromtimestamp(current_time, utc), ) - date_component = datetime.now(UTC) + date_component = datetime.now(timezone.utc) time_component = (date_component + timedelta(minutes=10)).time() compare( Timestamp.combine(date_component, time_component), @@ -309,7 +308,7 @@ def compare(x, y): compare(Timestamp.now(), datetime.now()) compare(Timestamp.now("UTC"), datetime.now(tzutc())) - compare(Timestamp.utcnow(), datetime.now(UTC)) + compare(Timestamp.utcnow(), datetime.now(timezone.utc)) compare(Timestamp.today(), datetime.today()) current_time = calendar.timegm(datetime.now().utctimetuple()) @@ -320,7 +319,7 @@ def compare(x, y): Timestamp.fromtimestamp(current_time), datetime.fromtimestamp(current_time) ) - date_component = datetime.now(UTC) + date_component = datetime.now(timezone.utc) time_component = (date_component + timedelta(minutes=10)).time() compare( Timestamp.combine(date_component, time_component), From b8f351d699302e17f45c77037080ed79dfa235b5 Mon Sep 17 00:00:00 2001 From: Matthew Roeschke <10647082+mroeschke@users.noreply.github.com> Date: Fri, 7 Jul 2023 12:07:00 -0700 Subject: [PATCH 10/23] Address typing, utcfromtimestamp --- pandas/io/sql.py | 2 +- pandas/tests/io/parser/test_parse_dates.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/io/sql.py b/pandas/io/sql.py index 875450f2b8202..ecc48c1f65422 100644 --- a/pandas/io/sql.py +++ b/pandas/io/sql.py @@ -2058,7 +2058,7 @@ def __init__(self, *args, **kwargs) -> None: self._register_date_adapters() - def _register_date_adapters(self): + def _register_date_adapters(self) -> None: # GH 8341 # register an adapter callable for datetime.time object import sqlite3 diff --git a/pandas/tests/io/parser/test_parse_dates.py b/pandas/tests/io/parser/test_parse_dates.py index 571e09bb5e9dd..b445510c82ae5 100644 --- a/pandas/tests/io/parser/test_parse_dates.py +++ b/pandas/tests/io/parser/test_parse_dates.py @@ -717,7 +717,7 @@ def test_date_parser_int_bug(all_parsers): StringIO(data), index_col=0, parse_dates=[0], - date_parser=lambda x: datetime.utcfromtimestamp(int(x)), + date_parser=lambda x: datetime.fromtimestamp(int(x)), ) expected = DataFrame( [ From 7cbfd7c84383520f2467f6defd1cb8869fdec4f3 Mon Sep 17 00:00:00 2001 From: Thomas Li <47963215+lithomas1@users.noreply.github.com> Date: Tue, 11 Jul 2023 17:28:54 -0700 Subject: [PATCH 11/23] fix some slice changes --- pandas/core/indexes/datetimelike.py | 7 +++++-- pandas/tests/indexes/test_indexing.py | 6 ++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/pandas/core/indexes/datetimelike.py b/pandas/core/indexes/datetimelike.py index c4be04c469fae..2a7854b5b8628 100644 --- a/pandas/core/indexes/datetimelike.py +++ b/pandas/core/indexes/datetimelike.py @@ -33,7 +33,10 @@ to_offset, ) from pandas.compat.numpy import function as nv -from pandas.errors import NullFrequencyError +from pandas.errors import ( + InvalidIndexError, + NullFrequencyError, +) from pandas.util._decorators import ( Appender, cache_readonly, @@ -165,7 +168,7 @@ def __contains__(self, key: Any) -> bool: hash(key) try: self.get_loc(key) - except (KeyError, TypeError, ValueError): + except (KeyError, TypeError, ValueError, InvalidIndexError): return False return True diff --git a/pandas/tests/indexes/test_indexing.py b/pandas/tests/indexes/test_indexing.py index 3bc55786e1d2f..26c92e1f93865 100644 --- a/pandas/tests/indexes/test_indexing.py +++ b/pandas/tests/indexes/test_indexing.py @@ -176,10 +176,8 @@ def test_contains_requires_hashable_raises(self, index): class TestGetLoc: def test_get_loc_non_hashable(self, index): - # MultiIndex and Index raise TypeError, others InvalidIndexError - - with pytest.raises((TypeError, InvalidIndexError), match="slice"): - index.get_loc(slice(0, 1)) + with pytest.raises(InvalidIndexError, match="[0, 1]"): + index.get_loc([0, 1]) def test_get_loc_non_scalar_hashable(self, index): # GH52877 From e507d454496db14148caeee1d2c082717985e0e9 Mon Sep 17 00:00:00 2001 From: Thomas Li <47963215+lithomas1@users.noreply.github.com> Date: Thu, 13 Jul 2023 17:36:48 -0700 Subject: [PATCH 12/23] fix all indexing bugs? --- pandas/compat/__init__.py | 2 ++ pandas/compat/_constants.py | 2 ++ pandas/core/indexes/base.py | 5 +++ pandas/core/indexing.py | 34 +++++++++++++++++-- pandas/core/series.py | 2 +- pandas/tests/series/indexing/test_indexing.py | 4 +-- 6 files changed, 43 insertions(+), 6 deletions(-) diff --git a/pandas/compat/__init__.py b/pandas/compat/__init__.py index 00957c45a7fbe..daa7c5837cf3e 100644 --- a/pandas/compat/__init__.py +++ b/pandas/compat/__init__.py @@ -19,6 +19,7 @@ ISMUSL, PY310, PY311, + PY312, PYPY, ) import pandas.compat.compressors @@ -164,5 +165,6 @@ def get_lzma_file() -> type[pandas.compat.compressors.LZMAFile]: "ISMUSL", "PY310", "PY311", + "PY312", "PYPY", ] diff --git a/pandas/compat/_constants.py b/pandas/compat/_constants.py index 1d7fe23b3d2ea..9e25bfecf5070 100644 --- a/pandas/compat/_constants.py +++ b/pandas/compat/_constants.py @@ -15,6 +15,7 @@ PY310 = sys.version_info >= (3, 10) PY311 = sys.version_info >= (3, 11) +PY312 = sys.version_info >= (3, 12) PYPY = platform.python_implementation() == "PyPy" ISMUSL = "musl" in (sysconfig.get_config_var("HOST_GNU_TYPE") or "") @@ -24,5 +25,6 @@ "ISMUSL", "PY310", "PY311", + "PY312", "PYPY", ] diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index 5f19f6d06a194..f9beba970565e 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -3784,6 +3784,11 @@ def get_loc(self, key): try: return self._engine.get_loc(casted_key) except KeyError as err: + if isinstance(casted_key, slice) or ( + isinstance(casted_key, Iterable) + and any(isinstance(x, slice) for x in casted_key) + ): + raise InvalidIndexError(key) raise KeyError(key) from err except TypeError: # If we have a listlike key, _check_indexing_error will raise diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index 4a2803f638c73..4158de1fc2435 100644 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -739,7 +739,12 @@ def _get_setitem_indexer(self, key): ax = self.obj._get_axis(0) - if isinstance(ax, MultiIndex) and self.name != "iloc" and is_hashable(key): + if ( + isinstance(ax, MultiIndex) + and self.name != "iloc" + and is_hashable(key) + and not isinstance(key, slice) + ): with suppress(KeyError, InvalidIndexError): # TypeError e.g. passed a bool return ax.get_loc(key) @@ -1060,6 +1065,16 @@ def _getitem_nested_tuple(self, tup: tuple): # we have a nested tuple so have at least 1 multi-index level # we should be able to match up the dimensionality here + def _contains_slice(x: object) -> bool: + # Check if object is a slice or a tuple containing a slice + if isinstance(x, tuple): + for v in x: + if isinstance(v, slice): + return True + elif isinstance(x, slice): + return True + return False + for key in tup: check_dict_or_set_indexers(key) @@ -1070,7 +1085,10 @@ def _getitem_nested_tuple(self, tup: tuple): if self.name != "loc": # This should never be reached, but let's be explicit about it raise ValueError("Too many indices") # pragma: no cover - if all(is_hashable(x) or com.is_null_slice(x) for x in tup): + if all( + (is_hashable(x) and not _contains_slice(x)) or com.is_null_slice(x) + for x in tup + ): # GH#10521 Series should reduce MultiIndex dimensions instead of # DataFrame, IndexingError is not raised when slice(None,None,None) # with one row. @@ -1419,7 +1437,17 @@ def _convert_to_indexer(self, key, axis: AxisInt): ): raise IndexingError("Too many indexers") - if is_scalar(key) or (isinstance(labels, MultiIndex) and is_hashable(key)): + # Slices are not valid keys passed in by the user, + # even though they are hashable in Python 3.12 + contains_slice = False + if isinstance(key, tuple): + for v in key: + if isinstance(v, slice): + contains_slice = True + + if is_scalar(key) or ( + isinstance(labels, MultiIndex) and is_hashable(key) and not contains_slice + ): # Otherwise get_loc will raise InvalidIndexError # if we are a label return me diff --git a/pandas/core/series.py b/pandas/core/series.py index 2fc926d7e43d1..2febc58540517 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -1019,7 +1019,7 @@ def __getitem__(self, key): elif key_is_scalar: return self._get_value(key) - if is_hashable(key): + if is_hashable(key) and not isinstance(key, slice): # Otherwise index.get_value will raise InvalidIndexError try: # For labels that don't resolve as scalars like tuples and frozensets diff --git a/pandas/tests/series/indexing/test_indexing.py b/pandas/tests/series/indexing/test_indexing.py index 83cae8d148feb..762b9ea74238f 100644 --- a/pandas/tests/series/indexing/test_indexing.py +++ b/pandas/tests/series/indexing/test_indexing.py @@ -230,9 +230,9 @@ def test_basic_getitem_setitem_corner(datetime_series): # OK msg = r"unhashable type(: 'slice')?" with pytest.raises(TypeError, match=msg): - datetime_series[[5, slice(None, None)]] + datetime_series[[5, [None, None]]] with pytest.raises(TypeError, match=msg): - datetime_series[[5, slice(None, None)]] = 2 + datetime_series[[5, [None, None]]] = 2 def test_slice(string_series, object_series, using_copy_on_write): From 90dbdeb2a11766a5b31380a31d07d215d0ac5ca0 Mon Sep 17 00:00:00 2001 From: Thomas Li <47963215+lithomas1@users.noreply.github.com> Date: Thu, 13 Jul 2023 19:58:41 -0700 Subject: [PATCH 13/23] fix import --- pandas/core/indexes/base.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index f9beba970565e..39bd93fa19437 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -1,5 +1,6 @@ from __future__ import annotations +from collections import abc from datetime import datetime import functools from itertools import zip_longest @@ -3785,7 +3786,7 @@ def get_loc(self, key): return self._engine.get_loc(casted_key) except KeyError as err: if isinstance(casted_key, slice) or ( - isinstance(casted_key, Iterable) + isinstance(casted_key, abc.Iterable) and any(isinstance(x, slice) for x in casted_key) ): raise InvalidIndexError(key) From 5e421f3b620f0f994abfb3fbe2759a89612a4a89 Mon Sep 17 00:00:00 2001 From: Thomas Li <47963215+lithomas1@users.noreply.github.com> Date: Fri, 14 Jul 2023 08:51:01 -0700 Subject: [PATCH 14/23] go for green --- pandas/core/series.py | 8 +++++--- pandas/tests/computation/test_eval.py | 16 +++++++++++++--- pandas/tests/frame/indexing/test_where.py | 2 ++ pandas/tests/tseries/offsets/test_year.py | 10 ++++++++-- 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/pandas/core/series.py b/pandas/core/series.py index 2febc58540517..4dab99ef3375f 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -1019,6 +1019,11 @@ def __getitem__(self, key): elif key_is_scalar: return self._get_value(key) + # Convert generator to list before going through hashable part + # (We will iterate through the generator there to check for slices) + if is_iterator(key): + key = list(key) + if is_hashable(key) and not isinstance(key, slice): # Otherwise index.get_value will raise InvalidIndexError try: @@ -1039,9 +1044,6 @@ def __getitem__(self, key): # Do slice check before somewhat-costly is_bool_indexer return self._getitem_slice(key) - if is_iterator(key): - key = list(key) - if com.is_bool_indexer(key): key = check_bool_indexer(self.index, key) key = np.asarray(key, dtype=bool) diff --git a/pandas/tests/computation/test_eval.py b/pandas/tests/computation/test_eval.py index b39fc37e71ecd..428057f475c97 100644 --- a/pandas/tests/computation/test_eval.py +++ b/pandas/tests/computation/test_eval.py @@ -1,5 +1,6 @@ from __future__ import annotations +import contextlib from functools import reduce from itertools import product import operator @@ -9,6 +10,7 @@ import numpy as np import pytest +from pandas.compat import PY312 from pandas.errors import ( NumExprClobberingError, PerformanceWarning, @@ -699,9 +701,17 @@ def test_disallow_python_keywords(self): def test_true_false_logic(self): # GH 25823 - assert pd.eval("not True") == -2 - assert pd.eval("not False") == -1 - assert pd.eval("True and not True") == 0 + # This behavior is deprecated in Python 3.12 + if PY312: + context_mgr = tm.assert_produces_warning( + DeprecationWarning, check_stacklevel=False + ) + else: + context_mgr = contextlib.nullcontext() + with context_mgr: + assert pd.eval("not True") == -2 + assert pd.eval("not False") == -1 + assert pd.eval("True and not True") == 0 def test_and_logic_string_match(self): # GH 25823 diff --git a/pandas/tests/frame/indexing/test_where.py b/pandas/tests/frame/indexing/test_where.py index 562f2fbe55c25..3b2a5ae902888 100644 --- a/pandas/tests/frame/indexing/test_where.py +++ b/pandas/tests/frame/indexing/test_where.py @@ -143,6 +143,8 @@ def _check_align(df, cond, other, check_dtypes=True): check_dtypes = all(not issubclass(s.type, np.integer) for s in df.dtypes) _check_align(df, cond, np.nan, check_dtypes=check_dtypes) + # Ignore deprecation warning in Python 3.12 for inverting a bool + @pytest.mark.filterwarnings("ignore::DeprecationWarning") def test_where_invalid(self): # invalid conditions df = DataFrame(np.random.randn(5, 3), columns=["A", "B", "C"]) diff --git a/pandas/tests/tseries/offsets/test_year.py b/pandas/tests/tseries/offsets/test_year.py index 480c875c36e04..742bed0615acb 100644 --- a/pandas/tests/tseries/offsets/test_year.py +++ b/pandas/tests/tseries/offsets/test_year.py @@ -10,7 +10,10 @@ import numpy as np import pytest -from pandas.compat import is_numpy_dev +from pandas.compat import ( + PY312, + is_numpy_dev, +) from pandas import Timestamp from pandas.tests.tseries.offsets.common import ( @@ -323,7 +326,10 @@ def test_is_on_offset(self, case): assert_is_on_offset(offset, dt, expected) -@pytest.mark.xfail(is_numpy_dev, reason="result year is 1973, unclear why") +# This works on Python 3.12 for some reason +@pytest.mark.xfail( + is_numpy_dev and not PY312, reason="result year is 1973, unclear why" +) def test_add_out_of_pydatetime_range(): # GH#50348 don't raise in Timestamp.replace ts = Timestamp(np.datetime64("-20000-12-31")) From 0e04fd2230af44523149595434efa8126565bd05 Mon Sep 17 00:00:00 2001 From: Thomas Li <47963215+lithomas1@users.noreply.github.com> Date: Fri, 14 Jul 2023 11:43:12 -0700 Subject: [PATCH 15/23] disable macos for now, fix other tests --- .github/workflows/unit-tests.yml | 6 +++++- pandas/core/indexing.py | 10 ++-------- pandas/tests/io/parser/test_parse_dates.py | 2 +- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index bb7d94b437112..af6273b16e5f4 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -315,7 +315,11 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-22.04, macOS-latest, windows-latest] + # TODO: Disable macOS for now, Github Actions bug where python is not + # symlinked correctly to 3.12 + # xref https://github.com/actions/setup-python/issues/701 + #os: [ubuntu-22.04, macOS-latest, windows-latest] + os: [ubuntu-22.04, windows-latest] timeout-minutes: 180 diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index 4158de1fc2435..2852eefbb9dd4 100644 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -1068,9 +1068,7 @@ def _getitem_nested_tuple(self, tup: tuple): def _contains_slice(x: object) -> bool: # Check if object is a slice or a tuple containing a slice if isinstance(x, tuple): - for v in x: - if isinstance(v, slice): - return True + return any(isinstance(v, slice) for v in key) elif isinstance(x, slice): return True return False @@ -1439,11 +1437,7 @@ def _convert_to_indexer(self, key, axis: AxisInt): # Slices are not valid keys passed in by the user, # even though they are hashable in Python 3.12 - contains_slice = False - if isinstance(key, tuple): - for v in key: - if isinstance(v, slice): - contains_slice = True + contains_slice = any(isinstance(v, slice) for v in key) if is_scalar(key) or ( isinstance(labels, MultiIndex) and is_hashable(key) and not contains_slice diff --git a/pandas/tests/io/parser/test_parse_dates.py b/pandas/tests/io/parser/test_parse_dates.py index b445510c82ae5..acd78999a4d8f 100644 --- a/pandas/tests/io/parser/test_parse_dates.py +++ b/pandas/tests/io/parser/test_parse_dates.py @@ -717,7 +717,7 @@ def test_date_parser_int_bug(all_parsers): StringIO(data), index_col=0, parse_dates=[0], - date_parser=lambda x: datetime.fromtimestamp(int(x)), + date_parser=lambda x: datetime.fromtimestamp(int(x), tz=timezone.utc), ) expected = DataFrame( [ From b5ae5107981e7683761099d9f2b8d1a5c27c62d0 Mon Sep 17 00:00:00 2001 From: Thomas Li <47963215+lithomas1@users.noreply.github.com> Date: Fri, 14 Jul 2023 13:05:46 -0700 Subject: [PATCH 16/23] Update indexing.py --- pandas/core/indexing.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index 2852eefbb9dd4..ab414e2f07d01 100644 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -1437,7 +1437,9 @@ def _convert_to_indexer(self, key, axis: AxisInt): # Slices are not valid keys passed in by the user, # even though they are hashable in Python 3.12 - contains_slice = any(isinstance(v, slice) for v in key) + contains_slice = False + if isinstance(key, tuple): + contains_slice = any(isinstance(v, slice) for v in key) if is_scalar(key) or ( isinstance(labels, MultiIndex) and is_hashable(key) and not contains_slice From b1182ac7b3c860c984fa1c245eefd0f39aef5000 Mon Sep 17 00:00:00 2001 From: Thomas Li <47963215+lithomas1@users.noreply.github.com> Date: Fri, 14 Jul 2023 14:46:23 -0700 Subject: [PATCH 17/23] finally fix? --- pandas/core/indexing.py | 2 +- pandas/tests/io/parser/test_parse_dates.py | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index ab414e2f07d01..7547c07a333d4 100644 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -1068,7 +1068,7 @@ def _getitem_nested_tuple(self, tup: tuple): def _contains_slice(x: object) -> bool: # Check if object is a slice or a tuple containing a slice if isinstance(x, tuple): - return any(isinstance(v, slice) for v in key) + return any(isinstance(v, slice) for v in x) elif isinstance(x, slice): return True return False diff --git a/pandas/tests/io/parser/test_parse_dates.py b/pandas/tests/io/parser/test_parse_dates.py index acd78999a4d8f..df18f03f418e6 100644 --- a/pandas/tests/io/parser/test_parse_dates.py +++ b/pandas/tests/io/parser/test_parse_dates.py @@ -717,7 +717,11 @@ def test_date_parser_int_bug(all_parsers): StringIO(data), index_col=0, parse_dates=[0], - date_parser=lambda x: datetime.fromtimestamp(int(x), tz=timezone.utc), + # Note: we must pass tz and then drop the tz attribute + # (if we don't CI will flake out depending on the runner's local time) + date_parser=lambda x: datetime.fromtimestamp(int(x), tz=timezone.utc).replace( + tzinfo=None + ), ) expected = DataFrame( [ From 64e12a9822def8eac8205a2c1f477beab7361d7c Mon Sep 17 00:00:00 2001 From: Thomas Li <47963215+lithomas1@users.noreply.github.com> Date: Mon, 17 Jul 2023 10:38:51 -0700 Subject: [PATCH 18/23] Update expr.py --- pandas/core/computation/expr.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pandas/core/computation/expr.py b/pandas/core/computation/expr.py index d00890dea5011..2f94856702465 100644 --- a/pandas/core/computation/expr.py +++ b/pandas/core/computation/expr.py @@ -543,18 +543,18 @@ def visit_UnaryOp(self, node, **kwargs): def visit_Name(self, node, **kwargs): return self.term_type(node.id, self.env, **kwargs) - # TODO: deprecated since Python 3.8. Remove after Python 3.14 is min + # TODO(py314): deprecated since Python 3.8. Remove after Python 3.14 is min def visit_NameConstant(self, node, **kwargs) -> Term: return self.const_type(node.value, self.env) - # TODO: deprecated since Python 3.8. Remove after Python 3.14 is min + # TODO(py314): deprecated since Python 3.8. Remove after Python 3.14 is min def visit_Num(self, node, **kwargs) -> Term: return self.const_type(node.value, self.env) def visit_Constant(self, node, **kwargs) -> Term: return self.const_type(node.value, self.env) - # TODO: deprecated since Python 3.8. Remove after Python 3.14 is min + # TODO(py314): deprecated since Python 3.8. Remove after Python 3.14 is min def visit_Str(self, node, **kwargs): name = self.env.add_tmp(node.s) return self.term_type(name, self.env) From 2c1755e63412ae051f8dade74a1e82877a853653 Mon Sep 17 00:00:00 2001 From: Thomas Li <47963215+lithomas1@users.noreply.github.com> Date: Mon, 24 Jul 2023 14:05:14 -0700 Subject: [PATCH 19/23] Update pandas/tests/computation/test_eval.py Co-authored-by: Matthew Roeschke <10647082+mroeschke@users.noreply.github.com> --- pandas/tests/computation/test_eval.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/pandas/tests/computation/test_eval.py b/pandas/tests/computation/test_eval.py index abf85411f719a..32f122dd2e513 100644 --- a/pandas/tests/computation/test_eval.py +++ b/pandas/tests/computation/test_eval.py @@ -702,13 +702,7 @@ def test_disallow_python_keywords(self): def test_true_false_logic(self): # GH 25823 # This behavior is deprecated in Python 3.12 - if PY312: - context_mgr = tm.assert_produces_warning( - DeprecationWarning, check_stacklevel=False - ) - else: - context_mgr = contextlib.nullcontext() - with context_mgr: + with tm.maybe_produces_warning(DeprecationWarning, PY312):: assert pd.eval("not True") == -2 assert pd.eval("not False") == -1 assert pd.eval("True and not True") == 0 From 5dfc14b0e3829d1d87a2683cc1da9a2900575975 Mon Sep 17 00:00:00 2001 From: Thomas Li <47963215+lithomas1@users.noreply.github.com> Date: Mon, 24 Jul 2023 20:52:03 -0700 Subject: [PATCH 20/23] Update test_eval.py --- pandas/tests/computation/test_eval.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/tests/computation/test_eval.py b/pandas/tests/computation/test_eval.py index 32f122dd2e513..a2ce47173fe2d 100644 --- a/pandas/tests/computation/test_eval.py +++ b/pandas/tests/computation/test_eval.py @@ -702,7 +702,7 @@ def test_disallow_python_keywords(self): def test_true_false_logic(self): # GH 25823 # This behavior is deprecated in Python 3.12 - with tm.maybe_produces_warning(DeprecationWarning, PY312):: + with tm.maybe_produces_warning(DeprecationWarning, PY312): assert pd.eval("not True") == -2 assert pd.eval("not False") == -1 assert pd.eval("True and not True") == 0 From a1bd210cef827eaa765aba30d7fee384ed29104c Mon Sep 17 00:00:00 2001 From: Thomas Li <47963215+lithomas1@users.noreply.github.com> Date: Mon, 24 Jul 2023 21:06:54 -0700 Subject: [PATCH 21/23] Update test_eval.py --- pandas/tests/computation/test_eval.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pandas/tests/computation/test_eval.py b/pandas/tests/computation/test_eval.py index a2ce47173fe2d..8d8195e90e92b 100644 --- a/pandas/tests/computation/test_eval.py +++ b/pandas/tests/computation/test_eval.py @@ -1,6 +1,5 @@ from __future__ import annotations -import contextlib from functools import reduce from itertools import product import operator From 298f31b343e572c2ac06c61f9771e872a70075a2 Mon Sep 17 00:00:00 2001 From: Thomas Li <47963215+lithomas1@users.noreply.github.com> Date: Tue, 25 Jul 2023 13:16:45 -0700 Subject: [PATCH 22/23] fixes --- .circleci/config.yml | 2 +- pandas/tests/computation/test_eval.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index fdcd5a205922a..ac9db5f451bf3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -47,7 +47,7 @@ jobs: - run: name: Build aarch64 wheels command: | - pip3 install cibuildwheel==2.13.1 + pip3 install cibuildwheel==2.14.1 cibuildwheel --prerelease-pythons --output-dir wheelhouse environment: CIBW_BUILD: << parameters.cibw-build >> diff --git a/pandas/tests/computation/test_eval.py b/pandas/tests/computation/test_eval.py index 8d8195e90e92b..f7bfb0eff96ed 100644 --- a/pandas/tests/computation/test_eval.py +++ b/pandas/tests/computation/test_eval.py @@ -701,7 +701,7 @@ def test_disallow_python_keywords(self): def test_true_false_logic(self): # GH 25823 # This behavior is deprecated in Python 3.12 - with tm.maybe_produces_warning(DeprecationWarning, PY312): + with tm.maybe_produces_warning(DeprecationWarning, PY312, check_stacklevel=False): assert pd.eval("not True") == -2 assert pd.eval("not False") == -1 assert pd.eval("True and not True") == 0 From 88a0cb837d832bf018b9891d4f13208a4552de54 Mon Sep 17 00:00:00 2001 From: Thomas Li <47963215+lithomas1@users.noreply.github.com> Date: Tue, 25 Jul 2023 13:40:06 -0700 Subject: [PATCH 23/23] formatting --- pandas/tests/computation/test_eval.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pandas/tests/computation/test_eval.py b/pandas/tests/computation/test_eval.py index f7bfb0eff96ed..e986fb5db9992 100644 --- a/pandas/tests/computation/test_eval.py +++ b/pandas/tests/computation/test_eval.py @@ -701,7 +701,9 @@ def test_disallow_python_keywords(self): def test_true_false_logic(self): # GH 25823 # This behavior is deprecated in Python 3.12 - with tm.maybe_produces_warning(DeprecationWarning, PY312, check_stacklevel=False): + with tm.maybe_produces_warning( + DeprecationWarning, PY312, check_stacklevel=False + ): assert pd.eval("not True") == -2 assert pd.eval("not False") == -1 assert pd.eval("True and not True") == 0