Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ jobs:
matrix:
os: [ubuntu-latest, windows-latest]
environment: [py310, py311, py312, py313]
with_optionals: [false]
include:
- os: ubuntu-latest
environment: py313-optionals
with_optionals: true
- os: windows-latest
environment: py313-optionals
with_optionals: true
steps:
- name: Checkout branch
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
Expand All @@ -51,7 +59,7 @@ jobs:
- name: Install repository
run: pixi run -e ${{ matrix.environment }} postinstall
- name: Run pytest
run: pixi run -e ${{ matrix.environment }} test-coverage --color=yes
run: pixi run -e ${{ matrix.environment }} test-coverage --color=yes ${{ matrix.with_optionals && '-m with_optionals' || '-m "not with_optionals"'}} --cov=dataframely --cov-report=xml
- name: Upload codecov
uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5.4.3
with:
Expand Down
19 changes: 18 additions & 1 deletion dataframely/_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ def __getattr__(self, name: str) -> Any:
try:
import sqlalchemy as sa
import sqlalchemy.dialects.mssql as sa_mssql
from sqlalchemy import Dialect
from sqlalchemy.dialects.mssql.pyodbc import MSDialect_pyodbc
from sqlalchemy.dialects.postgresql.psycopg2 import PGDialect_psycopg2
from sqlalchemy.sql.type_api import TypeEngine as sa_TypeEngine
except ImportError: # pragma: no cover
sa = _DummyModule("sqlalchemy") # type: ignore
Expand All @@ -26,7 +29,14 @@ def __getattr__(self, name: str) -> Any:
class sa_TypeEngine: # type: ignore # noqa: N801
pass

class MSDialect_pyodbc: # type: ignore # noqa: N801
pass

class PGDialect_psycopg2: # type: ignore # noqa: N801
pass

class Dialect: # type: ignore # noqa: N801
pass
# -------------------------------------- PYARROW ------------------------------------- #

try:
Expand All @@ -36,4 +46,11 @@ class sa_TypeEngine: # type: ignore # noqa: N801

# ------------------------------------------------------------------------------------ #

__all__ = ["sa", "sa_mssql", "sa_TypeEngine", "pa"]
__all__ = [
"sa",
"sa_mssql",
"sa_TypeEngine",
"pa",
"MSDialect_pyodbc",
"PGDialect_psycopg2",
]
3,908 changes: 1,488 additions & 2,420 deletions pixi.lock

Large diffs are not rendered by default.

8 changes: 6 additions & 2 deletions pixi.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,18 @@ readthedocs = "rm -rf $READTHEDOCS_OUTPUT/html && cp -r docs/_build/html $READTH
mypy = ">=1.13"
pandas = "*"
pandas-stubs = "*"
pyarrow = "*"
pyodbc = "*"
pytest = ">=6"
pytest-benchmark = "*"
pytest-cov = "*"
pytest-md = "*"
scikit-learn = "*"

[feature.optionals.dependencies]
pyarrow = "*"
sqlalchemy = ">=2"


[feature.test.tasks]
test = "pytest"
test-bench = "pytest tests/benches --benchmark-only --benchmark-sort mean --benchmark-columns min,max,mean,rounds"
Expand Down Expand Up @@ -102,11 +105,12 @@ install-polars-nightly = "pip install --pre --no-deps --upgrade --only-binary :a

[environments]
build = ["build"]
default = ["dev", "lint", "test"]
default = ["dev", "lint", "test", "optionals"]
docs = ["docs"]
lint = { features = ["lint"], no-default-feature = true }
nightly = ["nightly", "test"]
py310 = ["py310", "test"]
py311 = ["py311", "test"]
py312 = ["py312", "test"]
py313 = ["py313", "test"]
py313-optionals = ["py313", "test", "optionals"]
7 changes: 7 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ readme = "README.md"
requires-python = ">=3.10"
version = "0.0.0"

[project.optional-dependencies]
sqlalchemy = ["sqlalchemy"]
pyarrow = ["pyarrow"]

[project.urls]
Documentation = "https://dataframely.readthedocs.io/"
Repository = "https://github.com/quantco/dataframely"
Expand Down Expand Up @@ -94,6 +98,9 @@ filterwarnings = [
"ignore:The 'nullable' argument was not explicitly set:FutureWarning",
]
testpaths = ["tests"]
markers = [
"with_optionals: Tests that require optional dependencies to be installed",
]

[tool.coverage.run]
omit = ["dataframely/mypy.py", "dataframely/testing/generate.py"]
2 changes: 2 additions & 0 deletions tests/columns/test_pyarrow.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
create_schema,
)

pytestmark = pytest.mark.with_optionals


@pytest.mark.parametrize("column_type", ALL_COLUMN_TYPES)
def test_equal_to_polars_schema(column_type: type[Column]) -> None:
Expand Down
20 changes: 10 additions & 10 deletions tests/columns/test_sql_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
# SPDX-License-Identifier: BSD-3-Clause

import pytest
import sqlalchemy as sa
from sqlalchemy.dialects.mssql.pyodbc import MSDialect_pyodbc
from sqlalchemy.dialects.postgresql.psycopg2 import PGDialect_psycopg2

import dataframely as dy
from dataframely._compat import Dialect, MSDialect_pyodbc, PGDialect_psycopg2
from dataframely.columns import Column
from dataframely.testing import COLUMN_TYPES, create_schema

pytestmark = pytest.mark.with_optionals


@pytest.mark.parametrize(
("column", "datatype"),
Expand Down Expand Up @@ -107,7 +107,7 @@ def test_postgres_datatype(column: Column, datatype: str) -> None:
@pytest.mark.parametrize("nullable", [True, False])
@pytest.mark.parametrize("dialect", [MSDialect_pyodbc()])
def test_sql_nullability(
column_type: type[Column], nullable: bool, dialect: sa.Dialect
column_type: type[Column], nullable: bool, dialect: Dialect
) -> None:
schema = create_schema("test", {"a": column_type(nullable=nullable)})
columns = schema.sql_schema(dialect)
Expand All @@ -119,7 +119,7 @@ def test_sql_nullability(
@pytest.mark.parametrize("primary_key", [True, False])
@pytest.mark.parametrize("dialect", [MSDialect_pyodbc(), PGDialect_psycopg2()])
def test_sql_primary_key(
column_type: type[Column], primary_key: bool, dialect: sa.Dialect
column_type: type[Column], primary_key: bool, dialect: Dialect
) -> None:
schema = create_schema("test", {"a": column_type(primary_key=primary_key)})
columns = schema.sql_schema(dialect)
Expand All @@ -129,37 +129,37 @@ def test_sql_primary_key(


@pytest.mark.parametrize("dialect", [MSDialect_pyodbc(), PGDialect_psycopg2()])
def test_sql_multiple_columns(dialect: sa.Dialect) -> None:
def test_sql_multiple_columns(dialect: Dialect) -> None:
schema = create_schema("test", {"a": dy.Int32(nullable=False), "b": dy.Integer()})
assert len(schema.sql_schema(dialect)) == 2


@pytest.mark.parametrize("dialect", [MSDialect_pyodbc(), PGDialect_psycopg2()])
def test_raise_for_list_column(dialect: sa.Dialect) -> None:
def test_raise_for_list_column(dialect: Dialect) -> None:
with pytest.raises(
NotImplementedError, match="SQL column cannot have 'List' type."
):
dy.List(dy.String()).sqlalchemy_dtype(dialect)


@pytest.mark.parametrize("dialect", [MSDialect_pyodbc(), PGDialect_psycopg2()])
def test_raise_for_array_column(dialect: sa.Dialect) -> None:
def test_raise_for_array_column(dialect: Dialect) -> None:
with pytest.raises(
NotImplementedError, match="SQL column cannot have 'Array' type."
):
dy.Array(dy.String(), 1).sqlalchemy_dtype(dialect)


@pytest.mark.parametrize("dialect", [MSDialect_pyodbc(), PGDialect_psycopg2()])
def test_raise_for_struct_column(dialect: sa.Dialect) -> None:
def test_raise_for_struct_column(dialect: Dialect) -> None:
with pytest.raises(
NotImplementedError, match="SQL column cannot have 'Struct' type."
):
dy.Struct({"a": dy.String()}).sqlalchemy_dtype(dialect)


@pytest.mark.parametrize("dialect", [MSDialect_pyodbc(), PGDialect_psycopg2()])
def test_raise_for_object_column(dialect: sa.Dialect) -> None:
def test_raise_for_object_column(dialect: Dialect) -> None:
with pytest.raises(
NotImplementedError, match="SQL column cannot have 'Object' type."
):
Expand Down
Loading