pycopg 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pycopg-0.1.0/.github/workflows/publish.yml +45 -0
- pycopg-0.1.0/.gitignore +63 -0
- pycopg-0.1.0/.readthedocs.yaml +21 -0
- pycopg-0.1.0/AUDIT.md +265 -0
- pycopg-0.1.0/LICENSE +21 -0
- pycopg-0.1.0/PKG-INFO +470 -0
- pycopg-0.1.0/README.md +423 -0
- pycopg-0.1.0/docs/Makefile +46 -0
- pycopg-0.1.0/docs/_templates/sidebar/language-switcher.html +12 -0
- pycopg-0.1.0/docs/api-reference.md +363 -0
- pycopg-0.1.0/docs/async-database.md +334 -0
- pycopg-0.1.0/docs/backup-restore.md +388 -0
- pycopg-0.1.0/docs/conf.py +113 -0
- pycopg-0.1.0/docs/configuration.md +134 -0
- pycopg-0.1.0/docs/connection-pooling.md +248 -0
- pycopg-0.1.0/docs/database.md +397 -0
- pycopg-0.1.0/docs/getting-started.md +172 -0
- pycopg-0.1.0/docs/index.md +99 -0
- pycopg-0.1.0/docs/locale/fr/LC_MESSAGES/api-reference.mo +0 -0
- pycopg-0.1.0/docs/locale/fr/LC_MESSAGES/api-reference.po +1022 -0
- pycopg-0.1.0/docs/locale/fr/LC_MESSAGES/async-database.mo +0 -0
- pycopg-0.1.0/docs/locale/fr/LC_MESSAGES/async-database.po +199 -0
- pycopg-0.1.0/docs/locale/fr/LC_MESSAGES/backup-restore.mo +0 -0
- pycopg-0.1.0/docs/locale/fr/LC_MESSAGES/backup-restore.po +155 -0
- pycopg-0.1.0/docs/locale/fr/LC_MESSAGES/configuration.mo +0 -0
- pycopg-0.1.0/docs/locale/fr/LC_MESSAGES/configuration.po +253 -0
- pycopg-0.1.0/docs/locale/fr/LC_MESSAGES/connection-pooling.mo +0 -0
- pycopg-0.1.0/docs/locale/fr/LC_MESSAGES/connection-pooling.po +191 -0
- pycopg-0.1.0/docs/locale/fr/LC_MESSAGES/database.mo +0 -0
- pycopg-0.1.0/docs/locale/fr/LC_MESSAGES/database.po +192 -0
- pycopg-0.1.0/docs/locale/fr/LC_MESSAGES/getting-started.mo +0 -0
- pycopg-0.1.0/docs/locale/fr/LC_MESSAGES/getting-started.po +115 -0
- pycopg-0.1.0/docs/locale/fr/LC_MESSAGES/index.mo +0 -0
- pycopg-0.1.0/docs/locale/fr/LC_MESSAGES/index.po +160 -0
- pycopg-0.1.0/docs/locale/fr/LC_MESSAGES/migrations.mo +0 -0
- pycopg-0.1.0/docs/locale/fr/LC_MESSAGES/migrations.po +199 -0
- pycopg-0.1.0/docs/locale/fr/LC_MESSAGES/postgis.mo +0 -0
- pycopg-0.1.0/docs/locale/fr/LC_MESSAGES/postgis.po +135 -0
- pycopg-0.1.0/docs/locale/fr/LC_MESSAGES/roles-permissions.mo +0 -0
- pycopg-0.1.0/docs/locale/fr/LC_MESSAGES/roles-permissions.po +179 -0
- pycopg-0.1.0/docs/locale/fr/LC_MESSAGES/timescaledb.mo +0 -0
- pycopg-0.1.0/docs/locale/fr/LC_MESSAGES/timescaledb.po +199 -0
- pycopg-0.1.0/docs/make.bat +35 -0
- pycopg-0.1.0/docs/migrations.md +390 -0
- pycopg-0.1.0/docs/postgis.md +307 -0
- pycopg-0.1.0/docs/requirements.txt +6 -0
- pycopg-0.1.0/docs/roles-permissions.md +342 -0
- pycopg-0.1.0/docs/timescaledb.md +377 -0
- pycopg-0.1.0/pycopg/__init__.py +89 -0
- pycopg-0.1.0/pycopg/async_database.py +736 -0
- pycopg-0.1.0/pycopg/base.py +194 -0
- pycopg-0.1.0/pycopg/config.py +244 -0
- pycopg-0.1.0/pycopg/database.py +2255 -0
- pycopg-0.1.0/pycopg/exceptions.py +38 -0
- pycopg-0.1.0/pycopg/migrations.py +388 -0
- pycopg-0.1.0/pycopg/pool.py +416 -0
- pycopg-0.1.0/pycopg/py.typed +0 -0
- pycopg-0.1.0/pycopg/queries.py +262 -0
- pycopg-0.1.0/pycopg/utils.py +133 -0
- pycopg-0.1.0/pyproject.toml +85 -0
- pycopg-0.1.0/tests/__init__.py +1 -0
- pycopg-0.1.0/tests/conftest.py +113 -0
- pycopg-0.1.0/tests/test_async_database.py +417 -0
- pycopg-0.1.0/tests/test_base.py +207 -0
- pycopg-0.1.0/tests/test_config.py +251 -0
- pycopg-0.1.0/tests/test_database.py +991 -0
- pycopg-0.1.0/tests/test_exceptions.py +81 -0
- pycopg-0.1.0/tests/test_migrations.py +467 -0
- pycopg-0.1.0/tests/test_pool.py +413 -0
- pycopg-0.1.0/tests/test_utils.py +180 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
build:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
|
|
14
|
+
- name: Set up Python
|
|
15
|
+
uses: actions/setup-python@v5
|
|
16
|
+
with:
|
|
17
|
+
python-version: "3.12"
|
|
18
|
+
|
|
19
|
+
- name: Install build dependencies
|
|
20
|
+
run: pip install build
|
|
21
|
+
|
|
22
|
+
- name: Build package
|
|
23
|
+
run: python -m build
|
|
24
|
+
|
|
25
|
+
- name: Upload artifacts
|
|
26
|
+
uses: actions/upload-artifact@v4
|
|
27
|
+
with:
|
|
28
|
+
name: dist
|
|
29
|
+
path: dist/
|
|
30
|
+
|
|
31
|
+
publish:
|
|
32
|
+
needs: build
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
environment: pypi
|
|
35
|
+
permissions:
|
|
36
|
+
id-token: write
|
|
37
|
+
steps:
|
|
38
|
+
- name: Download artifacts
|
|
39
|
+
uses: actions/download-artifact@v4
|
|
40
|
+
with:
|
|
41
|
+
name: dist
|
|
42
|
+
path: dist/
|
|
43
|
+
|
|
44
|
+
- name: Publish to PyPI
|
|
45
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
pycopg-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
*.egg-info/
|
|
24
|
+
.installed.cfg
|
|
25
|
+
*.egg
|
|
26
|
+
|
|
27
|
+
# Virtual environments
|
|
28
|
+
venv/
|
|
29
|
+
ENV/
|
|
30
|
+
env/
|
|
31
|
+
.venv/
|
|
32
|
+
|
|
33
|
+
# IDE
|
|
34
|
+
.idea/
|
|
35
|
+
.vscode/
|
|
36
|
+
*.swp
|
|
37
|
+
*.swo
|
|
38
|
+
*~
|
|
39
|
+
|
|
40
|
+
# Testing
|
|
41
|
+
.pytest_cache/
|
|
42
|
+
.coverage
|
|
43
|
+
htmlcov/
|
|
44
|
+
.tox/
|
|
45
|
+
.nox/
|
|
46
|
+
|
|
47
|
+
# Documentation builds
|
|
48
|
+
docs/_build/
|
|
49
|
+
|
|
50
|
+
# Type checking
|
|
51
|
+
.mypy_cache/
|
|
52
|
+
.dmypy.json
|
|
53
|
+
|
|
54
|
+
# Jupyter
|
|
55
|
+
.ipynb_checkpoints/
|
|
56
|
+
|
|
57
|
+
# OS
|
|
58
|
+
.DS_Store
|
|
59
|
+
Thumbs.db
|
|
60
|
+
|
|
61
|
+
# Local config
|
|
62
|
+
.env
|
|
63
|
+
.env.local
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Read the Docs configuration file
|
|
2
|
+
# See https://docs.readthedocs.io/en/stable/config-file/v2.html
|
|
3
|
+
|
|
4
|
+
version: 2
|
|
5
|
+
|
|
6
|
+
build:
|
|
7
|
+
os: ubuntu-24.04
|
|
8
|
+
tools:
|
|
9
|
+
python: "3.12"
|
|
10
|
+
commands:
|
|
11
|
+
# Build all languages (EN + FR) with our custom target
|
|
12
|
+
- pip install -r docs/requirements.txt
|
|
13
|
+
- cd docs && make html-all
|
|
14
|
+
# Move to RTD expected location
|
|
15
|
+
- mkdir -p $READTHEDOCS_OUTPUT/html
|
|
16
|
+
- cp -r docs/_build/html/* $READTHEDOCS_OUTPUT/html/
|
|
17
|
+
|
|
18
|
+
python:
|
|
19
|
+
install:
|
|
20
|
+
- method: pip
|
|
21
|
+
path: .
|
pycopg-0.1.0/AUDIT.md
ADDED
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
# Audit du Projet pycopg
|
|
2
|
+
|
|
3
|
+
**Date** : 2026-01-02
|
|
4
|
+
**Version auditée** : 0.1.0
|
|
5
|
+
**Auditeur** : Claude Code
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. Vue d'ensemble
|
|
10
|
+
|
|
11
|
+
**pycopg** est une API Python de haut niveau pour PostgreSQL/PostGIS/TimescaleDB basée sur psycopg 3.
|
|
12
|
+
Le projet comprend ~3,800 lignes de code réparties sur 6 modules principaux.
|
|
13
|
+
|
|
14
|
+
### Structure du projet
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
pycopg/
|
|
18
|
+
├── __init__.py (78 lignes) - Exports publics
|
|
19
|
+
├── config.py (244 lignes) - Configuration et parsing d'URL
|
|
20
|
+
├── exceptions.py (38 lignes) - Hiérarchie d'exceptions
|
|
21
|
+
├── database.py (2061 lignes) - Interface sync principale
|
|
22
|
+
├── async_database.py (567 lignes) - Interface async
|
|
23
|
+
├── pool.py (416 lignes) - Connection pooling
|
|
24
|
+
└── migrations.py (388 lignes) - Système de migrations SQL
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 2. Points Positifs
|
|
30
|
+
|
|
31
|
+
| Aspect | Évaluation |
|
|
32
|
+
|--------|------------|
|
|
33
|
+
| **Architecture** | Bonne séparation des responsabilités (sync/async, pool, migrations) |
|
|
34
|
+
| **Documentation** | Excellente - docstrings complètes avec exemples |
|
|
35
|
+
| **Typage** | Bon usage de type hints et TYPE_CHECKING |
|
|
36
|
+
| **Sécurité SQL** | `_validate_identifier()` protège contre l'injection |
|
|
37
|
+
| **Context managers** | Gestion correcte des ressources |
|
|
38
|
+
| **Dépendances optionnelles** | Gestion élégante (dotenv, geopandas) |
|
|
39
|
+
| **API Pythonic** | Interface intuitive et cohérente |
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## 3. Issues Identifiées
|
|
44
|
+
|
|
45
|
+
### 3.1 Sécurité - Priorité HAUTE
|
|
46
|
+
|
|
47
|
+
#### 3.1.1 Identifiants SQL non validés
|
|
48
|
+
|
|
49
|
+
**Fichier** : `database.py`
|
|
50
|
+
|
|
51
|
+
| Méthode | Ligne | Paramètres non validés |
|
|
52
|
+
|---------|-------|------------------------|
|
|
53
|
+
| `create()` | 169-170 | `owner`, `template` |
|
|
54
|
+
| `create_database()` | 373-378 | `owner`, `template` |
|
|
55
|
+
| `add_foreign_key()` | 693-737 | tous les paramètres |
|
|
56
|
+
| `create_index()` | 758-797 | `method` |
|
|
57
|
+
| `enable_compression()` | 1110-1141 | `segment_by`, `order_by` |
|
|
58
|
+
| `create_hypertable()` | 1069-1108 | `chunk_time_interval` |
|
|
59
|
+
|
|
60
|
+
**Risque** : Injection SQL si des entrées utilisateur sont passées directement.
|
|
61
|
+
|
|
62
|
+
**Exemple vulnérable** :
|
|
63
|
+
```python
|
|
64
|
+
# Ligne 169-170
|
|
65
|
+
owner_clause = f" OWNER {owner}" if owner else ""
|
|
66
|
+
cur.execute(f"CREATE DATABASE {name}{owner_clause} TEMPLATE {template}")
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
#### 3.1.2 pool.py sans validation
|
|
70
|
+
|
|
71
|
+
**Fichier** : `pool.py`
|
|
72
|
+
|
|
73
|
+
Le module `pool.py` n'importe pas et n'utilise pas `_validate_identifier()`.
|
|
74
|
+
Si des méthodes avec construction SQL dynamique sont ajoutées, elles seront vulnérables.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
### 3.2 Bugs - Priorité HAUTE
|
|
79
|
+
|
|
80
|
+
#### 3.2.1 Accès incorrect au résultat dict
|
|
81
|
+
|
|
82
|
+
**Fichier** : `database.py:1984`
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
def copy_to_csv(...) -> int:
|
|
86
|
+
# ...
|
|
87
|
+
cur.execute(f"SELECT COUNT(*) FROM {schema}.{table}")
|
|
88
|
+
return cur.fetchone()[0] # BUG: dict_row retourne un dict, pas un tuple!
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**Correction** : `return cur.fetchone()["count"]` ou utiliser `fetch_val()`.
|
|
92
|
+
|
|
93
|
+
#### 3.2.2 Stub load_dotenv incompatible
|
|
94
|
+
|
|
95
|
+
**Fichier** : `config.py:20-22` vs `config.py:136`
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
# Stub (ligne 20-22)
|
|
99
|
+
def load_dotenv(dotenv_path=None):
|
|
100
|
+
"""No-op when python-dotenv is not installed."""
|
|
101
|
+
pass
|
|
102
|
+
|
|
103
|
+
# Utilisation (ligne 136)
|
|
104
|
+
load_dotenv(dotenv_path, override=True) # override= non supporté par le stub!
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
### 3.3 Dead Code - Priorité MOYENNE
|
|
110
|
+
|
|
111
|
+
#### 3.3.1 Attribut `_pool` inutilisé
|
|
112
|
+
|
|
113
|
+
**Fichier** : `async_database.py:54`
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
class AsyncDatabase:
|
|
117
|
+
def __init__(self, config: Config):
|
|
118
|
+
self.config = config
|
|
119
|
+
self._pool: Optional[AsyncConnectionPool] = None # Jamais utilisé!
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
L'attribut `_pool` est initialisé mais jamais assigné à un vrai pool.
|
|
123
|
+
L'import `AsyncConnectionPool` dans TYPE_CHECKING est donc aussi inutile.
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
### 3.4 Duplication de Code (DRY) - Priorité MOYENNE
|
|
128
|
+
|
|
129
|
+
#### 3.4.1 `_validate_identifier()` dupliquée
|
|
130
|
+
|
|
131
|
+
La même fonction est définie 3 fois :
|
|
132
|
+
- `database.py:2038-2046`
|
|
133
|
+
- `async_database.py:548-552`
|
|
134
|
+
- Absente de `pool.py` (problème de sécurité)
|
|
135
|
+
|
|
136
|
+
#### 3.4.2 Requêtes SQL dupliquées
|
|
137
|
+
|
|
138
|
+
Les requêtes suivantes sont identiques entre `Database` et `AsyncDatabase` :
|
|
139
|
+
- `list_schemas()`
|
|
140
|
+
- `list_tables()`
|
|
141
|
+
- `table_exists()`
|
|
142
|
+
- `table_info()`
|
|
143
|
+
- `row_count()`
|
|
144
|
+
- `has_extension()`
|
|
145
|
+
- `list_extensions()`
|
|
146
|
+
- `role_exists()`
|
|
147
|
+
- `list_roles()`
|
|
148
|
+
- `size()`
|
|
149
|
+
- `table_size()`
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
### 3.5 Performance - Priorité MOYENNE
|
|
154
|
+
|
|
155
|
+
#### 3.5.1 `execute_many()` non optimisé
|
|
156
|
+
|
|
157
|
+
**Fichier** : `database.py:298-319`
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
def execute_many(self, sql: str, params_seq: Sequence[Sequence]) -> int:
|
|
161
|
+
total = 0
|
|
162
|
+
with self.cursor() as cur:
|
|
163
|
+
for params in params_seq:
|
|
164
|
+
cur.execute(sql, params) # N requêtes séquentielles!
|
|
165
|
+
total += cur.rowcount
|
|
166
|
+
return total
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
**Optimisations possibles** :
|
|
170
|
+
1. Utiliser `cur.executemany()` natif de psycopg
|
|
171
|
+
2. Pour INSERT : utiliser `VALUES (...), (...), (...)` (batch)
|
|
172
|
+
3. Pour INSERT massif : utiliser `COPY` (10-100x plus rapide)
|
|
173
|
+
|
|
174
|
+
#### 3.5.2 `insert_many()` sous-optimal
|
|
175
|
+
|
|
176
|
+
**Fichier** : `async_database.py:384-426`
|
|
177
|
+
|
|
178
|
+
Utilise `execute_many()` qui fait N requêtes au lieu d'un batch INSERT.
|
|
179
|
+
|
|
180
|
+
#### 3.5.3 Connexions non réutilisées
|
|
181
|
+
|
|
182
|
+
Chaque appel à `execute()`, `fetch_one()`, etc. ouvre et ferme une connexion.
|
|
183
|
+
Pour des opérations multiples consécutives, cela génère un overhead significatif.
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## 4. Recommandations d'Amélioration
|
|
188
|
+
|
|
189
|
+
### 4.1 Sécurité
|
|
190
|
+
|
|
191
|
+
- [x] Extraire `_validate_identifier()` dans un module `utils.py` partagé
|
|
192
|
+
- [x] Valider TOUS les identifiants SQL dans toutes les méthodes
|
|
193
|
+
- [x] Ajouter une validation pour les valeurs d'intervalle (chunk_time_interval, etc.)
|
|
194
|
+
|
|
195
|
+
### 4.2 Bug Fixes
|
|
196
|
+
|
|
197
|
+
- [x] Corriger `copy_to_csv()` pour accéder correctement au dict
|
|
198
|
+
- [x] Corriger le stub `load_dotenv()` pour accepter `override=`
|
|
199
|
+
|
|
200
|
+
### 4.3 Nettoyage
|
|
201
|
+
|
|
202
|
+
- [x] Supprimer `_pool` inutilisé dans `AsyncDatabase`
|
|
203
|
+
- [x] Supprimer l'import `AsyncConnectionPool` dans TYPE_CHECKING
|
|
204
|
+
|
|
205
|
+
### 4.4 Factorisation
|
|
206
|
+
|
|
207
|
+
- [x] Créer `pycopg/utils.py` avec les fonctions utilitaires partagées
|
|
208
|
+
- [x] Créer `pycopg/queries.py` avec les requêtes SQL constantes
|
|
209
|
+
- [x] Créer une classe de base `BaseDatabase` pour la logique commune (`pycopg/base.py`)
|
|
210
|
+
|
|
211
|
+
### 4.5 Optimisation
|
|
212
|
+
|
|
213
|
+
- [x] Implémenter `executemany()` pour les opérations batch
|
|
214
|
+
- [x] Ajouter une méthode `insert_batch()` utilisant VALUES multiples
|
|
215
|
+
- [x] Ajouter une méthode `copy_insert()` utilisant COPY pour les gros volumes
|
|
216
|
+
- [x] Mode "session" pour réutiliser les connexions (`db.session()`)
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## 5. Plan d'Action (COMPLÉTÉ)
|
|
221
|
+
|
|
222
|
+
### Phase 1 : Corrections Critiques ✅
|
|
223
|
+
1. ✅ Créer `utils.py` avec `validate_identifier()`
|
|
224
|
+
2. ✅ Corriger les vulnérabilités d'injection SQL
|
|
225
|
+
3. ✅ Corriger le bug `copy_to_csv()`
|
|
226
|
+
4. ✅ Corriger le stub `load_dotenv()`
|
|
227
|
+
|
|
228
|
+
### Phase 2 : Nettoyage ✅
|
|
229
|
+
5. ✅ Supprimer le dead code (`_pool`, imports inutiles)
|
|
230
|
+
6. ✅ Créer `queries.py` pour centraliser les requêtes SQL
|
|
231
|
+
|
|
232
|
+
### Phase 3 : Optimisation ✅
|
|
233
|
+
7. ✅ Optimiser `execute_many()` avec `executemany()`
|
|
234
|
+
8. ✅ Ajouter `insert_batch()` pour les INSERT massifs
|
|
235
|
+
9. ✅ Ajouter support `COPY` pour les très gros volumes (`copy_insert()`)
|
|
236
|
+
|
|
237
|
+
### Phase 4 : Améliorations Optionnelles ✅
|
|
238
|
+
10. ✅ Créer `base.py` avec classes de base et mixins
|
|
239
|
+
11. ✅ Ajouter mode session (`db.session()`) pour réutilisation des connexions
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## 6. Métriques
|
|
244
|
+
|
|
245
|
+
| Métrique | Valeur |
|
|
246
|
+
|----------|--------|
|
|
247
|
+
| Lignes de code total | ~3,800 |
|
|
248
|
+
| Duplication estimée | ~10-15% |
|
|
249
|
+
| Issues sécurité (haute) | 2 |
|
|
250
|
+
| Bugs (haute) | 2 |
|
|
251
|
+
| Dead code (moyenne) | 2 |
|
|
252
|
+
| Optimisations possibles | 4 |
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## 7. Conclusion
|
|
257
|
+
|
|
258
|
+
Le projet pycopg est **bien conçu et documenté**. Les principales améliorations à apporter sont :
|
|
259
|
+
|
|
260
|
+
1. **Sécurité** : Valider systématiquement tous les identifiants SQL
|
|
261
|
+
2. **Qualité** : Corriger les bugs identifiés
|
|
262
|
+
3. **DRY** : Factoriser le code dupliqué
|
|
263
|
+
4. **Performance** : Optimiser les opérations batch
|
|
264
|
+
|
|
265
|
+
Le code est prêt pour la production après correction des issues de priorité haute.
|
pycopg-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Loc Cosnier <loc.cosnier@pm.me>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|