fix(backup): nettoyer le fichier temporaire en cas d'erreur dans restore (#89)

Wraps temp file operations in try/except to ensure the temporary database file is always cleaned up, even if an exception occurs during write_snapshot or verify_integrity.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Colin Maudry
2026-06-24 17:21:28 +02:00
parent cae0a528f3
commit ded5e66ccc
22 changed files with 6767 additions and 10 deletions
+16
View File
@@ -0,0 +1,16 @@
# CodeGraph data files
# These are local to each machine and should not be committed
# Database
*.db
*.db-wal
*.db-shm
# Cache
cache/
# Logs
*.log
# Hook markers
.dirty
+140
View File
@@ -0,0 +1,140 @@
{
"version": 1,
"include": [
"**/*.ts",
"**/*.tsx",
"**/*.js",
"**/*.jsx",
"**/*.py",
"**/*.go",
"**/*.rs",
"**/*.java",
"**/*.c",
"**/*.h",
"**/*.cpp",
"**/*.hpp",
"**/*.cc",
"**/*.cxx",
"**/*.cs",
"**/*.php",
"**/*.rb",
"**/*.swift",
"**/*.kt",
"**/*.kts",
"**/*.dart",
"**/*.svelte",
"**/*.liquid",
"**/*.pas",
"**/*.dpr",
"**/*.dpk",
"**/*.lpr",
"**/*.dfm",
"**/*.fmx"
],
"exclude": [
"**/.git/**",
"**/node_modules/**",
"**/vendor/**",
"**/Pods/**",
"**/dist/**",
"**/build/**",
"**/out/**",
"**/bin/**",
"**/obj/**",
"**/target/**",
"**/*.min.js",
"**/*.bundle.js",
"**/.next/**",
"**/.nuxt/**",
"**/.svelte-kit/**",
"**/.output/**",
"**/.turbo/**",
"**/.cache/**",
"**/.parcel-cache/**",
"**/.vite/**",
"**/.astro/**",
"**/.docusaurus/**",
"**/.gatsby/**",
"**/.webpack/**",
"**/.nx/**",
"**/.yarn/cache/**",
"**/.pnpm-store/**",
"**/storybook-static/**",
"**/.expo/**",
"**/web-build/**",
"**/ios/Pods/**",
"**/ios/build/**",
"**/android/build/**",
"**/android/.gradle/**",
"**/__pycache__/**",
"**/.venv/**",
"**/venv/**",
"**/site-packages/**",
"**/dist-packages/**",
"**/.pytest_cache/**",
"**/.mypy_cache/**",
"**/.ruff_cache/**",
"**/.tox/**",
"**/.nox/**",
"**/*.egg-info/**",
"**/.eggs/**",
"**/go/pkg/mod/**",
"**/target/debug/**",
"**/target/release/**",
"**/.gradle/**",
"**/.m2/**",
"**/generated-sources/**",
"**/.kotlin/**",
"**/.dart_tool/**",
"**/.vs/**",
"**/.nuget/**",
"**/artifacts/**",
"**/publish/**",
"**/cmake-build-*/**",
"**/CMakeFiles/**",
"**/bazel-*/**",
"**/vcpkg_installed/**",
"**/.conan/**",
"**/Debug/**",
"**/Release/**",
"**/x64/**",
"**/.pio/**",
"**/release/**",
"**/*.app/**",
"**/*.asar",
"**/DerivedData/**",
"**/.build/**",
"**/.swiftpm/**",
"**/xcuserdata/**",
"**/Carthage/Build/**",
"**/SourcePackages/**",
"**/__history/**",
"**/__recovery/**",
"**/*.dcu",
"**/.composer/**",
"**/storage/framework/**",
"**/bootstrap/cache/**",
"**/.bundle/**",
"**/tmp/cache/**",
"**/public/assets/**",
"**/public/packs/**",
"**/.yardoc/**",
"**/coverage/**",
"**/htmlcov/**",
"**/.nyc_output/**",
"**/test-results/**",
"**/.coverage/**",
"**/.idea/**",
"**/logs/**",
"**/tmp/**",
"**/temp/**",
"**/_build/**",
"**/docs/_build/**",
"**/site/**"
],
"languages": [],
"frameworks": [],
"maxFileSize": 1048576,
"extractDocstrings": true,
"trackCallSites": true
}
+169
View File
@@ -0,0 +1,169 @@
Arrêté du 22 mars 2019 relatif aux fonctionnalités et exigences minimales des profils d'acheteurs
Dernière mise à jour des données de ce texte : 01 avril 2019
NOR : ECOM1831551A
JORF n°0077 du 31 mars 2019
Le ministre de l'économie et des finances et la ministre des outre-mer,
Vu le règlement n° 910/2014 du Parlement européen et du Conseil du 23 juillet 2014 sur l'identification électronique et les services de confiance pour les transactions électroniques au sein du marché intérieur et abrogeant la directive 1999/93/CE ;
Vu le règlement d'exécution (UE) n° 2016/7 de la Commission européenne du 5 janvier 2016 établissant le formulaire type pour le document unique de marché européen ;
Vu le code de la commande publique, et notamment ses articles R. 2132-2, R. 2132-3, R. 2196-1 et R. 3131-1 ;
Vu la loi n° 2004-575 du 21 juin 2004 pour la confiance dans l'économique numérique ;
Vu l'ordonnance n° 2005-1516 du 8 décembre 2005 relative aux échanges électroniques entre les usagers et les autorités administratives et entre les autorités administratives, notamment ses articles 9, 10, 11 et 12,
Arrêtent :
Article 1
I. - Le profil d'acheteur permet à l'acheteur d'effectuer les actions suivantes :
1° S'identifier et s'authentifier ;
2° Publier des avis d'appel à la concurrence et leurs éventuelles modifications ;
3° Mettre à disposition des documents de la consultation ;
4° Réceptionner et conserver des candidatures y compris si elles se présentent sous la forme du document unique de marché européen électronique constituant un échange de données structurées ;
5° Réceptionner et conserver des offres, y compris hors délais ;
6° Compléter un formulaire nécessaire à la publication des données essentielles prévues par l'arrêté du 22 mars 2019 relatif aux données essentielles dans la commande publique ou importer ces données lorsqu'elles sont disponibles dans un autre système d'information ;
7° Accéder à un service de courrier électronique au sens de l'article 1 de la loi du 21 juin 2004 susvisée ;
8° Accéder à un historique des évènements permettant l'enregistrement et la traçabilité des actions ayant eu lieu sur le profil d'acheteur notamment le retrait et le dépôt de documents ;
9° Répondre aux questions soumises par les entreprises ;
10° Obtenir les documents justificatifs et moyens de preuve lorsque ceux-ci peuvent être directement obtenus auprès d'autres administrations.
II. - Le profil d'acheteurs permet à l'opérateur économique d'effectuer les actions suivantes :
1° S'identifier et s'authentifier ;
2° Connaître les prérequis techniques et les modules d'extension nécessaires pour utiliser le profil d'acheteur ;
3° Accéder à un espace permettant de tester que la configuration du poste de travail utilisé est en adéquation avec les prérequis techniques du profil d'acheteur ;
4° Effectuer une recherche permettant d'accéder notamment aux avis d'appel à la concurrence, aux consultations et aux données essentielles ;
5° Consulter et télécharger en accès gratuit, libre, direct et complet les documents de la consultation, les avis d'appel à la concurrence et leurs éventuelles modifications ;
6° Accéder à un espace permettant de simuler le dépôt de documents ;
7° Déposer une candidature y compris si elle se présente sous la forme du document unique de marché européen électronique constituant un échange de données structurées ;
8° Déposer des offres, y compris les dépôts successifs quand la procédure le requiert et les offres signées électroniquement ;
9° Solliciter une assistance ou consulter un support utilisateur permettant d'apporter des réponses aux problématiques techniques ;
10° Formuler des questions à l'acheteur ;
11° Consulter et télécharger les données essentielles conformément aux dispositions de l'arrêté du 22 mars 2019 relatif aux données essentielles dans la commande publique.
Article 2
I. - Le profil d'acheteur répond aux exigences fixées dans les référentiels généraux de sécurité, d'interopérabilité et d'accessibilité prévues aux articles 9 et 11 de l'ordonnance n° 2005-1516 du 8 décembre 2005 susvisée.
II. - Les fonctionnalités visées à l'article 1er répondent aux exigences techniques, de sécurité et d'accessibilité suivantes :
1° Le profil d'acheteur accepte les fichiers communément disponibles et notamment les fichiers aux formats .XML et .JSON ;
2° La taille et les formats des documents et avis d'appel à la concurrence sont indiqués ;
3° L'horodatage est qualifié conformément aux dispositions du règlement n° 910/2014 du Parlement européen et du Conseil du 23 juillet 2014 susvisé ;
4° Le profil d'acheteur assure l'intégrité des données ;
5° Le profil d'acheteur permet une visualisation adaptée au média utilisé ;
6° Le profil d'acheteur garantit la confidentialité des candidatures, des offres et des demandes de participation jusqu'à l'expiration du délai prévu pour leur présentation. Les documents sont inaccessibles avant cette date. A l'expiration de ce délai, ils ne sont accessibles qu'aux personnes autorisées. Le profil d'acheteur recourt à des moyens de cryptologie ou à un outil de gestion des droits d'accès et des privilèges ou à une technique équivalente ;
7° Le profil d'acheteur est interopérable avec les autres outils et dispositifs de communication électronique et d'échanges d'informations utilisés dans le cadre de la commande publique.
III. - Les dépôts, par l'opérateur économique, de documents sur le profil d'acheteur donnent immédiatement lieu à l'envoi d'un accusé de réception automatique portant les mentions suivantes :
- l'identification de l'opérateur économique auteur du dépôt ;
- le nom de l'acheteur public ;
- l'intitulé et l'objet de la consultation concernée ;
- la date et l'heure de réception des documents ;
- la liste détaillée des documents transmis.
Article 3
I. - Pour les autorités concédantes, le profil d'acheteur permet d'effectuer les actions suivantes :
1° S'identifier et s'authentifier ;
2° Mettre à disposition des documents de la consultation ;
3° Réceptionner et conserver des candidatures ;
4° Réceptionner et conserver des offres, y compris hors délais ;
5° Compléter un formulaire nécessaire à la publication des données essentielles prévues par l'arrêté du 22 mars 2019 relatif aux données essentielles dans la commande publique précité ou importer ces données lorsqu'elles sont disponibles dans un autre système d'information ;
6° Accéder à un historique des évènements permettant l'enregistrement et la traçabilité des actions ayant eu lieu sur le profil d'acheteur notamment le retrait et le dépôt de documents.
II. - Le profil d'acheteur permet à l'opérateur économique d'effectuer les actions suivantes :
1° S'identifier et s'authentifier ;
2° Connaître les prérequis techniques et les modules d'extension nécessaires pour utiliser le profil d'acheteur ;
3° Accéder à un espace permettant de tester que la configuration du poste de travail utilisé est en adéquation avec les prérequis techniques du profil d'acheteur ;
4° Effectuer une recherche permettant d'accéder notamment aux consultations et aux données essentielles ;
5° Consulter et télécharger en accès gratuit, libre, direct et complet les documents de la consultation ;
6° Accéder à un espace permettant de simuler le dépôt de documents ;
7° Déposer une candidature ;
8° Déposer des offres ;
9° Solliciter une assistance ou consulter un support utilisateur permettant d'apporter des réponses aux problématiques techniques ;
10° Consulter et télécharger les données essentielles conformément aux dispositions de l'arrêté du 22 mars 2019 relatif aux données essentielles dans la commande publique précité.
III. - Les fonctionnalités visées au I et au II de l'article 3 répondent aux exigences techniques, de sécurité et d'accessibilité suivantes :
1° Le profil d'acheteur garantit la confidentialité des candidatures, des offres et des demandes de participation jusqu'à l'expiration du délai prévu pour leur présentation. Les documents sont inaccessibles avant cette date. A l'expiration de ce délai, ils ne sont accessibles qu'aux personnes autorisées. Le profil d'acheteur recourt à des moyens de cryptologie ou à un outil de gestion des droits d'accès et des privilèges ou à une technique équivalente ;
2° Assurer l'intégrité des données ;
3° Permettre une visualisation adaptée au média utilisé ;
4° Le profil d'acheteur répond aux exigences fixées dans les référentiels généraux de sécurité, d'interopérabilité et d'accessibilité prévues aux articles 9 et 11 de l'ordonnance n° 2005-1516 du 8 décembre 2005.
IV. - Les dépôts, par l'opérateur économique, de documents sur le profil d'acheteur donnent immédiatement lieu à l'envoi d'un accusé réception automatique portant les mentions suivantes :
- l'identification de l'opérateur économique auteur du dépôt ;
- le nom de l'autorité concédante ;
- l'intitulé et l'objet de la consultation concernée ;
- la date et l'heure de réception des documents ;
- la liste détaillée des documents transmis.
Article 4
I. - Le profil d'acheteur figure sur une liste publiée sur le portail unique interministériel destiné à rassembler et à mettre à disposition librement l'ensemble des informations publiques.
II. - Chaque profil d'acheteur est identifié par :
- le SIRET de l'acheteur ;
- l'adresse URL du profil d'acheteur ;
- l'adresse URL du DCAT prévue à l'article 8 de l'arrêté du 22 mars 2019 relatif aux données essentielles dans la commande publique précité.
- les coordonnées du ou des acheteurs concernés.
III. - La déclaration du profil d'acheteur est effectuée par l'acheteur ou toute personne habilitée par celui-ci sur le portail unique interministériel destiné à rassembler et à mettre à disposition librement l'ensemble des informations publiques. La déclaration comporte l'identité du déclarant, l'identité de l'organisme chargé de la gestion du profil d'acheteur, l'adresse URL du profil d'acheteur, l'adresse URL du DCAT et les coordonnées du ou des acheteurs concernés.
Article 5
I. - Pour son application à Saint-Barthélemy et à Saint-Pierre-et-Miquelon le 3° de l'article 2 est ainsi rédigé  :
« l'horodatage est qualifié conformément aux dispositions applicables en métropole en vertu du règlement n° 910/2014 du Parlement européen et du Conseil du 23 juillet 2014 susvisé ; »
II. - Les dispositions du présent arrêté sont applicables en Nouvelle-Calédonie, en Polynésie française, dans les îles Wallis et Futuna et dans les Terres australes et antarctiques françaises pour les contrats de la commande publiques conclus par l'Etat et ses établissements publics, sous réserves des adaptations suivantes :
1° Pour son application en Nouvelle-Calédonie et en Polynésie française, le 3° de l'article 2 est ainsi rédigé  :
« l'horodatage est qualifié conformément aux dispositions applicables localement ; »
2° Pour son application les dans les îles Wallis et Futuna et dans les Terres australes et antarctiques françaises le 3° de l'article 2 est ainsi rédigé  :
« l'horodatage est qualifié conformément aux dispositions applicables en métropole en vertu du règlement n° 910/2014 du Parlement européen et du Conseil du 23 juillet 2014 susvisé. »
Article 6
Le présent arrêté constitue l'annexe 7 du code de la commande publique.
Article 7
A modifié les dispositions suivantes
Abroge Arrêté du 14 avril 2017 (Ab)
Abroge Arrêté du 14 avril 2017 - art. 1 (Ab)
Abroge Arrêté du 14 avril 2017 - art. 2 (Ab)
Abroge Arrêté du 14 avril 2017 - art. 3 (Ab)
Abroge Arrêté du 14 avril 2017 - art. 4 (Ab)
Abroge Arrêté du 14 avril 2017 - art. 5 (Ab)
Abroge Arrêté du 14 avril 2017 - art. 6 (Ab)
Article 8
Le présent arrêté entre en vigueur le 1er avril 2019.
Il s'applique aux marchés publics pour lesquels une consultation est engagée ou un avis d'appel à la concurrence est envoyé à la publication à compter de sa date d'entrée en vigueur.
Il s'applique aux contrats de concession pour lesquels une consultation est engagée ou un avis de concession est envoyé à la publication à compter de sa date d'entrée en vigueur.
Article 9
La directrice des affaires juridiques des ministères économiques et financiers et le directeur général des outre-mer sont chargés de l'exécution du présent arrêté, qui sera publié au Journal officiel de la République française.
Fait le 22 mars 2019.
Le ministre de l'économie et des finances,
Pour le ministre et par délégation :
La directrice des affaires juridiques,
L. Bedier
La ministre des outre-mer,
Pour la ministre et par délégation :
Le directeur général des outre-mer,
E. Berthier
+29
View File
@@ -0,0 +1,29 @@
# Contexte
Je souhate ajouter la possibilité pour les utilisateurs de créer un compte utilisateur. Les données des utilisateurs sont stockés dans une base de données sqlite située à la racine du projet. Les seules données demandées sont une adresse email et un mot de passe. Un lien dans le menu supérieur, tout à droite, permet d'accéder à une page qui permet soit de se connecter, soit de créer un compte.
Il s'agit des fondations des comptes utilisateurs, d'autres fonctionnalités viendront s'ajouter.
# Inscription
Données nécessaires :
- adresse email
- mot de passe
Le mot de passe est hashé en base de données.
# Connexion
- adresse email
- mot passe
Lien vers une page de réinitialisation du mot de passe.
# Page du compte
Possibilité de changer le mot de passe.
# Configuration
Ces fonctionnalités nécessitent d'envoyer des emails. Les options nécessaire à une connexion à un service SMTP sont fournies sous la forme de variables d'environnement.
+261
View File
@@ -0,0 +1,261 @@
code,libellé
0000,Organisme de placement collectif en valeurs mobilières sans personnalité morale
1000,Entrepreneur individuel
2110,Indivision entre personnes physiques
2120,Indivision avec personne morale
2210,Société créée de fait entre personnes physiques
2220,Société créée de fait avec personne morale
2310,Société en participation entre personnes physiques
2320,Société en participation avec personne morale
2385,Société en participation de professions libérales
2400,Fiducie
2700,Paroisse hors zone concordataire
2800,Assujetti unique à la TVA
2900,Autre groupement de droit privé non doté de la personnalité morale
3110,Représentation ou agence commerciale d'état ou organisme public étranger immatriculé au RCS
3120,Société commerciale étrangère immatriculée au RCS
3205,Organisation internationale
3210,"État, collectivité ou établissement public étranger"
3220,Société étrangère non immatriculée au RCS
3290,Autre personne morale de droit étranger
4110,Établissement public national à caractère industriel ou commercial doté d'un comptable public
4120,Établissement public national à caractère industriel ou commercial non doté d'un comptable public
4130,Exploitant public
4140,Établissement public local à caractère industriel ou commercial
4150,Régie d'une collectivité locale à caractère industriel ou commercial
4160,Institution Banque de France
5191,Société de caution mutuelle
5192,Société coopérative de banque populaire
5193,Caisse de crédit maritime mutuel
5194,Caisse (fédérale) de crédit mutuel
5195,Association coopérative inscrite (droit local Alsace Moselle)
5196,Caisse d'épargne et de prévoyance à forme coopérative
5202,Société en nom collectif
5203,Société en nom collectif coopérative
5306,Société en commandite simple
5307,Société en commandite simple coopérative
5308,Société en commandite par actions
5309,Société en commandite par actions coopérative
5310,Société en libre partenariat (SLP)
5370,Société de Participations Financières de Profession Libérale Société en commandite par actions (SPFPL SCA)
5385,Société d'exercice libéral en commandite par actions
5410,SARL nationale
5415,SARL d'économie mixte
5422,SARL immobilière pour le commerce et l'industrie (SICOMI)
5426,SARL immobilière de gestion
5430,SARL d'aménagement foncier et d'équipement rural (SAFER)
5431,SARL mixte d'intérêt agricole (SMIA)
5432,SARL d'intérêt collectif agricole (SICA)
5442,SARL d'attribution
5443,SARL coopérative de construction
5451,SARL coopérative de consommation
5453,SARL coopérative artisanale
5454,SARL coopérative d'intérêt maritime
5455,SARL coopérative de transport
5458,SARL coopérative de production (SCOP)
5459,SARL union de sociétés coopératives
5460,Autre SARL coopérative
5470,Société de Participations Financières de Profession Libérale Société à responsabilité limitée (SPFPL SARL)
5485,Société d'exercice libéral à responsabilité limitée
5499,Société à responsabilité limitée (sans autre indication)
5505,SA à participation ouvrière à conseil d'administration
5510,SA nationale à conseil d'administration
5515,SA d'économie mixte à conseil d'administration
5520,Fonds à forme sociétale à conseil d'administration
5522,SA immobilière pour le commerce et l'industrie (SICOMI) à conseil d'administration
5525,SA immobilière d'investissement à conseil d'administration
5530,SA d'aménagement foncier et d'équipement rural (SAFER) à conseil d'administration
5531,Société anonyme mixte d'intérêt agricole (SMIA) à conseil d'administration
5532,SA d'intérêt collectif agricole (SICA) à conseil d'administration
5542,SA d'attribution à conseil d'administration
5543,SA coopérative de construction à conseil d'administration
5546,SA de HLM à conseil d'administration
5547,SA coopérative de production de HLM à conseil d'administration
5548,SA de crédit immobilier à conseil d'administration
5551,SA coopérative de consommation à conseil d'administration
5552,SA coopérative de commerçants-détaillants à conseil d'administration
5553,SA coopérative artisanale à conseil d'administration
5554,SA coopérative (d'intérêt) maritime à conseil d'administration
5555,SA coopérative de transport à conseil d'administration
5558,SA coopérative de production (SCOP) à conseil d'administration
5559,SA union de sociétés coopératives à conseil d'administration
5560,Autre SA coopérative à conseil d'administration
5570,Société de Participations Financières de Profession Libérale Société anonyme à conseil d'administration (SPFPL SA à conseil d'administration)
5585,Société d'exercice libéral à forme anonyme à conseil d'administration
5599,SA à conseil d'administration (s.a.i.)
5605,SA à participation ouvrière à directoire
5610,SA nationale à directoire
5615,SA d'économie mixte à directoire
5620,Fonds à forme sociétale à directoire
5622,SA immobilière pour le commerce et l'industrie (SICOMI) à directoire
5625,SA immobilière d'investissement à directoire
5630,Safer anonyme à directoire
5631,SA mixte d'intérêt agricole (SMIA)
5632,SA d'intérêt collectif agricole (SICA)
5642,SA d'attribution à directoire
5643,SA coopérative de construction à directoire
5646,SA de HLM à directoire
5647,Société coopérative de production de HLM anonyme à directoire
5648,SA de crédit immobilier à directoire
5651,SA coopérative de consommation à directoire
5652,SA coopérative de commerçants-détaillants à directoire
5653,SA coopérative artisanale à directoire
5654,SA coopérative d'intérêt maritime à directoire
5655,SA coopérative de transport à directoire
5658,SA coopérative de production (SCOP) à directoire
5659,SA union de sociétés coopératives à directoire
5660,Autre SA coopérative à directoire
5670,Société de Participations Financières de Profession Libérale Société anonyme à Directoire (SPFPL SA à directoire)
5685,Société d'exercice libéral à forme anonyme à directoire
5699,SA à directoire (s.a.i.)
5710,"SAS, société par actions simplifiée"
5770,Société de Participations Financières de Profession Libérale Société par actions simplifiée (SPFPL SAS)
5785,Société d'exercice libéral par action simplifiée
5800,Société européenne
6100,Caisse d'Épargne et de Prévoyance
6210,Groupement européen d'intérêt économique (GEIE)
6220,Groupement d'intérêt économique (GIE)
6316,Coopérative d'utilisation de matériel agricole en commun (CUMA)
6317,Société coopérative agricole
6318,Union de sociétés coopératives agricoles
6411,Société d'assurance à forme mutuelle
6511,Sociétés Interprofessionnelles de Soins Ambulatoires 
6521,Société civile de placement collectif immobilier (SCPI)
6532,Société civile d'intérêt collectif agricole (SICA)
6533,Groupement agricole d'exploitation en commun (GAEC)
6534,Groupement foncier agricole
6535,Groupement agricole foncier
6536,Groupement forestier
6537,Groupement pastoral
6538,Groupement foncier et rural
6539,Société civile foncière
6540,Société civile immobilière
6541,Société civile immobilière de construction-vente
6542,Société civile d'attribution
6543,Société civile coopérative de construction
6544,Société civile immobilière d' accession progressive à la propriété
6551,Société civile coopérative de consommation
6554,Société civile coopérative d'intérêt maritime
6558,Société civile coopérative entre médecins
6560,Autre société civile coopérative
6561,SCP d'avocats
6562,SCP d'avocats aux conseils
6563,SCP d'avoués d'appel
6564,SCP d'huissiers
6565,SCP de notaires
6566,SCP de commissaires-priseurs
6567,SCP de greffiers de tribunal de commerce
6568,SCP de conseils juridiques
6569,SCP de commissaires aux comptes
6571,SCP de médecins
6572,SCP de dentistes
6573,SCP d'infirmiers
6574,SCP de masseurs-kinésithérapeutes
6575,SCP de directeurs de laboratoire d'analyse médicale
6576,SCP de vétérinaires
6577,SCP de géomètres experts
6578,SCP d'architectes
6585,Autre société civile professionnelle
6589,Société civile de moyens
6595,Caisse locale de crédit mutuel
6596,Caisse de crédit agricole mutuel
6597,Société civile d'exploitation agricole
6598,Exploitation agricole à responsabilité limitée
6599,Autre société civile
6901,Autre personne de droit privé inscrite au registre du commerce et des sociétés
7111,Autorité constitutionnelle
7112,Autorité administrative ou publique indépendante
7113,Ministère
7120,Service central d'un ministère
7150,Service du ministère de la Défense
7160,Service déconcentré à compétence nationale d'un ministère (hors Défense)
7171,Service déconcentré de l'État à compétence (inter) régionale
7172,Service déconcentré de l'État à compétence (inter) départementale
7179,(Autre) Service déconcentré de l'État à compétence territoriale
7190,Ecole nationale non dotée de la personnalité morale
7210,Commune et commune nouvelle
7220,Département
7225,Collectivité et territoire d'Outre Mer
7229,(Autre) Collectivité territoriale
7230,Région
7312,Commune associée et commune déléguée
7313,Section de commune
7314,Ensemble urbain
7321,Association syndicale autorisée
7322,Association foncière urbaine
7323,Association foncière de remembrement
7331,Établissement public local d'enseignement
7340,Pôle métropolitain
7341,Secteur de commune
7342,District urbain
7343,Communauté urbaine
7344,Métropole
7345,Syndicat intercommunal à vocation multiple (SIVOM)
7346,Communauté de communes
7347,Communauté de villes
7348,Communauté d'agglomération
7349,Autre établissement public local de coopération non spécialisé ou entente
7351,Institution interdépartementale ou entente
7352,Institution interrégionale ou entente
7353,Syndicat intercommunal à vocation unique (SIVU)
7354,Syndicat mixte fermé
7355,Syndicat mixte ouvert
7356,Commission syndicale pour la gestion des biens indivis des communes
7357,Pôle d'équilibre territorial et rural (PETR)
7361,Centre communal d'action sociale
7362,Caisse des écoles
7363,Caisse de crédit municipal
7364,Établissement d'hospitalisation
7365,Syndicat inter hospitalier
7366,Établissement public local social et médico-social
7367,Centre Intercommunal d'action sociale (CIAS)
7371,Office public d'habitation à loyer modéré (OPHLM)
7372,Service départemental d'incendie et de secours (SDIS)
7373,Établissement public local culturel
7378,Régie d'une collectivité locale à caractère administratif
7379,(Autre) Établissement public administratif local
7381,Organisme consulaire
7382,Établissement public national ayant fonction d'administration centrale
7383,Établissement public national à caractère scientifique culturel et professionnel
7384,Autre établissement public national d'enseignement
7385,Autre établissement public national administratif à compétence territoriale limitée
7389,Établissement public national à caractère administratif
7410,Groupement d'intérêt public (GIP)
7430,Établissement public des cultes d'Alsace-Lorraine
7450,"Etablissement public administratif, cercle et foyer dans les armées "
7470,Groupement de coopération sanitaire à gestion publique
7490,Autre personne morale de droit administratif
8110,Régime général de la Sécurité Sociale
8120,Régime spécial de Sécurité Sociale
8130,Institution de retraite complémentaire
8140,Mutualité sociale agricole
8150,Régime maladie des non-salariés non agricoles
8160,Régime vieillesse ne dépendant pas du régime général de la Sécurité Sociale
8170,Régime d'assurance chômage
8190,Autre régime de prévoyance sociale
8210,Mutuelle
8250,Assurance mutuelle agricole
8290,Autre organisme mutualiste
8310,Comité social économique dentreprise
8311,Comité social économique d'établissement
8410,Syndicat de salariés
8420,Syndicat patronal
8450,Ordre professionnel ou assimilé
8470,Centre technique industriel ou comité professionnel du développement économique
8490,Autre organisme professionnel
8510,Institution de prévoyance
8520,Institution de retraite supplémentaire
9110,Syndicat de copropriété
9150,Association syndicale libre
9210,Association non déclarée
9220,Association déclarée
9221,Association déclarée d'insertion par l'économique
9222,Association intermédiaire
9223,Groupement d'employeurs
9224,Association d'avocats à responsabilité professionnelle individuelle
9230,"Association déclarée, reconnue d'utilité publique"
9240,Congrégation
9260,"Association de droit local (Bas-Rhin, Haut-Rhin et Moselle)"
9300,Fondation
9900,Autre personne morale de droit privé
9970,Groupement de coopération sanitaire à gestion privée
1 code libellé
2 0000 Organisme de placement collectif en valeurs mobilières sans personnalité morale
3 1000 Entrepreneur individuel
4 2110 Indivision entre personnes physiques
5 2120 Indivision avec personne morale
6 2210 Société créée de fait entre personnes physiques
7 2220 Société créée de fait avec personne morale
8 2310 Société en participation entre personnes physiques
9 2320 Société en participation avec personne morale
10 2385 Société en participation de professions libérales
11 2400 Fiducie
12 2700 Paroisse hors zone concordataire
13 2800 Assujetti unique à la TVA
14 2900 Autre groupement de droit privé non doté de la personnalité morale
15 3110 Représentation ou agence commerciale d'état ou organisme public étranger immatriculé au RCS
16 3120 Société commerciale étrangère immatriculée au RCS
17 3205 Organisation internationale
18 3210 État, collectivité ou établissement public étranger
19 3220 Société étrangère non immatriculée au RCS
20 3290 Autre personne morale de droit étranger
21 4110 Établissement public national à caractère industriel ou commercial doté d'un comptable public
22 4120 Établissement public national à caractère industriel ou commercial non doté d'un comptable public
23 4130 Exploitant public
24 4140 Établissement public local à caractère industriel ou commercial
25 4150 Régie d'une collectivité locale à caractère industriel ou commercial
26 4160 Institution Banque de France
27 5191 Société de caution mutuelle
28 5192 Société coopérative de banque populaire
29 5193 Caisse de crédit maritime mutuel
30 5194 Caisse (fédérale) de crédit mutuel
31 5195 Association coopérative inscrite (droit local Alsace Moselle)
32 5196 Caisse d'épargne et de prévoyance à forme coopérative
33 5202 Société en nom collectif
34 5203 Société en nom collectif coopérative
35 5306 Société en commandite simple
36 5307 Société en commandite simple coopérative
37 5308 Société en commandite par actions
38 5309 Société en commandite par actions coopérative
39 5310 Société en libre partenariat (SLP)
40 5370 Société de Participations Financières de Profession Libérale Société en commandite par actions (SPFPL SCA)
41 5385 Société d'exercice libéral en commandite par actions
42 5410 SARL nationale
43 5415 SARL d'économie mixte
44 5422 SARL immobilière pour le commerce et l'industrie (SICOMI)
45 5426 SARL immobilière de gestion
46 5430 SARL d'aménagement foncier et d'équipement rural (SAFER)
47 5431 SARL mixte d'intérêt agricole (SMIA)
48 5432 SARL d'intérêt collectif agricole (SICA)
49 5442 SARL d'attribution
50 5443 SARL coopérative de construction
51 5451 SARL coopérative de consommation
52 5453 SARL coopérative artisanale
53 5454 SARL coopérative d'intérêt maritime
54 5455 SARL coopérative de transport
55 5458 SARL coopérative de production (SCOP)
56 5459 SARL union de sociétés coopératives
57 5460 Autre SARL coopérative
58 5470 Société de Participations Financières de Profession Libérale Société à responsabilité limitée (SPFPL SARL)
59 5485 Société d'exercice libéral à responsabilité limitée
60 5499 Société à responsabilité limitée (sans autre indication)
61 5505 SA à participation ouvrière à conseil d'administration
62 5510 SA nationale à conseil d'administration
63 5515 SA d'économie mixte à conseil d'administration
64 5520 Fonds à forme sociétale à conseil d'administration
65 5522 SA immobilière pour le commerce et l'industrie (SICOMI) à conseil d'administration
66 5525 SA immobilière d'investissement à conseil d'administration
67 5530 SA d'aménagement foncier et d'équipement rural (SAFER) à conseil d'administration
68 5531 Société anonyme mixte d'intérêt agricole (SMIA) à conseil d'administration
69 5532 SA d'intérêt collectif agricole (SICA) à conseil d'administration
70 5542 SA d'attribution à conseil d'administration
71 5543 SA coopérative de construction à conseil d'administration
72 5546 SA de HLM à conseil d'administration
73 5547 SA coopérative de production de HLM à conseil d'administration
74 5548 SA de crédit immobilier à conseil d'administration
75 5551 SA coopérative de consommation à conseil d'administration
76 5552 SA coopérative de commerçants-détaillants à conseil d'administration
77 5553 SA coopérative artisanale à conseil d'administration
78 5554 SA coopérative (d'intérêt) maritime à conseil d'administration
79 5555 SA coopérative de transport à conseil d'administration
80 5558 SA coopérative de production (SCOP) à conseil d'administration
81 5559 SA union de sociétés coopératives à conseil d'administration
82 5560 Autre SA coopérative à conseil d'administration
83 5570 Société de Participations Financières de Profession Libérale Société anonyme à conseil d'administration (SPFPL SA à conseil d'administration)
84 5585 Société d'exercice libéral à forme anonyme à conseil d'administration
85 5599 SA à conseil d'administration (s.a.i.)
86 5605 SA à participation ouvrière à directoire
87 5610 SA nationale à directoire
88 5615 SA d'économie mixte à directoire
89 5620 Fonds à forme sociétale à directoire
90 5622 SA immobilière pour le commerce et l'industrie (SICOMI) à directoire
91 5625 SA immobilière d'investissement à directoire
92 5630 Safer anonyme à directoire
93 5631 SA mixte d'intérêt agricole (SMIA)
94 5632 SA d'intérêt collectif agricole (SICA)
95 5642 SA d'attribution à directoire
96 5643 SA coopérative de construction à directoire
97 5646 SA de HLM à directoire
98 5647 Société coopérative de production de HLM anonyme à directoire
99 5648 SA de crédit immobilier à directoire
100 5651 SA coopérative de consommation à directoire
101 5652 SA coopérative de commerçants-détaillants à directoire
102 5653 SA coopérative artisanale à directoire
103 5654 SA coopérative d'intérêt maritime à directoire
104 5655 SA coopérative de transport à directoire
105 5658 SA coopérative de production (SCOP) à directoire
106 5659 SA union de sociétés coopératives à directoire
107 5660 Autre SA coopérative à directoire
108 5670 Société de Participations Financières de Profession Libérale Société anonyme à Directoire (SPFPL SA à directoire)
109 5685 Société d'exercice libéral à forme anonyme à directoire
110 5699 SA à directoire (s.a.i.)
111 5710 SAS, société par actions simplifiée
112 5770 Société de Participations Financières de Profession Libérale Société par actions simplifiée (SPFPL SAS)
113 5785 Société d'exercice libéral par action simplifiée
114 5800 Société européenne
115 6100 Caisse d'Épargne et de Prévoyance
116 6210 Groupement européen d'intérêt économique (GEIE)
117 6220 Groupement d'intérêt économique (GIE)
118 6316 Coopérative d'utilisation de matériel agricole en commun (CUMA)
119 6317 Société coopérative agricole
120 6318 Union de sociétés coopératives agricoles
121 6411 Société d'assurance à forme mutuelle
122 6511 Sociétés Interprofessionnelles de Soins Ambulatoires 
123 6521 Société civile de placement collectif immobilier (SCPI)
124 6532 Société civile d'intérêt collectif agricole (SICA)
125 6533 Groupement agricole d'exploitation en commun (GAEC)
126 6534 Groupement foncier agricole
127 6535 Groupement agricole foncier
128 6536 Groupement forestier
129 6537 Groupement pastoral
130 6538 Groupement foncier et rural
131 6539 Société civile foncière
132 6540 Société civile immobilière
133 6541 Société civile immobilière de construction-vente
134 6542 Société civile d'attribution
135 6543 Société civile coopérative de construction
136 6544 Société civile immobilière d' accession progressive à la propriété
137 6551 Société civile coopérative de consommation
138 6554 Société civile coopérative d'intérêt maritime
139 6558 Société civile coopérative entre médecins
140 6560 Autre société civile coopérative
141 6561 SCP d'avocats
142 6562 SCP d'avocats aux conseils
143 6563 SCP d'avoués d'appel
144 6564 SCP d'huissiers
145 6565 SCP de notaires
146 6566 SCP de commissaires-priseurs
147 6567 SCP de greffiers de tribunal de commerce
148 6568 SCP de conseils juridiques
149 6569 SCP de commissaires aux comptes
150 6571 SCP de médecins
151 6572 SCP de dentistes
152 6573 SCP d'infirmiers
153 6574 SCP de masseurs-kinésithérapeutes
154 6575 SCP de directeurs de laboratoire d'analyse médicale
155 6576 SCP de vétérinaires
156 6577 SCP de géomètres experts
157 6578 SCP d'architectes
158 6585 Autre société civile professionnelle
159 6589 Société civile de moyens
160 6595 Caisse locale de crédit mutuel
161 6596 Caisse de crédit agricole mutuel
162 6597 Société civile d'exploitation agricole
163 6598 Exploitation agricole à responsabilité limitée
164 6599 Autre société civile
165 6901 Autre personne de droit privé inscrite au registre du commerce et des sociétés
166 7111 Autorité constitutionnelle
167 7112 Autorité administrative ou publique indépendante
168 7113 Ministère
169 7120 Service central d'un ministère
170 7150 Service du ministère de la Défense
171 7160 Service déconcentré à compétence nationale d'un ministère (hors Défense)
172 7171 Service déconcentré de l'État à compétence (inter) régionale
173 7172 Service déconcentré de l'État à compétence (inter) départementale
174 7179 (Autre) Service déconcentré de l'État à compétence territoriale
175 7190 Ecole nationale non dotée de la personnalité morale
176 7210 Commune et commune nouvelle
177 7220 Département
178 7225 Collectivité et territoire d'Outre Mer
179 7229 (Autre) Collectivité territoriale
180 7230 Région
181 7312 Commune associée et commune déléguée
182 7313 Section de commune
183 7314 Ensemble urbain
184 7321 Association syndicale autorisée
185 7322 Association foncière urbaine
186 7323 Association foncière de remembrement
187 7331 Établissement public local d'enseignement
188 7340 Pôle métropolitain
189 7341 Secteur de commune
190 7342 District urbain
191 7343 Communauté urbaine
192 7344 Métropole
193 7345 Syndicat intercommunal à vocation multiple (SIVOM)
194 7346 Communauté de communes
195 7347 Communauté de villes
196 7348 Communauté d'agglomération
197 7349 Autre établissement public local de coopération non spécialisé ou entente
198 7351 Institution interdépartementale ou entente
199 7352 Institution interrégionale ou entente
200 7353 Syndicat intercommunal à vocation unique (SIVU)
201 7354 Syndicat mixte fermé
202 7355 Syndicat mixte ouvert
203 7356 Commission syndicale pour la gestion des biens indivis des communes
204 7357 Pôle d'équilibre territorial et rural (PETR)
205 7361 Centre communal d'action sociale
206 7362 Caisse des écoles
207 7363 Caisse de crédit municipal
208 7364 Établissement d'hospitalisation
209 7365 Syndicat inter hospitalier
210 7366 Établissement public local social et médico-social
211 7367 Centre Intercommunal d'action sociale (CIAS)
212 7371 Office public d'habitation à loyer modéré (OPHLM)
213 7372 Service départemental d'incendie et de secours (SDIS)
214 7373 Établissement public local culturel
215 7378 Régie d'une collectivité locale à caractère administratif
216 7379 (Autre) Établissement public administratif local
217 7381 Organisme consulaire
218 7382 Établissement public national ayant fonction d'administration centrale
219 7383 Établissement public national à caractère scientifique culturel et professionnel
220 7384 Autre établissement public national d'enseignement
221 7385 Autre établissement public national administratif à compétence territoriale limitée
222 7389 Établissement public national à caractère administratif
223 7410 Groupement d'intérêt public (GIP)
224 7430 Établissement public des cultes d'Alsace-Lorraine
225 7450 Etablissement public administratif, cercle et foyer dans les armées
226 7470 Groupement de coopération sanitaire à gestion publique
227 7490 Autre personne morale de droit administratif
228 8110 Régime général de la Sécurité Sociale
229 8120 Régime spécial de Sécurité Sociale
230 8130 Institution de retraite complémentaire
231 8140 Mutualité sociale agricole
232 8150 Régime maladie des non-salariés non agricoles
233 8160 Régime vieillesse ne dépendant pas du régime général de la Sécurité Sociale
234 8170 Régime d'assurance chômage
235 8190 Autre régime de prévoyance sociale
236 8210 Mutuelle
237 8250 Assurance mutuelle agricole
238 8290 Autre organisme mutualiste
239 8310 Comité social économique d’entreprise
240 8311 Comité social économique d'établissement
241 8410 Syndicat de salariés
242 8420 Syndicat patronal
243 8450 Ordre professionnel ou assimilé
244 8470 Centre technique industriel ou comité professionnel du développement économique
245 8490 Autre organisme professionnel
246 8510 Institution de prévoyance
247 8520 Institution de retraite supplémentaire
248 9110 Syndicat de copropriété
249 9150 Association syndicale libre
250 9210 Association non déclarée
251 9220 Association déclarée
252 9221 Association déclarée d'insertion par l'économique
253 9222 Association intermédiaire
254 9223 Groupement d'employeurs
255 9224 Association d'avocats à responsabilité professionnelle individuelle
256 9230 Association déclarée, reconnue d'utilité publique
257 9240 Congrégation
258 9260 Association de droit local (Bas-Rhin, Haut-Rhin et Moselle)
259 9300 Fondation
260 9900 Autre personne morale de droit privé
261 9970 Groupement de coopération sanitaire à gestion privée
+100
View File
@@ -0,0 +1,100 @@
File "<frozen importlib._bootstrap>", line 1149, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 690, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 940, in exec_module
File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
File "/var/www/decpinfo/run.py", line 1, in <module>
from src.app import app
File "/var/www/decpinfo/src/app.py", line 30, in <module>
app: Dash = Dash(
^^^^^
File "/var/www/decpinfo/.venv/lib/python3.11/site-packages/dash/dash.py", line 639, in __init__
self.init_app()
File "/var/www/decpinfo/.venv/lib/python3.11/site-packages/dash/dash.py", line 752, in init_app
self.enable_pages()
File "/var/www/decpinfo/.venv/lib/python3.11/site-packages/dash/dash.py", line 2535, in enable_pages
_import_layouts_from_pages(self.config.pages_folder)
File "/var/www/decpinfo/.venv/lib/python3.11/site-packages/dash/_pages.py", line 442, in _import_layouts_from_pages
spec.loader.exec_module(page_module) # type: ignore[reportOptionalMemberAccess]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/var/www/decpinfo/src/pages/observatoire.py", line 19, in <module>
from src.db import schema
File "/var/www/decpinfo/src/db.py", line 126, in <module>
DB_PATH = _ensure_database()
^^^^^^^^^^^^^^^^^^
File "/var/www/decpinfo/src/db.py", line 119, in _ensure_database
if should_rebuild(db_path, parquet_path):
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/var/www/decpinfo/src/db.py", line 23, in should_rebuild
return parquet_path.stat().st_mtime > db_path.stat().st_mtime
^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.11/pathlib.py", line 1014, in stat
return os.stat(self, follow_symlinks=follow_symlinks)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
FileNotFoundError: [Errno 2] No such file or directory: '/srv/shared/decp/prod/dist/decp.parquet'
[2026-05-01 08:00:30 +0200] [2216551] [INFO] Worker exiting (pid: 2216551)
[2026-05-01 08:00:30 +0200] [2216552] [ERROR] Exception in worker process
Traceback (most recent call last):
File "/var/www/decpinfo/.venv/lib/python3.11/site-packages/gunicorn/arbiter.py", line 608, in spawn_worker
worker.init_process()
File "/var/www/decpinfo/.venv/lib/python3.11/site-packages/gunicorn/workers/base.py", line 135, in init_process
self.load_wsgi()
File "/var/www/decpinfo/.venv/lib/python3.11/site-packages/gunicorn/workers/base.py", line 147, in load_wsgi
self.wsgi = self.app.wsgi()
^^^^^^^^^^^^^^^
File "/var/www/decpinfo/.venv/lib/python3.11/site-packages/gunicorn/app/base.py", line 66, in wsgi
self.callable = self.load()
^^^^^^^^^^^
File "/var/www/decpinfo/.venv/lib/python3.11/site-packages/gunicorn/app/wsgiapp.py", line 57, in load
return self.load_wsgiapp()
^^^^^^^^^^^^^^^^^^^
File "/var/www/decpinfo/.venv/lib/python3.11/site-packages/gunicorn/app/wsgiapp.py", line 47, in load_wsgiapp
return util.import_app(self.app_uri)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/var/www/decpinfo/.venv/lib/python3.11/site-packages/gunicorn/util.py", line 370, in import_app
mod = importlib.import_module(module)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.11/importlib/__init__.py", line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "<frozen importlib._bootstrap>", line 1206, in _gcd_import
File "<frozen importlib._bootstrap>", line 1178, in _find_and_load
File "<frozen importlib._bootstrap>", line 1149, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 690, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 940, in exec_module
File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
File "/var/www/decpinfo/run.py", line 1, in <module>
from src.app import app
File "/var/www/decpinfo/src/app.py", line 30, in <module>
app: Dash = Dash(
^^^^^
File "/var/www/decpinfo/.venv/lib/python3.11/site-packages/dash/dash.py", line 639, in __init__
self.init_app()
File "/var/www/decpinfo/.venv/lib/python3.11/site-packages/dash/dash.py", line 752, in init_app
self.enable_pages()
File "/var/www/decpinfo/.venv/lib/python3.11/site-packages/dash/dash.py", line 2535, in enable_pages
_import_layouts_from_pages(self.config.pages_folder)
File "/var/www/decpinfo/.venv/lib/python3.11/site-packages/dash/_pages.py", line 442, in _import_layouts_from_pages
spec.loader.exec_module(page_module) # type: ignore[reportOptionalMemberAccess]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/var/www/decpinfo/src/pages/observatoire.py", line 19, in <module>
from src.db import schema
File "/var/www/decpinfo/src/db.py", line 126, in <module>
DB_PATH = _ensure_database()
^^^^^^^^^^^^^^^^^^
File "/var/www/decpinfo/src/db.py", line 119, in _ensure_database
if should_rebuild(db_path, parquet_path):
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/var/www/decpinfo/src/db.py", line 23, in should_rebuild
return parquet_path.stat().st_mtime > db_path.stat().st_mtime
^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.11/pathlib.py", line 1014, in stat
return os.stat(self, follow_symlinks=follow_symlinks)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
FileNotFoundError: [Errno 2] No such file or directory: '/srv/shared/decp/prod/dist/decp.parquet'
[2026-05-01 08:00:30 +0200] [2216552] [INFO] Worker exiting (pid: 2216552)
[2026-05-01 08:00:30 +0200] [2216548] [ERROR] Worker (pid:2216549) exited with code 3
[2026-05-01 08:00:30 +0200] [2216548] [ERROR] Worker (pid:2216550) was sent SIGTERM!
[2026-05-01 08:00:30 +0200] [2216548] [ERROR] Worker (pid:2216552) was sent SIGTERM!
[2026-05-01 08:00:30 +0200] [2216548] [ERROR] Worker (pid:2216551) was sent SIGTERM!
[2026-05-01 08:00:31 +0200] [2216548] [ERROR] Shutting down: Master
[2026-05-01 08:00:31 +0200] [2216548] [ERROR] Reason: Worker failed to boot.
@@ -0,0 +1,318 @@
# Observatoire localStorage Filter Persistence Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Persist all 10 observatoire filter values in `localStorage` so they survive navigation and page reloads; URL params (`acheteur_id` / `titulaire_id`) override stored values.
**Architecture:** Add `dcc.Store(storage_type="local", id="observatoire-filters")` to the observatoire layout. A new save callback writes all 10 filter values to the store on any change (`prevent_initial_call=True` to avoid wiping localStorage on page mount). The existing `restore_filters_from_url` callback is expanded: it now outputs all 10 filters, accepts the store as `State`, and prioritises URL params over stored values.
**Tech Stack:** Dash 3.4 `dcc.Store` with `storage_type="local"`, Dash callbacks (Input / Output / State), pytest + Selenium (`DashComposite`).
---
## File Map
| Action | File |
| ------ | --------------------------------------------------------------------- |
| Modify | `src/pages/observatoire.py` — layout + 2 callbacks |
| Modify | `tests/test_main.py` — add `test_009_observatoire_filter_persistence` |
---
### Task 1: Write a failing integration test
**Files:**
- Modify: `tests/test_main.py`
- [ ] **Step 1: Add test_009 at the end of `tests/test_main.py`**
```python
def test_009_observatoire_filter_persistence(dash_duo: DashComposite):
from src.app import app
dash_duo.start_server(app)
dash_duo.wait_for_text_to_equal(".logo > h1", "decp.info", timeout=4)
# Clear localStorage to start from a clean state
dash_duo.driver.execute_script("localStorage.clear()")
# Navigate to observatoire without URL params
dash_duo.wait_for_page(f"{dash_duo.server_url}/observatoire")
dash_duo.wait_for_element("#dashboard_acheteur_id", timeout=4)
# Set the acheteur_id text input
# dcc.Input without debounce fires the save callback on every keystroke,
# so the value is written to localStorage as soon as typing finishes.
acheteur_input = dash_duo.find_element("#dashboard_acheteur_id")
dash_duo.clear_input(acheteur_input)
acheteur_input.send_keys("999000000000")
import time
time.sleep(0.3) # allow the save callback to complete
# Navigate away
dash_duo.wait_for_page(f"{dash_duo.server_url}/")
# Navigate back without URL params
dash_duo.wait_for_page(f"{dash_duo.server_url}/observatoire")
dash_duo.wait_for_element("#dashboard_acheteur_id", timeout=4)
import time
time.sleep(0.5) # allow callback chain to complete
acheteur_input = dash_duo.find_element("#dashboard_acheteur_id")
assert acheteur_input.get_attribute("value") == "999000000000", (
"acheteur_id should be restored from localStorage after navigating back"
)
# Also verify URL params still override localStorage
dash_duo.wait_for_page(
f"{dash_duo.server_url}/observatoire?acheteur_id=123"
)
dash_duo.wait_for_element("#dashboard_acheteur_id", timeout=4)
time.sleep(0.5)
acheteur_input = dash_duo.find_element("#dashboard_acheteur_id")
assert acheteur_input.get_attribute("value") == "123", (
"URL param acheteur_id should override the value stored in localStorage"
)
```
- [ ] **Step 2: Run the test to verify it fails**
```bash
pytest tests/test_main.py::test_009_observatoire_filter_persistence -v
```
Expected: **FAIL** — the input value after navigating back will be `""`, not `"999000000000"`.
- [ ] **Step 3: Commit**
```bash
git add tests/test_main.py
git commit -m "test: failing test for observatoire localStorage filter persistence #65"
```
---
### Task 2: Add `dcc.Store` to the layout and debounce the text inputs
**Files:**
- Modify: `src/pages/observatoire.py`
- [ ] **Step 1: Add the Store component to the layout**
In `src/pages/observatoire.py`, add this line immediately after the existing `dcc.Location` (line 123):
```python
dcc.Store(id="observatoire-filters", storage_type="local"),
```
So the top of the `layout` list becomes:
```python
layout = [
dcc.Location(id="dashboard_url", refresh="callback-nav"),
dcc.Store(id="observatoire-filters", storage_type="local"),
dbc.Modal(
...
```
- [ ] **Step 2: Add `debounce=True` to both text inputs**
`dcc.Input` without debounce fires on every keystroke, which would trigger the save callback (and the existing heavy `udpate_dashboard_cards` callback) on every character typed. `debounce=True` delays the callback until the user presses Enter or moves focus away.
Change `dashboard_acheteur_id` (around line 178):
```python
dcc.Input(
id="dashboard_acheteur_id",
placeholder="SIRET",
debounce=True,
style={"width": "100%"},
),
```
Change `dashboard_titulaire_id` (around line 209):
```python
dcc.Input(
id="dashboard_titulaire_id",
placeholder="SIRET",
debounce=True,
style={"width": "100%"},
),
```
- [ ] **Step 3: Run the test — still fails (restore not implemented yet)**
```bash
pytest tests/test_main.py::test_009_observatoire_filter_persistence -v
```
Expected: still **FAIL**.
- [ ] **Step 4: Commit**
```bash
git add src/pages/observatoire.py
git commit -m "feat: add dcc.Store and debounce text inputs on observatoire page #65"
```
---
### Task 3: Add a save-to-localStorage callback
**Files:**
- Modify: `src/pages/observatoire.py`
- [ ] **Step 1: Add the save callback after the existing `restore_filters_from_url` callback**
```python
@callback(
Output("observatoire-filters", "data"),
Input("dashboard_year", "value"),
Input("dashboard_acheteur_id", "value"),
Input("dashboard_acheteur_categorie", "value"),
Input("dashboard_acheteur_departement_code", "value"),
Input("dashboard_titulaire_id", "value"),
Input("dashboard_titulaire_categorie", "value"),
Input("dashboard_titulaire_departement_code", "value"),
Input("dashboard_marche_type", "value"),
Input("dashboard_marche_considerationsSociales", "value"),
Input("dashboard_marche_considerationsEnvironnementales", "value"),
prevent_initial_call=True,
)
def save_filters_to_storage(
year,
acheteur_id,
acheteur_categorie,
acheteur_departement_code,
titulaire_id,
titulaire_categorie,
titulaire_departement_code,
marche_type,
considerations_sociales,
considerations_environnementales,
):
return {
"year": year,
"acheteur_id": acheteur_id,
"acheteur_categorie": acheteur_categorie,
"acheteur_departement_code": acheteur_departement_code,
"titulaire_id": titulaire_id,
"titulaire_categorie": titulaire_categorie,
"titulaire_departement_code": titulaire_departement_code,
"marche_type": marche_type,
"considerations_sociales": considerations_sociales,
"considerations_environnementales": considerations_environnementales,
}
```
**Why `prevent_initial_call=True`:** Without it, this callback fires on every page load with all-`None` values (the component defaults), immediately overwriting any saved filters. Setting `prevent_initial_call=True` skips that first call; subsequent user-driven changes still fire normally.
- [ ] **Step 2: Run the test — still fails (restore callback not updated yet)**
```bash
pytest tests/test_main.py::test_009_observatoire_filter_persistence -v
```
Expected: still **FAIL**.
- [ ] **Step 3: Commit**
```bash
git add src/pages/observatoire.py
git commit -m "feat: save observatoire filters to localStorage on change #65"
```
---
### Task 4: Update the restore callback to read from localStorage
**Files:**
- Modify: `src/pages/observatoire.py`
This is the core change. Replace the existing `restore_filters_from_url` callback entirely.
- [ ] **Step 1: Replace the existing callback**
Remove the current `restore_filters_from_url` function and its `@callback` decorator (lines 302323) and replace with:
```python
@callback(
Output("dashboard_year", "value"),
Output("dashboard_acheteur_id", "value"),
Output("dashboard_acheteur_categorie", "value"),
Output("dashboard_acheteur_departement_code", "value"),
Output("dashboard_titulaire_id", "value"),
Output("dashboard_titulaire_categorie", "value"),
Output("dashboard_titulaire_departement_code", "value"),
Output("dashboard_marche_type", "value"),
Output("dashboard_marche_considerationsSociales", "value"),
Output("dashboard_marche_considerationsEnvironnementales", "value"),
Input("dashboard_url", "search"),
Input("dashboard_url", "pathname"),
State("observatoire-filters", "data"),
)
def restore_filters(search, _pathname, stored_filters):
# URL params take absolute priority: clear all other filters and apply only
# the values present in the URL (acheteur_id and/or titulaire_id).
if search:
params = urllib.parse.parse_qs(search.lstrip("?"))
acheteur_id = (params.get("acheteur_id") or [None])[0] or None
titulaire_id = (params.get("titulaire_id") or [None])[0] or None
if acheteur_id or titulaire_id:
return None, acheteur_id, None, None, titulaire_id, None, None, None, None, None
# No URL params: restore from localStorage if available.
if stored_filters:
return (
stored_filters.get("year"),
stored_filters.get("acheteur_id"),
stored_filters.get("acheteur_categorie"),
stored_filters.get("acheteur_departement_code"),
stored_filters.get("titulaire_id"),
stored_filters.get("titulaire_categorie"),
stored_filters.get("titulaire_departement_code"),
stored_filters.get("marche_type"),
stored_filters.get("considerations_sociales"),
stored_filters.get("considerations_environnementales"),
)
return (no_update,) * 10
```
**Key design decisions:**
- `Input("dashboard_url", "pathname")` added alongside `search`: guarantees the callback fires on every navigation to the observatoire page, even when `search` stays `""` (no query string) across two navigations. The `_pathname` value itself is unused in the body; it exists only as a trigger.
- `State("observatoire-filters", "data")` (not `Input`): the store triggers no re-run when the save callback writes to it, avoiding an infinite loop.
- When URL params are present, _all_ non-URL filters are cleared (`None`), which causes the save callback to overwrite localStorage with only the URL-provided values.
- `(no_update,) * 10` when there is nothing to restore: leaves defaults intact.
- [ ] **Step 2: Run the target test**
```bash
pytest tests/test_main.py::test_009_observatoire_filter_persistence -v
```
Expected: **PASS**.
- [ ] **Step 3: Run the full test suite**
```bash
pytest -v
```
Expected: all tests **PASS**. Pay special attention to `test_006` and `test_007` (URL → input / share URL), which exercise the code path that was just rewritten.
- [ ] **Step 4: Commit**
```bash
git add src/pages/observatoire.py
git commit -m "feat: restore observatoire filters from localStorage on page load #65"
```
+2544
View File
File diff suppressed because it is too large Load Diff
+2583
View File
File diff suppressed because it is too large Load Diff
+189
View File
@@ -0,0 +1,189 @@
# Spécifications fonctionnelles et techniques d'un profil d'acheteur
> Source : [Arrêté du 22 mars 2019](https://www.legifrance.gouv.fr/loda/id/JORFTEXT000038318516) relatif aux fonctionnalités et exigences minimales des profils d'acheteurs (NOR : ECOM1831551A). Annexe 7 du Code de la commande publique. En vigueur depuis le 1er avril 2019.
## 1. Fonctionnalités pour l'acheteur (marchés publics)
_Réf. : Article 1, I_
Le profil d'acheteur doit permettre à l'acheteur de :
| ID | Fonctionnalité | Description |
| ------ | ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ACH-01 | Identification et authentification | S'identifier et s'authentifier sur la plateforme |
| ACH-02 | Publication d'avis | Publier des avis d'appel à la concurrence et leurs éventuelles modifications |
| ACH-03 | Mise à disposition des DCE | Mettre à disposition des documents de la consultation |
| ACH-04 | Réception des candidatures | Réceptionner et conserver des candidatures, y compris sous forme de DUME (Document Unique de Marché Européen) électronique (échange de données structurées) |
| ACH-05 | Réception des offres | Réceptionner et conserver des offres, y compris hors délais |
| ACH-06 | Données essentielles | Compléter un formulaire de publication des données essentielles (DECP), ou importer ces données depuis un autre SI |
| ACH-07 | Courrier électronique | Accéder à un service de courrier électronique (au sens de l'article 1 de la loi n° 2004-575) |
| ACH-08 | Historique et traçabilité | Accéder à un historique des événements : enregistrement et traçabilité des actions (retrait, dépôt de documents, etc.) |
| ACH-09 | Réponses aux questions | Répondre aux questions soumises par les entreprises |
| ACH-10 | Justificatifs et preuves | Obtenir les documents justificatifs et moyens de preuve directement auprès d'autres administrations lorsque c'est possible |
## 2. Fonctionnalités pour l'opérateur économique (marchés publics)
_Réf. : Article 1, II_
Le profil d'acheteur doit permettre à l'opérateur économique de :
| ID | Fonctionnalité | Description |
| ----- | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| OE-01 | Identification et authentification | S'identifier et s'authentifier sur la plateforme |
| OE-02 | Prérequis techniques | Connaître les prérequis techniques et les modules d'extension nécessaires pour utiliser le profil d'acheteur |
| OE-03 | Test de configuration | Accéder à un espace de test permettant de vérifier l'adéquation de la configuration du poste de travail avec les prérequis techniques |
| OE-04 | Recherche | Effectuer une recherche donnant accès aux avis d'appel à la concurrence, aux consultations et aux données essentielles |
| OE-05 | Consultation des documents | Consulter et télécharger en accès gratuit, libre, direct et complet les documents de la consultation, les avis d'appel à la concurrence et leurs modifications |
| OE-06 | Simulation de dépôt | Accéder à un espace permettant de simuler le dépôt de documents |
| OE-07 | Dépôt de candidature | Déposer une candidature, y compris sous forme de DUME électronique (données structurées) |
| OE-08 | Dépôt d'offres | Déposer des offres, y compris les dépôts successifs (quand la procédure le requiert) et les offres signées électroniquement |
| OE-09 | Assistance | Solliciter une assistance ou consulter un support utilisateur pour les problématiques techniques |
| OE-10 | Questions à l'acheteur | Formuler des questions à l'acheteur |
| OE-11 | Données essentielles | Consulter et télécharger les données essentielles de la commande publique |
## 3. Exigences techniques, de sécurité et d'accessibilité (marchés publics)
_Réf. : Article 2_
### 3.1. Conformité aux référentiels
| ID | Exigence | Référentiel |
| ------ | ---------------- | ------------------------------------------------------------------------------------------------ |
| SEC-01 | Sécurité | Conformité au Référentiel Général de Sécurité (RGS) — art. 9 de l'ordonnance n° 2005-1516 |
| SEC-02 | Interopérabilité | Conformité au Référentiel Général d'Interopérabilité (RGI) — art. 9 de l'ordonnance n° 2005-1516 |
| SEC-03 | Accessibilité | Conformité au Référentiel Général d'Accessibilité (RGAA) — art. 11 de l'ordonnance n° 2005-1516 |
### 3.2. Exigences techniques
| ID | Exigence | Description |
| ------- | ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| TECH-01 | Formats de fichiers | Accepter les fichiers communément disponibles, et notamment les formats `.XML` et `.JSON` |
| TECH-02 | Information sur les formats | Indiquer la taille et les formats des documents et avis d'appel à la concurrence |
| TECH-03 | Horodatage qualifié | L'horodatage doit être qualifié conformément au règlement eIDAS (n° 910/2014) |
| TECH-04 | Intégrité des données | Assurer l'intégrité des données |
| TECH-05 | Responsive design | Permettre une visualisation adaptée au média utilisé (responsive) |
| TECH-06 | Confidentialité des soumissions | Garantir la confidentialité des candidatures, offres et demandes de participation jusqu'à l'expiration du délai de soumission. Les documents sont inaccessibles avant cette date, puis accessibles uniquement aux personnes autorisées. Recours obligatoire à des moyens de cryptologie, de gestion des droits d'accès/privilèges, ou technique équivalente |
| TECH-07 | Interopérabilité | Être interopérable avec les autres outils et dispositifs de communication électronique et d'échanges d'informations utilisés dans le cadre de la commande publique |
### 3.3. Accusé de réception
_Réf. : Article 2, III_
Chaque dépôt de documents par un opérateur économique doit déclencher **immédiatement** l'envoi d'un accusé de réception automatique contenant :
| ID | Champ | Description |
| ----- | -------------------------- | -------------------------------------------------------- |
| AR-01 | Identification du déposant | Identification de l'opérateur économique auteur du dépôt |
| AR-02 | Nom de l'acheteur | Nom de l'acheteur public |
| AR-03 | Consultation | Intitulé et objet de la consultation concernée |
| AR-04 | Horodatage | Date et heure de réception des documents |
| AR-05 | Liste des documents | Liste détaillée des documents transmis |
## 4. Fonctionnalités spécifiques aux concessions
_Réf. : Article 3_
### 4.1. Fonctionnalités pour l'autorité concédante
| ID | Fonctionnalité | Description |
| ----------- | ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| CONC-ACH-01 | Identification et authentification | S'identifier et s'authentifier |
| CONC-ACH-02 | Mise à disposition des DCE | Mettre à disposition des documents de la consultation |
| CONC-ACH-03 | Réception des candidatures | Réceptionner et conserver des candidatures |
| CONC-ACH-04 | Réception des offres | Réceptionner et conserver des offres, y compris hors délais |
| CONC-ACH-05 | Données essentielles | Compléter un formulaire de publication des données essentielles ou importer ces données depuis un autre SI |
| CONC-ACH-06 | Historique et traçabilité | Accéder à un historique des événements : enregistrement et traçabilité des actions (retrait, dépôt de documents, etc.) |
### 4.2. Fonctionnalités pour l'opérateur économique (concessions)
| ID | Fonctionnalité | Description |
| ---------- | ---------------------------------- | ---------------------------------------------------------------------------------------------------- |
| CONC-OE-01 | Identification et authentification | S'identifier et s'authentifier |
| CONC-OE-02 | Prérequis techniques | Connaître les prérequis techniques et modules d'extension nécessaires |
| CONC-OE-03 | Test de configuration | Accéder à un espace de test de la configuration du poste de travail |
| CONC-OE-04 | Recherche | Effectuer une recherche donnant accès aux consultations et aux données essentielles |
| CONC-OE-05 | Consultation des documents | Consulter et télécharger en accès gratuit, libre, direct et complet les documents de la consultation |
| CONC-OE-06 | Simulation de dépôt | Accéder à un espace de simulation de dépôt de documents |
| CONC-OE-07 | Dépôt de candidature | Déposer une candidature |
| CONC-OE-08 | Dépôt d'offres | Déposer des offres |
| CONC-OE-09 | Assistance | Solliciter une assistance ou consulter un support utilisateur |
| CONC-OE-10 | Données essentielles | Consulter et télécharger les données essentielles |
### 4.3. Exigences techniques (concessions)
| ID | Exigence | Description |
| ----------- | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| CONC-SEC-01 | Confidentialité | Garantir la confidentialité des candidatures, offres et demandes de participation jusqu'à expiration du délai. Recours à la cryptologie, gestion des droits d'accès, ou technique équivalente |
| CONC-SEC-02 | Intégrité | Assurer l'intégrité des données |
| CONC-SEC-03 | Responsive design | Permettre une visualisation adaptée au média utilisé |
| CONC-SEC-04 | Conformité aux référentiels | Conformité au RGS, RGI et RGAA (art. 9 et 11 de l'ordonnance n° 2005-1516) |
### 4.4. Accusé de réception (concessions)
Mêmes exigences que pour les marchés publics (section 3.3), à l'exception du champ AR-02 qui mentionne le nom de **l'autorité concédante** au lieu de l'acheteur public.
## 5. Référencement du profil d'acheteur
_Réf. : Article 4_
### 5.1. Publication
Le profil d'acheteur doit figurer sur une liste publiée sur le portail unique interministériel de données ouvertes (data.gouv.fr).
### 5.2. Identification
Chaque profil d'acheteur est identifié par :
| ID | Champ | Description |
| ------ | ------------- | ------------------------------------------------------ |
| REF-01 | SIRET | Numéro SIRET de l'acheteur |
| REF-02 | URL du profil | Adresse URL du profil d'acheteur |
| REF-03 | URL du DCAT | Adresse URL du catalogue DCAT des données essentielles |
| REF-04 | Coordonnées | Coordonnées du ou des acheteurs concernés |
### 5.3. Déclaration
La déclaration du profil est effectuée par l'acheteur ou une personne habilitée sur le portail de données ouvertes. Elle comporte :
- L'identité du déclarant
- L'identité de l'organisme chargé de la gestion du profil d'acheteur
- L'adresse URL du profil d'acheteur
- L'adresse URL du DCAT
- Les coordonnées du ou des acheteurs concernés
## 6. Dispositions particulières outre-mer
_Réf. : Article 5_
| Territoire | Adaptation |
| ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Saint-Barthélemy, Saint-Pierre-et-Miquelon | Horodatage qualifié conformément aux dispositions applicables en métropole en vertu du règlement eIDAS |
| Nouvelle-Calédonie, Polynésie française | Horodatage qualifié conformément aux dispositions applicables localement. Applicable uniquement aux contrats de l'État et de ses établissements publics |
| Wallis-et-Futuna, TAAF | Horodatage qualifié conformément aux dispositions applicables en métropole en vertu du règlement eIDAS. Applicable uniquement aux contrats de l'État et de ses établissements publics |
## 7. Matrice de correspondance fonctionnelle
Récapitulatif des fonctionnalités par type de contrat et rôle utilisateur :
| Fonctionnalité | Acheteur (marchés) | OE (marchés) | Autorité concédante | OE (concessions) |
| ------------------------------------------ | :----------------: | :----------: | :-----------------: | :--------------: |
| Authentification | x | x | x | x |
| Publication d'avis | x | | | |
| Mise à disposition DCE | x | | x | |
| Consultation/téléchargement DCE | | x | | x |
| Réception candidatures | x | | x | |
| Dépôt candidature (dont DUME) | | x | | x |
| Réception offres | x | | x | |
| Dépôt offres (dont signature électronique) | | x | | x |
| Données essentielles (saisie/import) | x | | x | |
| Données essentielles (consultation) | | x | | x |
| Courrier électronique | x | | | |
| Historique/traçabilité | x | | x | |
| Réponse aux questions | x | | | |
| Questions à l'acheteur | | x | | |
| Justificatifs via autres administrations | x | | | |
| Prérequis techniques | | x | | x |
| Test de configuration | | x | | x |
| Recherche | | x | | x |
| Simulation de dépôt | | x | | x |
| Assistance/support | | x | | x |
+197
View File
@@ -0,0 +1,197 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "c5b66458e29113e9",
"metadata": {},
"outputs": [],
"source": [
"import polars as pl\n",
"\n",
"pl.Config(\n",
" fmt_str_lengths=120,\n",
" fmt_table_cell_list_len=50,\n",
" set_tbl_rows=100,\n",
" tbl_cols=-1,\n",
")\n",
"\n",
"for methode_dividendes in (\"flat\", \"progressif\"):\n",
" df: pl.DataFrame = pl.DataFrame()\n",
"\n",
" for i in range(0, 11):\n",
" benefice_reel = 3000\n",
" ca = 50000\n",
" depenses_pro = 5000\n",
" remuneration_plus_is = ca - depenses_pro - benefice_reel\n",
" is_minimal = benefice_reel * 0.15\n",
"\n",
" salaires_brut = (remuneration_plus_is - is_minimal) * i / 10\n",
"\n",
" def taux_dividendes():\n",
" taux = {}\n",
" if methode_dividendes == \"flat\":\n",
" taux = {\"retenue_source\": 0.7, \"abattement\": 0}\n",
" elif methode_dividendes == \"progressif\":\n",
" taux = {\"retenue_source\": 0.828, \"abattement\": 0.6}\n",
" return taux\n",
"\n",
" def calcul_cout_dividendes():\n",
" return remuneration_plus_is - salaires_brut - is_minimal\n",
"\n",
" def calcul_dividendes_bruts():\n",
" return calcul_cout_dividendes() / 1.15\n",
"\n",
" def calcul_cout_remuneration():\n",
" return calcul_dividendes_bruts() * 1.15 + salaires_brut\n",
"\n",
" def calcul_dividendes_net():\n",
" dividendes_bruts = calcul_dividendes_bruts()\n",
" dividendes_net = dividendes_bruts * taux_dividendes()[\"retenue_source\"]\n",
" return dividendes_net\n",
"\n",
" def calcul_salaires_net():\n",
" return salaires_brut * 0.563\n",
"\n",
" def calcul_revenu_imposable():\n",
" return (calcul_salaires_net() * 0.9) + (\n",
" calcul_dividendes_net() * taux_dividendes()[\"abattement\"]\n",
" )\n",
"\n",
" def calcul_revenu_net():\n",
" return calcul_salaires_net() + calcul_dividendes_net()\n",
"\n",
" def calcul_benefice():\n",
" return ca - depenses_pro - salaires_brut\n",
"\n",
" def calcul_is():\n",
" return (calcul_benefice() - is_minimal) * 0.15\n",
"\n",
" def calcul_ir(revenu):\n",
" tranches_ir = [[11488, 0], [29315, 0.11], [83283, 0.3]]\n",
" revenu_restant = revenu\n",
" ir = 0\n",
" for tranche in tranches_ir:\n",
" if revenu_restant > 0:\n",
" ir_tranche = min(revenu_restant, tranche[0]) * tranche[1]\n",
" ir = +ir_tranche\n",
" revenu_restant = revenu_restant - tranche[0]\n",
"\n",
" return ir\n",
"\n",
" def calcul_revenu_ae():\n",
" apres_cotisations = calcul_cout_remuneration() * 0.76 - depenses_pro\n",
" impots = calcul_ir(apres_cotisations * 0.66)\n",
" return apres_cotisations - impots\n",
"\n",
" def fmt(value):\n",
" return str(int(value))\n",
"\n",
" # print(salaires_brut)\n",
" # print(calcul_cout_dividendes())\n",
" # print(calcul_dividendes_bruts())\n",
" # print(calcul_is())\n",
" # print(\"\")\n",
" # print(\"\")\n",
" #\n",
" # print(salaires_brut + calcul_dividendes_bruts() + calcul_is(), \" == \", remuneration_plus_is)\n",
"\n",
" # assert salaires_brut + calcul_dividendes_bruts() + calcul_is() == remuneration_plus_is\n",
"\n",
" row: dict = {\n",
" \"Salaires bruts\": [fmt(salaires_brut / 12)],\n",
" \"Dividendes bruts\": [fmt(calcul_cout_dividendes() / 12)],\n",
" \"Benefice\": [fmt(calcul_benefice())],\n",
" \"Benefice réél\": [\n",
" fmt(calcul_benefice() - calcul_is() - calcul_dividendes_bruts())\n",
" ],\n",
" \"IS\": [fmt(calcul_is())],\n",
" \"IR\": [fmt(calcul_ir(calcul_revenu_imposable()) / 12)],\n",
" \"IS + IR\": [fmt(calcul_is() + calcul_ir(calcul_revenu_imposable()))],\n",
" \"Salaires net\": [fmt(calcul_salaires_net() / 12)],\n",
" \"Dividendes net\": [fmt(calcul_dividendes_net() / 12)],\n",
" \"Revenu net ap. impôts\": [\n",
" fmt((calcul_revenu_net() - calcul_ir(calcul_revenu_imposable())) / 12)\n",
" ],\n",
" \"Revenue AE ap. impôts\": [fmt(calcul_revenu_ae() / 12)],\n",
" }\n",
"\n",
" df = pl.concat([df, pl.from_dict(row)])\n",
"\n",
" print(df)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "initial_id",
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"from dash import ALL, Dash, Input, Output, Patch, State, callback, dcc, html\n",
"\n",
"app = Dash()\n",
"\n",
"app.layout = html.Div(\n",
" [\n",
" html.Button(\"Add Filter\", id=\"add-filter-btn\", n_clicks=0),\n",
" html.Div(id=\"dropdown-container-div\", children=[]),\n",
" html.Div(id=\"dropdown-container-output-div\"),\n",
" ]\n",
")\n",
"\n",
"\n",
"@callback(\n",
" Output(\"dropdown-container-div\", \"children\"), Input(\"add-filter-btn\", \"n_clicks\")\n",
")\n",
"def display_dropdowns(n_clicks):\n",
" patched_children = Patch()\n",
" new_dropdown = dcc.Dropdown(\n",
" [\"NYC\", \"MTL\", \"LA\", \"TOKYO\"],\n",
" id={\"type\": \"city-filter-dropdown\", \"index\": n_clicks},\n",
" )\n",
" patched_children.append(new_dropdown)\n",
" return patched_children\n",
"\n",
"\n",
"@callback(\n",
" Output(\"dropdown-container-output-div\", \"children\"),\n",
" Input({\"type\": \"city-filter-dropdown\", \"index\": ALL}, \"value\"),\n",
" State({\"type\": \"city-dynamic-dropdown\", \"index\": ALL}, \"id\"),\n",
")\n",
"def display_output(values, ids):\n",
" return html.Div(\n",
" [html.Div(f\"Dropdown {i + 1} = {value}\") for (i, value) in enumerate(values)]\n",
" + [html.P(ids)],\n",
" )\n",
"\n",
"\n",
"if __name__ == \"__main__\":\n",
" app.run(debug=True)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 484 KiB

Binary file not shown.
Binary file not shown.
+4 -1
View File
@@ -45,9 +45,9 @@ def restore(config: BackupConfig, storage: Storage, key: str, now: datetime) ->
with tempfile.NamedTemporaryFile(suffix=".sqlite", delete=False) as tmp: with tempfile.NamedTemporaryFile(suffix=".sqlite", delete=False) as tmp:
tmp_path = Path(tmp.name) tmp_path = Path(tmp.name)
try:
snapshot.write_snapshot(data, tmp_path) snapshot.write_snapshot(data, tmp_path)
if not snapshot.verify_integrity(tmp_path): if not snapshot.verify_integrity(tmp_path):
tmp_path.unlink(missing_ok=True)
raise ValueError(f"Sauvegarde corrompue, restauration annulée : {key}") raise ValueError(f"Sauvegarde corrompue, restauration annulée : {key}")
db_path = config.db_path db_path = config.db_path
@@ -56,4 +56,7 @@ def restore(config: BackupConfig, storage: Storage, key: str, now: datetime) ->
if db_path.exists(): if db_path.exists():
backup_copy.write_bytes(db_path.read_bytes()) backup_copy.write_bytes(db_path.read_bytes())
os.replace(tmp_path, db_path) os.replace(tmp_path, db_path)
except Exception:
tmp_path.unlink(missing_ok=True)
raise
return backup_copy return backup_copy
+71
View File
@@ -0,0 +1,71 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "initial_id",
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"import duckdb\n",
"\n",
"conn = duckdb.connect(\"tests/\")\n",
"cursor = conn.cursor()\n",
"df = cursor.execute(\"select * from decp limit 1\").pl()\n",
"df.columns"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "859cd599b5befafb",
"metadata": {
"ExecuteTime": {
"end_time": "2026-04-22T15:00:32.430249Z",
"start_time": "2026-04-22T15:00:31.843470Z"
}
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import polars as pl\n",
"\n",
"schema = pl.read_parquet(\"../decp-processing/decp_prod.parquet\").schema\n",
"schema[\"dureeMois\"].is_integer()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
+26
View File
@@ -0,0 +1,26 @@
import dash_ag_grid as dag
import pandas as pd
from dash import Dash, html
df = pd.read_csv(
"https://raw.githubusercontent.com/plotly/datasets/master/gapminder2007.csv"
)
app = Dash()
columnDefs = [
{"field": "country", "filter": True},
{"field": "pop", "headerName": "Population"},
{"field": "lifeExp", "headerName": "Life Expectancy", "filter": True},
]
grid = dag.AgGrid(
id="getting-started-filter",
rowData=df.to_dict("records"),
columnDefs=columnDefs,
)
app.layout = html.Div([grid])
if __name__ == "__main__":
app.run(debug=True)
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Generated
+111
View File
@@ -215,6 +215,34 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc", size = 8458, upload-time = "2024-11-08T17:25:46.184Z" }, { url = "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc", size = 8458, upload-time = "2024-11-08T17:25:46.184Z" },
] ]
[[package]]
name = "boto3"
version = "1.43.36"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "botocore" },
{ name = "jmespath" },
{ name = "s3transfer" },
]
sdist = { url = "https://files.pythonhosted.org/packages/ff/9f/897287e955db0f50b12fd69ef45956e4fd2c7ddb48c736872f7ea2314443/boto3-1.43.36.tar.gz", hash = "sha256:587d7ee92a12e440ad12b0e7f11f3358f0c4d65b19f64726efc94aaf194aff28", size = 112690, upload-time = "2026-06-23T02:47:14.561Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/9f/f1/274303f52483ecf199eae6f8d9b6f5951670397ee4d72c06cfd4eb644612/boto3-1.43.36-py3-none-any.whl", hash = "sha256:42942dde254673abcbc9e6e60017c88341a4f49d99d24e1f2e290fb38138c26f", size = 140031, upload-time = "2026-06-23T02:47:13.178Z" },
]
[[package]]
name = "botocore"
version = "1.43.36"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "jmespath" },
{ name = "python-dateutil" },
{ name = "urllib3" },
]
sdist = { url = "https://files.pythonhosted.org/packages/7c/37/da9e7f6ca73ac73afd7f0bb7f238aa5daba35c081e98d7f48a7c399599c0/botocore-1.43.36.tar.gz", hash = "sha256:4cae47d1b2d426316b85a0087d9e69e048f13bc003b5177d74639fe9dfd28205", size = 15625488, upload-time = "2026-06-23T02:47:03.192Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/5c/19/934f81592527a3f7f9b943c893e334c721a4644948642bc33885d584e9ec/botocore-1.43.36-py3-none-any.whl", hash = "sha256:3c65fdc39ed01d8dfde1e961b34038aed03c459f8ddf80717a12ac006475e49d", size = 15313630, upload-time = "2026-06-23T02:46:59.327Z" },
]
[[package]] [[package]]
name = "brevo-python" name = "brevo-python"
version = "5.0.0rc1" version = "5.0.0rc1"
@@ -826,7 +854,9 @@ name = "decp-info"
version = "2.8.0" version = "2.8.0"
source = { virtual = "." } source = { virtual = "." }
dependencies = [ dependencies = [
{ name = "boto3" },
{ name = "brevo-python" }, { name = "brevo-python" },
{ name = "cryptography" },
{ name = "dash", extra = ["compress"] }, { name = "dash", extra = ["compress"] },
{ name = "dash-bootstrap-components" }, { name = "dash-bootstrap-components" },
{ name = "dash-extensions", version = "1.0.20", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "dash-extensions", version = "1.0.20", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
@@ -857,6 +887,7 @@ dependencies = [
dev = [ dev = [
{ name = "dash", extra = ["testing"] }, { name = "dash", extra = ["testing"] },
{ name = "fastexcel" }, { name = "fastexcel" },
{ name = "moto", extra = ["s3"] },
{ name = "openpyxl" }, { name = "openpyxl" },
{ name = "pre-commit" }, { name = "pre-commit" },
{ name = "pytest" }, { name = "pytest" },
@@ -867,7 +898,9 @@ dev = [
[package.metadata] [package.metadata]
requires-dist = [ requires-dist = [
{ name = "boto3" },
{ name = "brevo-python", specifier = "==5.0.0rc1" }, { name = "brevo-python", specifier = "==5.0.0rc1" },
{ name = "cryptography" },
{ name = "dash", specifier = "==3.4.0" }, { name = "dash", specifier = "==3.4.0" },
{ name = "dash", extras = ["compress"] }, { name = "dash", extras = ["compress"] },
{ name = "dash-bootstrap-components" }, { name = "dash-bootstrap-components" },
@@ -896,6 +929,7 @@ requires-dist = [
dev = [ dev = [
{ name = "dash", extras = ["testing"] }, { name = "dash", extras = ["testing"] },
{ name = "fastexcel" }, { name = "fastexcel" },
{ name = "moto", extras = ["s3"] },
{ name = "openpyxl" }, { name = "openpyxl" },
{ name = "pre-commit" }, { name = "pre-commit" },
{ name = "pytest" }, { name = "pytest" },
@@ -1273,6 +1307,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" },
] ]
[[package]]
name = "jmespath"
version = "1.1.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/d3/59/322338183ecda247fb5d1763a6cbe46eff7222eaeebafd9fa65d4bf5cb11/jmespath-1.1.0.tar.gz", hash = "sha256:472c87d80f36026ae83c6ddd0f1d05d4e510134ed462851fd5f754c8c3cbb88d", size = 27377, upload-time = "2026-01-22T16:35:26.279Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl", hash = "sha256:a5663118de4908c91729bea0acadca56526eb2698e83de10cd116ae0f4e97c64", size = 20419, upload-time = "2026-01-22T16:35:24.919Z" },
]
[[package]] [[package]]
name = "jsbeautifier" name = "jsbeautifier"
version = "1.15.4" version = "1.15.4"
@@ -1566,6 +1609,30 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/e8/3d/1087453384dbde46a8c7f9356eead2c58be8a7bf156bca40243377c85715/more_itertools-11.1.0-py3-none-any.whl", hash = "sha256:4b65538ae22f6fed0ce4874efd317463a7489796a0939fa66824dd542125a192", size = 72226, upload-time = "2026-05-22T14:14:28.824Z" }, { url = "https://files.pythonhosted.org/packages/e8/3d/1087453384dbde46a8c7f9356eead2c58be8a7bf156bca40243377c85715/more_itertools-11.1.0-py3-none-any.whl", hash = "sha256:4b65538ae22f6fed0ce4874efd317463a7489796a0939fa66824dd542125a192", size = 72226, upload-time = "2026-05-22T14:14:28.824Z" },
] ]
[[package]]
name = "moto"
version = "5.2.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "boto3" },
{ name = "botocore" },
{ name = "cryptography" },
{ name = "requests" },
{ name = "responses" },
{ name = "werkzeug" },
{ name = "xmltodict" },
]
sdist = { url = "https://files.pythonhosted.org/packages/47/63/d944f387582cc53f53febbff2b3fa36a6d2ed7c1feef8990bf646cfa9cba/moto-5.2.2.tar.gz", hash = "sha256:aac8023a429e125e91c91f8f4730a67b54f518cda587352f7e67252fe3168f75", size = 8678761, upload-time = "2026-06-06T18:57:54.931Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/c1/45/13cff46f4f617a6e97e1d497d75abd913e250bb4c823a4985668c6e593e4/moto-5.2.2-py3-none-any.whl", hash = "sha256:3817f1e39721ca833579b921e53e3b68547ace6a34d848c9486fbb5905808de9", size = 6698689, upload-time = "2026-06-06T18:57:51.435Z" },
]
[package.optional-dependencies]
s3 = [
{ name = "py-partiql-parser" },
{ name = "pyyaml" },
]
[[package]] [[package]]
name = "multiprocess" name = "multiprocess"
version = "0.70.19" version = "0.70.19"
@@ -2136,6 +2203,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/8c/c7/7bb2e321574b10df20cbde462a94e2b71d05f9bbda251ef27d104668306a/psutil-7.2.2-cp37-abi3-win_arm64.whl", hash = "sha256:8c233660f575a5a89e6d4cb65d9f938126312bca76d8fe087b947b3a1aaac9ee", size = 134617, upload-time = "2026-01-28T18:15:36.514Z" }, { url = "https://files.pythonhosted.org/packages/8c/c7/7bb2e321574b10df20cbde462a94e2b71d05f9bbda251ef27d104668306a/psutil-7.2.2-cp37-abi3-win_arm64.whl", hash = "sha256:8c233660f575a5a89e6d4cb65d9f938126312bca76d8fe087b947b3a1aaac9ee", size = 134617, upload-time = "2026-01-28T18:15:36.514Z" },
] ]
[[package]]
name = "py-partiql-parser"
version = "0.6.3"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/56/7a/a0f6bda783eb4df8e3dfd55973a1ac6d368a89178c300e1b5b91cd181e5e/py_partiql_parser-0.6.3.tar.gz", hash = "sha256:09cecf916ce6e3da2c050f0cb6106166de42c33d34a078ec2eb19377ea70389a", size = 17456, upload-time = "2025-10-18T13:56:13.441Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/c9/33/a7cbfccc39056a5cf8126b7aab4c8bafbedd4f0ca68ae40ecb627a2d2cd3/py_partiql_parser-0.6.3-py2.py3-none-any.whl", hash = "sha256:deb0769c3346179d2f590dcbde556f708cdb929059fb654bad75f4cf6e07f582", size = 23752, upload-time = "2025-10-18T13:56:12.256Z" },
]
[[package]] [[package]]
name = "pyarrow" name = "pyarrow"
version = "24.0.0" version = "24.0.0"
@@ -2518,6 +2594,20 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl", hash = "sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0", size = 73075, upload-time = "2026-05-14T19:25:26.443Z" }, { url = "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl", hash = "sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0", size = 73075, upload-time = "2026-05-14T19:25:26.443Z" },
] ]
[[package]]
name = "responses"
version = "0.26.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pyyaml" },
{ name = "requests" },
{ name = "urllib3" },
]
sdist = { url = "https://files.pythonhosted.org/packages/c2/58/1fb6de3503428196df78638f991ec8095274f1ee9723e272ee4d9ff0092b/responses-0.26.1.tar.gz", hash = "sha256:2eb3218553cc8f79b57d257bac23af5e1bf381f5b9390b1767816f0843e01dc2", size = 83088, upload-time = "2026-05-21T19:56:39.747Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/3a/31/6a620b4427d546b9e7cca8b3b8c5f0559d9cef2bb9eedcda7f73c1473c19/responses-0.26.1-py3-none-any.whl", hash = "sha256:8aacc4586eb08fb2208ef64a9eb4258d9b0c6e6f4260845f2f018ab847495345", size = 35502, upload-time = "2026-05-21T19:56:38.046Z" },
]
[[package]] [[package]]
name = "retrying" name = "retrying"
version = "1.4.2" version = "1.4.2"
@@ -2527,6 +2617,18 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/67/f3/6cd296376653270ac1b423bb30bd70942d9916b6978c6f40472d6ac038e7/retrying-1.4.2-py3-none-any.whl", hash = "sha256:bbc004aeb542a74f3569aeddf42a2516efefcdaff90df0eb38fbfbf19f179f59", size = 10859, upload-time = "2025-08-03T03:35:23.829Z" }, { url = "https://files.pythonhosted.org/packages/67/f3/6cd296376653270ac1b423bb30bd70942d9916b6978c6f40472d6ac038e7/retrying-1.4.2-py3-none-any.whl", hash = "sha256:bbc004aeb542a74f3569aeddf42a2516efefcdaff90df0eb38fbfbf19f179f59", size = 10859, upload-time = "2025-08-03T03:35:23.829Z" },
] ]
[[package]]
name = "s3transfer"
version = "0.19.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "botocore" },
]
sdist = { url = "https://files.pythonhosted.org/packages/f6/94/dcdaeb1713cab9c84def276cfac7388b17c7d9855bbcfe88d77e4dbafd44/s3transfer-0.19.0.tar.gz", hash = "sha256:ce436931687addc4c1712d52d40b32f53e88315723f107ffa20ba82b05a0f685", size = 165171, upload-time = "2026-06-16T19:44:51.599Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/46/5f/4c174edad94f82de888ac00a5ddd8d07b35609b6c94f0bdf4d74af57703e/s3transfer-0.19.0-py3-none-any.whl", hash = "sha256:777cc2415536f1debadb5c2ef7779275d0fc0fe0e042411cdd6caebeb2685262", size = 90101, upload-time = "2026-06-16T19:44:50.439Z" },
]
[[package]] [[package]]
name = "selenium" name = "selenium"
version = "4.2.0" version = "4.2.0"
@@ -2838,6 +2940,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/3a/0c/3662f4a66880196a590b202f0db82d919dd2f89e99a27fadef91c4a33d41/xlsxwriter-3.2.9-py3-none-any.whl", hash = "sha256:9a5db42bc5dff014806c58a20b9eae7322a134abb6fce3c92c181bfb275ec5b3", size = 175315, upload-time = "2025-09-16T00:16:20.108Z" }, { url = "https://files.pythonhosted.org/packages/3a/0c/3662f4a66880196a590b202f0db82d919dd2f89e99a27fadef91c4a33d41/xlsxwriter-3.2.9-py3-none-any.whl", hash = "sha256:9a5db42bc5dff014806c58a20b9eae7322a134abb6fce3c92c181bfb275ec5b3", size = 175315, upload-time = "2025-09-16T00:16:20.108Z" },
] ]
[[package]]
name = "xmltodict"
version = "1.0.4"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/19/70/80f3b7c10d2630aa66414bf23d210386700aa390547278c789afa994fd7e/xmltodict-1.0.4.tar.gz", hash = "sha256:6d94c9f834dd9e44514162799d344d815a3a4faec913717a9ecbfa5be1bb8e61", size = 26124, upload-time = "2026-02-22T02:21:22.074Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/38/34/98a2f52245f4d47be93b580dae5f9861ef58977d73a79eb47c58f1ad1f3a/xmltodict-1.0.4-py3-none-any.whl", hash = "sha256:a4a00d300b0e1c59fc2bfccb53d7b2e88c32f200df138a0dd2229f842497026a", size = 13580, upload-time = "2026-02-22T02:21:21.039Z" },
]
[[package]] [[package]]
name = "zipp" name = "zipp"
version = "4.1.0" version = "4.1.0"