Skip to content

Commit 9110f2c

Browse files
Merge remote-tracking branch 'upstream/main' into read_iceberg
2 parents f973e61 + 337d40e commit 9110f2c

File tree

7 files changed

+112
-58
lines changed

7 files changed

+112
-58
lines changed

.github/workflows/unit-tests.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ jobs:
2727
strategy:
2828
matrix:
2929
platform: [ubuntu-22.04, ubuntu-24.04-arm]
30-
env_file: [actions-310.yaml, actions-311.yaml, actions-312.yaml]
30+
env_file: [actions-310.yaml, actions-311.yaml, actions-312.yaml, actions-313.yaml]
3131
# Prevent the include jobs from overriding other jobs
3232
pattern: [""]
3333
pandas_future_infer_string: ["0"]
@@ -188,7 +188,7 @@ jobs:
188188
matrix:
189189
# Note: Don't use macOS latest since macos 14 appears to be arm64 only
190190
os: [macos-13, macos-14, windows-latest]
191-
env_file: [actions-310.yaml, actions-311.yaml, actions-312.yaml]
191+
env_file: [actions-310.yaml, actions-311.yaml, actions-312.yaml, actions-313.yaml]
192192
fail-fast: false
193193
runs-on: ${{ matrix.os }}
194194
name: ${{ format('{0} {1}', matrix.os, matrix.env_file) }}
@@ -316,7 +316,7 @@ jobs:
316316
# To freeze this file, uncomment out the ``if: false`` condition, and migrate the jobs
317317
# to the corresponding posix/windows-macos/sdist etc. workflows.
318318
# Feel free to modify this comment as necessary.
319-
# if: false # Uncomment this to freeze the workflow, comment it to unfreeze
319+
if: false
320320
defaults:
321321
run:
322322
shell: bash -eou pipefail {0}

ci/deps/actions-313.yaml

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
name: pandas-dev-313
2+
channels:
3+
- conda-forge
4+
dependencies:
5+
- python=3.13
6+
7+
# build dependencies
8+
- versioneer
9+
- cython>=0.29.33
10+
- meson=1.2.1
11+
- meson-python=0.13.1
12+
13+
# test dependencies
14+
- pytest>=7.3.2
15+
- pytest-cov
16+
- pytest-xdist>=3.4.0
17+
- pytest-localserver>=0.8.1
18+
- pytest-qt>=4.4.0
19+
- boto3
20+
21+
# required dependencies
22+
- python-dateutil
23+
- numpy
24+
25+
# optional dependencies
26+
- beautifulsoup4>=4.12.3
27+
- blosc>=1.21.3
28+
- bottleneck>=1.3.6
29+
- fastparquet>=2024.2.0
30+
- fsspec>=2024.2.0
31+
- html5lib>=1.1
32+
- hypothesis>=6.84.0
33+
- gcsfs>=2024.2.0
34+
- jinja2>=3.1.3
35+
- lxml>=4.9.2
36+
- matplotlib>=3.8.3
37+
- numba>=0.59.0
38+
- numexpr>=2.9.0
39+
- odfpy>=1.4.1
40+
- qtpy>=2.3.0
41+
- pyqt>=5.15.9
42+
- openpyxl>=3.1.2
43+
- psycopg2>=2.9.6
44+
- pyarrow>=10.0.1
45+
- pymysql>=1.1.0
46+
- pyreadstat>=1.2.6
47+
- pytables>=3.8.0
48+
- python-calamine>=0.1.7
49+
- pytz>=2023.4
50+
- pyxlsb>=1.0.10
51+
- s3fs>=2024.2.0
52+
- scipy>=1.12.0
53+
- sqlalchemy>=2.0.0
54+
- tabulate>=0.9.0
55+
- xarray>=2024.1.1, <=2024.9.0
56+
- xlrd>=2.0.1
57+
- xlsxwriter>=3.2.0
58+
- zstandard>=0.22.0
59+
60+
- pip:
61+
- adbc-driver-postgresql>=0.10.0
62+
- adbc-driver-sqlite>=0.8.0
63+
- tzdata>=2022.7

doc/source/_static/css/getting_started.css

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,13 +249,15 @@ ul.task-bullet > li > p:first-child {
249249

250250
.tutorial-card .card-header {
251251
--bs-card-cap-color: var(--pst-color-text-base);
252+
color: var(--pst-color-text-base);
252253
cursor: pointer;
253254
background-color: var(--pst-color-surface);
254255
border: 1px solid var(--pst-color-border)
255256
}
256257

257258
.tutorial-card .card-body {
258259
background-color: var(--pst-color-on-background);
260+
color: var(--pst-color-text-base);
259261
}
260262

261263
.tutorial-card .badge {

doc/source/reference/arrays.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,7 @@ Data type introspection
664664
api.types.is_datetime64_dtype
665665
api.types.is_datetime64_ns_dtype
666666
api.types.is_datetime64tz_dtype
667+
api.types.is_dtype_equal
667668
api.types.is_extension_array_dtype
668669
api.types.is_float_dtype
669670
api.types.is_int64_dtype

pandas/core/dtypes/common.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -655,24 +655,38 @@ def is_dtype_equal(source, target) -> bool:
655655
656656
Parameters
657657
----------
658-
source : The first dtype to compare
659-
target : The second dtype to compare
658+
source : type or str
659+
The first dtype to compare.
660+
target : type or str
661+
The second dtype to compare.
660662
661663
Returns
662664
-------
663665
boolean
664666
Whether or not the two dtypes are equal.
665667
668+
See Also
669+
--------
670+
api.types.is_categorical_dtype : Check whether the provided array or dtype
671+
is of the Categorical dtype.
672+
api.types.is_string_dtype : Check whether the provided array or dtype
673+
is of the string dtype.
674+
api.types.is_object_dtype : Check whether an array-like or dtype is of the
675+
object dtype.
676+
666677
Examples
667678
--------
679+
>>> from pandas.api.types import is_dtype_equal
668680
>>> is_dtype_equal(int, float)
669681
False
670682
>>> is_dtype_equal("int", int)
671683
True
672684
>>> is_dtype_equal(object, "category")
673685
False
686+
>>> from pandas.core.dtypes.dtypes import CategoricalDtype
674687
>>> is_dtype_equal(CategoricalDtype(), "category")
675688
True
689+
>>> from pandas.core.dtypes.dtypes import DatetimeTZDtype
676690
>>> is_dtype_equal(DatetimeTZDtype(tz="UTC"), "datetime64")
677691
False
678692
"""

pandas/plotting/_matplotlib/style.py

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@
2222

2323
from pandas.core.dtypes.common import is_list_like
2424

25-
import pandas.core.common as com
26-
2725
if TYPE_CHECKING:
2826
from matplotlib.colors import Colormap
2927

@@ -251,31 +249,17 @@ def _is_floats_color(color: Color | Collection[Color]) -> bool:
251249
def _get_colors_from_color_type(color_type: str, num_colors: int) -> list[Color]:
252250
"""Get colors from user input color type."""
253251
if color_type == "default":
254-
return _get_default_colors(num_colors)
252+
prop_cycle = mpl.rcParams["axes.prop_cycle"]
253+
return [
254+
c["color"]
255+
for c in itertools.islice(prop_cycle, min(num_colors, len(prop_cycle)))
256+
]
255257
elif color_type == "random":
256-
return _get_random_colors(num_colors)
258+
return np.random.default_rng(num_colors).random((num_colors, 3)).tolist()
257259
else:
258260
raise ValueError("color_type must be either 'default' or 'random'")
259261

260262

261-
def _get_default_colors(num_colors: int) -> list[Color]:
262-
"""Get `num_colors` of default colors from matplotlib rc params."""
263-
colors = [c["color"] for c in mpl.rcParams["axes.prop_cycle"]]
264-
return colors[0:num_colors]
265-
266-
267-
def _get_random_colors(num_colors: int) -> list[Color]:
268-
"""Get `num_colors` of random colors."""
269-
return [_random_color(num) for num in range(num_colors)]
270-
271-
272-
def _random_color(column: int) -> list[float]:
273-
"""Get a random color represented as a list of length 3"""
274-
# GH17525 use common._random_state to avoid resetting the seed
275-
rs = com.random_state(column)
276-
return rs.rand(3).tolist()
277-
278-
279263
def _is_single_string_color(color: Color) -> bool:
280264
"""Check if `color` is a single string color.
281265

pandas/tests/io/test_sql.py

Lines changed: 21 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2498,10 +2498,8 @@ def test_sqlalchemy_integer_overload_mapping(conn, request, integer):
24982498
sql.SQLTable("test_type", db, frame=df)
24992499

25002500

2501-
@pytest.mark.parametrize("conn", all_connectable)
2502-
def test_database_uri_string(conn, request, test_frame1):
2501+
def test_database_uri_string(request, test_frame1):
25032502
pytest.importorskip("sqlalchemy")
2504-
conn = request.getfixturevalue(conn)
25052503
# Test read_sql and .to_sql method with a database URI (GH10654)
25062504
# db_uri = 'sqlite:///:memory:' # raises
25072505
# sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) near
@@ -2520,10 +2518,8 @@ def test_database_uri_string(conn, request, test_frame1):
25202518

25212519

25222520
@td.skip_if_installed("pg8000")
2523-
@pytest.mark.parametrize("conn", all_connectable)
2524-
def test_pg8000_sqlalchemy_passthrough_error(conn, request):
2521+
def test_pg8000_sqlalchemy_passthrough_error(request):
25252522
pytest.importorskip("sqlalchemy")
2526-
conn = request.getfixturevalue(conn)
25272523
# using driver that will not be installed on CI to trigger error
25282524
# in sqlalchemy.create_engine -> test passing of this error to user
25292525
db_uri = "postgresql+pg8000://user:pass@host/dbname"
@@ -2731,25 +2727,26 @@ def test_delete_rows_is_atomic(conn_name, request):
27312727
replacing_df = DataFrame({"a": [5, 6, 7], "b": [8, 8, 8]}, dtype="int32")
27322728

27332729
conn = request.getfixturevalue(conn_name)
2734-
pandasSQL = pandasSQL_builder(conn)
2730+
with pandasSQL_builder(conn) as pandasSQL:
2731+
with pandasSQL.run_transaction() as cur:
2732+
cur.execute(table_stmt)
27352733

2736-
with pandasSQL.run_transaction() as cur:
2737-
cur.execute(table_stmt)
2734+
with pandasSQL.run_transaction():
2735+
pandasSQL.to_sql(original_df, table_name, if_exists="append", index=False)
27382736

2739-
with pandasSQL.run_transaction():
2740-
pandasSQL.to_sql(original_df, table_name, if_exists="append", index=False)
2737+
# inserting duplicated values in a UNIQUE constraint column
2738+
with pytest.raises(pd.errors.DatabaseError):
2739+
with pandasSQL.run_transaction():
2740+
pandasSQL.to_sql(
2741+
replacing_df, table_name, if_exists="delete_rows", index=False
2742+
)
27412743

2742-
# inserting duplicated values in a UNIQUE constraint column
2743-
with pytest.raises(pd.errors.DatabaseError):
2744+
# failed "delete_rows" is rolled back preserving original data
27442745
with pandasSQL.run_transaction():
2745-
pandasSQL.to_sql(
2746-
replacing_df, table_name, if_exists="delete_rows", index=False
2746+
result_df = pandasSQL.read_query(
2747+
f"SELECT * FROM {table_name}", dtype="int32"
27472748
)
2748-
2749-
# failed "delete_rows" is rolled back preserving original data
2750-
with pandasSQL.run_transaction():
2751-
result_df = pandasSQL.read_query(f"SELECT * FROM {table_name}", dtype="int32")
2752-
tm.assert_frame_equal(result_df, original_df)
2749+
tm.assert_frame_equal(result_df, original_df)
27532750

27542751

27552752
@pytest.mark.parametrize("conn", all_connectable)
@@ -2759,10 +2756,10 @@ def test_roundtrip(conn, request, test_frame1):
27592756

27602757
conn_name = conn
27612758
conn = request.getfixturevalue(conn)
2762-
pandasSQL = pandasSQL_builder(conn)
2763-
with pandasSQL.run_transaction():
2764-
assert pandasSQL.to_sql(test_frame1, "test_frame_roundtrip") == 4
2765-
result = pandasSQL.read_query("SELECT * FROM test_frame_roundtrip")
2759+
with pandasSQL_builder(conn) as pandasSQL:
2760+
with pandasSQL.run_transaction():
2761+
assert pandasSQL.to_sql(test_frame1, "test_frame_roundtrip") == 4
2762+
result = pandasSQL.read_query("SELECT * FROM test_frame_roundtrip")
27662763

27672764
if "adbc" in conn_name:
27682765
result = result.rename(columns={"__index_level_0__": "level_0"})
@@ -3577,13 +3574,6 @@ def test_options_get_engine():
35773574
assert isinstance(get_engine("sqlalchemy"), SQLAlchemyEngine)
35783575

35793576

3580-
def test_get_engine_auto_error_message():
3581-
# Expect different error messages from get_engine(engine="auto")
3582-
# if engines aren't installed vs. are installed but bad version
3583-
pass
3584-
# TODO(GH#36893) fill this in when we add more engines
3585-
3586-
35873577
@pytest.mark.parametrize("conn", all_connectable)
35883578
@pytest.mark.parametrize("func", ["read_sql", "read_sql_query"])
35893579
def test_read_sql_dtype_backend(

0 commit comments

Comments
 (0)