permisapi-client 0.7.2__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.2 → permisapi_client-0.8.0}/PKG-INFO +1 -1
- {permisapi_client-0.7.2 → permisapi_client-0.8.0}/permisapi_client/__init__.py +1 -1
- {permisapi_client-0.7.2 → permisapi_client-0.8.0}/permisapi_client/client.py +89 -2
- {permisapi_client-0.7.2 → permisapi_client-0.8.0}/pyproject.toml +1 -1
- {permisapi_client-0.7.2 → permisapi_client-0.8.0}/.gitignore +0 -0
- {permisapi_client-0.7.2 → permisapi_client-0.8.0}/README.md +0 -0
- {permisapi_client-0.7.2 → permisapi_client-0.8.0}/permisapi_client/exceptions.py +0 -0
- {permisapi_client-0.7.2 → 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:
|
|
@@ -65,11 +65,30 @@ class _PermitsResource:
|
|
|
65
65
|
Tout autre champ retourne 422 (et non ignore silencieusement).
|
|
66
66
|
|
|
67
67
|
Filtre `min_score` (Pro+ uniquement) : retourne uniquement les
|
|
68
|
-
|
|
68
|
+
permis avec un Score Opportunite MDB >= N (0-100). Use case
|
|
69
69
|
marchand de biens : shortliste les top opportunites en 1 call
|
|
70
70
|
au lieu de fetch + filter cote client. Cout quota special :
|
|
71
71
|
`limit` unites au lieu de 1 (anti-abus, equivalent a N calls
|
|
72
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.
|
|
73
92
|
"""
|
|
74
93
|
return self._c._get("/v1/permits", params=params)
|
|
75
94
|
|
|
@@ -108,6 +127,24 @@ class _PermitsResource:
|
|
|
108
127
|
params={"section": section, "numero": numero},
|
|
109
128
|
)
|
|
110
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
|
+
|
|
111
148
|
def dvf(
|
|
112
149
|
self,
|
|
113
150
|
num_pa: str,
|
|
@@ -437,6 +474,37 @@ class PermisAPI:
|
|
|
437
474
|
self.alerts = _AlertsResource(self)
|
|
438
475
|
self.me = _MeResource(self)
|
|
439
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
|
+
|
|
440
508
|
def close(self) -> None:
|
|
441
509
|
self._http.close()
|
|
442
510
|
|
|
@@ -553,6 +621,11 @@ class _AsyncPermitsResource:
|
|
|
553
621
|
Voir _PermitsResource.risks pour la doc complete."""
|
|
554
622
|
return await self._c._get(f"/v1/permits/{num_pa}/risks")
|
|
555
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
|
+
|
|
556
629
|
async def full_view(self, num_pa: str) -> dict[str, Any]:
|
|
557
630
|
"""GET /v1/permits/{num_pa}/360 : version async. Vue agregee 6-en-1.
|
|
558
631
|
|
|
@@ -689,6 +762,20 @@ class AsyncPermisAPI:
|
|
|
689
762
|
self.alerts = _AsyncAlertsResource(self)
|
|
690
763
|
self.me = _AsyncMeResource(self)
|
|
691
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
|
+
|
|
692
779
|
async def close(self) -> None:
|
|
693
780
|
await self._http.aclose()
|
|
694
781
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|