2026TypeScript · VS Code Extension API · tree-sitter · hyparquet · esbuild

PolarSense

Extension VS Code. Visualisez les lignes de vos fichiers de données, les statistiques et les graphiques de leurs colonnes + complétion des noms de colonnes, détection des fautes de frappe et statistiques au survol pour polars, pandas et duckdb.

Le problème

L'autocomplétion s'arrête au guillemet.

Vous écrivez une requête polars, vous allez chercher une colonne, et l'éditeur n'a rien à dire — parce que les noms de colonnes sont des chaînes de caractères, et qu'aucun vérificateur de types ne voit à l'intérieur d'une chaîne. Alors vous basculez sur un terminal, vous affichez le schéma, vous y lisez un nom, vous revenez, vous le tapez, vous vous trompez d'une lettre, et vous l'apprenez à l'exécution, après un scan que vous avez payé. Dix fois par heure, sur un fichier dont vous connaissez les colonnes à moitié.

La solution évidente est d'exécuter le code. Démarrer un noyau, importer polars, exécuter assez du script pour avoir un vrai DataFrame en mémoire, et l'interroger. Toutes les réponses existantes à ce problème fonctionnent ainsi, et je l'ai écartée.

Ce que j'ai choisi

Le schéma est déjà posé sur le disque. Le pied de page d'un fichier parquet l'enregistre. La ligne d'en-tête d'un CSV aussi, comme le flatbuffer de schéma d'un Arrow IPC, le journal de commits d'un Delta, le pointeur de métadonnées d'un Iceberg, la ligne d'en-tête à l'intérieur du zip d'un .xlsx. PolarSense ouvre le fichier dont votre frame provient réellement, lit ça, et propose les noms.

Il n'importe jamais polars, ne lance jamais d'interpréteur Python, n'exécute jamais une ligne de votre code. Pour le parquet, toute la lecture tient en deux plages d'octets du pied de page, si bien qu'un fichier de quatre millions de lignes coûte exactement ce que coûte un fichier de deux cents. Les schémas sont lus à l'ouverture du fichier plutôt qu'à la première demande, et mis en cache sur le mtime et la taille : la première complétion est déjà un succès de cache.

L'autre moitié du travail consiste à savoir de quel fichier vient le frame sous votre curseur, et quelle forme il a une fois arrivé là. Les affectations sont suivies à travers le fichier ; une chaîne de méthodes est suivie ; un select restreint, un rename renomme, un join propose les deux côtés avec les collisions suffixées, un group_by().agg() rend les clés plus les agrégats, un unnest met les champs d'un struct à sa place. Les chemins n'ont pas besoin d'être littéraux — constantes de module, f-strings, os.path.join, Path(__file__).parent / "sales.parquet" se réduisent d'abord à un chemin. Les imports sont suivis sur deux sauts dans le workspace, donc une fonction de chargement écrite dans un autre fichier se résout quand même.

Ce que j'ai écarté

Exécuter le code. C'est la bonne réponse pour les cas que la lecture statique n'atteint pas, et cela veut dire une extension d'éditeur qui exécute le script d'un dépôt inconnu à l'instant où vous l'ouvrez. Effets de bord, identifiants, un DROP TABLE dans un script de migration, et un démarrage à froid que vous sentez à chaque frappe. Une autocomplétion ne vaut pas ça, et « lit des octets, n'exécute rien » est tout le produit.

Indexer le workspace en arrière-plan. Écarté pour la raison qui rend désagréable un linter parcourant site-packages : seuls les modules que votre fichier ouvert importe réellement sont lus, et rien ne tourne tant que vous ne demandez rien.

Deviner. C'était le point difficile, et il ressort à quatre endroits. L'avertissement de colonne inconnue reste totalement muet dès que quelque chose, entre le fichier et le curseur, n'a pas pu être modélisé — un sélecteur illisible, un remodelage non modélisé, un fichier impossible à ouvrir — parce qu'un diagnostic qui crie au loup se fait désactiver et ne se réactive jamais. La complétion de valeurs ne propose plus rien du tout au-delà de cinquante valeurs distinctes, plutôt qu'une liste tronquée, parce que cent identifiants de commande sur quatre millions sont une affirmation sur leur nombre, et une affirmation fausse. Une lecture qui n'a pas couvert toutes les lignes le dit sur chaque élément. Et pyarrow n'est pas supporté du tout : read_table veut dire parquet chez pyarrow et CSV chez pandas, et les distinguer suppose de savoir de quel module vient l'appel.

Ce que ça a coûté

Certains remodelages ne peuvent pas être résolus sans lire des lignes. pivot, to_dummies et un transpose sans noms explicites tirent leurs colonnes de sortie des valeurs du fichier plutôt que de quoi que ce soit d'écrit dans le code. L'extension garde les colonnes qu'elle avait, les classe sous les réponses certaines, et les marque comme une supposition.

Le SQL est scanné, pas parsé — littéraux et commentaires masqués, puis ce qui suit FROM et JOIN est une table. Du coup chaque table d'une requête est visible partout dans celle-ci, une jointure propose les deux côtés marqués incertains, et les positions SQL ne sont jamais vérifiées contre les fautes de frappe.

Le compromis qui m'agace encore, ce sont les panneaux d'aperçu. Ils décrivent le fichier, pas le frame : les colonnes sont correctement restreintes par tout ce qui se trouve sur le chemin de votre curseur, mais le nombre de lignes, la taille et le codec appartiennent au fichier derrière, et un filter n'y change rien. Ils affichent transforms not applied plutôt que de montrer quatre millions de lignes en les appelant le frame. Combler cet écart suppose d'exécuter votre code — ce que le panneau de graphe fait désormais, dans un notebook avec un noyau vivant, sur activation explicite, en lecture seule, et en demandant le consentement la première fois. C'est le seul endroit où la règle du zéro exécution est enfreinte. Elle l'est délibérément, dans une seule fonctionnalité, derrière un réglage, et dite à voix haute plutôt que généralisée en silence.

Le résultat

Publié sur le Marketplace VS Code. Le nombre d'installations ne vaut pas encore la peine d'être cité, alors voici ceux qui sont honnêtes : sept formats de fichiers lus, une quarantaine de points de complétion à travers polars, pandas et duckdb, une extension packagée d'environ 200 kB ne transportant aucun node_modules, aucune télémétrie, et rien qui quitte la machine hormis des plages d'octets des fichiers que vous lui désignez.

← Tous les projets