adressevaelger 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.
@@ -0,0 +1,25 @@
1
+ Metadata-Version: 2.3
2
+ Name: adressevaelger
3
+ Version: 0.1.0
4
+ Summary: Client library for accessing 'Adressevælger'
5
+ Author: Erik Petersen
6
+ Author-email: Erik Petersen <eht@it-trans.dk>
7
+ Requires-Dist: dacite>=1.9.2
8
+ Requires-Dist: pyproj>=3.7.2
9
+ Requires-Dist: requests>=2.34.1
10
+ Requires-Python: >=3.13
11
+ Description-Content-Type: text/markdown
12
+
13
+ # Adressevælger API Client
14
+
15
+
16
+ ## Introduction
17
+
18
+ Client library for accessing "Adressevælger" Web API.
19
+
20
+ - [API Documentation](https://confluence.sdfi.dk/pages/viewpage.action?pageId=234782998)
21
+ - [API Base Address](https://adressevaelger.dk)
22
+
23
+
24
+ ## Example
25
+
@@ -0,0 +1,13 @@
1
+ # Adressevælger API Client
2
+
3
+
4
+ ## Introduction
5
+
6
+ Client library for accessing "Adressevælger" Web API.
7
+
8
+ - [API Documentation](https://confluence.sdfi.dk/pages/viewpage.action?pageId=234782998)
9
+ - [API Base Address](https://adressevaelger.dk)
10
+
11
+
12
+ ## Example
13
+
@@ -0,0 +1,24 @@
1
+ [project]
2
+ name = "adressevaelger"
3
+ version = "0.1.0"
4
+ description = "Client library for accessing 'Adressevælger'"
5
+ readme = "README.md"
6
+ authors = [
7
+ { name = "Erik Petersen", email = "eht@it-trans.dk" }
8
+ ]
9
+ requires-python = ">=3.13"
10
+ dependencies = [
11
+ "dacite>=1.9.2",
12
+ "pyproj>=3.7.2",
13
+ "requests>=2.34.1",
14
+ ]
15
+
16
+ [build-system]
17
+ requires = ["uv_build>=0.9.8,<0.10.0"]
18
+ build-backend = "uv_build"
19
+
20
+ [dependency-groups]
21
+ dev = [
22
+ "pytest>=9.0.3",
23
+ "responses>=0.26.0",
24
+ ]
@@ -0,0 +1,5 @@
1
+ from .client import Client
2
+ from .exceptions import ApiConnectionError, ApiError
3
+ from .models import Adressesoegning, Fund
4
+
5
+ __all__ = ["Client", "Fund", "ApiError", "ApiConnectionError", "Adressesoegning"]
@@ -0,0 +1,90 @@
1
+ import logging
2
+ from dacite import Config
3
+ from dataclasses import asdict
4
+ from datetime import datetime, timezone
5
+ from typing import List, Optional
6
+
7
+ import requests
8
+ from dacite import from_dict
9
+
10
+ #from typing import TypeVar
11
+ #virkningfra = TypeVar("virkningfra", str, datetime.datetime)
12
+ #virkningtil = TypeVar("virkningtil", str, datetime.datetime)
13
+
14
+
15
+ from .exceptions import ApiConnectionError, ApiError, ApiUnkownError
16
+ from .models import Adresse, Adresseopslag, Adressesoegning, Fund, Husnummer, Husnummeropslag, Husnummersoegning, Soegeresultat
17
+
18
+ logger = logging.getLogger(__name__)
19
+ logger.addHandler(logging.NullHandler())
20
+
21
+ def parse_iso_z(value: str) -> datetime:
22
+ if value.endswith("Z"):
23
+ return datetime.fromisoformat(value[:-1]).replace(tzinfo=timezone.utc)
24
+ return datetime.fromisoformat(value)
25
+
26
+ class Client:
27
+ def __init__(self, token: str = "adressevaelger123") -> None:
28
+ self.base_url = "https://adressevaelger.dk"
29
+ self.token = token
30
+
31
+ def _request(self, method: str, path: str, headers: dict = {}, params: dict = {}):
32
+ headers.update({"Accept": "application/json"})
33
+ params.update({"token": self.token})
34
+ try:
35
+ response = requests.request(
36
+ method=method,
37
+ url=self.base_url + f"/{path}",
38
+ headers=headers,
39
+ params=params,
40
+ )
41
+ logger.debug(f"Requ: {response.request.url}")
42
+ logger.debug(
43
+ f"Resp: Status code={response.status_code}, Payload={response.text}"
44
+ )
45
+ response.raise_for_status()
46
+ return response
47
+ except requests.ConnectionError as err:
48
+ logger.exception(err)
49
+ raise ApiConnectionError(err.strerror) from err
50
+ except requests.HTTPError as err:
51
+ logger.exception(err)
52
+ raise ApiError(response.text) from err
53
+
54
+
55
+ def soeg_fonetisk(self, soegning: Adressesoegning | Husnummersoegning) -> List[Fund]:
56
+ params = asdict(soegning)
57
+ if isinstance(soegning, Adressesoegning):
58
+ response = self._request("GET", "adresser/soeg", params=params)
59
+ elif isinstance(soegning, Husnummersoegning):
60
+ response = self._request("GET", "husnumre/soeg", params=params)
61
+ else:
62
+ raise ValueError("Parameter must be of type Adressesoegning or HusnummerSoegning")
63
+ result = from_dict(data_class=Soegeresultat, data=response.json())
64
+ if result.status == "ok":
65
+ return result.fund
66
+ else:
67
+ raise ApiError(result.beskrivelse)
68
+
69
+
70
+ def husnummer_id(self, husnummer_id: str) -> Husnummer | None:
71
+ config = Config(type_hooks={datetime: parse_iso_z})
72
+
73
+ response = self._request("GET", f"husnumre/{husnummer_id}")
74
+ result = from_dict(data_class=Husnummeropslag, data=response.json(), config=config)
75
+ if result.status == "ok":
76
+ return result.husnummer
77
+ else:
78
+ return None
79
+
80
+ def adresse_id(self, adresse_id: str) -> Optional[Adresse]:
81
+ config = Config(type_hooks={datetime: parse_iso_z})
82
+
83
+ response = self._request("GET", f"adresser/{adresse_id}")
84
+ result = from_dict(data_class=Adresseopslag, data=response.json(), config=config)
85
+ if result.status == "ok":
86
+ return result.adresse
87
+ else:
88
+ return None
89
+
90
+
@@ -0,0 +1,12 @@
1
+
2
+ class ApiError(Exception):
3
+
4
+ def __init__(self, message: str | None):
5
+ self.message = message
6
+ super().__init__(self.message)
7
+
8
+ class ApiConnectionError(ApiError):
9
+ pass
10
+
11
+ class ApiUnkownError(ApiError):
12
+ pass
@@ -0,0 +1,186 @@
1
+ import datetime
2
+ from dataclasses import dataclass, asdict
3
+ from typing import List, Optional
4
+
5
+
6
+ @dataclass
7
+ class Adressesoegning:
8
+ tekst: Optional[str] = None
9
+ vejnavn: Optional[str] = None
10
+ husnummer: Optional[str] = None
11
+ postnummer: Optional[str] = None
12
+ kommunekode: Optional[str] = None
13
+ medtagforeloebige: Optional[str] = None
14
+ etage: Optional[str] = None
15
+ doer: Optional[str] = None
16
+ maksimum: Optional[int] = None
17
+
18
+
19
+ @dataclass
20
+ class Husnummersoegning:
21
+ tekst: Optional[str] = None
22
+ vejnavn: Optional[str] = None
23
+ husnummer: Optional[str] = None
24
+ postnummer: Optional[str] = None
25
+ kommunekode: Optional[str] = None
26
+ medtagforeloebige: Optional[str] = None
27
+ maksimum: Optional[int] = None
28
+
29
+
30
+ @dataclass
31
+ class Fund:
32
+ type: str
33
+ id: Optional[str] = None
34
+ titel: Optional[str] = None
35
+ vejnavn: Optional[str] = None
36
+ husnummer: Optional[str] = None
37
+ postnr: Optional[str] = None
38
+ postdistrikt: Optional[str] = None
39
+ antal_husnumre: Optional[int] = None
40
+ husnummerId: Optional[str] = None
41
+
42
+ def asdict(self):
43
+ return asdict(self)
44
+
45
+
46
+ @dataclass
47
+ class Soegeresultat:
48
+ status: str
49
+ beskrivelse: str
50
+ fund: List[Fund]
51
+
52
+
53
+ @dataclass
54
+ class Koordinater:
55
+ x: Optional[float]
56
+ y: Optional[float]
57
+
58
+
59
+ @dataclass
60
+ class CRSProperties:
61
+ name: Optional[str]
62
+
63
+
64
+ @dataclass
65
+ class CRS:
66
+ type: Optional[str]
67
+ properties: Optional[CRSProperties]
68
+
69
+
70
+ @dataclass
71
+ class Geometri:
72
+ type: Optional[str]
73
+ crs: Optional[CRS]
74
+ coordinates: Optional[List[float]]
75
+
76
+
77
+ @dataclass
78
+ class Adgangspunkt:
79
+ id_lokalid: Optional[str]
80
+ status: Optional[str]
81
+ virkningfra: Optional[datetime.datetime]
82
+ virkningtil: Optional[datetime.datetime]
83
+ registreringfra: Optional[datetime.datetime]
84
+ registreringtil: Optional[datetime.datetime]
85
+ geometri: Optional[Geometri]
86
+ koordinater: Optional[Koordinater]
87
+
88
+
89
+ @dataclass
90
+ class Postnummer:
91
+ id_lokalid: Optional[str]
92
+ navn: Optional[str]
93
+ postnr: Optional[str]
94
+ status: Optional[str]
95
+ virkningfra: Optional[datetime.datetime]
96
+ virkningtil: Optional[datetime.datetime]
97
+ registreringfra: Optional[datetime.datetime]
98
+ registreringtil: Optional[datetime.datetime]
99
+
100
+
101
+ @dataclass()
102
+ class NavngivenVej:
103
+ id_lokalid: Optional[str]
104
+ vejnavn: Optional[str]
105
+ virkningfra: Optional[datetime.datetime]
106
+ virkningtil: Optional[datetime.datetime]
107
+ registreringfra: Optional[datetime.datetime]
108
+ registreringtil: Optional[datetime.datetime]
109
+
110
+
111
+ @dataclass()
112
+ class NavngivenVejKommunedel:
113
+ id_lokalid: Optional[str]
114
+ kommune: Optional[str]
115
+ vejkode: Optional[str]
116
+ navngivenvej: Optional[str]
117
+ virkningfra: Optional[datetime.datetime]
118
+ virkningtil: Optional[datetime.datetime]
119
+ registreringfra: Optional[datetime.datetime]
120
+ registreringtil: Optional[datetime.datetime]
121
+
122
+
123
+ @dataclass()
124
+ class NavngivenVejPostnummer:
125
+ id_lokalid: Optional[str]
126
+ virkningfra: Optional[datetime.datetime]
127
+ virkningtil: Optional[datetime.datetime]
128
+ registreringfra: Optional[datetime.datetime]
129
+ registreringtil: Optional[datetime.datetime]
130
+
131
+
132
+ @dataclass()
133
+ class SupplerendeBynavn:
134
+ id_lokalid: Optional[str]
135
+ status: Optional[str]
136
+ supplerendebynavn: Optional[str]
137
+ navn: Optional[str]
138
+ virkningfra: Optional[datetime.datetime]
139
+ virkningtil: Optional[datetime.datetime]
140
+ registreringfra: Optional[datetime.datetime]
141
+ registreringtil: Optional[datetime.datetime]
142
+
143
+
144
+ @dataclass
145
+ class Husnummer:
146
+ id_lokalid: str
147
+ husnummertekst: Optional[str]
148
+ adgangsadressebetegnelse: Optional[str]
149
+ vejnavn: Optional[str]
150
+ status: Optional[str]
151
+ virkningfra: Optional[datetime.datetime]
152
+ virkningtil: Optional[datetime.datetime]
153
+ registreringfra: Optional[datetime.datetime]
154
+ registreringtil: Optional[datetime.datetime]
155
+ adgangspunkt: Optional[Adgangspunkt]
156
+ postnummer: Optional[Postnummer]
157
+ navngivenvej: Optional[NavngivenVej]
158
+ navngivenvejkommunedel: Optional[NavngivenVejKommunedel]
159
+ navngivenvejpostnummer: Optional[NavngivenVejPostnummer]
160
+ supplerendebynavn: Optional[SupplerendeBynavn]
161
+
162
+
163
+ @dataclass
164
+ class Husnummeropslag:
165
+ status: str
166
+ husnummer: Husnummer
167
+
168
+
169
+ @dataclass
170
+ class Adresse:
171
+ id_lokalid: str
172
+ adressebetegnelse: Optional[str]
173
+ etagebetegnelse: Optional[str]
174
+ doerbetegnelse: Optional[str]
175
+ status: Optional[str]
176
+ virkningfra: Optional[datetime.datetime]
177
+ virkningtil: Optional[datetime.datetime]
178
+ registreringfra: Optional[datetime.datetime]
179
+ registreringtil: Optional[datetime.datetime]
180
+ husnummer: Optional[Husnummer]
181
+
182
+
183
+ @dataclass
184
+ class Adresseopslag:
185
+ status: Optional[str]
186
+ adresse: Optional[Adresse]
File without changes