Mise en place du moteur de streaming

Le candidat‑release 2.0 bascule le collect des LazyFrame vers le moteur de streaming. Selon l’annonce, ce moteur fournit jusqu’à 5 fois plus de vitesse sur la plupart des requêtes et réduit fortement l’empreinte mémoire, car les données sont traitées en flux plutôt qu’en bloc. Cette amélioration justifie le passage à une version majeure, même si aucune nouvelle fonctionnalité visible n’est ajoutée.

Le changement implique que l’ordre des lignes n’est plus garanti pour les opérations join, group_by ou unpivot. Les utilisateurs peuvent rétablir un ordre observable en activant maintain_order=True. Le code suivant montre le comportement par défaut et l’option d’ordre :

lf = pl.LazyFrame({"k": [2, 1, 0], "v": ["a", "b", "c"]})
other = pl.LazyFrame({"k": [0, 1, 2], "r": ["x", "y", "z"]})
(
    lf.join(other, on="k", how="left").collect()
)  # ordre non garanti
(
    lf.join(other, on="k", how="left", maintain_order="left").collect()
)  # ordre conservé

Pour les projets qui préfèrent l’ancien moteur « in‑memory », Polars propose une affinité d’engin configurable globalement ou par requête :

pl.Config.set_engine_affinity("in-memory")
# ou
lf.join(other, on="k").collect(engine="in-memory")

Nouveaux comportements stricts

Polars 2.0 renforce la détection précoce des incohérences. L’opération is_in ne réalise plus de conversion de type implicite qui pouvait masquer des erreurs de précision. Exemple : un Int64 comparé à une liste Float64 dépasse la précision exacte de Float64 (2^53) et était auparavant arrondi, créant un faux positif. En 2.0, la même expression lève une InvalidOperationError :

flagged_ids = pl.Series([9007199254740992.0])
user_id = pl.Series([9007199254740993])
user_id.is_in(flagged_ids)
# → InvalidOperationError: 'is_in' cannot check for Int64 values in List(Float64) data.

La concaténation horizontale devient également stricte : si les DataFrames n’ont pas la même hauteur, Polars lève une ShapeError au lieu de remplir les lignes manquantes avec des valeurs nulles. Cette règle oblige le développeur à choisir explicitement how="horizontal_extend" lorsqu’un remplissage est souhaité.

transactions = pl.DataFrame({"day": [1,2,3,4,5], "count": [120,98,143,87,156]})
fraud_flags = pl.DataFrame({"flagged": [2,0,5,1]})
pl.concat([transactions, fraud_flags], how="horizontal")
# → ShapeError: cannot concat dataframes with different heights in 'strict' mode

Par ailleurs, de nombreuses conversions ambiguës ont été retirées. Les transformations entre entiers et catégories utilisent désormais les méthodes .cat.to() et .cat.physical(), tandis que la conversion de chaînes en dates s’effectue via .str.to_date() ou .str.to_datetime(), offrant un contrôle explicite du format.

Gestion des erreurs et migration

Pour faciliter la transition, Polars introduit deux nouvelles exceptions typées : AttributeRemovedError et ArgumentRemovedError. Elles indiquent clairement quels attributs ou arguments ont disparu et suggèrent l’API de remplacement. Exemple :

>> lf.melt(id_vars="a", value_vars="b")
polars.exceptions.AttributeRemovedError: `melt` was removed in version 2.0; use `LazyFrame.unpivot` instead
>>> df.join(df, on="a", join_nulls=True)
polars.exceptions.ArgumentRemovedError: the argument 'join_nulls' was renamed to 'nulls_equal' in version 2.0

Ces messages, combinés au guide de migration publié par l’équipe, permettent aux pipelines existants de détecter rapidement les incompatibilités et d’ajuster le code sans exécution complète. L’ensemble des changements vise à rendre Polars plus prévisible, surtout dans les environnements automatisés où les agents IA valident les requêtes à la compilation.