diff --git a/.github/workflows/ibis-backends.yml b/.github/workflows/ibis-backends.yml index 6b357bdeb6c2..43311d15d00a 100644 --- a/.github/workflows/ibis-backends.yml +++ b/.github/workflows/ibis-backends.yml @@ -144,30 +144,6 @@ jobs: - druid services: - druid - include: - - os: ubuntu-latest - python-version: "3.8" - backend: - name: pyspark - title: PySpark - serial: true - extras: - - pyspark - - os: ubuntu-latest - python-version: "3.10" - backend: - name: pyspark - title: PySpark - serial: true - extras: - - pyspark - - os: ubuntu-latest - python-version: "3.11" - backend: - name: pyspark - title: PySpark - extras: - - pyspark exclude: - os: windows-latest backend: @@ -267,12 +243,6 @@ jobs: if: matrix.os == 'windows-latest' && matrix.backend.name == 'sqlite' run: choco install sqlite - - uses: actions/setup-java@v3 - if: matrix.backend.name == 'pyspark' - with: - distribution: microsoft - java-version: 17 - - name: checkout uses: actions/checkout@v3 @@ -362,6 +332,7 @@ jobs: title: Dask deps: - "dask[array,dataframe]@2022.9.1" + - "pandas@1.5.3" extras: - dask - name: postgres @@ -467,6 +438,86 @@ jobs: if: ${{ failure() }} run: docker compose logs + test_pyspark: + name: PySpark ${{ matrix.os }} python-${{ matrix.python-version }} pandas<${{ matrix.pandas-upper-bound }} numpy<${{ matrix.numpy-upper-bound }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: + - ubuntu-latest + python-version: + - "3.10" + pandas-upper-bound: + - "2" + - "3" + numpy-upper-bound: + - "1.24" + - "2" + include: + - os: ubuntu-latest + python-version: "3.8" + pandas-upper-bound: "2" + numpy-upper-bound: "1.24" + - os: ubuntu-latest + python-version: "3.11" + pandas-upper-bound: "2" + numpy-upper-bound: "1.24" + steps: + - name: checkout + uses: actions/checkout@v3 + + - uses: actions/setup-java@v3 + with: + distribution: microsoft + java-version: 17 + + - uses: extractions/setup-just@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: download backend data + run: just download-data + + - name: install python + uses: actions/setup-python@v4 + id: install_python + with: + python-version: ${{ matrix.python-version }} + + - run: python -m pip install --upgrade pip 'poetry<1.4' + + - name: install minimum versions + run: poetry add --lock 'pandas>=1.2.5,<${{ matrix.pandas-upper-bound }}' 'numpy>=1,<${{ matrix.numpy-upper-bound }}' + + - name: checkout the lock file + run: git checkout poetry.lock + + - name: lock with no updates + # poetry add is aggressive and will update other dependencies like + # numpy and pandas so we keep the pyproject.toml edits and then relock + # without updating anything except the requested versions + run: poetry lock --no-update + + - name: install ibis + run: poetry install --without dev --without docs --extras pyspark + + - name: run tests + run: just ci-check -m pyspark --numprocesses auto --dist=loadgroup + + - name: upload code coverage + if: success() + uses: codecov/codecov-action@v3 + with: + flags: backend,pyspark,${{ runner.os }},python-${{ steps.install_python.outputs.python-version }},pandas-upper-bound-${{ matrix.pandas-upper-bound }},numpy-upper-bound-${{ matrix.numpy-upper-bound }} + + - name: publish test report + uses: actions/upload-artifact@v3 + if: success() || failure() + with: + name: pyspark-${{ matrix.os }}-${{ matrix.python-version }} + path: junit.xml + gen_lockfile_sqlalchemy2: name: Generate Poetry Lockfile for SQLAlchemy 2 runs-on: ubuntu-latest @@ -634,5 +685,6 @@ jobs: - test_backends_min_version - test_backends - test_backends_sqlalchemy2 + - test_pyspark steps: - run: exit 0 diff --git a/ci/schema/sqlite.sql b/ci/schema/sqlite.sql index 18512b8f196e..1335f6b48ef3 100644 --- a/ci/schema/sqlite.sql +++ b/ci/schema/sqlite.sql @@ -13,7 +13,7 @@ CREATE TABLE functional_alltypes ( double_col REAL, date_string_col TEXT, string_col TEXT, - timestamp_col TEXT, + timestamp_col TIMESTAMP, year BIGINT, month BIGINT, CHECK (bool_col IN (0, 1)) diff --git a/ibis/backends/base/sql/alchemy/registry.py b/ibis/backends/base/sql/alchemy/registry.py index 0550e68bc3b4..174b1838ddd8 100644 --- a/ibis/backends/base/sql/alchemy/registry.py +++ b/ibis/backends/base/sql/alchemy/registry.py @@ -175,7 +175,7 @@ def _cast(t, op): # specialize going from an integer type to a timestamp if arg_dtype.is_integer() and typ.is_timestamp(): - return t.integer_to_timestamp(sa_arg) + return t.integer_to_timestamp(sa_arg, tz=typ.timezone) if arg_dtype.is_binary() and typ.is_string(): return sa.func.encode(sa_arg, 'escape') diff --git a/ibis/backends/base/sql/alchemy/translator.py b/ibis/backends/base/sql/alchemy/translator.py index 4a3c859a119c..af013ba379d1 100644 --- a/ibis/backends/base/sql/alchemy/translator.py +++ b/ibis/backends/base/sql/alchemy/translator.py @@ -44,8 +44,15 @@ class AlchemyExprTranslator(ExprTranslator): _bool_aggs_need_cast_to_int32 = True _has_reduction_filter_syntax = False + _integer_to_timestamp = staticmethod(sa.func.to_timestamp) + _timestamp_type = sa.TIMESTAMP + + def integer_to_timestamp(self, arg, tz: str | None = None): + return sa.cast( + self._integer_to_timestamp(arg), + self._timestamp_type(timezone=tz is not None), + ) - integer_to_timestamp = sa.func.to_timestamp native_json_type = True _always_quote_columns = None # let the dialect decide how to quote diff --git a/ibis/backends/bigquery/tests/system/test_client.py b/ibis/backends/bigquery/tests/system/test_client.py index a57834e94480..2b14465152fd 100644 --- a/ibis/backends/bigquery/tests/system/test_client.py +++ b/ibis/backends/bigquery/tests/system/test_client.py @@ -7,6 +7,7 @@ import pandas.testing as tm import pytest import pytz +import toolz import ibis import ibis.expr.datatypes as dt @@ -73,15 +74,12 @@ def test_count_distinct_with_filter(alltypes): assert result == expected -@pytest.mark.parametrize("type", ["date", dt.date]) -def test_cast_string_to_date(alltypes, df, type): - import toolz - +def test_cast_string_to_date(alltypes, df): string_col = alltypes.date_string_col month, day, year = toolz.take(3, string_col.split("/")) expr = "20" + ibis.literal("-").join([year, month, day]) - expr = expr.cast(type) + expr = expr.cast("date") result = ( expr.execute() @@ -91,7 +89,7 @@ def test_cast_string_to_date(alltypes, df, type): .rename("date_string_col") ) expected = ( - pd.to_datetime(df.date_string_col) + pd.to_datetime(df.date_string_col, format="%m/%d/%y") .dt.normalize() .sort_values() .reset_index(drop=True) diff --git a/ibis/backends/clickhouse/compiler/values.py b/ibis/backends/clickhouse/compiler/values.py index 893f86fd2dea..d9fe9c1a1809 100644 --- a/ibis/backends/clickhouse/compiler/values.py +++ b/ibis/backends/clickhouse/compiler/values.py @@ -77,7 +77,10 @@ def _cast(op, **kw): return f"toInterval{suffix}({arg})" to = translate_val(op.to, **kw) - return f"CAST({arg} AS {to})" + result = f"CAST({arg} AS {to})" + if (timezone := getattr(op.to, "timezone", None)) is not None: + return f"toTimeZone({result}, {timezone!r})" + return result @translate_val.register(ops.Between) @@ -575,11 +578,11 @@ def _date_from_ymd(op, **kw): m = translate_val(op.month, **kw) d = translate_val(op.day, **kw) return ( - f"toDate(concat(" + "toDate(concat(" f"toString({y}), '-', " f"leftPad(toString({m}), 2, '0'), '-', " f"leftPad(toString({d}), 2, '0')" - f"))" + "))" ) @@ -591,20 +594,20 @@ def _timestamp_from_ymdhms(op, **kw): h = translate_val(op.hours, **kw) min = translate_val(op.minutes, **kw) s = translate_val(op.seconds, **kw) - timezone_arg = '' - if timezone := op.output_dtype.timezone: - timezone_arg = f', {timezone}' - return ( - f"toDateTime(" + to_datetime = ( + "toDateTime(" f"concat(toString({y}), '-', " f"leftPad(toString({m}), 2, '0'), '-', " f"leftPad(toString({d}), 2, '0'), ' ', " f"leftPad(toString({h}), 2, '0'), ':', " f"leftPad(toString({min}), 2, '0'), ':', " f"leftPad(toString({s}), 2, '0')" - f"), {timezone_arg})" + "))" ) + if timezone := op.output_dtype.timezone: + return f"toTimeZone({to_datetime}, {timezone})" + return to_datetime @translate_val.register(ops.ExistsSubquery) diff --git a/ibis/backends/conftest.py b/ibis/backends/conftest.py index 4312b08f3f79..9c3e89f3e288 100644 --- a/ibis/backends/conftest.py +++ b/ibis/backends/conftest.py @@ -12,6 +12,7 @@ from typing import Any, TextIO import _pytest +import numpy as np import pandas as pd import pytest import sqlalchemy as sa @@ -307,8 +308,12 @@ def pytest_collection_modifyitems(session, config, items): item, pytest.mark.xfail( ( - sys.version_info >= (3, 11) - and not isinstance(item, pytest.DoctestItem) + not isinstance(item, pytest.DoctestItem) + and ( + sys.version_info >= (3, 11) + or vparse(pd.__version__) >= vparse("2") + or vparse(np.__version__) >= vparse("1.24") + ) ), reason="PySpark doesn't support Python 3.11", ), diff --git a/ibis/backends/dask/client.py b/ibis/backends/dask/client.py index bfeb03cfb913..8306712c7745 100644 --- a/ibis/backends/dask/client.py +++ b/ibis/backends/dask/client.py @@ -4,18 +4,15 @@ import dask.dataframe as dd import numpy as np +import pandas as pd +from dateutil.parser import parse as date_parse from pandas.api.types import DatetimeTZDtype import ibis.expr.datatypes as dt import ibis.expr.operations as ops import ibis.expr.schema as sch from ibis.backends.base import Database -from ibis.backends.pandas.client import ( - PANDAS_DATE_TYPES, - PANDAS_STRING_TYPES, - ibis_dtype_to_pandas, - ibis_schema_to_pandas, -) +from ibis.backends.pandas.client import ibis_dtype_to_pandas, ibis_schema_to_pandas @sch.schema.register(dd.Series) @@ -54,15 +51,31 @@ def infer_dask_schema(df, schema=None): @sch.convert.register(DatetimeTZDtype, dt.Timestamp, dd.Series) -def convert_datetimetz_to_timestamp(in_dtype, out_dtype, column): +def convert_datetimetz_to_timestamp(_, out_dtype, column): output_timezone = out_dtype.timezone if output_timezone is not None: return column.dt.tz_convert(output_timezone) - return column.astype(out_dtype.to_dask()) + else: + return column.dt.tz_localize(None) -DASK_STRING_TYPES = PANDAS_STRING_TYPES -DASK_DATE_TYPES = PANDAS_DATE_TYPES +@sch.convert.register(np.dtype, dt.Timestamp, dd.Series) +def convert_any_to_timestamp(_, out_dtype, column): + if isinstance(dtype := out_dtype.to_dask(), DatetimeTZDtype): + column = dd.to_datetime(column) + timezone = out_dtype.timezone + if getattr(column.dtype, "tz", None) is not None: + return column.dt.tz_convert(timezone) + else: + return column.dt.tz_localize(timezone) + else: + try: + return column.astype(dtype) + except pd.errors.OutOfBoundsDatetime: + try: + return column.map(date_parse) + except TypeError: + return column @sch.convert.register(np.dtype, dt.Interval, dd.Series) diff --git a/ibis/backends/dask/execution/generic.py b/ibis/backends/dask/execution/generic.py index a4fe01104aab..c59bc01e698d 100644 --- a/ibis/backends/dask/execution/generic.py +++ b/ibis/backends/dask/execution/generic.py @@ -271,7 +271,7 @@ def execute_cast_scalar_timestamp(op, data, type, **kwargs): def cast_series_to_timestamp(data, tz): if pd.api.types.is_string_dtype(data): - timestamps = to_datetime(data, infer_datetime_format=True) + timestamps = to_datetime(data) else: timestamps = to_datetime(data, unit="s") if getattr(timestamps.dtype, "tz", None) is not None: @@ -290,10 +290,17 @@ def execute_cast_series_timestamp(op, data, type, **kwargs): tz = type.timezone dtype = 'M8[ns]' if tz is None else DatetimeTZDtype('ns', tz) - if from_type.is_timestamp() or from_type.is_date(): - return data.astype(dtype) - - if from_type.is_string() or from_type.is_integer(): + if from_type.is_timestamp(): + from_tz = from_type.timezone + if tz is None and from_tz is None: + return data + elif tz is None or from_tz is None: + return data.dt.tz_localize(tz) + elif tz is not None and from_tz is not None: + return data.dt.tz_convert(tz) + elif from_type.is_date(): + return data if tz is None else data.dt.tz_localize(tz) + elif from_type.is_string() or from_type.is_integer(): return data.map_partitions( cast_series_to_timestamp, tz, @@ -319,11 +326,7 @@ def execute_cast_series_date(op, data, type, **kwargs): if from_type.equals(dt.string): # TODO - this is broken - datetimes = data.map_partitions( - to_datetime, - infer_datetime_format=True, - meta=(data.name, 'datetime64[ns]'), - ) + datetimes = data.map_partitions(to_datetime, meta=(data.name, 'datetime64[ns]')) # TODO - we are getting rid of the index here return datetimes.dt.normalize() diff --git a/ibis/backends/dask/execution/temporal.py b/ibis/backends/dask/execution/temporal.py index bea2fccc966d..3826ca47305c 100644 --- a/ibis/backends/dask/execution/temporal.py +++ b/ibis/backends/dask/execution/temporal.py @@ -152,10 +152,13 @@ (dd.Series, str, datetime.time), ) def execute_between_time(op, data, lower, upper, **kwargs): - # TODO - Can this be done better? - indexer = ( - (data.dt.time.astype(str) >= lower) & (data.dt.time.astype(str) <= upper) - ).to_dask_array(True) + if getattr(data.dtype, "tz", None) is not None: + localized = data.dt.tz_convert("UTC").dt.tz_localize(None) + else: + localized = data + + time = localized.dt.time.astype(str) + indexer = ((time >= lower) & (time <= upper)).to_dask_array(True) result = da.zeros(len(data), dtype=np.bool_) result[indexer] = True diff --git a/ibis/backends/dask/tests/execution/test_arrays.py b/ibis/backends/dask/tests/execution/test_arrays.py index 6a0915f3fd47..1bb182c55e26 100644 --- a/ibis/backends/dask/tests/execution/test_arrays.py +++ b/ibis/backends/dask/tests/execution/test_arrays.py @@ -3,6 +3,7 @@ import numpy as np import pandas as pd import pytest +from pytest import param import ibis @@ -134,7 +135,10 @@ def test_array_slice_scalar(client, start, stop): assert np.array_equal(result, expected) -@pytest.mark.parametrize('index', [1, 3, 4, 11, -11]) +@pytest.mark.parametrize( + 'index', + [param(1, marks=pytest.mark.xfail_version(dask=["pandas>=2"])), 3, 4, 11, -11], +) def test_array_index(t, df, index): expr = t[t.array_of_float64[index].name('indexed')] result = expr.compile() diff --git a/ibis/backends/dask/tests/execution/test_operations.py b/ibis/backends/dask/tests/execution/test_operations.py index 997c87e30add..0e97143f2850 100644 --- a/ibis/backends/dask/tests/execution/test_operations.py +++ b/ibis/backends/dask/tests/execution/test_operations.py @@ -548,10 +548,10 @@ def test_value_counts(t, df): expected = ( df.compute() .dup_strings.value_counts() - .reset_index() - .rename(columns={'dup_strings': 'dup_strings_count'}) - .rename(columns={'index': 'dup_strings'}) - .sort_values(['dup_strings']) + .rename("dup_strings") + .reset_index(name="dup_strings_count") + .rename(columns={"index": "dup_strings"}) + .sort_values(["dup_strings"]) .reset_index(drop=True) ) tm.assert_frame_equal( @@ -861,6 +861,7 @@ def test_summary_numeric(batting, batting_df): assert dict(result.iloc[0]) == expected +@pytest.mark.xfail_version(dask=["pandas>=2"]) def test_summary_numeric_group_by(batting, batting_df): with pytest.warns(FutureWarning, match="is deprecated"): expr = batting.group_by('teamID').G.summary() @@ -900,6 +901,7 @@ def test_summary_non_numeric(batting, batting_df): assert dict(result.iloc[0]) == expected +@pytest.mark.xfail_version(dask=["pandas>=2"]) def test_summary_non_numeric_group_by(batting, batting_df): with pytest.warns(FutureWarning, match="is deprecated"): expr = batting.group_by('teamID').playerID.summary() diff --git a/ibis/backends/dask/tests/execution/test_temporal.py b/ibis/backends/dask/tests/execution/test_temporal.py index 36e1afcc3f81..7913e3a89782 100644 --- a/ibis/backends/dask/tests/execution/test_temporal.py +++ b/ibis/backends/dask/tests/execution/test_temporal.py @@ -68,10 +68,7 @@ def test_cast_datetime_strings_to_date(t, df, column): result = expr.compile() df_computed = df.compute() expected = dd.from_pandas( - pd.to_datetime( - df_computed[column], - infer_datetime_format=True, - ).dt.normalize(), + pd.to_datetime(df_computed[column]).dt.normalize(), npartitions=1, ) tm.assert_series_equal( @@ -88,10 +85,7 @@ def test_cast_datetime_strings_to_timestamp(t, df, column): expr = t[column].cast('timestamp') result = expr.compile() df_computed = df.compute() - expected = dd.from_pandas( - pd.to_datetime(df_computed[column], infer_datetime_format=True), - npartitions=1, - ) + expected = dd.from_pandas(pd.to_datetime(df_computed[column]), npartitions=1) if getattr(expected.dtype, 'tz', None) is not None: expected = expected.dt.tz_convert(None) tm.assert_series_equal( @@ -158,10 +152,17 @@ def test_times_ops(t, df): @pytest.mark.parametrize( - ('tz', 'rconstruct'), - [('US/Eastern', np.zeros), ('UTC', np.ones), (None, np.ones)], + ('tz', 'rconstruct', 'column'), + [ + ('US/Eastern', np.ones, 'plain_datetimes_utc'), + ('US/Eastern', np.zeros, 'plain_datetimes_naive'), + ('UTC', np.ones, 'plain_datetimes_utc'), + ('UTC', np.ones, 'plain_datetimes_naive'), + (None, np.ones, 'plain_datetimes_utc'), + (None, np.ones, 'plain_datetimes_naive'), + ], + ids=lambda x: str(getattr(x, "__name__", x)).lower().replace("/", "_"), ) -@pytest.mark.parametrize('column', ['plain_datetimes_utc', 'plain_datetimes_naive']) def test_times_ops_with_tz(t, df, tz, rconstruct, column): expected = dd.from_array( rconstruct(len(df), dtype=bool), diff --git a/ibis/backends/dask/tests/test_schema.py b/ibis/backends/dask/tests/test_schema.py index 14d04e829454..eca5d448c571 100644 --- a/ibis/backends/dask/tests/test_schema.py +++ b/ibis/backends/dask/tests/test_schema.py @@ -157,7 +157,7 @@ def test_infer_exhaustive_dataframe(npartitions): def test_apply_to_schema_with_timezone(npartitions): data = {'time': pd.date_range('2018-01-01', '2018-01-02', freq='H')} df = dd.from_pandas(pd.DataFrame(data), npartitions=npartitions) - expected = df.assign(time=df.time.astype('datetime64[ns, EST]')) + expected = df.assign(time=df.time.dt.tz_localize("EST")) desired_schema = ibis.schema([('time', 'timestamp("EST")')]) result = desired_schema.apply_to(df.copy()) tm.assert_frame_equal(result.compute(), expected.compute()) diff --git a/ibis/backends/mssql/compiler.py b/ibis/backends/mssql/compiler.py index 8c08ff8b48e7..7751ba146d35 100644 --- a/ibis/backends/mssql/compiler.py +++ b/ibis/backends/mssql/compiler.py @@ -1,5 +1,7 @@ from __future__ import annotations +from sqlalchemy.dialects.mssql import DATETIME2 + import ibis.expr.operations as ops from ibis.backends.base.sql.alchemy import ( AlchemyCompiler, @@ -12,7 +14,10 @@ class MsSqlExprTranslator(AlchemyExprTranslator): _registry = operation_registry _rewrites = AlchemyExprTranslator._rewrites.copy() _bool_aggs_need_cast_to_int32 = True - integer_to_timestamp = staticmethod(_timestamp_from_unix) + + _timestamp_type = DATETIME2 + _integer_to_timestamp = staticmethod(_timestamp_from_unix) + native_json_type = False _forbids_frame_clause = AlchemyExprTranslator._forbids_frame_clause + ( diff --git a/ibis/backends/mysql/compiler.py b/ibis/backends/mysql/compiler.py index 1281af13ff77..4207721da8be 100644 --- a/ibis/backends/mysql/compiler.py +++ b/ibis/backends/mysql/compiler.py @@ -16,7 +16,7 @@ class MySQLExprTranslator(AlchemyExprTranslator): # https://dev.mysql.com/doc/refman/8.0/en/spatial-function-reference.html _registry = operation_registry.copy() _rewrites = AlchemyExprTranslator._rewrites.copy() - integer_to_timestamp = sa.func.from_unixtime + _integer_to_timestamp = sa.func.from_unixtime native_json_type = False _dialect_name = "mysql" diff --git a/ibis/backends/pandas/client.py b/ibis/backends/pandas/client.py index 9044f1f88efc..9273e8073f40 100644 --- a/ibis/backends/pandas/client.py +++ b/ibis/backends/pandas/client.py @@ -127,11 +127,8 @@ def convert_datetimetz_to_timestamp(_, out_dtype, column): output_timezone = out_dtype.timezone if output_timezone is not None: return column.dt.tz_convert(output_timezone) - return column.astype(out_dtype.to_pandas(), errors='ignore') - - -PANDAS_STRING_TYPES = {'string', 'unicode', 'bytes'} -PANDAS_DATE_TYPES = {'datetime', 'datetime64', 'date'} + else: + return column.dt.tz_localize(None) @sch.convert.register(np.dtype, dt.Interval, pd.Series) @@ -171,6 +168,14 @@ def convert_timestamp_to_date(in_dtype, out_dtype, column): @sch.convert.register(object, dt.DataType, pd.Series) def convert_any_to_any(_, out_dtype, column): + try: + return column.astype(out_dtype.to_pandas()) + except Exception: # noqa: BLE001 + return column + + +@sch.convert.register(np.dtype, dt.Timestamp, pd.Series) +def convert_any_to_timestamp(_, out_dtype, column): try: return column.astype(out_dtype.to_pandas()) except pd.errors.OutOfBoundsDatetime: @@ -178,8 +183,13 @@ def convert_any_to_any(_, out_dtype, column): return column.map(date_parse) except TypeError: return column - except Exception: # noqa: BLE001 - return column + except TypeError: + column = pd.to_datetime(column) + timezone = out_dtype.timezone + try: + return column.dt.tz_convert(timezone) + except TypeError: + return column.dt.tz_localize(timezone) @sch.convert.register(object, dt.Struct, pd.Series) diff --git a/ibis/backends/pandas/execution/generic.py b/ibis/backends/pandas/execution/generic.py index c2d64909d7a2..79bee3dfa99e 100644 --- a/ibis/backends/pandas/execution/generic.py +++ b/ibis/backends/pandas/execution/generic.py @@ -16,7 +16,6 @@ import pandas as pd import pytz import toolz -from pandas.api.types import DatetimeTZDtype from pandas.core.groupby import DataFrameGroupBy, SeriesGroupBy import ibis.common.exceptions as com @@ -152,14 +151,22 @@ def execute_cast_series_timestamp(op, data, type, **kwargs): tz = type.timezone - if from_type.is_timestamp() or from_type.is_date(): - return data.astype('M8[ns]' if tz is None else DatetimeTZDtype('ns', tz)) + if from_type.is_timestamp(): + from_tz = from_type.timezone + if tz is None and from_tz is None: + return data + elif tz is None or from_tz is None: + return data.dt.tz_localize(tz) + elif tz is not None and from_tz is not None: + return data.dt.tz_convert(tz) + elif from_type.is_date(): + return data if tz is None else data.dt.tz_localize(tz) if from_type.is_string() or from_type.is_integer(): if from_type.is_integer(): timestamps = pd.to_datetime(data.values, unit="s") else: - timestamps = pd.to_datetime(data.values, infer_datetime_format=True) + timestamps = pd.to_datetime(data.values) if getattr(timestamps.dtype, "tz", None) is not None: method_name = "tz_convert" else: @@ -192,7 +199,7 @@ def execute_cast_series_date(op, data, type, **kwargs): # TODO: remove String as subclass of JSON if from_type.is_string() and not from_type.is_json(): values = data.values - datetimes = pd.to_datetime(values, infer_datetime_format=True) + datetimes = pd.to_datetime(values) with contextlib.suppress(TypeError): datetimes = datetimes.tz_convert(None) dates = _normalize(datetimes, data.index, data.name) diff --git a/ibis/backends/pandas/execution/temporal.py b/ibis/backends/pandas/execution/temporal.py index ee403f701afe..b68eace8a10c 100644 --- a/ibis/backends/pandas/execution/temporal.py +++ b/ibis/backends/pandas/execution/temporal.py @@ -71,7 +71,10 @@ def execute_epoch_seconds(op, data, **kwargs): (pd.Series, str, datetime.time), ) def execute_between_time(op, data, lower, upper, **kwargs): - indexer = pd.DatetimeIndex(data).indexer_between_time(lower, upper) + idx = pd.DatetimeIndex(data) + if idx.tz is not None: + idx = idx.tz_convert(None) # make naive because times are naive + indexer = idx.indexer_between_time(lower, upper) result = np.zeros(len(data), dtype=np.bool_) result[indexer] = True return pd.Series(result) diff --git a/ibis/backends/pandas/tests/execution/test_operations.py b/ibis/backends/pandas/tests/execution/test_operations.py index 15ce9f6e1ab2..eae9da448b6c 100644 --- a/ibis/backends/pandas/tests/execution/test_operations.py +++ b/ibis/backends/pandas/tests/execution/test_operations.py @@ -392,10 +392,10 @@ def test_value_counts(t, df): result = expr.execute() expected = ( df.dup_strings.value_counts() - .reset_index() - .rename(columns={'dup_strings': 'dup_strings_count'}) - .rename(columns={'index': 'dup_strings'}) - .sort_values(['dup_strings']) + .rename("dup_strings") + .reset_index(name="dup_strings_count") + .rename(columns={"index": "dup_strings"}) + .sort_values(["dup_strings"]) .reset_index(drop=True) ) tm.assert_frame_equal(result[expected.columns], expected) diff --git a/ibis/backends/pandas/tests/execution/test_temporal.py b/ibis/backends/pandas/tests/execution/test_temporal.py index cbc00bc15232..6be03c43675b 100644 --- a/ibis/backends/pandas/tests/execution/test_temporal.py +++ b/ibis/backends/pandas/tests/execution/test_temporal.py @@ -63,11 +63,7 @@ def test_timestamp_functions(case_func, expected_func): def test_cast_datetime_strings_to_date(t, df, column): expr = t[column].cast('date') result = expr.execute() - expected = ( - pd.to_datetime(df[column], infer_datetime_format=True) - .dt.normalize() - .dt.tz_localize(None) - ) + expected = pd.to_datetime(df[column]).dt.normalize().dt.tz_localize(None) tm.assert_series_equal(result, expected) @@ -78,7 +74,7 @@ def test_cast_datetime_strings_to_date(t, df, column): def test_cast_datetime_strings_to_timestamp(t, df, column): expr = t[column].cast('timestamp') result = expr.execute() - expected = pd.to_datetime(df[column], infer_datetime_format=True) + expected = pd.to_datetime(df[column]) if getattr(expected.dtype, 'tz', None) is not None: expected = expected.dt.tz_convert(None) tm.assert_series_equal(result, expected) @@ -122,10 +118,17 @@ def test_times_ops(t, df): @pytest.mark.parametrize( - ('tz', 'rconstruct'), - [('US/Eastern', np.zeros), ('UTC', np.ones), (None, np.ones)], + ('tz', 'rconstruct', 'column'), + [ + ('US/Eastern', np.ones, 'plain_datetimes_utc'), + ('US/Eastern', np.zeros, 'plain_datetimes_naive'), + ('UTC', np.ones, 'plain_datetimes_utc'), + ('UTC', np.ones, 'plain_datetimes_naive'), + (None, np.ones, 'plain_datetimes_utc'), + (None, np.ones, 'plain_datetimes_naive'), + ], + ids=lambda x: str(getattr(x, "__name__", x)).lower().replace("/", "_"), ) -@pytest.mark.parametrize('column', ['plain_datetimes_utc', 'plain_datetimes_naive']) def test_times_ops_with_tz(t, df, tz, rconstruct, column): expected = pd.Series(rconstruct(len(df), dtype=bool)) time = t[column].time() diff --git a/ibis/backends/pandas/tests/test_schema.py b/ibis/backends/pandas/tests/test_schema.py index 7f8bfd677d7c..fcb8e3016628 100644 --- a/ibis/backends/pandas/tests/test_schema.py +++ b/ibis/backends/pandas/tests/test_schema.py @@ -178,9 +178,10 @@ def test_infer_array(): def test_apply_to_schema_with_timezone(): data = {'time': pd.date_range('2018-01-01', '2018-01-02', freq='H')} - df = pd.DataFrame(data) - expected = df.assign(time=df.time.astype('datetime64[ns, EST]')) - desired_schema = ibis.schema([('time', 'timestamp("EST")')]) + df = expected = pd.DataFrame(data).assign( + time=lambda df: df.time.dt.tz_localize("EST") + ) + desired_schema = ibis.schema(dict(time='timestamp("EST")')) result = desired_schema.apply_to(df.copy()) tm.assert_frame_equal(expected, result) diff --git a/ibis/backends/postgres/tests/test_client.py b/ibis/backends/postgres/tests/test_client.py index eb8c55ca5e59..da5814bf8acc 100644 --- a/ibis/backends/postgres/tests/test_client.py +++ b/ibis/backends/postgres/tests/test_client.py @@ -111,7 +111,7 @@ def test_schema_type_conversion(): def test_interval_films_schema(con): t = con.table("films") assert t.len.type() == dt.Interval(unit="m") - assert t.len.execute().dtype == np.dtype("timedelta64[ns]") + assert issubclass(t.len.execute().dtype.type, np.timedelta64) @pytest.mark.parametrize( @@ -129,7 +129,7 @@ def test_all_interval_types_execute(intervals, column, expected_dtype): assert expr.type() == expected_dtype series = expr.execute() - assert series.dtype == np.dtype("timedelta64[ns]") + assert issubclass(series.dtype.type, np.timedelta64) @pytest.mark.xfail( diff --git a/ibis/backends/postgres/tests/test_functions.py b/ibis/backends/postgres/tests/test_functions.py index 138c7c2966b8..e933d4cdde84 100644 --- a/ibis/backends/postgres/tests/test_functions.py +++ b/ibis/backends/postgres/tests/test_functions.py @@ -124,7 +124,7 @@ def test_timestamp_cast_noop(alltypes, at, translate): assert isinstance(result2, ir.TimestampColumn) expected1 = at.c.timestamp_col - expected2 = sa.func.to_timestamp(at.c.int_col) + expected2 = sa.cast(sa.func.to_timestamp(at.c.int_col), sa.TIMESTAMP()) assert str(translate(result1.op())) == str(expected1) assert str(translate(result2.op())) == str(expected2) diff --git a/ibis/backends/snowflake/datatypes.py b/ibis/backends/snowflake/datatypes.py index 92f20d9a29e6..ef07b518d837 100644 --- a/ibis/backends/snowflake/datatypes.py +++ b/ibis/backends/snowflake/datatypes.py @@ -98,3 +98,10 @@ def _sf_map_struct(_, itype): @to_sqla_type.register(SnowflakeDialect, dt.JSON) def _sf_json(_, itype): return VARIANT + + +@to_sqla_type.register(SnowflakeDialect, dt.Timestamp) +def _sf_timestamp(_, itype): + if itype.timezone is None: + return TIMESTAMP_NTZ + return TIMESTAMP_TZ diff --git a/ibis/backends/sqlite/tests/test_functions.py b/ibis/backends/sqlite/tests/test_functions.py index 008d71279058..22d004e57393 100644 --- a/ibis/backends/sqlite/tests/test_functions.py +++ b/ibis/backends/sqlite/tests/test_functions.py @@ -43,13 +43,15 @@ def test_cast(alltypes, alltypes_sqla, translate, func, expected): @pytest.mark.parametrize( ('func', 'expected_func'), [ - ( + param( lambda t: t.timestamp_col.cast(dt.timestamp), - lambda at: sa.func.strftime('%Y-%m-%d %H:%M:%f', at.c.timestamp_col), + lambda at: at.c.timestamp_col, + id="timestamp_col", ), - ( + param( lambda t: t.int_col.cast(dt.timestamp), lambda at: sa.func.datetime(at.c.int_col, 'unixepoch'), + id="cast_integer_to_timestamp", ), ], ) diff --git a/ibis/backends/sqlite/tests/test_types.py b/ibis/backends/sqlite/tests/test_types.py index 9effc1268ba6..8b4f0e93c1a7 100644 --- a/ibis/backends/sqlite/tests/test_types.py +++ b/ibis/backends/sqlite/tests/test_types.py @@ -65,7 +65,9 @@ def test_timestamps(db, table, data): t = con.table(table) assert t.ts.type() == dt.timestamp res = t.ts.execute() - sol = pd.Series([to_datetime(s) for s in data]).dt.tz_localize(None) + # we're casting to timestamp without a timezone, so remove it in the + # expected output + sol = pd.Series(to_datetime(s) for s in data).dt.tz_localize(None) assert res.equals(sol) diff --git a/ibis/backends/tests/snapshots/test_string/test_rlike/sqlite/out.sql b/ibis/backends/tests/snapshots/test_string/test_rlike/sqlite/out.sql index d6732a61a0ce..c3811fb27285 100644 --- a/ibis/backends/tests/snapshots/test_string/test_rlike/sqlite/out.sql +++ b/ibis/backends/tests/snapshots/test_string/test_rlike/sqlite/out.sql @@ -11,7 +11,7 @@ SELECT t0.double_col, t0.date_string_col, t0.string_col, - STRFTIME('%Y-%m-%d %H:%M:%f', t0.timestamp_col) AS timestamp_col, + t0.timestamp_col, t0.year, t0.month FROM main.functional_alltypes AS t0 diff --git a/ibis/backends/tests/test_client.py b/ibis/backends/tests/test_client.py index 2433023dd788..d358d809b93e 100644 --- a/ibis/backends/tests/test_client.py +++ b/ibis/backends/tests/test_client.py @@ -11,6 +11,7 @@ import pytest import rich.console import sqlalchemy as sa +from packaging.version import parse as vparse from pytest import mark, param import ibis @@ -519,7 +520,9 @@ def test_unsigned_integer_type(alchemy_con): marks=[ mark.pyspark, pytest.mark.skipif( - sys.version_info >= (3, 11), + sys.version_info >= (3, 11) + or vparse(pd.__version__) >= vparse("2") + or vparse(np.__version__) >= vparse("1.24"), reason="passes on 3.11, but no other pyspark tests do", ), ], @@ -530,7 +533,9 @@ def test_unsigned_integer_type(alchemy_con): marks=[ mark.pyspark, pytest.mark.skipif( - sys.version_info >= (3, 11), + sys.version_info >= (3, 11) + or vparse(pd.__version__) >= vparse("2") + or vparse(np.__version__) >= vparse("1.24"), reason="passes on 3.11, but no other pyspark tests do", ), ], @@ -541,7 +546,9 @@ def test_unsigned_integer_type(alchemy_con): marks=[ mark.pyspark, pytest.mark.skipif( - sys.version_info >= (3, 11), + sys.version_info >= (3, 11) + or vparse(pd.__version__) >= vparse("2") + or vparse(np.__version__) >= vparse("1.24"), reason="passes on 3.11, but no other pyspark tests do", ), ], diff --git a/ibis/backends/tests/test_temporal.py b/ibis/backends/tests/test_temporal.py index 86604a9ea17a..41d7262255fa 100644 --- a/ibis/backends/tests/test_temporal.py +++ b/ibis/backends/tests/test_temporal.py @@ -681,7 +681,7 @@ def convert_to_offset(offset, displacement_type=displacement_type): expected = df.timestamp_col + offset expected = backend.default_series_rename(expected) - backend.assert_series_equal(result, expected) + backend.assert_series_equal(result, expected.astype("datetime64[ns]")) @pytest.mark.parametrize( @@ -726,11 +726,13 @@ def convert_to_offset(x): offset = df.int_col.apply(convert_to_offset) with warnings.catch_warnings(): - warnings.simplefilter("ignore", category=pd.errors.PerformanceWarning) + warnings.simplefilter( + "ignore", category=(UserWarning, pd.errors.PerformanceWarning) + ) expected = pd.to_datetime(df.date_string_col) + offset - expected = backend.default_series_rename(expected) - backend.assert_series_equal(result, expected) + expected = backend.default_series_rename(expected) + backend.assert_series_equal(result, expected.map(lambda ts: ts.normalize())) date_value = pd.Timestamp('2017-12-31') @@ -876,7 +878,7 @@ def test_temporal_binop(backend, con, alltypes, df, expr_fn, expected_fn): result = con.execute(expr) expected = backend.default_series_rename(expected) - backend.assert_series_equal(result, expected) + backend.assert_series_equal(result, expected.astype(result.dtype)) plus = lambda t, td: t.timestamp_col + pd.Timedelta(td) @@ -1491,8 +1493,8 @@ def test_integer_to_timestamp(backend, con, unit): # convert the timestamp to the input unit being tested int_expr = ibis.literal(pandas_ts // factor) - expr = int_expr.to_timestamp(unit) - result = con.execute(expr.name("tmp")) + expr = int_expr.to_timestamp(unit).name("tmp") + result = con.execute(expr) expected = pd.Timestamp(pandas_ts, unit='ns').floor(backend_unit) assert result == expected @@ -1700,13 +1702,13 @@ def test_now_from_projection(alltypes): ts = result.ts assert isinstance(result, pd.DataFrame) assert isinstance(ts, pd.Series) - assert issubclass(ts.dtype.type, np.datetime64) assert len(result) == n assert ts.nunique() == 1 now = pd.Timestamp('now') + year = ts.dt.year year_expected = pd.Series([now.year] * n, name='ts') - tm.assert_series_equal(ts.dt.year, year_expected) + tm.assert_series_equal(year, year_expected, check_dtype=False) DATE_BACKEND_TYPES = { @@ -1754,7 +1756,7 @@ def test_date_literal(con, backend): 'impala': 'TIMESTAMP', 'snowflake': 'TIMESTAMP_NTZ', 'sqlite': "text", - 'trino': 'timestamp(3) with time zone', + 'trino': 'timestamp(3)', "duckdb": "TIMESTAMP", "postgres": "timestamp without time zone", } @@ -1823,18 +1825,14 @@ def test_timestamp_literal(con, backend): ) @pytest.mark.notyet(["impala"], raises=com.OperationNotDefinedError) @pytest.mark.parametrize( - ('timezone', 'expected_result'), + ('timezone', 'expected'), [ param( 'Europe/London', '2022-02-04 16:20:00GMT', id="name", marks=[ - pytest.mark.broken( - ['mssql'], - "bytes' object has no attribute 'strftime", - raises=AttributeError, - ), + pytest.mark.broken(['mssql'], raises=TypeError), pytest.mark.broken( ['clickhouse'], 'Code: 62. DB::Exception: Syntax error: failed at position 340 (\'/\') ' @@ -1848,13 +1846,7 @@ def test_timestamp_literal(con, backend): '2022-02-04 08:20:00PST', # The time zone for Berkeley, California. id="iso", - marks=[ - pytest.mark.broken( - ['mssql'], - "bytes' object has no attribute 'strftime", - raises=AttributeError, - ) - ], + marks=[pytest.mark.broken(['mssql'], raises=TypeError)], ), ], ) @@ -1871,18 +1863,12 @@ def test_timestamp_literal(con, backend): ", , , )" ), ) -def test_timestamp_with_timezone_literal(con, backend, timezone, expected_result): +def test_timestamp_with_timezone_literal(con, backend, timezone, expected): expr = ibis.timestamp(2022, 2, 4, 16, 20, 0).cast(dt.Timestamp(timezone=timezone)) result = con.execute(expr) if not isinstance(result, str): result = result.strftime('%Y-%m-%d %H:%M:%S%Z') - assert result == expected_result - - with contextlib.suppress(com.OperationNotDefinedError): - backend_name = backend.name() - assert ( - con.execute(expr.typeof()) == TIMESTAMP_TIMEZONE_BACKEND_TYPES[backend_name] - ) + assert result == expected TIME_BACKEND_TYPES = { diff --git a/ibis/backends/tests/test_timecontext.py b/ibis/backends/tests/test_timecontext.py index ece6150c406c..91104aa90898 100644 --- a/ibis/backends/tests/test_timecontext.py +++ b/ibis/backends/tests/test_timecontext.py @@ -103,6 +103,7 @@ def test_context_adjustment_filter_before_window(alltypes, context, ctx_col): @pytest.mark.notimpl(["duckdb", "pyspark"]) +@pytest.mark.xfail_version(dask=["pandas>=2"]) def test_context_adjustment_multi_col_udf_non_grouped( alltypes, context, diff --git a/ibis/backends/tests/test_vectorized_udf.py b/ibis/backends/tests/test_vectorized_udf.py index 92e114916cd6..03a3d0f803f0 100644 --- a/ibis/backends/tests/test_vectorized_udf.py +++ b/ibis/backends/tests/test_vectorized_udf.py @@ -573,6 +573,7 @@ def test_elementwise_udf_struct(udf_backend, udf_alltypes): @pytest.mark.parametrize('udf', demean_struct_udfs) @pytest.mark.notimpl(["pyspark"]) +@pytest.mark.broken(["dask"], strict=False) def test_analytic_udf_destruct(udf_backend, udf_alltypes, udf): w = ibis.window(preceding=None, following=None, group_by='year') @@ -609,6 +610,7 @@ def test_analytic_udf_destruct_no_group_by(udf_backend, udf_alltypes): @pytest.mark.notimpl(["pyspark"]) +@pytest.mark.xfail_version(dask=["pandas>=2"]) def test_analytic_udf_destruct_overwrite(udf_backend, udf_alltypes): w = ibis.window(preceding=None, following=None, group_by='year') diff --git a/ibis/backends/trino/compiler.py b/ibis/backends/trino/compiler.py index 94b723f94114..d4ae8583bbed 100644 --- a/ibis/backends/trino/compiler.py +++ b/ibis/backends/trino/compiler.py @@ -11,7 +11,8 @@ class TrinoSQLExprTranslator(AlchemyExprTranslator): _registry = operation_registry.copy() _rewrites = AlchemyExprTranslator._rewrites.copy() _has_reduction_filter_syntax = True - integer_to_timestamp = sa.func.from_unixtime + _integer_to_timestamp = staticmethod(sa.func.from_unixtime) + _forbids_frame_clause = ( *AlchemyExprTranslator._forbids_frame_clause, ops.Lead, diff --git a/ibis/backends/trino/registry.py b/ibis/backends/trino/registry.py index 39914a34188a..968b8d1e4208 100644 --- a/ibis/backends/trino/registry.py +++ b/ibis/backends/trino/registry.py @@ -115,15 +115,16 @@ def _timestamp_from_unix(t, op): arg //= 1_000 except TypeError: arg = sa.func.floor(arg / 1_000) - return sa.func.from_unixtime(arg) + res = sa.func.from_unixtime(arg) elif unit == "s": - return sa.func.from_unixtime(arg) + res = sa.func.from_unixtime(arg) elif unit == "us": - return sa.func.from_unixtime_nanos((arg - arg % 1_000_000) * 1_000) + res = sa.func.from_unixtime_nanos((arg - arg % 1_000_000) * 1_000) elif unit == "ns": - return sa.func.from_unixtime_nanos(arg - (arg % 1_000_000_000)) + res = sa.func.from_unixtime_nanos(arg - arg % 1_000_000_000) else: raise com.UnsupportedOperationError(f"{unit!r} unit is not supported") + return sa.cast(res, t.get_sqla_type(op.output_dtype)) def _neg_idx_to_pos(array, idx): @@ -298,8 +299,11 @@ def _array_filter(t, op): 3, ), ops.TimestampFromYMDHMS: fixed_arity( - lambda y, mo, d, h, m, s: sa.func.from_iso8601_timestamp( - sa.func.format('%04d-%02d-%02dT%02d:%02d:%02d', y, mo, d, h, m, s) + lambda y, mo, d, h, m, s: sa.cast( + sa.func.from_iso8601_timestamp( + sa.func.format('%04d-%02d-%02dT%02d:%02d:%02d', y, mo, d, h, m, s) + ), + sa.TIMESTAMP(timezone=False), ), 6, ), diff --git a/poetry.lock b/poetry.lock index 1f7c28a69028..fb4103063e53 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3099,40 +3099,40 @@ setuptools = "*" [[package]] name = "numpy" -version = "1.23.5" -description = "NumPy is the fundamental package for array computing with Python." +version = "1.24.2" +description = "Fundamental package for array computing in Python" category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "numpy-1.23.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9c88793f78fca17da0145455f0d7826bcb9f37da4764af27ac945488116efe63"}, - {file = "numpy-1.23.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e9f4c4e51567b616be64e05d517c79a8a22f3606499941d97bb76f2ca59f982d"}, - {file = "numpy-1.23.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7903ba8ab592b82014713c491f6c5d3a1cde5b4a3bf116404e08f5b52f6daf43"}, - {file = "numpy-1.23.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e05b1c973a9f858c74367553e236f287e749465f773328c8ef31abe18f691e1"}, - {file = "numpy-1.23.5-cp310-cp310-win32.whl", hash = "sha256:522e26bbf6377e4d76403826ed689c295b0b238f46c28a7251ab94716da0b280"}, - {file = "numpy-1.23.5-cp310-cp310-win_amd64.whl", hash = "sha256:dbee87b469018961d1ad79b1a5d50c0ae850000b639bcb1b694e9981083243b6"}, - {file = "numpy-1.23.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ce571367b6dfe60af04e04a1834ca2dc5f46004ac1cc756fb95319f64c095a96"}, - {file = "numpy-1.23.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:56e454c7833e94ec9769fa0f86e6ff8e42ee38ce0ce1fa4cbb747ea7e06d56aa"}, - {file = "numpy-1.23.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5039f55555e1eab31124a5768898c9e22c25a65c1e0037f4d7c495a45778c9f2"}, - {file = "numpy-1.23.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58f545efd1108e647604a1b5aa809591ccd2540f468a880bedb97247e72db387"}, - {file = "numpy-1.23.5-cp311-cp311-win32.whl", hash = "sha256:b2a9ab7c279c91974f756c84c365a669a887efa287365a8e2c418f8b3ba73fb0"}, - {file = "numpy-1.23.5-cp311-cp311-win_amd64.whl", hash = "sha256:0cbe9848fad08baf71de1a39e12d1b6310f1d5b2d0ea4de051058e6e1076852d"}, - {file = "numpy-1.23.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f063b69b090c9d918f9df0a12116029e274daf0181df392839661c4c7ec9018a"}, - {file = "numpy-1.23.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0aaee12d8883552fadfc41e96b4c82ee7d794949e2a7c3b3a7201e968c7ecab9"}, - {file = "numpy-1.23.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92c8c1e89a1f5028a4c6d9e3ccbe311b6ba53694811269b992c0b224269e2398"}, - {file = "numpy-1.23.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d208a0f8729f3fb790ed18a003f3a57895b989b40ea4dce4717e9cf4af62c6bb"}, - {file = "numpy-1.23.5-cp38-cp38-win32.whl", hash = "sha256:06005a2ef6014e9956c09ba07654f9837d9e26696a0470e42beedadb78c11b07"}, - {file = "numpy-1.23.5-cp38-cp38-win_amd64.whl", hash = "sha256:ca51fcfcc5f9354c45f400059e88bc09215fb71a48d3768fb80e357f3b457e1e"}, - {file = "numpy-1.23.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8969bfd28e85c81f3f94eb4a66bc2cf1dbdc5c18efc320af34bffc54d6b1e38f"}, - {file = "numpy-1.23.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a7ac231a08bb37f852849bbb387a20a57574a97cfc7b6cabb488a4fc8be176de"}, - {file = "numpy-1.23.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf837dc63ba5c06dc8797c398db1e223a466c7ece27a1f7b5232ba3466aafe3d"}, - {file = "numpy-1.23.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33161613d2269025873025b33e879825ec7b1d831317e68f4f2f0f84ed14c719"}, - {file = "numpy-1.23.5-cp39-cp39-win32.whl", hash = "sha256:af1da88f6bc3d2338ebbf0e22fe487821ea4d8e89053e25fa59d1d79786e7481"}, - {file = "numpy-1.23.5-cp39-cp39-win_amd64.whl", hash = "sha256:09b7847f7e83ca37c6e627682f145856de331049013853f344f37b0c9690e3df"}, - {file = "numpy-1.23.5-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:abdde9f795cf292fb9651ed48185503a2ff29be87770c3b8e2a14b0cd7aa16f8"}, - {file = "numpy-1.23.5-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9a909a8bae284d46bbfdefbdd4a262ba19d3bc9921b1e76126b1d21c3c34135"}, - {file = "numpy-1.23.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:01dd17cbb340bf0fc23981e52e1d18a9d4050792e8fb8363cecbf066a84b827d"}, - {file = "numpy-1.23.5.tar.gz", hash = "sha256:1b1766d6f397c18153d40015ddfc79ddb715cabadc04d2d228d4e5a8bc4ded1a"}, + {file = "numpy-1.24.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eef70b4fc1e872ebddc38cddacc87c19a3709c0e3e5d20bf3954c147b1dd941d"}, + {file = "numpy-1.24.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e8d2859428712785e8a8b7d2b3ef0a1d1565892367b32f915c4a4df44d0e64f5"}, + {file = "numpy-1.24.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6524630f71631be2dabe0c541e7675db82651eb998496bbe16bc4f77f0772253"}, + {file = "numpy-1.24.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a51725a815a6188c662fb66fb32077709a9ca38053f0274640293a14fdd22978"}, + {file = "numpy-1.24.2-cp310-cp310-win32.whl", hash = "sha256:2620e8592136e073bd12ee4536149380695fbe9ebeae845b81237f986479ffc9"}, + {file = "numpy-1.24.2-cp310-cp310-win_amd64.whl", hash = "sha256:97cf27e51fa078078c649a51d7ade3c92d9e709ba2bfb97493007103c741f1d0"}, + {file = "numpy-1.24.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7de8fdde0003f4294655aa5d5f0a89c26b9f22c0a58790c38fae1ed392d44a5a"}, + {file = "numpy-1.24.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4173bde9fa2a005c2c6e2ea8ac1618e2ed2c1c6ec8a7657237854d42094123a0"}, + {file = "numpy-1.24.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4cecaed30dc14123020f77b03601559fff3e6cd0c048f8b5289f4eeabb0eb281"}, + {file = "numpy-1.24.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a23f8440561a633204a67fb44617ce2a299beecf3295f0d13c495518908e910"}, + {file = "numpy-1.24.2-cp311-cp311-win32.whl", hash = "sha256:e428c4fbfa085f947b536706a2fc349245d7baa8334f0c5723c56a10595f9b95"}, + {file = "numpy-1.24.2-cp311-cp311-win_amd64.whl", hash = "sha256:557d42778a6869c2162deb40ad82612645e21d79e11c1dc62c6e82a2220ffb04"}, + {file = "numpy-1.24.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d0a2db9d20117bf523dde15858398e7c0858aadca7c0f088ac0d6edd360e9ad2"}, + {file = "numpy-1.24.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c72a6b2f4af1adfe193f7beb91ddf708ff867a3f977ef2ec53c0ffb8283ab9f5"}, + {file = "numpy-1.24.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c29e6bd0ec49a44d7690ecb623a8eac5ab8a923bce0bea6293953992edf3a76a"}, + {file = "numpy-1.24.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2eabd64ddb96a1239791da78fa5f4e1693ae2dadc82a76bc76a14cbb2b966e96"}, + {file = "numpy-1.24.2-cp38-cp38-win32.whl", hash = "sha256:e3ab5d32784e843fc0dd3ab6dcafc67ef806e6b6828dc6af2f689be0eb4d781d"}, + {file = "numpy-1.24.2-cp38-cp38-win_amd64.whl", hash = "sha256:76807b4063f0002c8532cfeac47a3068a69561e9c8715efdad3c642eb27c0756"}, + {file = "numpy-1.24.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4199e7cfc307a778f72d293372736223e39ec9ac096ff0a2e64853b866a8e18a"}, + {file = "numpy-1.24.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:adbdce121896fd3a17a77ab0b0b5eedf05a9834a18699db6829a64e1dfccca7f"}, + {file = "numpy-1.24.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:889b2cc88b837d86eda1b17008ebeb679d82875022200c6e8e4ce6cf549b7acb"}, + {file = "numpy-1.24.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f64bb98ac59b3ea3bf74b02f13836eb2e24e48e0ab0145bbda646295769bd780"}, + {file = "numpy-1.24.2-cp39-cp39-win32.whl", hash = "sha256:63e45511ee4d9d976637d11e6c9864eae50e12dc9598f531c035265991910468"}, + {file = "numpy-1.24.2-cp39-cp39-win_amd64.whl", hash = "sha256:a77d3e1163a7770164404607b7ba3967fb49b24782a6ef85d9b5f54126cc39e5"}, + {file = "numpy-1.24.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:92011118955724465fb6853def593cf397b4a1367495e0b59a7e69d40c4eb71d"}, + {file = "numpy-1.24.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9006288bcf4895917d02583cf3411f98631275bc67cce355a7f39f8c14338fa"}, + {file = "numpy-1.24.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:150947adbdfeceec4e5926d956a06865c1c690f2fd902efede4ca6fe2e657c3f"}, + {file = "numpy-1.24.2.tar.gz", hash = "sha256:003a9f530e880cb2cd177cba1af7220b9aa42def9c4afc2a2fc3ee6be7eb2b22"}, ] [[package]] @@ -3181,39 +3181,37 @@ files = [ [[package]] name = "pandas" -version = "1.5.3" +version = "2.0.0" description = "Powerful data structures for data analysis, time series, and statistics" category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "pandas-1.5.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3749077d86e3a2f0ed51367f30bf5b82e131cc0f14260c4d3e499186fccc4406"}, - {file = "pandas-1.5.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:972d8a45395f2a2d26733eb8d0f629b2f90bebe8e8eddbb8829b180c09639572"}, - {file = "pandas-1.5.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:50869a35cbb0f2e0cd5ec04b191e7b12ed688874bd05dd777c19b28cbea90996"}, - {file = "pandas-1.5.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3ac844a0fe00bfaeb2c9b51ab1424e5c8744f89860b138434a363b1f620f354"}, - {file = "pandas-1.5.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a0a56cef15fd1586726dace5616db75ebcfec9179a3a55e78f72c5639fa2a23"}, - {file = "pandas-1.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:478ff646ca42b20376e4ed3fa2e8d7341e8a63105586efe54fa2508ee087f328"}, - {file = "pandas-1.5.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6973549c01ca91ec96199e940495219c887ea815b2083722821f1d7abfa2b4dc"}, - {file = "pandas-1.5.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c39a8da13cede5adcd3be1182883aea1c925476f4e84b2807a46e2775306305d"}, - {file = "pandas-1.5.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f76d097d12c82a535fda9dfe5e8dd4127952b45fea9b0276cb30cca5ea313fbc"}, - {file = "pandas-1.5.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e474390e60ed609cec869b0da796ad94f420bb057d86784191eefc62b65819ae"}, - {file = "pandas-1.5.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f2b952406a1588ad4cad5b3f55f520e82e902388a6d5a4a91baa8d38d23c7f6"}, - {file = "pandas-1.5.3-cp311-cp311-win_amd64.whl", hash = "sha256:bc4c368f42b551bf72fac35c5128963a171b40dce866fb066540eeaf46faa003"}, - {file = "pandas-1.5.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:14e45300521902689a81f3f41386dc86f19b8ba8dd5ac5a3c7010ef8d2932813"}, - {file = "pandas-1.5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9842b6f4b8479e41968eced654487258ed81df7d1c9b7b870ceea24ed9459b31"}, - {file = "pandas-1.5.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:26d9c71772c7afb9d5046e6e9cf42d83dd147b5cf5bcb9d97252077118543792"}, - {file = "pandas-1.5.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5fbcb19d6fceb9e946b3e23258757c7b225ba450990d9ed63ccceeb8cae609f7"}, - {file = "pandas-1.5.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:565fa34a5434d38e9d250af3c12ff931abaf88050551d9fbcdfafca50d62babf"}, - {file = "pandas-1.5.3-cp38-cp38-win32.whl", hash = "sha256:87bd9c03da1ac870a6d2c8902a0e1fd4267ca00f13bc494c9e5a9020920e1d51"}, - {file = "pandas-1.5.3-cp38-cp38-win_amd64.whl", hash = "sha256:41179ce559943d83a9b4bbacb736b04c928b095b5f25dd2b7389eda08f46f373"}, - {file = "pandas-1.5.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c74a62747864ed568f5a82a49a23a8d7fe171d0c69038b38cedf0976831296fa"}, - {file = "pandas-1.5.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c4c00e0b0597c8e4f59e8d461f797e5d70b4d025880516a8261b2817c47759ee"}, - {file = "pandas-1.5.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a50d9a4336a9621cab7b8eb3fb11adb82de58f9b91d84c2cd526576b881a0c5a"}, - {file = "pandas-1.5.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd05f7783b3274aa206a1af06f0ceed3f9b412cf665b7247eacd83be41cf7bf0"}, - {file = "pandas-1.5.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f69c4029613de47816b1bb30ff5ac778686688751a5e9c99ad8c7031f6508e5"}, - {file = "pandas-1.5.3-cp39-cp39-win32.whl", hash = "sha256:7cec0bee9f294e5de5bbfc14d0573f65526071029d036b753ee6507d2a21480a"}, - {file = "pandas-1.5.3-cp39-cp39-win_amd64.whl", hash = "sha256:dfd681c5dc216037e0b0a2c821f5ed99ba9f03ebcf119c7dac0e9a7b960b9ec9"}, - {file = "pandas-1.5.3.tar.gz", hash = "sha256:74a3fd7e5a7ec052f183273dc7b0acd3a863edf7520f5d3a1765c04ffdb3b0b1"}, + {file = "pandas-2.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bbb2c5e94d6aa4e632646a3bacd05c2a871c3aa3e85c9bec9be99cb1267279f2"}, + {file = "pandas-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b5337c87c4e963f97becb1217965b6b75c6fe5f54c4cf09b9a5ac52fc0bd03d3"}, + {file = "pandas-2.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ded51f7e3dd9b4f8b87f2ceb7bd1a8df2491f7ee72f7074c6927a512607199e"}, + {file = "pandas-2.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:52c858de9e9fc422d25e67e1592a6e6135d7bcf9a19fcaf4d0831a0be496bf21"}, + {file = "pandas-2.0.0-cp310-cp310-win32.whl", hash = "sha256:2d1d138848dd71b37e3cbe7cd952ff84e2ab04d8988972166e18567dcc811245"}, + {file = "pandas-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:d08e41d96bc4de6f500afe80936c68fce6099d5a434e2af7c7fd8e7c72a3265d"}, + {file = "pandas-2.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:24472cfc7ced511ac90608728b88312be56edc8f19b9ed885a7d2e47ffaf69c0"}, + {file = "pandas-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ffb14f50c74ee541610668137830bb93e9dfa319b1bef2cedf2814cd5ac9c70"}, + {file = "pandas-2.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c24c7d12d033a372a9daf9ff2c80f8b0af6f98d14664dbb0a4f6a029094928a7"}, + {file = "pandas-2.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8318de0f886e4dcb8f9f36e45a3d6a6c3d1cfdc508354da85e739090f0222991"}, + {file = "pandas-2.0.0-cp311-cp311-win32.whl", hash = "sha256:57c34b79c13249505e850d0377b722961b99140f81dafbe6f19ef10239f6284a"}, + {file = "pandas-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:8f987ec26e96a8490909bc5d98c514147236e49830cba7df8690f6087c12bbae"}, + {file = "pandas-2.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b3ba8f5dd470d8bfbc4259829589f4a32881151c49e36384d9eb982b35a12020"}, + {file = "pandas-2.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fcd471c9d9f60926ab2f15c6c29164112f458acb42280365fbefa542d0c2fc74"}, + {file = "pandas-2.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9253edfd015520ce77a9343eb7097429479c039cd3ebe81d7810ea11b4b24695"}, + {file = "pandas-2.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:977326039bd1ded620001a1889e2ed4798460a6bc5a24fbaebb5f07a41c32a55"}, + {file = "pandas-2.0.0-cp38-cp38-win32.whl", hash = "sha256:78425ca12314b23356c28b16765639db10ebb7d8983f705d6759ff7fe41357fa"}, + {file = "pandas-2.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:d93b7fcfd9f3328072b250d6d001dcfeec5d3bb66c1b9c8941e109a46c0c01a8"}, + {file = "pandas-2.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:425705cee8be54db2504e8dd2a730684790b15e5904b750c367611ede49098ab"}, + {file = "pandas-2.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a4f789b7c012a608c08cda4ff0872fd979cb18907a37982abe884e6f529b8793"}, + {file = "pandas-2.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3bb9d840bf15656805f6a3d87eea9dcb7efdf1314a82adcf7f00b820427c5570"}, + {file = "pandas-2.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0778ab54c8f399d83d98ffb674d11ec716449956bc6f6821891ab835848687f2"}, + {file = "pandas-2.0.0-cp39-cp39-win32.whl", hash = "sha256:70db5c278bbec0306d32bf78751ff56b9594c05a5098386f6c8a563659124f91"}, + {file = "pandas-2.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:4f3320bb55f34af4193020158ef8118ee0fb9aec7cc47d2084dbfdd868a0a24f"}, + {file = "pandas-2.0.0.tar.gz", hash = "sha256:cda9789e61b44463c1c4fe17ef755de77bcd13b09ba31c940d20f193d63a5dc8"}, ] [package.dependencies] @@ -3222,11 +3220,32 @@ numpy = [ {version = ">=1.21.0", markers = "python_version >= \"3.10\""}, {version = ">=1.23.2", markers = "python_version >= \"3.11\""}, ] -python-dateutil = ">=2.8.1" +python-dateutil = ">=2.8.2" pytz = ">=2020.1" +tzdata = ">=2022.1" [package.extras] -test = ["hypothesis (>=5.5.3)", "pytest (>=6.0)", "pytest-xdist (>=1.31)"] +all = ["PyQt5 (>=5.15.1)", "SQLAlchemy (>=1.4.16)", "beautifulsoup4 (>=4.9.3)", "bottleneck (>=1.3.2)", "brotlipy (>=0.7.0)", "fastparquet (>=0.6.3)", "fsspec (>=2021.07.0)", "gcsfs (>=2021.07.0)", "html5lib (>=1.1)", "hypothesis (>=6.34.2)", "jinja2 (>=3.0.0)", "lxml (>=4.6.3)", "matplotlib (>=3.6.1)", "numba (>=0.53.1)", "numexpr (>=2.7.3)", "odfpy (>=1.4.1)", "openpyxl (>=3.0.7)", "pandas-gbq (>=0.15.0)", "psycopg2 (>=2.8.6)", "pyarrow (>=7.0.0)", "pymysql (>=1.0.2)", "pyreadstat (>=1.1.2)", "pytest (>=7.0.0)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)", "python-snappy (>=0.6.0)", "pyxlsb (>=1.0.8)", "qtpy (>=2.2.0)", "s3fs (>=2021.08.0)", "scipy (>=1.7.1)", "tables (>=3.6.1)", "tabulate (>=0.8.9)", "xarray (>=0.21.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=1.4.3)", "zstandard (>=0.15.2)"] +aws = ["s3fs (>=2021.08.0)"] +clipboard = ["PyQt5 (>=5.15.1)", "qtpy (>=2.2.0)"] +compression = ["brotlipy (>=0.7.0)", "python-snappy (>=0.6.0)", "zstandard (>=0.15.2)"] +computation = ["scipy (>=1.7.1)", "xarray (>=0.21.0)"] +excel = ["odfpy (>=1.4.1)", "openpyxl (>=3.0.7)", "pyxlsb (>=1.0.8)", "xlrd (>=2.0.1)", "xlsxwriter (>=1.4.3)"] +feather = ["pyarrow (>=7.0.0)"] +fss = ["fsspec (>=2021.07.0)"] +gcp = ["gcsfs (>=2021.07.0)", "pandas-gbq (>=0.15.0)"] +hdf5 = ["tables (>=3.6.1)"] +html = ["beautifulsoup4 (>=4.9.3)", "html5lib (>=1.1)", "lxml (>=4.6.3)"] +mysql = ["SQLAlchemy (>=1.4.16)", "pymysql (>=1.0.2)"] +output-formatting = ["jinja2 (>=3.0.0)", "tabulate (>=0.8.9)"] +parquet = ["pyarrow (>=7.0.0)"] +performance = ["bottleneck (>=1.3.2)", "numba (>=0.53.1)", "numexpr (>=2.7.1)"] +plot = ["matplotlib (>=3.6.1)"] +postgresql = ["SQLAlchemy (>=1.4.16)", "psycopg2 (>=2.8.6)"] +spss = ["pyreadstat (>=1.1.2)"] +sql-other = ["SQLAlchemy (>=1.4.16)"] +test = ["hypothesis (>=6.34.2)", "pytest (>=7.0.0)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)"] +xml = ["lxml (>=4.6.3)"] [[package]] name = "pandocfilters" @@ -5204,7 +5223,7 @@ name = "tzdata" version = "2023.3" description = "Provider of IANA time zone data" category = "main" -optional = true +optional = false python-versions = ">=2" files = [ {file = "tzdata-2023.3-py2.py3-none-any.whl", hash = "sha256:7e65763eef3120314099b6939b5546db7adce1e7d6f2e179e3df563c70511eda"}, @@ -5588,4 +5607,4 @@ visualization = ["graphviz"] [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "eb479d37376d9c34bb81dfda27f0e347cb767d74a66b624c28c49ca801c0e00a" +content-hash = "45c41fe5574bfd2626bbc86724734d36f3aa682e49d80f71022356e01ad1398f" diff --git a/pyproject.toml b/pyproject.toml index 531aac922f5f..9bf9ecd8b836 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,7 +35,7 @@ bidict = ">=0.22.1,<1" importlib-resources = { version = ">=5,<6", python = "<3.9" } multipledispatch = ">=0.6,<1" numpy = ">=1,<2" -pandas = ">=1.2.5,<2" +pandas = ">=1.2.5,<3" parsy = ">=2,<3" pooch = { version = ">=1.6.0,<2", extras = ["progress", "xxhash"] } python-dateutil = ">=2.8.2,<3" diff --git a/requirements.txt b/requirements.txt index 42634d0db315..932286ecc7c1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -116,11 +116,11 @@ nbconvert==7.2.10 ; python_version >= "3.8" and python_version < "4.0" nbformat==5.8.0 ; python_version >= "3.8" and python_version < "4.0" nest-asyncio==1.5.6 ; python_version >= "3.8" and python_version < "4.0" nodeenv==1.7.0 ; python_version >= "3.8" and python_version < "4.0" -numpy==1.23.5 ; python_version < "4.0" and python_version >= "3.8" +numpy==1.24.2 ; python_version < "4.0" and python_version >= "3.8" oauthlib==3.2.2 ; python_version >= "3.8" and python_version < "4.0" oscrypto==1.3.0 ; python_version >= "3.8" and python_version < "4.0" packaging==23.0 ; python_version >= "3.8" and python_version < "4.0" -pandas==1.5.3 ; python_version >= "3.8" and python_version < "4.0" +pandas==2.0.0 ; python_version >= "3.8" and python_version < "4.0" pandocfilters==1.5.0 ; python_version >= "3.8" and python_version < "4.0" parso==0.8.3 ; python_version >= "3.8" and python_version < "4.0" parsy==2.1 ; python_version >= "3.8" and python_version < "4.0" @@ -211,7 +211,7 @@ tqdm==4.65.0 ; python_version >= "3.8" and python_version < "4.0" traitlets==5.9.0 ; python_version >= "3.8" and python_version < "4.0" trino[sqlalchemy]==0.322.0 ; python_version >= "3.8" and python_version < "4.0" typing-extensions==4.5.0 ; python_version >= "3.8" and python_version < "4.0" -tzdata==2023.3 ; python_version >= "3.8" and python_version < "4" +tzdata==2023.3 ; python_version >= "3.8" and python_version < "4.0" tzlocal==4.3 ; python_version >= "3.8" and python_version < "4" urllib3==1.26.15 ; python_version >= "3.8" and python_version < "4" virtualenv==20.21.0 ; python_version >= "3.8" and python_version < "4.0"