apache / apache/iceberg-python

Expression constructors are not mypy-compatible without the pydantic plugin

Ouverte
#3,101 1 commentaire 0 réactions 0 personnes assignées Voir sur GitHub
Langage dominant
Python
Étoiles
1.1k
Forks
581
Merge moyen
1 j 17 h
PR mergées (30 j)
78

Description

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.

Guide de contribution

Aucun guide de contribution indexé pour ce dépôt

Piste de recherche

Commencez dans pyiceberg/expressions/__init__.py par les constructeurs de UnboundPredicate, LiteralPredicate et UnaryPredicate, ainsi que par les déclarations de leur champ term. Vérifiez le comportement actuel du validateur, puis vérifiez que mypy sans le plugin Pydantic accepte les constructeurs de prédicats indiqués et que les termes de type string sont toujours correctement convertis à l’exécution.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
python
Domaine
developer-experience
Type d'issue
Bug
Difficulté
3/5
Temps estimé
1-2 jours
Activité
Calme
Clarté
Plutôt claire
Accessibilité débutants
65/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.