pydiverse-common 0.3.10__tar.gz → 0.3.12__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/PKG-INFO +1 -1
  2. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/docs/source/changelog.md +7 -0
  3. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/pyproject.toml +1 -1
  4. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/src/pydiverse/common/dtypes.py +47 -9
  5. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/tests/dtypes/test_dtype_pandas.py +18 -0
  6. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/tests/dtypes/test_dtype_sqlalchemy.py +2 -2
  7. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/.gitattributes +0 -0
  8. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/.github/CODEOWNERS +0 -0
  9. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  10. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/.github/dependabot.yml +0 -0
  11. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/.github/scripts/check_deps.sh +0 -0
  12. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/.github/workflows/release.yml +0 -0
  13. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/.github/workflows/tests.yml +0 -0
  14. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/.github/workflows/update-lockfiles.yml +0 -0
  15. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/.gitignore +0 -0
  16. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/.pre-commit-config.yaml +0 -0
  17. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/.readthedocs.yaml +0 -0
  18. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/LICENSE +0 -0
  19. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/README.md +0 -0
  20. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/docs/Makefile +0 -0
  21. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/docs/make.bat +0 -0
  22. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/docs/package/README.md +0 -0
  23. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/docs/source/conf.py +0 -0
  24. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/docs/source/index.md +0 -0
  25. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/docs/source/license.md +0 -0
  26. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/docs/source/reference/api.rst +0 -0
  27. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/pixi.lock +0 -0
  28. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/pixi.toml +0 -0
  29. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/pytest.ini +0 -0
  30. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/src/pydiverse/common/__init__.py +0 -0
  31. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/src/pydiverse/common/errors/__init__.py +0 -0
  32. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/src/pydiverse/common/testing.py +0 -0
  33. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/src/pydiverse/common/util/__init__.py +0 -0
  34. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/src/pydiverse/common/util/computation_tracing.py +0 -0
  35. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/src/pydiverse/common/util/deep_map.py +0 -0
  36. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/src/pydiverse/common/util/deep_merge.py +0 -0
  37. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/src/pydiverse/common/util/disposable.py +0 -0
  38. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/src/pydiverse/common/util/hashing.py +0 -0
  39. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/src/pydiverse/common/util/import_.py +0 -0
  40. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/src/pydiverse/common/util/structlog.py +0 -0
  41. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/src/pydiverse/common/version.py +0 -0
  42. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/tests/conftest.py +0 -0
  43. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/tests/dtypes/test_dtype_polars.py +0 -0
  44. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/tests/dtypes/test_dtype_pyarrow.py +0 -0
  45. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/tests/test_util.py +0 -0
  46. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/tests/test_version.py +0 -0
  47. {pydiverse_common-0.3.10 → pydiverse_common-0.3.12}/typos.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pydiverse-common
3
- Version: 0.3.10
3
+ Version: 0.3.12
4
4
  Summary: Common functionality shared between pydiverse libraries
5
5
  Author: QuantCo, Inc.
6
6
  Author-email: Martin Trautmann <windiana@users.sf.net>, Finn Rudolph <finn.rudolph@t-online.de>
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.12 (2025-08-21)
4
+ - fixed Dtype.to_pandas() for parameterized String and Decimal types
5
+
6
+ ## 0.3.11 (2025-08-21)
7
+ - fixed __eq__, __hash__, and __repr__ for types with parameters
8
+ - import string length from sqlalchemy VARCHAR(n) type
9
+
3
10
  ## 0.3.10 (2025-08-21)
4
11
  - implemented String with max_length argument for SQL VARCHAR(n) generation
5
12
  - implemented Decimal with precision and scale arguments
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "pydiverse-common"
3
- version = "0.3.10"
3
+ version = "0.3.12"
4
4
  description = "Common functionality shared between pydiverse libraries"
5
5
  authors = [
6
6
  { name = "QuantCo, Inc." },
@@ -23,6 +23,10 @@ class Dtype:
23
23
  """Return a string representation of this dtype."""
24
24
  return self.__class__.__name__
25
25
 
26
+ def __str__(self):
27
+ """Return a string representation of this dtype."""
28
+ return self.__repr__()
29
+
26
30
  @classmethod
27
31
  def is_int(cls):
28
32
  """Return ``True`` if this dtype is an integer type."""
@@ -71,7 +75,7 @@ class Dtype:
71
75
  # otherwise.
72
76
  return Float64()
73
77
  if isinstance(sql_type, sa.String):
74
- return String()
78
+ return String(sql_type.length)
75
79
  if isinstance(sql_type, sa.Boolean):
76
80
  return Bool()
77
81
  if isinstance(sql_type, sa.Date):
@@ -307,6 +311,15 @@ class Dtype:
307
311
 
308
312
  if isinstance(self, Enum):
309
313
  return pd.CategoricalDtype(self.categories)
314
+ if isinstance(self, String):
315
+ return pd.StringDtype() # max_length not needed for dataframes
316
+ if isinstance(self, Decimal):
317
+ # NumericDtype exists but is not used because fixpoint is more common
318
+ # in SQL than in dataframes.
319
+ return pd.Float64Dtype()
320
+ if isinstance(self, List):
321
+ # we don't want to produce object columns
322
+ raise TypeError("pandas doesn't have a native list dtype")
310
323
 
311
324
  return {
312
325
  Int(): pd.Int64Dtype(), # we default to 64 bit
@@ -321,8 +334,6 @@ class Dtype:
321
334
  Float(): pd.Float64Dtype(), # we default to 64 bit
322
335
  Float32(): pd.Float32Dtype(),
323
336
  Float64(): pd.Float64Dtype(),
324
- Decimal(): pd.Float64Dtype(), # NumericDtype exists but is not used
325
- String(): pd.StringDtype(),
326
337
  Bool(): pd.BooleanDtype(),
327
338
  Date(): "datetime64[s]",
328
339
  Datetime(): "datetime64[us]",
@@ -416,6 +427,20 @@ class Decimal(Float):
416
427
  self.precision = precision or 31
417
428
  self.scale = scale or (self.precision // 3 + 1)
418
429
 
430
+ def __eq__(self, rhs):
431
+ return (
432
+ isinstance(rhs, self.__class__)
433
+ and self.precision == rhs.precision
434
+ and self.scale == rhs.scale
435
+ )
436
+
437
+ def __hash__(self):
438
+ return hash((self.__class__.__name__, self.precision, self.scale))
439
+
440
+ def __repr__(self):
441
+ """Return a string representation of this dtype."""
442
+ return f"{self.__class__.__name__}({self.precision}, {self.scale})"
443
+
419
444
  def to_sql(self):
420
445
  import sqlalchemy as sa
421
446
 
@@ -480,6 +505,16 @@ class String(Dtype):
480
505
  """
481
506
  self.max_length = max_length
482
507
 
508
+ def __eq__(self, rhs):
509
+ return isinstance(rhs, self.__class__) and self.max_length == rhs.max_length
510
+
511
+ def __hash__(self):
512
+ return hash((self.__class__.__name__, self.max_length))
513
+
514
+ def __repr__(self):
515
+ """Return a string representation of this dtype."""
516
+ return f"{self.__class__.__name__}({self.max_length})"
517
+
483
518
  def to_sql(self):
484
519
  """Convert this Dtype to a SQL type."""
485
520
  import sqlalchemy as sa
@@ -523,10 +558,11 @@ class List(Dtype):
523
558
  return isinstance(rhs, List) and self.inner == rhs.inner
524
559
 
525
560
  def __hash__(self):
526
- return hash((0, hash(self.inner)))
561
+ return hash((self.__class__.__name__, hash(self.inner)))
527
562
 
528
563
  def __repr__(self):
529
- return f"List[{repr(self.inner)}]"
564
+ """Return a string representation of this dtype."""
565
+ return f"{self.__class__.__name__}[{self.inner}]"
530
566
 
531
567
  def to_sql(self):
532
568
  import sqlalchemy as sa
@@ -556,11 +592,13 @@ class Enum(String):
556
592
  def __eq__(self, rhs):
557
593
  return isinstance(rhs, Enum) and self.categories == rhs.categories
558
594
 
559
- def __repr__(self) -> str:
560
- return f"Enum[{', '.join(repr(c) for c in self.categories)}]"
561
-
562
595
  def __hash__(self):
563
- return hash(tuple(self.categories))
596
+ return hash((self.__class__.__name__, tuple(self.categories)))
597
+
598
+ def __repr__(self) -> str:
599
+ return (
600
+ f"{self.__class__.__name__}[{', '.join(repr(c) for c in self.categories)}]"
601
+ )
564
602
 
565
603
  def to_polars(self):
566
604
  import polars as pl
@@ -113,7 +113,15 @@ def test_dtype_to_pandas_numpy():
113
113
  assert_conversion(UInt16(), pd.UInt16Dtype())
114
114
  assert_conversion(UInt8(), pd.UInt8Dtype())
115
115
 
116
+ assert_conversion(Float64(), pd.Float64Dtype())
117
+ assert_conversion(Float32(), pd.Float32Dtype())
118
+
119
+ assert_conversion(Decimal(), pd.Float64Dtype())
120
+ assert_conversion(Decimal(15), pd.Float64Dtype())
121
+ assert_conversion(Decimal(15, 2), pd.Float64Dtype())
122
+
116
123
  assert_conversion(String(), pd.StringDtype())
124
+ assert_conversion(String(10), pd.StringDtype())
117
125
  assert_conversion(Bool(), pd.BooleanDtype())
118
126
 
119
127
  assert_conversion(Date(), "datetime64[s]")
@@ -142,7 +150,17 @@ def test_dtype_to_pandas_pyarrow():
142
150
  assert_conversion(UInt16(), pa.uint16())
143
151
  assert_conversion(UInt8(), pa.uint8())
144
152
 
153
+ assert_conversion(Float64(), pa.float64())
154
+ assert_conversion(Float32(), pa.float32())
155
+
156
+ assert_conversion(Decimal(), pa.decimal128(31, 11))
157
+ assert_conversion(Decimal(76), pa.decimal256(76, 76 // 3 + 1))
158
+ assert_conversion(Decimal(15), pa.decimal64(15, 6))
159
+ assert_conversion(Decimal(18, 2), pa.decimal64(18, 2))
160
+ assert_conversion(Decimal(9, 9), pa.decimal32(9, 9))
161
+
145
162
  assert_conversion(String(), pd.StringDtype(storage="pyarrow"))
163
+ assert_conversion(String(10), pd.StringDtype(storage="pyarrow"))
146
164
  assert_conversion(Bool(), pa.bool_())
147
165
 
148
166
  assert_conversion(Date(), pa.date32())
@@ -111,7 +111,7 @@ def test_all_types(type_):
111
111
  if type_ is pdc.List:
112
112
  type_obj = type_(pdc.Int64())
113
113
  elif type_ is pdc.Enum:
114
- type_obj = type_("a", "b", "c")
114
+ type_obj = type_("a", "bbb", "cc")
115
115
  else:
116
116
  type_obj = type_()
117
117
  dst_type = type_obj.to_sql()
@@ -129,6 +129,6 @@ def test_all_types(type_):
129
129
  Float: Float64(),
130
130
  Int: Int64(),
131
131
  # there is no Enum
132
- Enum: String(),
132
+ Enum: String(3),
133
133
  }
134
134
  assert back_type == acceptance_map.get(type_, type_obj)