permisapi-client 0.7.1__tar.gz → 0.8.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.
- {permisapi_client-0.7.1 → permisapi_client-0.8.0}/PKG-INFO +1 -1
- {permisapi_client-0.7.1 → permisapi_client-0.8.0}/permisapi_client/__init__.py +1 -1
- {permisapi_client-0.7.1 → permisapi_client-0.8.0}/permisapi_client/client.py +95 -1
- {permisapi_client-0.7.1 → permisapi_client-0.8.0}/pyproject.toml +1 -1
- {permisapi_client-0.7.1 → permisapi_client-0.8.0}/.gitignore +0 -0
- {permisapi_client-0.7.1 → permisapi_client-0.8.0}/README.md +0 -0
- {permisapi_client-0.7.1 → permisapi_client-0.8.0}/permisapi_client/exceptions.py +0 -0
- {permisapi_client-0.7.1 → permisapi_client-0.8.0}/tests/test_client.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: permisapi-client
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.0
|
|
4
4
|
Summary: Client Python officiel pour PermisAPI : permis de construire France en API REST.
|
|
5
5
|
Project-URL: Homepage, https://permisapi.fr
|
|
6
6
|
Project-URL: Documentation, https://permisapi.fr/docs
|
|
@@ -13,7 +13,7 @@ from permisapi_client.exceptions import error_from_response
|
|
|
13
13
|
|
|
14
14
|
DEFAULT_BASE_URL = "https://api.permisapi.fr"
|
|
15
15
|
DEFAULT_TIMEOUT = 15.0
|
|
16
|
-
USER_AGENT = "permisapi-client-python/0.
|
|
16
|
+
USER_AGENT = "permisapi-client-python/0.8.0"
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
def _raise_for_status(resp: httpx.Response) -> None:
|
|
@@ -63,6 +63,32 @@ class _PermitsResource:
|
|
|
63
63
|
Champs autorises : date_reelle_autorisation, date_depot,
|
|
64
64
|
an_depot, superficie_terrain. Prefixe `-` pour descendant.
|
|
65
65
|
Tout autre champ retourne 422 (et non ignore silencieusement).
|
|
66
|
+
|
|
67
|
+
Filtre `min_score` (Pro+ uniquement) : retourne uniquement les
|
|
68
|
+
permis avec un Score Opportunite MDB >= N (0-100). Use case
|
|
69
|
+
marchand de biens : shortliste les top opportunites en 1 call
|
|
70
|
+
au lieu de fetch + filter cote client. Cout quota special :
|
|
71
|
+
`limit` unites au lieu de 1 (anti-abus, equivalent a N calls
|
|
72
|
+
/score). Header X-RateLimit-Cost confirme.
|
|
73
|
+
|
|
74
|
+
Filtre `max_risk` (Pro+ uniquement) : exclut les permis dont
|
|
75
|
+
la commune est classee au-dessus du tier specifie (low /
|
|
76
|
+
moderate / high / critical). Exemple `max_risk="moderate"`
|
|
77
|
+
retourne uniquement les permis low + moderate. Cout quota =
|
|
78
|
+
limit (anti-abus, equivalent a N calls /risks). Lookup via
|
|
79
|
+
colonne materialisee `permits.risk_tier` (refresh par
|
|
80
|
+
scripts/materialize_risks.py mensuel).
|
|
81
|
+
|
|
82
|
+
Filtre `plu_zone_type` (Pro+ uniquement) : prefix de zonage
|
|
83
|
+
urbanisme parmi U / AU / A / N / OTHER. Exemple
|
|
84
|
+
`plu_zone_type="U"` retourne uniquement les permis en zone
|
|
85
|
+
urbaine constructible. Cout quota = limit.
|
|
86
|
+
|
|
87
|
+
Filtre `plu_constructible` (Pro+ uniquement) : booleen.
|
|
88
|
+
`plu_constructible=True` retourne uniquement les permis ou le
|
|
89
|
+
verdict heuristique est constructible (zone U ou AU). Pratique
|
|
90
|
+
combine avec `min_score` pour shortlister les vraies
|
|
91
|
+
opportunites MDB. Cout quota = limit.
|
|
66
92
|
"""
|
|
67
93
|
return self._c._get("/v1/permits", params=params)
|
|
68
94
|
|
|
@@ -101,6 +127,24 @@ class _PermitsResource:
|
|
|
101
127
|
params={"section": section, "numero": numero},
|
|
102
128
|
)
|
|
103
129
|
|
|
130
|
+
def parcelle(self, num_pa: str) -> dict[str, Any]:
|
|
131
|
+
"""GET /v1/permits/{num_pa}/parcelle : geometrie cadastre DGFiP.
|
|
132
|
+
|
|
133
|
+
Plans Pro et superieurs uniquement (402 si Free / Explorer).
|
|
134
|
+
Retourne {num_pa, comm_code, section, numero, cadastre_id,
|
|
135
|
+
surface_m2 (contenance officielle DGFiP), geometry (GeoJSON
|
|
136
|
+
Polygon WGS84), cached_at, source}.
|
|
137
|
+
|
|
138
|
+
404 si la parcelle n'est pas encore en cache (commune hors
|
|
139
|
+
couverture Etalab ou pas encore materialise par
|
|
140
|
+
scripts/ingest_cadastre.py).
|
|
141
|
+
|
|
142
|
+
Use case : afficher le polygon precis sur une carte (vs juste
|
|
143
|
+
un point lat/lng), comparer surface DGFiP vs Sitadel, cross-ref
|
|
144
|
+
avec DVF en parcelle precise.
|
|
145
|
+
"""
|
|
146
|
+
return self._c._get(f"/v1/permits/{num_pa}/parcelle")
|
|
147
|
+
|
|
104
148
|
def dvf(
|
|
105
149
|
self,
|
|
106
150
|
num_pa: str,
|
|
@@ -430,6 +474,37 @@ class PermisAPI:
|
|
|
430
474
|
self.alerts = _AlertsResource(self)
|
|
431
475
|
self.me = _MeResource(self)
|
|
432
476
|
|
|
477
|
+
def search(
|
|
478
|
+
self,
|
|
479
|
+
q: str,
|
|
480
|
+
*,
|
|
481
|
+
dep_code: str | None = None,
|
|
482
|
+
limit: int = 20,
|
|
483
|
+
) -> list[dict[str, Any]]:
|
|
484
|
+
"""GET /v1/search : recherche fuzzy par texte sur les adresses.
|
|
485
|
+
|
|
486
|
+
Utilise pg_trgm cote DB. Insensible aux accents et a la casse,
|
|
487
|
+
tolerant aux typos courants. Latence ~50-200ms.
|
|
488
|
+
|
|
489
|
+
Tous plans (Free, Explorer, Pro, Business, Enterprise) avec
|
|
490
|
+
respect du scope geo. Cout quota = 1 unite (endpoint
|
|
491
|
+
d'acquisition, pas premium).
|
|
492
|
+
|
|
493
|
+
Args:
|
|
494
|
+
q: texte libre, min 2 chars (ex "republique bordeaux",
|
|
495
|
+
"rue victor hugo paris", "cours de l'ile")
|
|
496
|
+
dep_code: optionnel, restreindre a un departement
|
|
497
|
+
limit: 1-50, default 20
|
|
498
|
+
|
|
499
|
+
Returns:
|
|
500
|
+
Liste de PermitSummary tries par pertinence (similarity)
|
|
501
|
+
puis date desc.
|
|
502
|
+
"""
|
|
503
|
+
params: dict[str, Any] = {"q": q, "limit": limit}
|
|
504
|
+
if dep_code is not None:
|
|
505
|
+
params["dep_code"] = dep_code
|
|
506
|
+
return self._get("/v1/search", params=params)
|
|
507
|
+
|
|
433
508
|
def close(self) -> None:
|
|
434
509
|
self._http.close()
|
|
435
510
|
|
|
@@ -546,6 +621,11 @@ class _AsyncPermitsResource:
|
|
|
546
621
|
Voir _PermitsResource.risks pour la doc complete."""
|
|
547
622
|
return await self._c._get(f"/v1/permits/{num_pa}/risks")
|
|
548
623
|
|
|
624
|
+
async def parcelle(self, num_pa: str) -> dict[str, Any]:
|
|
625
|
+
"""GET /v1/permits/{num_pa}/parcelle : version async. Plans Pro+ only.
|
|
626
|
+
Voir _PermitsResource.parcelle pour la doc complete."""
|
|
627
|
+
return await self._c._get(f"/v1/permits/{num_pa}/parcelle")
|
|
628
|
+
|
|
549
629
|
async def full_view(self, num_pa: str) -> dict[str, Any]:
|
|
550
630
|
"""GET /v1/permits/{num_pa}/360 : version async. Vue agregee 6-en-1.
|
|
551
631
|
|
|
@@ -682,6 +762,20 @@ class AsyncPermisAPI:
|
|
|
682
762
|
self.alerts = _AsyncAlertsResource(self)
|
|
683
763
|
self.me = _AsyncMeResource(self)
|
|
684
764
|
|
|
765
|
+
async def search(
|
|
766
|
+
self,
|
|
767
|
+
q: str,
|
|
768
|
+
*,
|
|
769
|
+
dep_code: str | None = None,
|
|
770
|
+
limit: int = 20,
|
|
771
|
+
) -> list[dict[str, Any]]:
|
|
772
|
+
"""GET /v1/search : version async. Voir PermisAPI.search pour
|
|
773
|
+
la doc complete (fuzzy pg_trgm sur full_address)."""
|
|
774
|
+
params: dict[str, Any] = {"q": q, "limit": limit}
|
|
775
|
+
if dep_code is not None:
|
|
776
|
+
params["dep_code"] = dep_code
|
|
777
|
+
return await self._get("/v1/search", params=params)
|
|
778
|
+
|
|
685
779
|
async def close(self) -> None:
|
|
686
780
|
await self._http.aclose()
|
|
687
781
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|