① Scène et choix d’outil : pip, uv, conda — quand privilégier uv
Sur un runner macOS partagé, le goulot est souvent le volume HTTP (latence, pertes, proxies) multiplié par des centaines de petits fichiers metadata et quelques archives lourdes. Il faut donc arbitrer entre vitesse de résolution, parallélisme contrôlé, politique de cache et culture de verrouillage des versions.
| Outil | Cas favorables | Limite typique en CI Mac distant |
|---|---|---|
| pip | Scripts simples, pas de lockfile imposé | Peu de leviers natifs sur le parallélisme et le cache unifié ; tirages massifs plus fragiles sur WAN |
| uv | Projets pyproject, uv.lock, ou coexistence avec uv pip pour d’anciens requirements.txt |
Variables explicites (concurrence, timeouts, retries, cache) et outils de sync figés |
| conda / mamba | Stacks scientifiques hors PyPI, binaires channel | Images plus lourdes, gouvernance des miroirs et des channels plus coûteuse |
Règle pratique 2026 : si l’essentiel vient de PyPI et que vous voulez des installs reproductibles sur Apple Silicon, commencez par uv. Les équipes déjà stabilisées sur conda pour leurs binaires spécifiques peuvent garder conda pour ces couches et n’utiliser uv que pour les paquets PyPI périphériques, mais évitez deux mondes sans documentation des frontières.
② Matrice de paramètres exécutables : concurrence, timeouts, retries, cache, index
Sur liaison transfrontalière, augmentez d’abord timeouts et retries, puis ajustez la concurrence : trop de flux parallèles sur un proxy saturé déclenche des tempêtes de nouvelles tentatives collectivement pires qu’un débit modéré.
| Objectif | Variable | Point de départ indicatif |
|---|---|---|
| Téléchargements parallèles | UV_CONCURRENT_DOWNLOADS | WAN instable : 4 ; LAN / miroir proche : 8–16 |
| Timeout lecture HTTP (s) | UV_HTTP_TIMEOUT | 120–300 si wheels > quelques centaines de Mo |
| Timeout connexion TCP (s) | UV_HTTP_CONNECT_TIMEOUT | 30–60 |
| Nombre de retries HTTP | UV_HTTP_RETRIES | 5–8 |
| Répertoire de cache isolé | UV_CACHE_DIR | Ex. $HOME/.cache/uv-ci-${CI_PIPELINE_ID:-local} |
| Index simple par défaut | UV_DEFAULT_INDEX ou UV_INDEX_URL | Amont : https://pypi.org/simple ; remplacez par votre miroir d’org ou géographique |
| Index supplémentaires | UV_INDEX (espaces) | Ajoutez l’URL …/simple privée ; croisez avec UV_INDEX_STRATEGY seulement si le risque supply-chain est accepté |
En changeant de miroir, ne réutilisez pas le même UV_CACHE_DIR sans purge : les métadonnées « simple » peuvent ne plus correspondre aux blobs en cache.
③ Réseau transfrontalier : modes d’échec et dépannage (TLS, certificats, proxy)
- Échec TLS / certificat inconnu : importez la chaîne d’entreprise dans le trousseau macOS ou pointez
SSL_CERT_FILE/SSL_CERT_DIRvers un bundle PEM. Selon la version d’uv, testezUV_NATIVE_TLS=true(TLS via le stack système) ou les options documentées équivalentes pour forcer les certificats plateforme. - Sortie obligatoire via proxy :
HTTPS_PROXY,HTTP_PROXY; excluez les index internes avecNO_PROXY. Si le proxy ferme les connexions idle plus vite queUV_HTTP_TIMEOUT, réglez d’abord le proxy ou baissez la concurrence. - Réinitialisations TCP intermittentes : diminuez
UV_CONCURRENT_DOWNLOADS, augmentezUV_HTTP_RETRIES, encapsulezuv syncdans une boucle de retry au niveau orchestrateur avec backoff et jitter.
Pour la même problématique sur Git et images OCI, voir les guides anglais (sans login) : Git & Docker pull acceleration et Remote Mac cache strategy: Git & npm CI, ainsi que le miroir Git / npm / Homebrew transfrontalier sur la version française.
④ Cohérence pyproject / requirements.lock et étapes CI reproductibles
- Exécutez
uv locklors des changements de dépendances et versionnezuv.lock. - En CI :
uv sync --frozen(ou--lockedselon votre politique) pour interdire toute réécriture silencieuse du lock pendant le job. - Flux
requirements.txt: générezrequirements.lockavecuv pip compile … --generate-hashes; en installation,uv pip sync requirements.locketUV_REQUIRE_HASHESsi le fichier impose des hashes. - Clé de cache CI : commit + hash de
uv.lock+ hôte deUV_DEFAULT_INDEX+ version mineure de Python.
Une merge request qui modifie des dépendances sans mettre à jour le lock doit faire échouer le pipeline tôt : le Mac distant ne doit pas passer dix minutes à télécharger avant d’apprendre que la résolution ne correspond plus au dépôt.
⑤ FAQ : pollution de cache, wheels plateforme, index privé
Cache : un répertoire partagé entre jobs concurrents sans convention, ou la réutilisation du même cache après bascule de miroir, produit des métadonnées incohérentes. Préfixez par identifiant de pipeline ou de tenant et planifiez uv cache prune dans une fenêtre de maintenance.
Wheels et architecture : un lock généré sur x86_64 ne garantit pas les mêmes artefacts sur arm64 Apple Silicon. Fixez UV_PYTHON au même chemin qu’en production ou générez le lock sur un runner représentatif.
Index multiples : tenez UV_DEFAULT_INDEX pour la voie principale et ajoutez l’index privé via UV_INDEX. Toute stratégie « meilleure correspondance » entre index doit être explicitement approuvée en revue de sécurité.
En résumé : sur Mac distant, stabilisez d’abord timeouts et retries, puis réglez la concurrence ; isolez UV_CACHE_DIR ; figez les dépendances avec uv lock et uv sync --frozen. Pour monter un runner homogène Apple Silicon avec bande passante prévisible, parcourez les pages sans connexion obligatoire : tarifs, achat, centre d’aide. Approfondissement en anglais : accélération Git & Docker.
Même stack locale, même wheel — côté CI
MacPull propose des nœuds Mac mini cloud pour exécuter vos installs uv proches de vos utilisateurs finaux. Comparez les forfaits, lisez l’aide et enchaînez avec les guides anglais sur les tirages Git / Docker — le tout accessible sans compte.