brreg-wrapper 0.2.3__tar.gz → 0.3.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.
- brreg_wrapper-0.3.0/.gitattributes +11 -0
- brreg_wrapper-0.3.0/.github/workflows/ci.yml +32 -0
- brreg_wrapper-0.3.0/.github/workflows/publish-to-pypi.yml +41 -0
- brreg_wrapper-0.3.0/.gitignore +22 -0
- brreg_wrapper-0.3.0/.python-version +1 -0
- {brreg_wrapper-0.2.3/src/brreg_wrapper.egg-info → brreg_wrapper-0.3.0}/PKG-INFO +36 -30
- {brreg_wrapper-0.2.3 → brreg_wrapper-0.3.0}/README.md +20 -13
- brreg_wrapper-0.3.0/examples/README.md +57 -0
- brreg_wrapper-0.3.0/examples/sample.py +157 -0
- {brreg_wrapper-0.2.3 → brreg_wrapper-0.3.0}/pyproject.toml +11 -2
- brreg_wrapper-0.3.0/scripts/README.md +50 -0
- brreg_wrapper-0.3.0/scripts/test_install.bat +69 -0
- brreg_wrapper-0.3.0/scripts/test_install.sh +72 -0
- {brreg_wrapper-0.2.3 → brreg_wrapper-0.3.0}/src/brreg_wrapper/__init__.py +2 -0
- brreg_wrapper-0.3.0/src/brreg_wrapper/client.py +1126 -0
- {brreg_wrapper-0.2.3 → brreg_wrapper-0.3.0}/src/brreg_wrapper/exceptions.py +29 -12
- {brreg_wrapper-0.2.3 → brreg_wrapper-0.3.0}/src/brreg_wrapper/models/__init__.py +147 -147
- brreg_wrapper-0.3.0/src/brreg_wrapper/py.typed +0 -0
- {brreg_wrapper-0.2.3 → brreg_wrapper-0.3.0}/tests/test_client.py +375 -161
- brreg_wrapper-0.3.0/uv.lock +511 -0
- brreg_wrapper-0.2.3/PKG-INFO +0 -225
- brreg_wrapper-0.2.3/setup.cfg +0 -4
- brreg_wrapper-0.2.3/src/brreg_wrapper/client.py +0 -1282
- brreg_wrapper-0.2.3/src/brreg_wrapper.egg-info/SOURCES.txt +0 -14
- brreg_wrapper-0.2.3/src/brreg_wrapper.egg-info/dependency_links.txt +0 -1
- brreg_wrapper-0.2.3/src/brreg_wrapper.egg-info/requires.txt +0 -16
- brreg_wrapper-0.2.3/src/brreg_wrapper.egg-info/top_level.txt +0 -1
- {brreg_wrapper-0.2.3 → brreg_wrapper-0.3.0}/LICENSE +0 -0
- {brreg_wrapper-0.2.3 → brreg_wrapper-0.3.0}/tests/test_exceptions.py +0 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Auto detect text files and ensure they use LF line endings
|
|
2
|
+
* text=auto eol=lf
|
|
3
|
+
|
|
4
|
+
# Explicitly declare files that will always have LF line endings
|
|
5
|
+
*.py text eol=lf
|
|
6
|
+
*.toml text eol=lf
|
|
7
|
+
*.md text eol=lf
|
|
8
|
+
*.yaml text eol=lf
|
|
9
|
+
*.yml text eol=lf
|
|
10
|
+
.gitignore text eol=lf
|
|
11
|
+
LICENSE text eol=lf
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
|
|
15
|
+
- name: Set up Python
|
|
16
|
+
uses: actions/setup-python@v5
|
|
17
|
+
with:
|
|
18
|
+
python-version: "3.13"
|
|
19
|
+
|
|
20
|
+
- name: Install package with dev dependencies
|
|
21
|
+
run: |
|
|
22
|
+
python -m pip install --upgrade pip
|
|
23
|
+
pip install .[dev]
|
|
24
|
+
|
|
25
|
+
- name: Check formatting with Ruff
|
|
26
|
+
run: ruff format --check .
|
|
27
|
+
|
|
28
|
+
- name: Lint with Ruff
|
|
29
|
+
run: ruff check .
|
|
30
|
+
|
|
31
|
+
- name: Run tests
|
|
32
|
+
run: pytest
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
name: Publish Python Package to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
deploy:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
id-token: write
|
|
13
|
+
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
|
|
17
|
+
- name: Set up Python
|
|
18
|
+
uses: actions/setup-python@v5
|
|
19
|
+
with:
|
|
20
|
+
python-version: "3.13"
|
|
21
|
+
|
|
22
|
+
- name: Install dependencies including dev dependencies
|
|
23
|
+
run: |
|
|
24
|
+
python -m pip install --upgrade pip
|
|
25
|
+
pip install .[dev] # Installs package + dev dependencies (like ruff, pytest)
|
|
26
|
+
pip install build twine # Still need build and twine for publishing steps
|
|
27
|
+
|
|
28
|
+
- name: Check formatting with Ruff
|
|
29
|
+
run: ruff format --check .
|
|
30
|
+
|
|
31
|
+
- name: Lint with Ruff
|
|
32
|
+
run: ruff check .
|
|
33
|
+
|
|
34
|
+
- name: Run tests
|
|
35
|
+
run: pytest
|
|
36
|
+
|
|
37
|
+
- name: Build package
|
|
38
|
+
run: python -m build
|
|
39
|
+
|
|
40
|
+
- name: Publish package to PyPI
|
|
41
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Python-generated files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[oc]
|
|
4
|
+
build/
|
|
5
|
+
dist/
|
|
6
|
+
wheels/
|
|
7
|
+
*.egg-info
|
|
8
|
+
|
|
9
|
+
# Virtual environments
|
|
10
|
+
.venv
|
|
11
|
+
.test_venv
|
|
12
|
+
test_venv/
|
|
13
|
+
|
|
14
|
+
# IDE directories
|
|
15
|
+
.vscode/
|
|
16
|
+
.idea/
|
|
17
|
+
|
|
18
|
+
# Test artifacts
|
|
19
|
+
.pytest_cache/
|
|
20
|
+
|
|
21
|
+
# Downloaded schema
|
|
22
|
+
openapi.json
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.13
|
|
@@ -1,35 +1,34 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: brreg-wrapper
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: A Python wrapper for the Brønnøysund Register Centre (Brreg) API.
|
|
5
|
-
Author-email: Sondre Dyrnes <sondre@villdyr.no>
|
|
6
|
-
License-Expression: MIT
|
|
7
5
|
Project-URL: Homepage, https://github.com/sondreal/brreg-wrapper
|
|
8
6
|
Project-URL: Repository, https://github.com/sondreal/brreg-wrapper
|
|
7
|
+
Author-email: Sondre Dyrnes <sondre@villdyr.no>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
9
10
|
Classifier: Development Status :: 3 - Alpha
|
|
10
11
|
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
11
13
|
Classifier: Programming Language :: Python :: 3
|
|
12
14
|
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
-
Classifier: Operating System :: OS Independent
|
|
14
|
-
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
15
15
|
Classifier: Topic :: Office/Business
|
|
16
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
16
17
|
Requires-Python: >=3.13
|
|
17
|
-
Description-Content-Type: text/markdown
|
|
18
|
-
License-File: LICENSE
|
|
19
18
|
Requires-Dist: httpx<1.0,>=0.27
|
|
20
19
|
Requires-Dist: pydantic<3.0,>=2.0
|
|
21
20
|
Requires-Dist: tenacity<10.0,>=8.2
|
|
21
|
+
Provides-Extra: all
|
|
22
|
+
Requires-Dist: h2<5.0,>=4.0; extra == 'all'
|
|
22
23
|
Provides-Extra: dev
|
|
23
|
-
Requires-Dist:
|
|
24
|
-
Requires-Dist: pytest-asyncio<1.0,>=0.23; extra ==
|
|
25
|
-
Requires-Dist: pytest-httpx<1.0,>=0.29; extra ==
|
|
26
|
-
Requires-Dist:
|
|
27
|
-
Requires-Dist:
|
|
24
|
+
Requires-Dist: datamodel-code-generator[http]<1.0,>=0.25; extra == 'dev'
|
|
25
|
+
Requires-Dist: pytest-asyncio<1.0,>=0.23; extra == 'dev'
|
|
26
|
+
Requires-Dist: pytest-httpx<1.0,>=0.29; extra == 'dev'
|
|
27
|
+
Requires-Dist: pytest<9.0,>=8.0; extra == 'dev'
|
|
28
|
+
Requires-Dist: ruff==0.11.2; extra == 'dev'
|
|
28
29
|
Provides-Extra: http2
|
|
29
|
-
Requires-Dist: h2<5.0,>=4.0; extra ==
|
|
30
|
-
|
|
31
|
-
Requires-Dist: h2<5.0,>=4.0; extra == "all"
|
|
32
|
-
Dynamic: license-file
|
|
30
|
+
Requires-Dist: h2<5.0,>=4.0; extra == 'http2'
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
33
32
|
|
|
34
33
|
# 🔥 Brreg Wrapper
|
|
35
34
|
|
|
@@ -129,8 +128,8 @@ async def main():
|
|
|
129
128
|
# Second request uses cache
|
|
130
129
|
entity2 = await client.get_enhet("923609016")
|
|
131
130
|
|
|
132
|
-
# Clear specific cache entries
|
|
133
|
-
client.clear_cache(pattern="
|
|
131
|
+
# Clear specific cache entries (keys are request paths + query string)
|
|
132
|
+
client.clear_cache(pattern="/enheter/923609016")
|
|
134
133
|
|
|
135
134
|
# Get cache statistics
|
|
136
135
|
cache_info = client.get_cache_info()
|
|
@@ -140,14 +139,22 @@ async def main():
|
|
|
140
139
|
### Error Handling & Retry Logic
|
|
141
140
|
|
|
142
141
|
```python
|
|
143
|
-
from brreg_wrapper import
|
|
142
|
+
from brreg_wrapper import (
|
|
143
|
+
BrregAPIError,
|
|
144
|
+
BrregClient,
|
|
145
|
+
BrregRateLimitError,
|
|
146
|
+
BrregResourceNotFoundError,
|
|
147
|
+
)
|
|
144
148
|
|
|
145
149
|
async def main():
|
|
146
|
-
#
|
|
147
|
-
|
|
150
|
+
# Transient errors (5xx, 429, timeouts, connection errors) are retried
|
|
151
|
+
# with exponential backoff, honouring the server's Retry-After header.
|
|
152
|
+
client = BrregClient(max_retries=3) # up to 4 attempts in total
|
|
148
153
|
|
|
149
154
|
try:
|
|
150
|
-
entity = await client.get_enhet("
|
|
155
|
+
entity = await client.get_enhet("999999999") # Will raise exception
|
|
156
|
+
except BrregResourceNotFoundError:
|
|
157
|
+
print("No such organization")
|
|
151
158
|
except BrregRateLimitError:
|
|
152
159
|
# Handle rate limit specifically
|
|
153
160
|
print("Rate limit exceeded, try again later")
|
|
@@ -164,12 +171,12 @@ from brreg_wrapper import BrregClient
|
|
|
164
171
|
async def main():
|
|
165
172
|
client = BrregClient()
|
|
166
173
|
|
|
167
|
-
# Fetch multiple entities in
|
|
174
|
+
# Fetch multiple entities concurrently (at most 10 requests in flight)
|
|
168
175
|
org_numbers = ["923609016", "998463718", "913492978"]
|
|
169
|
-
results = await client.get_multiple_enheter(org_numbers)
|
|
176
|
+
results = await client.get_multiple_enheter(org_numbers, max_concurrency=10)
|
|
170
177
|
|
|
171
178
|
for org_nr, entity in results.items():
|
|
172
|
-
if isinstance(entity,
|
|
179
|
+
if isinstance(entity, BrregAPIError):
|
|
173
180
|
print(f"Error fetching {org_nr}: {entity}")
|
|
174
181
|
else:
|
|
175
182
|
print(f"{org_nr}: {entity.navn}")
|
|
@@ -192,13 +199,12 @@ async def main():
|
|
|
192
199
|
We use pytest for testing. To run the tests:
|
|
193
200
|
|
|
194
201
|
```bash
|
|
202
|
+
# Using UV (recommended)
|
|
203
|
+
uv run --extra dev pytest
|
|
204
|
+
|
|
195
205
|
# Using pip
|
|
196
206
|
pip install -e ".[dev]"
|
|
197
207
|
pytest
|
|
198
|
-
|
|
199
|
-
# Using UV (recommended)
|
|
200
|
-
uv pip install -e ".[dev]"
|
|
201
|
-
pytest
|
|
202
208
|
```
|
|
203
209
|
|
|
204
210
|
To test the package installation locally before publishing:
|
|
@@ -96,8 +96,8 @@ async def main():
|
|
|
96
96
|
# Second request uses cache
|
|
97
97
|
entity2 = await client.get_enhet("923609016")
|
|
98
98
|
|
|
99
|
-
# Clear specific cache entries
|
|
100
|
-
client.clear_cache(pattern="
|
|
99
|
+
# Clear specific cache entries (keys are request paths + query string)
|
|
100
|
+
client.clear_cache(pattern="/enheter/923609016")
|
|
101
101
|
|
|
102
102
|
# Get cache statistics
|
|
103
103
|
cache_info = client.get_cache_info()
|
|
@@ -107,14 +107,22 @@ async def main():
|
|
|
107
107
|
### Error Handling & Retry Logic
|
|
108
108
|
|
|
109
109
|
```python
|
|
110
|
-
from brreg_wrapper import
|
|
110
|
+
from brreg_wrapper import (
|
|
111
|
+
BrregAPIError,
|
|
112
|
+
BrregClient,
|
|
113
|
+
BrregRateLimitError,
|
|
114
|
+
BrregResourceNotFoundError,
|
|
115
|
+
)
|
|
111
116
|
|
|
112
117
|
async def main():
|
|
113
|
-
#
|
|
114
|
-
|
|
118
|
+
# Transient errors (5xx, 429, timeouts, connection errors) are retried
|
|
119
|
+
# with exponential backoff, honouring the server's Retry-After header.
|
|
120
|
+
client = BrregClient(max_retries=3) # up to 4 attempts in total
|
|
115
121
|
|
|
116
122
|
try:
|
|
117
|
-
entity = await client.get_enhet("
|
|
123
|
+
entity = await client.get_enhet("999999999") # Will raise exception
|
|
124
|
+
except BrregResourceNotFoundError:
|
|
125
|
+
print("No such organization")
|
|
118
126
|
except BrregRateLimitError:
|
|
119
127
|
# Handle rate limit specifically
|
|
120
128
|
print("Rate limit exceeded, try again later")
|
|
@@ -131,12 +139,12 @@ from brreg_wrapper import BrregClient
|
|
|
131
139
|
async def main():
|
|
132
140
|
client = BrregClient()
|
|
133
141
|
|
|
134
|
-
# Fetch multiple entities in
|
|
142
|
+
# Fetch multiple entities concurrently (at most 10 requests in flight)
|
|
135
143
|
org_numbers = ["923609016", "998463718", "913492978"]
|
|
136
|
-
results = await client.get_multiple_enheter(org_numbers)
|
|
144
|
+
results = await client.get_multiple_enheter(org_numbers, max_concurrency=10)
|
|
137
145
|
|
|
138
146
|
for org_nr, entity in results.items():
|
|
139
|
-
if isinstance(entity,
|
|
147
|
+
if isinstance(entity, BrregAPIError):
|
|
140
148
|
print(f"Error fetching {org_nr}: {entity}")
|
|
141
149
|
else:
|
|
142
150
|
print(f"{org_nr}: {entity.navn}")
|
|
@@ -159,13 +167,12 @@ async def main():
|
|
|
159
167
|
We use pytest for testing. To run the tests:
|
|
160
168
|
|
|
161
169
|
```bash
|
|
170
|
+
# Using UV (recommended)
|
|
171
|
+
uv run --extra dev pytest
|
|
172
|
+
|
|
162
173
|
# Using pip
|
|
163
174
|
pip install -e ".[dev]"
|
|
164
175
|
pytest
|
|
165
|
-
|
|
166
|
-
# Using UV (recommended)
|
|
167
|
-
uv pip install -e ".[dev]"
|
|
168
|
-
pytest
|
|
169
176
|
```
|
|
170
177
|
|
|
171
178
|
To test the package installation locally before publishing:
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Brreg Wrapper Examples
|
|
2
|
+
|
|
3
|
+
This directory contains example scripts that demonstrate how to use the `brreg-wrapper` package to interact with the Brønnøysund Register Centre API.
|
|
4
|
+
|
|
5
|
+
## Available Examples
|
|
6
|
+
|
|
7
|
+
- `sample.py`: A comprehensive example demonstrating basic usage, caching, batch operations, error handling, and search functionality.
|
|
8
|
+
|
|
9
|
+
## Running the Examples
|
|
10
|
+
|
|
11
|
+
Before running the examples, ensure you have installed the package:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# Using pip
|
|
15
|
+
pip install -e ..
|
|
16
|
+
|
|
17
|
+
# Using UV (recommended)
|
|
18
|
+
uv pip install -e ..
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Then run an example with:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# Using Python
|
|
25
|
+
python sample.py
|
|
26
|
+
|
|
27
|
+
# Or with UV's Python (if installed)
|
|
28
|
+
uv python sample.py
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Creating Your Own Examples
|
|
32
|
+
|
|
33
|
+
Feel free to add your own examples to this directory. Here's a simple template to get started:
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
#!/usr/bin/env python3
|
|
37
|
+
import asyncio
|
|
38
|
+
from brreg_wrapper import BrregClient
|
|
39
|
+
|
|
40
|
+
async def main():
|
|
41
|
+
# Create a client
|
|
42
|
+
async with BrregClient() as client:
|
|
43
|
+
# Your code here
|
|
44
|
+
# For example:
|
|
45
|
+
org_nr = "923609016" # Equinor ASA
|
|
46
|
+
entity = await client.get_enhet(org_nr)
|
|
47
|
+
print(f"Company name: {entity.navn}")
|
|
48
|
+
|
|
49
|
+
if __name__ == "__main__":
|
|
50
|
+
asyncio.run(main())
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Notes
|
|
54
|
+
|
|
55
|
+
- The examples assume you're running them from within the `examples` directory.
|
|
56
|
+
- Remember to always close the client using `await client.close()` or use it as an async context manager with `async with BrregClient() as client:`
|
|
57
|
+
- The Brreg API has rate limits, so be mindful when making many requests in quick succession.
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Sample script to demonstrate the Brreg API wrapper.
|
|
4
|
+
|
|
5
|
+
This script shows how to use the BrregClient with various configurations to access
|
|
6
|
+
Norwegian business registry data from Brønnøysund Register Centre (Brreg).
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
python examples/sample.py
|
|
10
|
+
|
|
11
|
+
Requirements:
|
|
12
|
+
pip install -e . # Install the package in development mode
|
|
13
|
+
# or
|
|
14
|
+
uv pip install -e . # Using UV installer
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import asyncio
|
|
18
|
+
import json
|
|
19
|
+
import logging
|
|
20
|
+
from datetime import timedelta
|
|
21
|
+
|
|
22
|
+
from brreg_wrapper import (
|
|
23
|
+
BrregAPIError,
|
|
24
|
+
BrregClient,
|
|
25
|
+
BrregRateLimitError,
|
|
26
|
+
BrregResourceNotFoundError,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
# Set up logging
|
|
30
|
+
logging.basicConfig(
|
|
31
|
+
level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
|
32
|
+
)
|
|
33
|
+
logger = logging.getLogger("brreg_sample")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
async def main():
|
|
37
|
+
"""Main function to demonstrate BrregClient features."""
|
|
38
|
+
# Example organization numbers
|
|
39
|
+
org_numbers = [
|
|
40
|
+
"923609016", # Equinor ASA
|
|
41
|
+
"914594685", # KPMG AS
|
|
42
|
+
"982463718", # Microsoft Norge AS
|
|
43
|
+
"999999999", # Invalid/non-existent
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
# Create a client with caching, rate limiting, and retry logic
|
|
47
|
+
logger.info("Initializing BrregClient with caching and rate limiting")
|
|
48
|
+
client = BrregClient(
|
|
49
|
+
timeout=15.0,
|
|
50
|
+
cache_ttl=timedelta(minutes=5),
|
|
51
|
+
rate_limit=1.0, # 1 request per second
|
|
52
|
+
max_retries=2,
|
|
53
|
+
logger=logger,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
try:
|
|
57
|
+
# 1. Basic usage - Get a single entity
|
|
58
|
+
logger.info("\n1. Getting information for a single entity (Equinor ASA)")
|
|
59
|
+
try:
|
|
60
|
+
equinor = await client.get_enhet(org_numbers[0])
|
|
61
|
+
print(f"Company Name: {equinor.navn}")
|
|
62
|
+
print(f"Organization Number: {equinor.organisasjonsnummer}")
|
|
63
|
+
print(f"Business Type: {equinor.organisasjonsform.beskrivelse}")
|
|
64
|
+
print(f"Registration Date: {equinor.registreringsdatoEnhetsregisteret}")
|
|
65
|
+
|
|
66
|
+
# Optional: serialize to JSON
|
|
67
|
+
print("\nJSON representation:")
|
|
68
|
+
equinor_dict = equinor.model_dump(
|
|
69
|
+
mode="json", by_alias=True, exclude_none=True
|
|
70
|
+
)
|
|
71
|
+
print(
|
|
72
|
+
json.dumps(equinor_dict, indent=2, ensure_ascii=False)[:500] + "...\n"
|
|
73
|
+
)
|
|
74
|
+
except BrregAPIError as e:
|
|
75
|
+
print(f"Error fetching Equinor data: {e}")
|
|
76
|
+
if e.response_json:
|
|
77
|
+
print(f"API response: {e.response_json}")
|
|
78
|
+
|
|
79
|
+
# 2. Caching demonstration
|
|
80
|
+
logger.info("\n2. Demonstrating caching")
|
|
81
|
+
logger.info("First request (will hit API):")
|
|
82
|
+
start_time = asyncio.get_event_loop().time()
|
|
83
|
+
await client.get_enhet(
|
|
84
|
+
org_numbers[1]
|
|
85
|
+
) # Just make the request, don't need to store result
|
|
86
|
+
first_request_time = asyncio.get_event_loop().time() - start_time
|
|
87
|
+
print(f"First request took {first_request_time:.4f} seconds")
|
|
88
|
+
|
|
89
|
+
logger.info("Second request (should use cache):")
|
|
90
|
+
start_time = asyncio.get_event_loop().time()
|
|
91
|
+
await client.get_enhet(
|
|
92
|
+
org_numbers[1]
|
|
93
|
+
) # Just make the request, don't need to store result
|
|
94
|
+
second_request_time = asyncio.get_event_loop().time() - start_time
|
|
95
|
+
print(f"Second request took {second_request_time:.4f} seconds")
|
|
96
|
+
print(f"Cache info: {client.get_cache_info()}")
|
|
97
|
+
|
|
98
|
+
# 3. Batch operations
|
|
99
|
+
logger.info("\n3. Getting multiple entities in parallel")
|
|
100
|
+
results = await client.get_multiple_enheter(
|
|
101
|
+
[org_numbers[0], org_numbers[1], org_numbers[2]]
|
|
102
|
+
)
|
|
103
|
+
for org_nr, entity in results.items():
|
|
104
|
+
if isinstance(entity, BrregAPIError):
|
|
105
|
+
print(f"❌ {org_nr}: Error - {entity}")
|
|
106
|
+
else:
|
|
107
|
+
print(f"✅ {org_nr}: {entity.navn}")
|
|
108
|
+
|
|
109
|
+
# 4. Error handling
|
|
110
|
+
logger.info("\n4. Error handling demonstration")
|
|
111
|
+
try:
|
|
112
|
+
await client.get_enhet(org_numbers[3]) # Invalid org number
|
|
113
|
+
except BrregResourceNotFoundError as e:
|
|
114
|
+
print(f"✅ Correct exception raised: {type(e).__name__}")
|
|
115
|
+
print(f" Message: {e}")
|
|
116
|
+
print(f" Status code: {e.status_code}")
|
|
117
|
+
print(f" Request URL: {e.request_url}")
|
|
118
|
+
except BrregAPIError as e:
|
|
119
|
+
print(f"❌ Wrong exception type: {type(e).__name__}")
|
|
120
|
+
|
|
121
|
+
# 5. Searching
|
|
122
|
+
logger.info("\n5. Searching for organizations")
|
|
123
|
+
search_results = await client.search_enheter(navn="Microsoft")
|
|
124
|
+
print(
|
|
125
|
+
f"Found {search_results.page.totalElements:.0f} "
|
|
126
|
+
"organizations matching 'Microsoft'"
|
|
127
|
+
)
|
|
128
|
+
for i, org in enumerate(search_results.field_embedded.enheter[:3], 1):
|
|
129
|
+
print(f" {i}. {org.navn} ({org.organisasjonsnummer})")
|
|
130
|
+
|
|
131
|
+
# 6. Looking up code lists
|
|
132
|
+
logger.info("\n6. Getting organization forms")
|
|
133
|
+
org_forms = await client.get_organisasjonsformer()
|
|
134
|
+
org_forms_sample = list(org_forms.field_embedded.organisasjonsformer)[:3]
|
|
135
|
+
print(
|
|
136
|
+
f"Found {len(org_forms.field_embedded.organisasjonsformer)} "
|
|
137
|
+
"organization forms"
|
|
138
|
+
)
|
|
139
|
+
for form in org_forms_sample:
|
|
140
|
+
print(f" • {form.kode}: {form.beskrivelse}")
|
|
141
|
+
|
|
142
|
+
except BrregRateLimitError as e:
|
|
143
|
+
print(f"Rate limit exceeded: {e}")
|
|
144
|
+
except BrregAPIError as e:
|
|
145
|
+
print(f"API error: {e} (Status code: {e.status_code})")
|
|
146
|
+
except Exception as e:
|
|
147
|
+
print(f"Unexpected error: {e}")
|
|
148
|
+
finally:
|
|
149
|
+
# Always close the client to clean up resources
|
|
150
|
+
await client.close()
|
|
151
|
+
print("\nClient closed successfully")
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
if __name__ == "__main__":
|
|
155
|
+
print("Brreg API Wrapper Demo")
|
|
156
|
+
print("======================\n")
|
|
157
|
+
asyncio.run(main())
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "brreg-wrapper"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.3.0"
|
|
4
4
|
description = "A Python wrapper for the Brønnøysund Register Centre (Brreg) API."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.13"
|
|
@@ -43,6 +43,10 @@ all = [
|
|
|
43
43
|
"h2>=4.0,<5.0", # HTTP/2 support
|
|
44
44
|
]
|
|
45
45
|
|
|
46
|
+
[build-system]
|
|
47
|
+
requires = ["hatchling"]
|
|
48
|
+
build-backend = "hatchling.build"
|
|
49
|
+
|
|
46
50
|
[tool.pytest.ini_options]
|
|
47
51
|
asyncio_mode = "strict" # Or "auto" if preferred
|
|
48
52
|
# Explicitly set the default loop scope to 'function' to silence the warning
|
|
@@ -86,9 +90,14 @@ target-version = "py313"
|
|
|
86
90
|
# Enable flake8-warning `W` codes by default.
|
|
87
91
|
# Enable isort `I` codes by default.
|
|
88
92
|
# See https://docs.astral.sh/ruff/rules/ for all rules.
|
|
89
|
-
|
|
93
|
+
# B = flake8-bugbear, UP = pyupgrade.
|
|
94
|
+
select = ["E", "F", "W", "I", "B", "UP"]
|
|
90
95
|
ignore = []
|
|
91
96
|
|
|
97
|
+
[tool.ruff.lint.per-file-ignores]
|
|
98
|
+
# Generated by datamodel-code-generator; keep diffs against regenerations small.
|
|
99
|
+
"src/brreg_wrapper/models/*" = ["UP"]
|
|
100
|
+
|
|
92
101
|
# Allow autofix for all enabled rules (when `--fix`) is used.
|
|
93
102
|
fixable = ["ALL"]
|
|
94
103
|
unfixable = []
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Brreg Wrapper Development Scripts
|
|
2
|
+
|
|
3
|
+
This directory contains utility scripts for developing and testing the `brreg-wrapper` package.
|
|
4
|
+
|
|
5
|
+
## Available Scripts
|
|
6
|
+
|
|
7
|
+
- `test_install.sh`: Shell script for testing the package installation on Unix-like systems (Linux, macOS)
|
|
8
|
+
- `test_install.bat`: Batch script for testing the package installation on Windows
|
|
9
|
+
|
|
10
|
+
## Using the Scripts
|
|
11
|
+
|
|
12
|
+
These scripts help verify that the package installs correctly before publishing to PyPI. They:
|
|
13
|
+
|
|
14
|
+
1. Create a test virtual environment
|
|
15
|
+
2. Install the package in development mode
|
|
16
|
+
3. Run a sample script to verify functionality
|
|
17
|
+
4. Build a wheel package
|
|
18
|
+
5. Install the wheel
|
|
19
|
+
6. Run the sample script again with the installed package
|
|
20
|
+
7. Clean up
|
|
21
|
+
|
|
22
|
+
### On Unix-like Systems (Linux, macOS)
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# Make the script executable
|
|
26
|
+
chmod +x scripts/test_install.sh
|
|
27
|
+
|
|
28
|
+
# Run the script
|
|
29
|
+
./scripts/test_install.sh
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### On Windows
|
|
33
|
+
|
|
34
|
+
```cmd
|
|
35
|
+
scripts\test_install.bat
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Requirements
|
|
39
|
+
|
|
40
|
+
- Python 3.13 or later
|
|
41
|
+
- UV package manager (recommended) or pip
|
|
42
|
+
- bash shell (for Unix-like systems)
|
|
43
|
+
- Windows command prompt or PowerShell (for Windows)
|
|
44
|
+
|
|
45
|
+
## Notes
|
|
46
|
+
|
|
47
|
+
- The scripts use the sample script in the `examples` directory to verify functionality
|
|
48
|
+
- UV is used by default for faster installation and better dependency resolution
|
|
49
|
+
- If UV is not available, it will be installed automatically on Unix systems
|
|
50
|
+
- On Windows, you'll be given installation instructions if UV is not found
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
@echo off
|
|
2
|
+
REM This script demonstrates how to test the brreg-wrapper package installation locally on Windows using UV
|
|
3
|
+
|
|
4
|
+
echo Brreg Wrapper Local Testing with UV
|
|
5
|
+
echo ==================================
|
|
6
|
+
echo.
|
|
7
|
+
|
|
8
|
+
REM Check if UV is installed
|
|
9
|
+
where uv > nul 2>&1
|
|
10
|
+
if %ERRORLEVEL% NEQ 0 (
|
|
11
|
+
echo UV not found. Please install UV first using:
|
|
12
|
+
echo curl -LsSf https://astral.sh/uv/install.ps1 ^| powershell -c -
|
|
13
|
+
exit /b 1
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
REM Check if a virtual environment exists
|
|
17
|
+
if not exist test_venv (
|
|
18
|
+
echo Creating a test virtual environment with UV...
|
|
19
|
+
uv venv test_venv
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
REM Activate the virtual environment
|
|
23
|
+
echo Activating virtual environment...
|
|
24
|
+
call test_venv\Scripts\activate.bat
|
|
25
|
+
|
|
26
|
+
REM Clean existing installations
|
|
27
|
+
echo Cleaning any existing installations...
|
|
28
|
+
uv pip uninstall -y brreg-wrapper
|
|
29
|
+
|
|
30
|
+
REM Option 1: Install in development mode (editable)
|
|
31
|
+
echo Installing package in development mode with UV...
|
|
32
|
+
uv pip install -e .
|
|
33
|
+
echo Package installed in development mode
|
|
34
|
+
|
|
35
|
+
REM Run the sample script
|
|
36
|
+
echo Running sample script...
|
|
37
|
+
python examples\sample.py
|
|
38
|
+
|
|
39
|
+
REM Option 2: Build and install the package from the wheel
|
|
40
|
+
echo.
|
|
41
|
+
echo.
|
|
42
|
+
echo Building the package...
|
|
43
|
+
uv pip install build
|
|
44
|
+
python -m build
|
|
45
|
+
|
|
46
|
+
REM Install the wheel
|
|
47
|
+
echo Installing the built package from wheel with UV...
|
|
48
|
+
uv pip uninstall -y brreg-wrapper
|
|
49
|
+
uv pip install --find-links=dist\ brreg-wrapper
|
|
50
|
+
echo Package installed from wheel
|
|
51
|
+
|
|
52
|
+
REM Verify installation
|
|
53
|
+
echo Verifying installation:
|
|
54
|
+
uv pip show brreg-wrapper
|
|
55
|
+
|
|
56
|
+
REM Run same sample script with the installed package
|
|
57
|
+
echo Running sample script again...
|
|
58
|
+
python examples\sample.py
|
|
59
|
+
|
|
60
|
+
REM Deactivate virtual environment
|
|
61
|
+
echo Cleaning up...
|
|
62
|
+
call deactivate
|
|
63
|
+
|
|
64
|
+
echo.
|
|
65
|
+
echo All tests completed successfully!
|
|
66
|
+
echo You can now upload the package to PyPI if all tests passed.
|
|
67
|
+
echo Command to upload: python -m twine upload dist/*
|
|
68
|
+
|
|
69
|
+
pause
|