mreg-api 0.2.2__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.
Files changed (78) hide show
  1. mreg_api-0.3.0/.github/workflows/test.yml +52 -0
  2. {mreg_api-0.2.2 → mreg_api-0.3.0}/.gitignore +5 -0
  3. {mreg_api-0.2.2 → mreg_api-0.3.0}/CHANGELOG.md +23 -0
  4. {mreg_api-0.2.2 → mreg_api-0.3.0}/PKG-INFO +2 -2
  5. mreg_api-0.3.0/TESTING.md +136 -0
  6. mreg_api-0.3.0/ci/Dockerfile +15 -0
  7. mreg_api-0.3.0/ci/docker-compose.yml +39 -0
  8. mreg_api-0.3.0/ci/run_tests.sh +94 -0
  9. {mreg_api-0.2.2 → mreg_api-0.3.0}/mreg_api/_version.py +3 -3
  10. {mreg_api-0.2.2 → mreg_api-0.3.0}/mreg_api/cache.py +27 -2
  11. {mreg_api-0.2.2 → mreg_api-0.3.0}/mreg_api/client.py +228 -171
  12. {mreg_api-0.2.2 → mreg_api-0.3.0}/mreg_api/endpoints.py +3 -0
  13. {mreg_api-0.2.2 → mreg_api-0.3.0}/mreg_api/events.py +49 -5
  14. mreg_api-0.3.0/mreg_api/managers.py +4617 -0
  15. {mreg_api-0.2.2 → mreg_api-0.3.0}/mreg_api/models/__init__.py +2 -0
  16. mreg_api-0.3.0/mreg_api/models/abstracts.py +33 -0
  17. mreg_api-0.3.0/mreg_api/models/fields.py +198 -0
  18. {mreg_api-0.2.2 → mreg_api-0.3.0}/mreg_api/models/history.py +0 -30
  19. mreg_api-0.3.0/mreg_api/models/models.py +1293 -0
  20. {mreg_api-0.2.2 → mreg_api-0.3.0}/mreg_api/types.py +1 -11
  21. {mreg_api-0.2.2 → mreg_api-0.3.0}/mreg_api.egg-info/PKG-INFO +2 -2
  22. {mreg_api-0.2.2 → mreg_api-0.3.0}/mreg_api.egg-info/SOURCES.txt +25 -1
  23. {mreg_api-0.2.2 → mreg_api-0.3.0}/mreg_api.egg-info/requires.txt +1 -1
  24. mreg_api-0.3.0/mreg_api.egg-info/scm_file_list.json +65 -0
  25. mreg_api-0.3.0/mreg_api.egg-info/scm_version.json +8 -0
  26. {mreg_api-0.2.2 → mreg_api-0.3.0}/pyproject.toml +60 -23
  27. mreg_api-0.3.0/tests/__init__.py +0 -0
  28. mreg_api-0.3.0/tests/conftest.py +12 -0
  29. mreg_api-0.3.0/tests/integration/__init__.py +0 -0
  30. mreg_api-0.3.0/tests/integration/conftest.py +226 -0
  31. mreg_api-0.3.0/tests/integration/test_atoms.py +316 -0
  32. mreg_api-0.3.0/tests/integration/test_cname.py +175 -0
  33. mreg_api-0.3.0/tests/integration/test_dhcp.py +68 -0
  34. mreg_api-0.3.0/tests/integration/test_host_records.py +773 -0
  35. mreg_api-0.3.0/tests/integration/test_hostgroups.py +284 -0
  36. mreg_api-0.3.0/tests/integration/test_hosts.py +234 -0
  37. mreg_api-0.3.0/tests/integration/test_ip.py +158 -0
  38. mreg_api-0.3.0/tests/integration/test_labels.py +192 -0
  39. mreg_api-0.3.0/tests/integration/test_meta.py +49 -0
  40. mreg_api-0.3.0/tests/integration/test_network_policy.py +377 -0
  41. mreg_api-0.3.0/tests/integration/test_networks.py +324 -0
  42. mreg_api-0.3.0/tests/integration/test_permissions.py +202 -0
  43. mreg_api-0.3.0/tests/integration/test_roles.py +323 -0
  44. mreg_api-0.3.0/tests/integration/test_zones.py +242 -0
  45. mreg_api-0.3.0/tests/models/test_fields.py +457 -0
  46. {mreg_api-0.2.2 → mreg_api-0.3.0}/tests/models/test_models.py +20 -2
  47. {mreg_api-0.2.2 → mreg_api-0.3.0}/tests/test_client.py +141 -196
  48. {mreg_api-0.2.2 → mreg_api-0.3.0}/tests/test_events.py +5 -9
  49. {mreg_api-0.2.2 → mreg_api-0.3.0}/tests/test_exceptions.py +1 -5
  50. mreg_api-0.3.0/tests/test_managers.py +131 -0
  51. {mreg_api-0.2.2 → mreg_api-0.3.0}/uv.lock +79 -8
  52. mreg_api-0.2.2/.github/workflows/test.yml +0 -30
  53. mreg_api-0.2.2/mreg_api/models/abstracts.py +0 -558
  54. mreg_api-0.2.2/mreg_api/models/fields.py +0 -198
  55. mreg_api-0.2.2/mreg_api/models/models.py +0 -4435
  56. mreg_api-0.2.2/tests/conftest.py +0 -39
  57. mreg_api-0.2.2/tests/models/test_fields.py +0 -275
  58. mreg_api-0.2.2/tests/models/test_history.py +0 -40
  59. /mreg_api-0.2.2/mreg_api/py.typed → /mreg_api-0.3.0/.claude/CLAUDE.md +0 -0
  60. {mreg_api-0.2.2 → mreg_api-0.3.0}/.github/workflows/publish.yml +0 -0
  61. {mreg_api-0.2.2 → mreg_api-0.3.0}/.markdownlint.json +0 -0
  62. {mreg_api-0.2.2 → mreg_api-0.3.0}/.pre-commit-config.yaml +0 -0
  63. {mreg_api-0.2.2 → mreg_api-0.3.0}/LICENSE +0 -0
  64. {mreg_api-0.2.2 → mreg_api-0.3.0}/NOTES.md +0 -0
  65. {mreg_api-0.2.2 → mreg_api-0.3.0}/README.md +0 -0
  66. {mreg_api-0.2.2 → mreg_api-0.3.0}/mreg_api/__about__.py +0 -0
  67. {mreg_api-0.2.2 → mreg_api-0.3.0}/mreg_api/__init__.py +0 -0
  68. {mreg_api-0.2.2 → mreg_api-0.3.0}/mreg_api/exceptions.py +0 -0
  69. /mreg_api-0.2.2/tests/__init__.py → /mreg_api-0.3.0/mreg_api/py.typed +0 -0
  70. {mreg_api-0.2.2 → mreg_api-0.3.0}/mreg_api/utilities/__init__.py +0 -0
  71. {mreg_api-0.2.2 → mreg_api-0.3.0}/mreg_api/utilities/fs.py +0 -0
  72. {mreg_api-0.2.2 → mreg_api-0.3.0}/mreg_api/utilities/shared.py +0 -0
  73. {mreg_api-0.2.2 → mreg_api-0.3.0}/mreg_api.egg-info/dependency_links.txt +0 -0
  74. {mreg_api-0.2.2 → mreg_api-0.3.0}/mreg_api.egg-info/top_level.txt +0 -0
  75. {mreg_api-0.2.2 → mreg_api-0.3.0}/setup.cfg +0 -0
  76. {mreg_api-0.2.2 → mreg_api-0.3.0}/tests/models/__init__.py +0 -0
  77. {mreg_api-0.2.2 → mreg_api-0.3.0}/tests/test_cache.py +0 -0
  78. {mreg_api-0.2.2 → mreg_api-0.3.0}/tests/test_types.py +0 -0
@@ -0,0 +1,52 @@
1
+ on:
2
+ push:
3
+ pull_request:
4
+
5
+ env:
6
+ UV_FROZEN: 1
7
+
8
+ name: Tests
9
+ jobs:
10
+ unit:
11
+ name: Unit tests
12
+ runs-on: ubuntu-latest
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ python-version:
17
+ - "3.11"
18
+ - "3.12"
19
+ - "3.13"
20
+ - "3.14"
21
+ steps:
22
+ - uses: actions/checkout@v4
23
+ - name: Install uv
24
+ uses: astral-sh/setup-uv@v2
25
+ - name: Set up Python ${{ matrix.python-version }}
26
+ run: uv python install ${{ matrix.python-version }}
27
+ - name: Install dependencies
28
+ run: uv sync
29
+ - name: Run unit tests
30
+ run: bash ci/run_tests.sh --unit-only --no-cov
31
+
32
+ integration:
33
+ name: Integration tests
34
+ runs-on: ubuntu-latest
35
+ strategy:
36
+ fail-fast: false
37
+ matrix:
38
+ python-version:
39
+ - "3.11"
40
+ - "3.12"
41
+ - "3.13"
42
+ - "3.14"
43
+ steps:
44
+ - uses: actions/checkout@v4
45
+ - name: Install uv
46
+ uses: astral-sh/setup-uv@v2
47
+ - name: Set up Python ${{ matrix.python-version }}
48
+ run: uv python install ${{ matrix.python-version }}
49
+ - name: Install dependencies
50
+ run: uv sync
51
+ - name: Run integration tests
52
+ run: bash ci/run_tests.sh --integration-only --no-cov
@@ -110,3 +110,8 @@ venv.bak/
110
110
  mreg/.idea
111
111
 
112
112
  *.log
113
+
114
+ # Claude
115
+ .claude/settings.local.json
116
+ CLAUDE.local.md
117
+ !.claude/CLAUDE.md
@@ -7,6 +7,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  <!-- ## Unreleased -->
9
9
 
10
+ ## [0.3.0](https://github.com/unioslo/mreg-api/releases/tag/0.3.0) - 2026-08-12
11
+
12
+ ### Added
13
+
14
+ - `Host.get_community_associations(name: str)` method to retrieve all ipaddress->community associations for the host with the given community name.
15
+ - `Network.get_communities(name: str)` method to retrieve all communities with the given name.
16
+
17
+ ### Changed
18
+
19
+ - **BREAKING**: `MregClient` is no longer a singleton. Each instance is independent and maintains its own state. The `MregClient.get_instance()` method has been removed. Each instantiation of `MregClient` is now independent and maintains its own state, including history, events and cache.
20
+ - `Network.get_community()` now ignores case when searching for communities by name. It returns the first community with the given name, or None if not found.
21
+
22
+
23
+ ### Removed
24
+
25
+ - **BREAKING**: `MregClient.reset_instance` removed because the singleton pattern has been removed.
26
+
27
+ ## [0.2.3](https://github.com/unioslo/mreg-api/releases/tag/0.2.3) - 2026-05-21
28
+
29
+ ### Fixed
30
+
31
+ - Fixed `NAPTR` fields missing defaults after removal of nullability.
32
+
10
33
  ## [0.2.2](https://github.com/unioslo/mreg-api/releases/tag/0.2.2) - 2026-04-23
11
34
 
12
35
  ### Changed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mreg-api
3
- Version: 0.2.2
3
+ Version: 0.3.0
4
4
  Summary: MREG API
5
5
  Author-email: Terje Kvernes <terjekv@uio.no>
6
6
  Maintainer-email: Peder Hovdan Andresen <pederhan@uio.no>
@@ -692,7 +692,7 @@ Requires-Python: >=3.11
692
692
  Description-Content-Type: text/markdown
693
693
  License-File: LICENSE
694
694
  Requires-Dist: httpx[socks]>=0.28.1
695
- Requires-Dist: typing_extensions>=4.12.0
695
+ Requires-Dist: typing-extensions>=4.16.0
696
696
  Requires-Dist: pydantic>=2.12
697
697
  Requires-Dist: pydantic-extra-types>=2.1.0
698
698
  Requires-Dist: diskcache>=5.6.3
@@ -0,0 +1,136 @@
1
+ # Testing
2
+
3
+ mreg-api has two types of tests:
4
+
5
+ - **Unit tests** — Unit testing of functions and methods used by the package. No interaction with a live mreg server is required.
6
+ - **Integration tests** — Run against a live (containerized) mreg server. Skipped automatically when no server URL is configured.
7
+
8
+ ## Unit tests
9
+
10
+ Unit tests use `pytest-httpserver` to mock MREG server responses for any tests that require HTTP interactions. No external services required.
11
+
12
+ Bare `pytest` invocations ignore integration tests (skipped automatically when no server URL is configured):
13
+
14
+ ```bash
15
+ uv run pytest
16
+ ```
17
+
18
+ In case some configuration defines `MREG_URL`, unit tests can still be run exclusively by ignoring the integration tests via markers:
19
+
20
+ ```bash
21
+ uv run pytest -m "not integration"
22
+ ```
23
+
24
+ ## Integration tests
25
+
26
+ Integration tests run against a live mreg server. They are **skipped automatically** when no server URL is configured, so `uv run pytest` never fails due to a missing server.
27
+
28
+ ### Prerequisites
29
+
30
+ A running mreg instance (and PostgreSQL). The fastest way is the containerized setup:
31
+
32
+ ```bash
33
+ bash ci/run_tests.sh
34
+
35
+ # If port 8000 is already in use (e.g., a local mreg dev server):
36
+ MREG_PORT=8081 bash ci/run_tests.sh
37
+ ```
38
+
39
+ This starts containers, creates a superuser, then runs both unit and integration tests with combined coverage output in `htmlcov/`.
40
+
41
+ Flags:
42
+
43
+ | Flag | Effect |
44
+ |---|---|
45
+ | `--unit-only` | Skip integration tests (no containers started) |
46
+ | `--integration-only` | Skip unit tests |
47
+ | `--no-cov` | Disable coverage. Used in CI |
48
+
49
+ ```bash
50
+ # Fast run without coverage
51
+ bash ci/run_tests.sh --no-cov
52
+ ```
53
+
54
+ ### Running manually against a local server
55
+
56
+ ```bash
57
+ # Minimal — username/password default to "test"
58
+ MREG_URL=http://127.0.0.1:8000 uv run pytest tests/integration/
59
+
60
+ # All options explicit
61
+ MREG_URL=http://127.0.0.1:8000 \
62
+ MREG_USERNAME=myuser \
63
+ MREG_PASSWORD=secret \
64
+ MREG_DOMAIN=example.com \
65
+ MREG_CACHE=0 \
66
+ MREG_TEST_NETWORK=10.0.0.0/8 \
67
+ uv run pytest tests/integration/ -v
68
+
69
+ # Via CLI flags instead of env vars
70
+ uv run pytest tests/integration/ \
71
+ --mreg-url http://127.0.0.1:8000 \
72
+ --mreg-username myuser \
73
+ --mreg-password secret
74
+ ```
75
+
76
+ ### Configuration
77
+
78
+ | Env var | CLI flag | Default | Description |
79
+ |---|---|---|---|
80
+ | `MREG_URL` | `--mreg-url` | *(none — required to activate integration tests)* | mreg server base URL |
81
+ | `MREG_USERNAME` | `--mreg-username` | `test` | Login username |
82
+ | `MREG_PASSWORD` | `--mreg-password` | `test` | Login password |
83
+ | `MREG_DOMAIN` | `--mreg-domain` | `example.com` | Default domain for the client. Controls the main zone used in integration tests |
84
+ | `MREG_CACHE` | `--mreg-cache` | `false` | Enable mreg client cache (`1`/`true`/`yes` = on) |
85
+ | `MREG_TEST_NETWORK` | `--test-network` | `10.0.0.0/8` | Network CIDR created as shared test network |
86
+ | `MREG_TEST_IP` | `--test-ip` | `10.0.0.1` | IP address used in IP-related tests |
87
+
88
+ CLI flags take precedence over env vars.
89
+
90
+
91
+ ### Subset runs
92
+
93
+ ```bash
94
+ # Read-only tests only (safe against staging/production)
95
+ uv run pytest tests/integration/ -m readonly
96
+
97
+ # Single resource type
98
+ uv run pytest tests/integration/test_labels.py
99
+
100
+ # Specific test
101
+ uv run pytest tests/integration/test_labels.py::test_delete_by_name
102
+ ```
103
+
104
+ ## Coverage
105
+
106
+ ### Unit tests only
107
+
108
+ ```bash
109
+ uv run pytest tests/ --ignore=tests/integration \
110
+ --cov=mreg_api --cov-report=term-missing
111
+ ```
112
+
113
+ ### Combined unit + integration
114
+
115
+ Run `ci/run_tests.sh` (uses `--cov-append` to merge both passes), or manually:
116
+
117
+ ```bash
118
+ # Pass 1: unit tests — write .coverage
119
+ uv run pytest tests/ --ignore=tests/integration \
120
+ --cov=mreg_api --cov-report=
121
+
122
+ # Pass 2: integration tests — append to .coverage
123
+ MREG_URL=http://127.0.0.1:8000 MREG_USERNAME=test MREG_PASSWORD=test \
124
+ uv run pytest tests/integration/ \
125
+ --cov=mreg_api --cov-append --cov-report=html --cov-report=term
126
+
127
+ # Open report
128
+ open htmlcov/index.html
129
+ ```
130
+
131
+ ## Markers
132
+
133
+ | Marker | Meaning |
134
+ |---|---|
135
+ | `integration` | Requires live mreg server — skipped without `MREG_URL` |
136
+ | `readonly` | Test only reads data, safe against staging/production servers |
@@ -0,0 +1,15 @@
1
+ FROM ubuntu:latest
2
+
3
+ RUN apt-get update && apt-get install -y --no-install-recommends \
4
+ curl \
5
+ git \
6
+ && rm -rf /var/lib/apt/lists/*
7
+
8
+ RUN curl -LsSf https://astral.sh/uv/install.sh | sh
9
+ ENV PATH="/root/.local/bin:$PATH"
10
+
11
+ RUN uv python install 3.12
12
+
13
+ WORKDIR /build
14
+ COPY . .
15
+ RUN uv sync -q
@@ -0,0 +1,39 @@
1
+ services:
2
+ postgres:
3
+ image: postgres
4
+ environment:
5
+ POSTGRES_USER: mreg
6
+ POSTGRES_DB: mreg
7
+ POSTGRES_PASSWORD: mreg
8
+ healthcheck:
9
+ test: ["CMD", "pg_isready", "--username=mreg"]
10
+ interval: 5s
11
+ timeout: 5s
12
+ retries: 10
13
+
14
+ mreg:
15
+ image: ${MREG_IMAGE:-ghcr.io/unioslo/mreg:master}
16
+ container_name: mreg
17
+ depends_on:
18
+ postgres:
19
+ condition: service_healthy
20
+ ports:
21
+ - "${MREG_PORT:-8000}:8000"
22
+ environment:
23
+ MREG_DB_HOST: postgres
24
+ MREG_DB_NAME: mreg
25
+ MREG_DB_USER: mreg
26
+ MREG_DB_PASSWORD: mreg
27
+ MREG_MAP_GLOBAL_COMMUNITY_NAMES: "1"
28
+ CI: "yes"
29
+ healthcheck:
30
+ test: ["CMD", "test", "-f", "/var/run/gunicorn.pid"]
31
+ interval: 5s
32
+ timeout: 5s
33
+ retries: 20
34
+
35
+ wait:
36
+ image: hello-world
37
+ depends_on:
38
+ mreg:
39
+ condition: service_healthy
@@ -0,0 +1,94 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
+ REPO_ROOT="$(dirname "$SCRIPT_DIR")"
6
+
7
+ RUN_UNIT=true
8
+ RUN_INTEGRATION=true
9
+ RUN_COVERAGE=true
10
+ MREG_IMAGE="${MREG_IMAGE:-ghcr.io/unioslo/mreg:master}"
11
+ # Host port the mreg container is exposed on. Override if 8000 is already in use.
12
+ MREG_PORT="${MREG_PORT:-8000}"
13
+ MREG_URL="${MREG_URL:-http://127.0.0.1:${MREG_PORT}}"
14
+ MREG_USERNAME="${MREG_USERNAME:-test}"
15
+ MREG_PASSWORD="${MREG_PASSWORD:-test}"
16
+ MREG_CACHE="${MREG_CACHE:-0}"
17
+
18
+ while [[ $# -gt 0 ]]; do
19
+ case $1 in
20
+ --unit-only) RUN_INTEGRATION=false; shift ;;
21
+ --integration-only) RUN_UNIT=false; shift ;;
22
+ --no-cov) RUN_COVERAGE=false; shift ;;
23
+ *) shift ;;
24
+ esac
25
+ done
26
+
27
+ if command -v podman &>/dev/null && ! command -v docker &>/dev/null; then
28
+ DOCKER=podman
29
+ else
30
+ DOCKER=docker
31
+ fi
32
+
33
+ if [[ "$RUN_INTEGRATION" == "true" ]]; then
34
+ # Check if port is already in use before starting containers
35
+ if lsof -i ":${MREG_PORT}" 2>/dev/null | grep -q LISTEN; then
36
+ echo "ERROR: Port ${MREG_PORT} is already in use." >&2
37
+ echo "Set MREG_PORT to a free port: MREG_PORT=8081 bash ci/run_tests.sh" >&2
38
+ exit 1
39
+ fi
40
+
41
+ cleanup() {
42
+ cd "$SCRIPT_DIR"
43
+ $DOCKER compose down --remove-orphans 2>/dev/null || true
44
+ }
45
+ trap cleanup EXIT
46
+
47
+ cd "$SCRIPT_DIR"
48
+
49
+ echo "Starting mreg and postgres on port ${MREG_PORT}..."
50
+ MREG_IMAGE="$MREG_IMAGE" MREG_PORT="$MREG_PORT" $DOCKER compose up -d
51
+
52
+ echo "Creating superuser..."
53
+ $DOCKER exec mreg uv run /app/manage.py create_mreg_superuser \
54
+ --username "$MREG_USERNAME" --password "$MREG_PASSWORD" 2>/dev/null \
55
+ || $DOCKER exec mreg /app/manage.py create_mreg_superuser \
56
+ --username "$MREG_USERNAME" --password "$MREG_PASSWORD"
57
+
58
+
59
+ fi
60
+
61
+ cd "$REPO_ROOT"
62
+
63
+ UNIT_EXIT=0
64
+ INTEGRATION_EXIT=0
65
+
66
+ if [[ "$RUN_UNIT" == "true" ]]; then
67
+ echo "Running unit tests..."
68
+ UNIT_ARGS=(tests/ --ignore=tests/integration -v)
69
+ if [[ "$RUN_COVERAGE" == "true" ]]; then
70
+ UNIT_ARGS+=(--cov=mreg_api --cov-report=)
71
+ else
72
+ UNIT_ARGS+=(--no-cov)
73
+ fi
74
+ uv run pytest "${UNIT_ARGS[@]}" || UNIT_EXIT=$?
75
+ fi
76
+
77
+ if [[ "$RUN_INTEGRATION" == "true" ]]; then
78
+ echo "Running integration tests..."
79
+ INTEGRATION_ARGS=(tests/integration/ -v)
80
+ if [[ "$RUN_COVERAGE" == "true" ]]; then
81
+ INTEGRATION_ARGS+=(--cov=mreg_api --cov-append --cov-report=html --cov-report=term)
82
+ else
83
+ INTEGRATION_ARGS+=(--no-cov)
84
+ fi
85
+ MREG_URL="$MREG_URL" \
86
+ MREG_USERNAME="$MREG_USERNAME" \
87
+ MREG_PASSWORD="$MREG_PASSWORD" \
88
+ uv run pytest "${INTEGRATION_ARGS[@]}" || INTEGRATION_EXIT=$?
89
+ fi
90
+
91
+ if [[ $UNIT_EXIT -ne 0 || $INTEGRATION_EXIT -ne 0 ]]; then
92
+ exit 1
93
+ fi
94
+ exit 0
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '0.2.2'
22
- __version_tuple__ = version_tuple = (0, 2, 2)
21
+ __version__ = version = '0.3.0'
22
+ __version_tuple__ = version_tuple = (0, 3, 0)
23
23
 
24
- __commit_id__ = commit_id = 'ge065b8b90'
24
+ __commit_id__ = commit_id = 'gd440dfea6'
@@ -17,6 +17,15 @@ from pydantic import field_serializer
17
17
  from mreg_api.exceptions import CacheError
18
18
  from mreg_api.exceptions import CacheMiss
19
19
 
20
+ __all__ = [
21
+ "CacheConfig",
22
+ "MregApiCache",
23
+ "CacheInfo",
24
+ "CacheError",
25
+ "CacheMiss",
26
+ ]
27
+
28
+
20
29
  logger = logging.getLogger(__name__)
21
30
 
22
31
 
@@ -77,6 +86,10 @@ class CacheConfig(BaseModel):
77
86
  directory: str | None = None
78
87
 
79
88
 
89
+ # NOTE: this class used to make more sense when we had a protocol type for
90
+ # the backend class. Now that the backend class is explicitly `diskcache.Cache`,
91
+ # this class is mostly a wrapper around the cache instance and config.
92
+ # TODO: support other cache types: in-memory, etc.
80
93
  @final
81
94
  class MregApiCache(Generic[T]):
82
95
  """Wrapper around the mreg-api cache.
@@ -93,8 +106,8 @@ class MregApiCache(Generic[T]):
93
106
 
94
107
  Warning:
95
108
  NEVER use `if self._cache` checks! diskcache.Cache implements `__bool__`
96
- to check if the cache is non-empty, not whether it exists. Always use
97
- `if self._cache is None` instead.
109
+ to report whether the cache is NON-EMPTY, not whether it EXISTS.
110
+ Always use `if self._cache is None` instead in this class.
98
111
  """
99
112
 
100
113
  def __init__(self, cache: Cache | None, config: CacheConfig) -> None:
@@ -141,6 +154,18 @@ class MregApiCache(Generic[T]):
141
154
  """Disable the cache."""
142
155
  self.config.enable = False
143
156
 
157
+ def close(self) -> None:
158
+ """Close the cache and release resources."""
159
+ if self._cache is not None:
160
+ try:
161
+ self._cache.close()
162
+ except Exception as e:
163
+ logger.warning("Failed to close cache: %s", e)
164
+ finally:
165
+ # Unbind the object reference, allowing it to be garbage collected
166
+ # regardless of whether close() succeeded or not.
167
+ self._cache = None
168
+
144
169
  def get_info(self) -> CacheInfo | None:
145
170
  """Get information about the cache.
146
171