mreg-cli 1.1.0__tar.gz → 1.2.1__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 (86) hide show
  1. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/.github/workflows/publish.yml +1 -1
  2. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/.github/workflows/test.yml +11 -1
  3. mreg_cli-1.2.1/.markdownlint.json +9 -0
  4. mreg_cli-1.1.0/CHANGELOG → mreg_cli-1.2.1/CHANGELOG.md +32 -6
  5. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/PKG-INFO +1 -9
  6. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/README.md +0 -8
  7. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/ci/testsuite +1 -0
  8. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/ci/testsuite-result.json +126 -13
  9. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/_version.py +2 -2
  10. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/api/endpoints.py +7 -0
  11. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/api/fields.py +26 -11
  12. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/api/models.py +357 -65
  13. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/cli.py +3 -2
  14. mreg_cli-1.2.1/mreg_cli/commands/help.py +136 -0
  15. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/commands/host_submodules/a_aaaa.py +3 -3
  16. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/commands/host_submodules/core.py +16 -9
  17. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/commands/host_submodules/rr.py +4 -4
  18. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/commands/network.py +1 -1
  19. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/commands/permission.py +2 -2
  20. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/config.py +5 -0
  21. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/errorbuilder.py +41 -39
  22. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/exceptions.py +20 -14
  23. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/main.py +2 -2
  24. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/outputmanager.py +4 -5
  25. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/prompt.py +3 -5
  26. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/tokenfile.py +7 -0
  27. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/utilities/api.py +7 -5
  28. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli.egg-info/PKG-INFO +1 -9
  29. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli.egg-info/SOURCES.txt +2 -1
  30. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/tests/api/test_models.py +26 -2
  31. mreg_cli-1.2.1/tests/test_errorbuilder.py +75 -0
  32. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/tests/test_prompt.py +18 -0
  33. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/tests/test_tokenfile.py +34 -0
  34. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/tests/utilities/test_api.py +28 -4
  35. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/uv.lock +1 -1
  36. mreg_cli-1.1.0/mreg_cli/commands/help.py +0 -77
  37. mreg_cli-1.1.0/tests/test_errorbuilder.py +0 -56
  38. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/.gitignore +0 -0
  39. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/AUTHORS +0 -0
  40. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/CONTRIBUTING +0 -0
  41. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/LICENSE +0 -0
  42. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/ci/diff.py +0 -0
  43. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/ci/docker-compose.yml +0 -0
  44. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/ci/run_testsuite_and_record.sh +0 -0
  45. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/data/mreg-cli.conf +0 -0
  46. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/__about__.py +0 -0
  47. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/__init__.py +0 -0
  48. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/__main__.py +0 -0
  49. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/api/__init__.py +0 -0
  50. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/api/abstracts.py +0 -0
  51. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/api/history.py +0 -0
  52. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/commands/__init__.py +0 -0
  53. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/commands/base.py +0 -0
  54. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/commands/dhcp.py +0 -0
  55. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/commands/group.py +0 -0
  56. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/commands/host.py +0 -0
  57. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/commands/host_submodules/__init__.py +0 -0
  58. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/commands/host_submodules/bacnet.py +0 -0
  59. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/commands/host_submodules/cname.py +0 -0
  60. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/commands/label.py +0 -0
  61. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/commands/logging.py +0 -0
  62. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/commands/policy.py +0 -0
  63. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/commands/recording.py +0 -0
  64. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/commands/registry.py +0 -0
  65. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/commands/root.py +0 -0
  66. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/commands/zone.py +0 -0
  67. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/help_formatter.py +0 -0
  68. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/py.typed +0 -0
  69. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/tags.txt +0 -0
  70. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/types.py +0 -0
  71. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/utilities/__init__.py +0 -0
  72. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/utilities/shared.py +0 -0
  73. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli/utilities/validators.py +0 -0
  74. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli.egg-info/dependency_links.txt +0 -0
  75. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli.egg-info/entry_points.txt +0 -0
  76. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli.egg-info/requires.txt +0 -0
  77. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/mreg_cli.egg-info/top_level.txt +0 -0
  78. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/pyproject.toml +0 -0
  79. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/run.py +0 -0
  80. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/setup.cfg +0 -0
  81. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/tests/__init__.py +0 -0
  82. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/tests/api/__init__.py +0 -0
  83. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/tests/api/test_fields.py +0 -0
  84. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/tests/conftest.py +0 -0
  85. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/tests/utilities/__init__.py +0 -0
  86. {mreg_cli-1.1.0 → mreg_cli-1.2.1}/tox.ini +0 -0
@@ -130,8 +130,8 @@ jobs:
130
130
  publish_github:
131
131
  name: Publish GitHub release
132
132
  needs:
133
- - build_pypi
134
133
  - build_pyinstaller
134
+ - publish_pypi
135
135
  runs-on: ubuntu-latest
136
136
 
137
137
  steps:
@@ -48,7 +48,17 @@ jobs:
48
48
  run: uv sync --group ci
49
49
  - name: Test building with tox
50
50
  run: uv run tox r
51
-
51
+
52
+ lint:
53
+ name: Lint
54
+ runs-on: ubuntu-latest
55
+ steps:
56
+ - uses: actions/checkout@v4
57
+ - uses: DavidAnson/markdownlint-cli2-action@v18
58
+ with:
59
+ config: '.markdownlint.json'
60
+ globs: '**/*.md'
61
+
52
62
  unit:
53
63
  name: Unit tests
54
64
  runs-on: ubuntu-latest
@@ -0,0 +1,9 @@
1
+ {
2
+ "default": true,
3
+ "no-duplicate-heading": {
4
+ "siblings_only": true
5
+ },
6
+ "line-length": false,
7
+ "no-bare-urls": false,
8
+ "no-inline-html": false
9
+ }
@@ -5,9 +5,34 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
- <!-- ## [Unreleased] -->
8
+ <!-- ## Unreleased -->
9
9
 
10
- ## [1.1.0] - 2024-11-19
10
+ ## [1.2.1](https://github.com/unioslo/mreg-cli/releases/tag/1.2.1) - 2024-12-02
11
+
12
+ ### Fixed
13
+
14
+ - Host lookup with IPv6 addresses raising `ValidationError` when no host can be found with the given address.
15
+
16
+ ### Removed
17
+
18
+ - Support for fetching hosts that have a valid IP/MAC address as their hostname.
19
+
20
+ ## [1.2.0](https://github.com/unioslo/mreg-cli/releases/tag/1.2.0) - 2024-11-25
21
+
22
+ ### Added
23
+
24
+ - Support for `help versions` which shows versions of the CLI and the server for servers that have implemented the `/meta/version` (and `/meta/libraries` endpoints for superusers).
25
+ - Support for `help whoami` which shows information about the current user as the server sees them. This includes the username, attributes, groups, and permissions. This command is only available if the server has implemented the `/meta/users` endpoint.
26
+ - Support for `help whois <username>` which allows elevated users to see information about the given user. Also requires the `/meta/users` endpoint to be implemented on the server.
27
+
28
+ ### Fixed
29
+
30
+ - REPL command completion not showing descriptions for commands.
31
+ - `host info` with MAC address argument not working for hosts with multiple IPs associated with the same MAC address.
32
+ - Failed token file write causing the application to crash.
33
+ - Connection strings without domains and with ports are now parsed properly for prompt interpolation.
34
+
35
+ ## [1.1.0](https://github.com/unioslo/mreg-cli/releases/tag/1.1.0) - 2024-11-19
11
36
 
12
37
  ### Added
13
38
 
@@ -21,18 +46,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
21
46
 
22
47
  ### Fixed
23
48
 
24
- - `host add`: Re-introduced support for network/ip ending with `/`.
49
+ - MAC adress validation. Now supports all common formats. See the [Pydantic docs](https://docs.pydantic.dev/latest/api/pydantic_extra_types_mac_address/) for more information.
50
+ - `host add`: Re-introduced support for network/IP ending with `/`.
25
51
  - Automatically deduces the correct network to assign an IP from.
26
- - `host add`: No longer possible to assign the network ID (first address of subnet) to a host.
52
+ - `host add`: No longer possible to assign network address (first address of subnet) or broadcast address (last address of subnet) to a host.
27
53
 
28
- ## [1.0.1] - 2024-10-21
54
+ ## [1.0.1](https://github.com/unioslo/mreg-cli/releases/tag/1.0.1) - 2024-10-21
29
55
 
30
56
  ### Fixed
31
57
 
32
58
  - Rendering of top level command autocompletion in REPL.
33
59
  - `OK:` messages not being displayed outside of `--record` mode
34
60
 
35
- ## [1.0.0] - 2024-10-12
61
+ ## [1.0.0](https://github.com/unioslo/mreg-cli/releases/tag/1.0.0) - 2024-10-12
36
62
 
37
63
  The big Pydantic update. The entire codebase has been rewritten to use Pydantic for request and response validation. This brings with it a huge improvement to the development experience and the robustness of the code.
38
64
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mreg-cli
3
- Version: 1.1.0
3
+ Version: 1.2.1
4
4
  Summary: MREG interactive command line client
5
5
  Author: Others (see AUTHORS)
6
6
  Author-email: Øyvind Kolbu <oyvind.kolbu@usit.uio.no>, Safet A <amedov@usit.uio.no>, Magnus Hirth <mhmorgan42@gmail.com>, Nico <nicolaydmohebi@gmail.com>, Marius Bakke <marius.bakke@usit.uio.no>, Fredrik Larsen <fredrik.larsen@usit.uio.no>, Paal Braathen <paal.braathen@usit.uio.no>, Nils Hiorth <nils@nls.me>, Dmytro Karpenko <dmytrok@usit.uio.no>
@@ -726,15 +726,7 @@ Requires-Dist: platformdirs>=4.3.0
726
726
  - [DHCP](#dhcp)
727
727
  - [subnet](#subnet)
728
728
  - [zone](#zone)
729
- - [history](#history)
730
729
  - [other](#other)
731
- - [Devhelp](#devhelp)
732
- - [client.py](#clientpy)
733
- - [commands.py](#commandspy)
734
- - [util.py](#utilpy)
735
- - [history.py](#historypy)
736
- - [config.py](#configpy)
737
- - [log.py](#logpy)
738
730
 
739
731
  ## Setup
740
732
 
@@ -22,15 +22,7 @@
22
22
  - [DHCP](#dhcp)
23
23
  - [subnet](#subnet)
24
24
  - [zone](#zone)
25
- - [history](#history)
26
25
  - [other](#other)
27
- - [Devhelp](#devhelp)
28
- - [client.py](#clientpy)
29
- - [commands.py](#commandspy)
30
- - [util.py](#utilpy)
31
- - [history.py](#historypy)
32
- - [config.py](#configpy)
33
- - [log.py](#logpy)
34
26
 
35
27
  ## Setup
36
28
 
@@ -203,6 +203,7 @@ dhcp assoc foo aa:bb:cc:dd:ee:ff # should fail, the host has two IPs of differen
203
203
  host aaaa_remove foo 2001:db9::5
204
204
  host aaaa_add foo 2001:db8::5 -f
205
205
  dhcp assoc foo aa:bb:cc:dd:ee:ff # should work, the host now has two IPs of different types on the same VLAN.
206
+ host info foo # should work and show both IPs
206
207
  host remove foo -f
207
208
  network remove 10.0.0.0/24 -f
208
209
  network remove 2001:db8::/64 -f
@@ -6,7 +6,6 @@
6
6
  "command_issued": "zone create example.org hostmaster@example.org ns1.example.org # should require force because ns1 is unknown",
7
7
  "ok": [],
8
8
  "warning": [
9
- "Host ns1.example.org not found.",
10
9
  "ns1.example.org is not in mreg, must force"
11
10
  ],
12
11
  "error": [],
@@ -41,9 +40,7 @@
41
40
  "ok": [
42
41
  "Created zone example.org"
43
42
  ],
44
- "warning": [
45
- "Host ns1.example.org not found."
46
- ],
43
+ "warning": [],
47
44
  "error": [],
48
45
  "output": [],
49
46
  "api_requests": [
@@ -210,10 +207,9 @@
210
207
  "command": "zone set_ns example.org ns2.example.org",
211
208
  "command_filter": null,
212
209
  "command_filter_negate": false,
213
- "command_issued": "zone set_ns example.org ns2.example.org # requires force because ns2 is unknown",
210
+ "command_issued": "zone set_ns example.org ns2.example.org # requires force because ns2 is unknown",
214
211
  "ok": [],
215
212
  "warning": [
216
- "Host ns2.example.org not found.",
217
213
  "ns2.example.org is not in mreg, must force"
218
214
  ],
219
215
  "error": [],
@@ -271,9 +267,7 @@
271
267
  "ok": [
272
268
  "Updated nameservers for example.org"
273
269
  ],
274
- "warning": [
275
- "Host ns2.example.org not found."
276
- ],
270
+ "warning": [],
277
271
  "error": [],
278
272
  "output": [],
279
273
  "api_requests": [
@@ -15283,9 +15277,7 @@
15283
15277
  "ok": [
15284
15278
  "Created zone delegation wut.example.org"
15285
15279
  ],
15286
- "warning": [
15287
- "Host ns2.example.org not found."
15288
- ],
15280
+ "warning": [],
15289
15281
  "error": [],
15290
15282
  "output": [],
15291
15283
  "api_requests": [
@@ -20022,6 +20014,127 @@
20022
20014
  ],
20023
20015
  "time": null
20024
20016
  },
20017
+ {
20018
+ "command": "host info foo",
20019
+ "command_filter": null,
20020
+ "command_filter_negate": false,
20021
+ "command_issued": "host info foo # should work and show both IPs",
20022
+ "ok": [],
20023
+ "warning": [],
20024
+ "error": [],
20025
+ "output": [
20026
+ "Name: foo.example.org",
20027
+ "Contact: ",
20028
+ "A_Records IP MAC",
20029
+ " 10.0.0.5 aa:bb:cc:dd:ee:ff",
20030
+ "AAAA_Records IP MAC",
20031
+ " 2001:db8::5 <not set>",
20032
+ "TTL: (Default)",
20033
+ "TXT: v=spf1 -all",
20034
+ "Created: Thu Nov 21 10:34:55 2024",
20035
+ "Updated: Thu Nov 21 10:34:55 2024"
20036
+ ],
20037
+ "api_requests": [
20038
+ {
20039
+ "method": "GET",
20040
+ "url": "/api/v1/hosts/foo.example.org",
20041
+ "data": {},
20042
+ "status": 200,
20043
+ "response": {
20044
+ "ipaddresses": [
20045
+ {
20046
+ "macaddress": "aa:bb:cc:dd:ee:ff",
20047
+ "ipaddress": "10.0.0.5",
20048
+ "host": 13
20049
+ },
20050
+ {
20051
+ "macaddress": "",
20052
+ "ipaddress": "2001:db8::5",
20053
+ "host": 13
20054
+ }
20055
+ ],
20056
+ "cnames": [],
20057
+ "mxs": [],
20058
+ "txts": [
20059
+ {
20060
+ "txt": "v=spf1 -all",
20061
+ "host": 13
20062
+ }
20063
+ ],
20064
+ "ptr_overrides": [],
20065
+ "hinfo": null,
20066
+ "loc": null,
20067
+ "bacnetid": null,
20068
+ "name": "foo.example.org",
20069
+ "contact": "",
20070
+ "ttl": null,
20071
+ "comment": "",
20072
+ "zone": 1
20073
+ }
20074
+ },
20075
+ {
20076
+ "method": "GET",
20077
+ "url": "/api/v1/srvs/?host=13",
20078
+ "data": {},
20079
+ "status": 200,
20080
+ "response": {
20081
+ "count": 0,
20082
+ "next": null,
20083
+ "previous": null,
20084
+ "results": []
20085
+ }
20086
+ },
20087
+ {
20088
+ "method": "GET",
20089
+ "url": "/api/v1/naptrs/?host=13",
20090
+ "data": {},
20091
+ "status": 200,
20092
+ "response": {
20093
+ "count": 0,
20094
+ "next": null,
20095
+ "previous": null,
20096
+ "results": []
20097
+ }
20098
+ },
20099
+ {
20100
+ "method": "GET",
20101
+ "url": "/api/v1/sshfps/?host=13",
20102
+ "data": {},
20103
+ "status": 200,
20104
+ "response": {
20105
+ "count": 0,
20106
+ "next": null,
20107
+ "previous": null,
20108
+ "results": []
20109
+ }
20110
+ },
20111
+ {
20112
+ "method": "GET",
20113
+ "url": "/api/v1/hostpolicy/roles/?hosts=13",
20114
+ "data": {},
20115
+ "status": 200,
20116
+ "response": {
20117
+ "count": 0,
20118
+ "next": null,
20119
+ "previous": null,
20120
+ "results": []
20121
+ }
20122
+ },
20123
+ {
20124
+ "method": "GET",
20125
+ "url": "/api/v1/hostgroups/?hosts=13",
20126
+ "data": {},
20127
+ "status": 200,
20128
+ "response": {
20129
+ "count": 0,
20130
+ "next": null,
20131
+ "previous": null,
20132
+ "results": []
20133
+ }
20134
+ }
20135
+ ],
20136
+ "time": null
20137
+ },
20025
20138
  {
20026
20139
  "command": "host remove foo -f",
20027
20140
  "command_filter": null,
@@ -24928,7 +25041,7 @@
24928
25041
  "api_requests": [
24929
25042
  {
24930
25043
  "method": "GET",
24931
- "url": "/api/v1/hosts/?ipaddresses__ipaddress=10.0.0.20&ordering=name",
25044
+ "url": "/api/v1/hosts/?ipaddresses__ipaddress=10.0.0.20",
24932
25045
  "data": {},
24933
25046
  "status": 200,
24934
25047
  "response": {
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '1.1.0'
16
- __version_tuple__ = version_tuple = (1, 1, 0)
15
+ __version__ = version = '1.2.1'
16
+ __version_tuple__ = version_tuple = (1, 2, 1)
@@ -77,6 +77,13 @@ class Endpoint(str, Enum):
77
77
 
78
78
  ForwardZoneForHost = f"{ForwardZones}hostname/"
79
79
 
80
+ TokenIsValid = "/api/token-is-valid/"
81
+
82
+ MetaUser = "/api/meta/user"
83
+ MetaVersion = "/api/meta/version"
84
+ MetaLibraries = "/api/meta/libraries"
85
+ MetaHeartbeat = "/api/meta/heartbeat"
86
+
80
87
  def __str__(self):
81
88
  """Prevent direct usage without parameters where needed."""
82
89
  if "{}" in self.value:
@@ -21,25 +21,40 @@ class MACAddressField(FrozenModel):
21
21
 
22
22
  address: MacAddress
23
23
 
24
- @classmethod
25
- def validate(cls, value: str | MacAddress | Self) -> Self:
26
- """Validate a MAC address and return it as a string."""
27
- try:
28
- return cls.validate_naive(value)
29
- except ValueError as e:
30
- raise InputFailure(e) from e
31
-
32
24
  # HACK: extremely hacky workaround for our custom exceptions always
33
25
  # logging errors/warnings even when caught.
34
26
  @classmethod
35
- def validate_naive(cls, value: str | MacAddress | Self) -> Self:
27
+ def validate(cls, value: str | MacAddress | Self) -> Self:
36
28
  """Validate but raise built-in exceptions on failure."""
37
29
  if isinstance(value, MACAddressField):
38
- return cls.validate_naive(value.address)
30
+ return cls.validate(value.address)
39
31
  try:
40
32
  return cls(address=value) # pyright: ignore[reportArgumentType]
41
33
  except ValidationError as e:
42
- raise ValueError(f"Invalid MAC address '{value}'") from e
34
+ raise InputFailure(f"Invalid MAC address '{value}'") from e
35
+
36
+ @classmethod
37
+ def parse_or_raise(cls, obj: Any) -> MacAddress:
38
+ """Parse a MAC address from a string. Returns the MAC address as a string.
39
+
40
+ :param obj: The object to parse.
41
+ :returns: The MAC address as a string.
42
+ :raises ValueError: If the object is not a valid MAC address.
43
+ """
44
+ # Match interface of NetworkOrIP.parse_or_raise
45
+ return cls.validate(obj).address
46
+
47
+ @classmethod
48
+ def parse(cls, obj: Any) -> MacAddress | None:
49
+ """Parse a MAC address from a string. Returns None if the MAC address is invalid.
50
+
51
+ :param obj: The object to parse.
52
+ :returns: The MAC address as a string or None if it is invalid.
53
+ """
54
+ try:
55
+ return cls.parse_or_raise(obj)
56
+ except ValueError:
57
+ return None
43
58
 
44
59
  def __str__(self) -> str:
45
60
  """Return the MAC address as a string."""