apache / apache/iceberg-python

Expression constructors are not mypy-compatible without the pydantic plugin

Abierto
#3,101 1 comentario 0 reacciones 0 asignados Ver en GitHub
Lenguaje dominante
Python
Estrellas
1.1k
Forks
581
Merge medio
1 d 17 h
PR fusionados (30 d)
78

Descripción

Constructing expression predicates like `EqualTo("col", value)` produces mypy errors because the Pydantic model field declarations use `UnboundTerm` as the type for `term`, and without the pydantic mypy plugin active, mypy generates `__init__` signatures from the field types rather than from the explicit `__init__` overrides.

**Example:**

```python
from pyiceberg import expressions as ice

expr = ice.EqualTo("my_column", 42)
```

**mypy output (v1.19.1, pyiceberg 0.11.0, no pydantic mypy plugin):**

```
error: Argument 1 to "EqualTo" has incompatible type "str"; expected "UnboundTerm" [arg-type]
```

**Root cause:**

The base classes define explicit `__init__` methods that accept `str | UnboundTerm`:

- [`UnboundPredicate.__init__`](https://github.com/apache/iceberg-python/blob/main/pyiceberg/expressions/__init__.py#L500): `def __init__(self, term: str | UnboundTerm, **kwargs: Any) -> None`
- [`LiteralPredicate.__init__`](https://github.com/apache/iceberg-python/blob/main/pyiceberg/expressions/__init__.py#L864): `def __init__(self, term: str | UnboundTerm, literal: Any | None = None, **kwargs: Any) -> None`
- [`UnaryPredicate.__init__`](https://github.com/apache/iceberg-python/blob/main/pyiceberg/expressions/__init__.py#L520): `def __init__(self, term: str | UnboundTerm, **_: Any) -> None`

But since these classes extend `IcebergBaseModel` (Pydantic `BaseModel`), mypy ignores the explicit `__init__` and instead generates the constructor signature from the field declaration `term: UnboundTerm`, which does not include `str`.

This affects all predicate constructors: `EqualTo`, `NotEqualTo`, `GreaterThan`, `GreaterThanOrEqual`, `LessThan`, `LessThanOrEqual`, `IsNull`, `NotNull`, `IsNaN`, `NotNaN`, `In`, `NotIn`, `StartsWith`, `NotStartsWith`.

**Workaround:**

Downstream projects can either enable the pydantic mypy plugin or suppress type checking for the affected call sites.

**Possible fix:**

Widen the field type annotation on `UnboundPredicate` from `term: UnboundTerm` to `term: str | UnboundTerm` with a validator that coerces `str` to `UnboundTerm`. This way the type seen by mypy (from the field declaration) matches what the constructor actually accepts at runtime, regardless of whether the pydantic mypy plugin is enabled.

Guía de contribución

No hay ninguna guía de contribución indexada para este repositorio

Línea de trabajo

Start in pyiceberg/expressions/__init__.py at the UnboundPredicate, LiteralPredicate, and UnaryPredicate constructors and their term field declarations. Check the existing validator behavior, then verify that mypy without the Pydantic plugin accepts the listed predicate constructors and that string terms are still coerced correctly at runtime.

Escrito por el modelo de indexación a partir del texto del issue.

Evaluación

Stack tecnológico
python
Área
developer-experience
Tipo de issue
Error
Dificultad
3/5
Tiempo estimado
1-2 días
Estado de actividad
Tranquilo
Claridad
Bastante claro
Aptitud para principiantes
65/100

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.