Skip to content

Commit

Permalink
chore: fixes for python 3.9 (all tests passing)
Browse files Browse the repository at this point in the history
chore(patito): cleanup
  • Loading branch information
brendancooley committed Feb 8, 2024
1 parent 327e9fd commit 008d28d
Show file tree
Hide file tree
Showing 8 changed files with 29 additions and 24 deletions.
2 changes: 1 addition & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src/patito/_pydantic/column_info.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

import json
from typing import (
Any,
Expand Down
4 changes: 3 additions & 1 deletion src/patito/_pydantic/dtypes/dtypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@


@cache
def valid_dtypes_for_model(cls: Type[ModelType]) -> Mapping[str, FrozenSet[DataTypeClass]]:
def valid_dtypes_for_model(
cls: Type[ModelType],
) -> Mapping[str, FrozenSet[DataTypeClass]]:
return {
column: DtypeResolver(cls.model_fields[column].annotation).valid_polars_dtypes()
if cls.column_infos[column].dtype is None
Expand Down
17 changes: 9 additions & 8 deletions src/patito/polars.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,25 @@
TYPE_CHECKING,
Any,
Collection,
Dict,
Generic,
Iterable,
Optional,
Sequence,
Tuple,
Type,
TypeVar,
Union,
cast,
Dict,
Sequence,
Mapping,
Tuple
)

import polars as pl
from polars.type_aliases import IntoExpr
from pydantic import AliasChoices, AliasPath, create_model
from typing_extensions import Literal

from patito.exceptions import MultipleRowsReturned, RowDoesNotExist
from patito._pydantic.column_info import ColumnInfo
from patito.exceptions import MultipleRowsReturned, RowDoesNotExist

if TYPE_CHECKING:
import numpy as np
Expand Down Expand Up @@ -360,7 +359,9 @@ def unalias(self: DF) -> DF:
"""
return self.lazy().unalias().collect()

def cast(self: DF, strict: bool = False, columns: Optional[Sequence[str]] = None) -> DF:
def cast(
self: DF, strict: bool = False, columns: Optional[Sequence[str]] = None
) -> DF:
"""
Cast columns to `dtypes` specified by the associated Patito model.
Expand Down Expand Up @@ -568,7 +569,7 @@ def fill_null(
provided ``strategy`` parameter.
Example:
>>> import bla_aloo as pt
>>> import patito as pt
>>> class Product(pt.Model):
... name: str
... price: int = 19
Expand Down Expand Up @@ -712,7 +713,7 @@ def _pydantic_model(self) -> Type[Model]:
**pydantic_annotations, # pyright: ignore
),
)

def as_polars(self) -> pl.DataFrame:
return pl.DataFrame._from_pydf(self._df)

Expand Down
15 changes: 7 additions & 8 deletions src/patito/pydantic.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import itertools
from collections.abc import Iterable
from datetime import date, datetime, time, timedelta
from functools import partial
from inspect import getfullargspec
from typing import (
TYPE_CHECKING,
Any,
Expand All @@ -23,9 +25,6 @@
cast,
get_args,
)
from inspect import getfullargspec
from functools import partial


import polars as pl
from polars.datatypes import DataType, DataTypeClass
Expand Down Expand Up @@ -131,7 +130,7 @@ def columns(cls: Type[ModelType]) -> List[str]: # type: ignore
List of column names.
Example:
>>> import bla_aloo as pt
>>> import patito as pt
>>> class Product(pt.Model):
... name: str
... price: int
Expand Down Expand Up @@ -212,7 +211,7 @@ def defaults( # type: ignore
Example:
>>> from typing_extensions import Literal
>>> import bla_aloo as pt
>>> import patito as pt
>>> class Product(pt.Model):
... name: str
... price: int = 0
Expand Down Expand Up @@ -441,7 +440,6 @@ def _from_polars(
else:
return cls.model_construct(**dataframe.to_dicts()[0])


@classmethod
def validate(
cls,
Expand All @@ -462,7 +460,7 @@ def validate(
the given schema.
Examples:
>>> import bla_aloo as pt
>>> import patito as pt
>>> import polars as pl
Expand Down Expand Up @@ -493,7 +491,6 @@ def validate(
"""
validate(dataframe=dataframe, columns=columns, schema=cls, **kwargs)


@classmethod
def example_value( # noqa: C901
cls,
Expand Down Expand Up @@ -1237,8 +1234,10 @@ def _derive_field(
field_new.metadata = field.metadata
return field_type, field_new


FIELD_KWARGS = getfullargspec(fields.Field)


def FieldCI(
column_info: CI, *args: Any, **kwargs: Any
) -> Any: # annotate with Any to make the downstream type annotations happy
Expand Down
1 change: 1 addition & 0 deletions tests/test_dummy_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ class UniqueModel(pt.Model):

def test_enum_field_example_values() -> None:
"""It should produce correct example values for enums."""

class DefaultEnumModel(pt.Model):
row_number: int
# Here the first value will be used as the example value
Expand Down
4 changes: 1 addition & 3 deletions tests/test_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import enum
import re
from datetime import date, datetime, time
from typing import ClassVar, Optional, Type
from typing import Optional, Type

import patito as pt
import polars as pl
Expand All @@ -14,7 +14,6 @@
DATE_DTYPES,
TIME_DTYPES,
)
from patito.pydantic import ColumnInfo, FieldCI, ModelMetaclass
from polars.datatypes import DataTypeGroup
from polars.datatypes.constants import (
DATETIME_DTYPES,
Expand All @@ -23,7 +22,6 @@
INTEGER_DTYPES,
)
from pydantic import AliasChoices, AwareDatetime, ValidationError
from pydantic import Field as PdField

from tests.examples import CompleteModel, ManyTypes, SmallModel

Expand Down
8 changes: 5 additions & 3 deletions tests/test_polars.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,13 @@ def test_create_missing_columns_with_defaults() -> None:

class NestedModel(pt.Model):
foo: int = 2
small_model: SmallModel | None = None
small_model: Optional[SmallModel] = None

class DefaultModel(pt.Model):
foo: int = 2
bar: Optional[str] = "default"
small_model: SmallModel | None = None # works ok on polars==0.20.3
nested_model: NestedModel | None = None # fails to convert on polars==0.20.3
small_model: Optional[SmallModel] = None # works ok on polars==0.20.3
nested_model: Optional[NestedModel] = None # fails to convert on polars==0.20.3

missing_df = pt.DataFrame({"foo": [1, 2]})
filled_df = missing_df.set_model(DefaultModel).fill_null(strategy="defaults")
Expand Down Expand Up @@ -389,6 +389,7 @@ class Model(pt.Model):
# Or a list of columns
assert df.drop(["column_1", "column_2"]).columns == []


def test_polars_conversion():
"""You should be able to convert a DataFrame to a polars DataFrame."""

Expand All @@ -404,6 +405,7 @@ class Model(pt.Model):
assert polars_df.columns == ["a", "b"]
assert polars_df.dtypes == [pl.Int64, pl.Utf8]


def test_validation_alias() -> None:
class AliasModel(pt.Model):
my_val_a: int = pt.Field(validation_alias="myValA")
Expand Down

0 comments on commit 008d28d

Please sign in to comment.