mreg-api 0.2.0__tar.gz → 0.2.2__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 (47) hide show
  1. {mreg_api-0.2.0 → mreg_api-0.2.2}/.github/workflows/publish.yml +1 -7
  2. {mreg_api-0.2.0 → mreg_api-0.2.2}/CHANGELOG.md +26 -0
  3. {mreg_api-0.2.0 → mreg_api-0.2.2}/PKG-INFO +1 -1
  4. {mreg_api-0.2.0 → mreg_api-0.2.2}/mreg_api/_version.py +3 -3
  5. {mreg_api-0.2.0 → mreg_api-0.2.2}/mreg_api/endpoints.py +0 -1
  6. {mreg_api-0.2.0 → mreg_api-0.2.2}/mreg_api/models/abstracts.py +40 -97
  7. {mreg_api-0.2.0 → mreg_api-0.2.2}/mreg_api/models/fields.py +1 -1
  8. {mreg_api-0.2.0 → mreg_api-0.2.2}/mreg_api/models/history.py +2 -1
  9. {mreg_api-0.2.0 → mreg_api-0.2.2}/mreg_api/models/models.py +15 -51
  10. {mreg_api-0.2.0 → mreg_api-0.2.2}/mreg_api.egg-info/PKG-INFO +1 -1
  11. {mreg_api-0.2.0 → mreg_api-0.2.2}/.github/workflows/test.yml +0 -0
  12. {mreg_api-0.2.0 → mreg_api-0.2.2}/.gitignore +0 -0
  13. {mreg_api-0.2.0 → mreg_api-0.2.2}/.markdownlint.json +0 -0
  14. {mreg_api-0.2.0 → mreg_api-0.2.2}/.pre-commit-config.yaml +0 -0
  15. {mreg_api-0.2.0 → mreg_api-0.2.2}/LICENSE +0 -0
  16. {mreg_api-0.2.0 → mreg_api-0.2.2}/NOTES.md +0 -0
  17. {mreg_api-0.2.0 → mreg_api-0.2.2}/README.md +0 -0
  18. {mreg_api-0.2.0 → mreg_api-0.2.2}/mreg_api/__about__.py +0 -0
  19. {mreg_api-0.2.0 → mreg_api-0.2.2}/mreg_api/__init__.py +0 -0
  20. {mreg_api-0.2.0 → mreg_api-0.2.2}/mreg_api/cache.py +0 -0
  21. {mreg_api-0.2.0 → mreg_api-0.2.2}/mreg_api/client.py +0 -0
  22. {mreg_api-0.2.0 → mreg_api-0.2.2}/mreg_api/events.py +0 -0
  23. {mreg_api-0.2.0 → mreg_api-0.2.2}/mreg_api/exceptions.py +0 -0
  24. {mreg_api-0.2.0 → mreg_api-0.2.2}/mreg_api/models/__init__.py +0 -0
  25. {mreg_api-0.2.0 → mreg_api-0.2.2}/mreg_api/py.typed +0 -0
  26. {mreg_api-0.2.0 → mreg_api-0.2.2}/mreg_api/types.py +0 -0
  27. {mreg_api-0.2.0 → mreg_api-0.2.2}/mreg_api/utilities/__init__.py +0 -0
  28. {mreg_api-0.2.0 → mreg_api-0.2.2}/mreg_api/utilities/fs.py +0 -0
  29. {mreg_api-0.2.0 → mreg_api-0.2.2}/mreg_api/utilities/shared.py +0 -0
  30. {mreg_api-0.2.0 → mreg_api-0.2.2}/mreg_api.egg-info/SOURCES.txt +0 -0
  31. {mreg_api-0.2.0 → mreg_api-0.2.2}/mreg_api.egg-info/dependency_links.txt +0 -0
  32. {mreg_api-0.2.0 → mreg_api-0.2.2}/mreg_api.egg-info/requires.txt +0 -0
  33. {mreg_api-0.2.0 → mreg_api-0.2.2}/mreg_api.egg-info/top_level.txt +0 -0
  34. {mreg_api-0.2.0 → mreg_api-0.2.2}/pyproject.toml +0 -0
  35. {mreg_api-0.2.0 → mreg_api-0.2.2}/setup.cfg +0 -0
  36. {mreg_api-0.2.0 → mreg_api-0.2.2}/tests/__init__.py +0 -0
  37. {mreg_api-0.2.0 → mreg_api-0.2.2}/tests/conftest.py +0 -0
  38. {mreg_api-0.2.0 → mreg_api-0.2.2}/tests/models/__init__.py +0 -0
  39. {mreg_api-0.2.0 → mreg_api-0.2.2}/tests/models/test_fields.py +0 -0
  40. {mreg_api-0.2.0 → mreg_api-0.2.2}/tests/models/test_history.py +0 -0
  41. {mreg_api-0.2.0 → mreg_api-0.2.2}/tests/models/test_models.py +0 -0
  42. {mreg_api-0.2.0 → mreg_api-0.2.2}/tests/test_cache.py +0 -0
  43. {mreg_api-0.2.0 → mreg_api-0.2.2}/tests/test_client.py +0 -0
  44. {mreg_api-0.2.0 → mreg_api-0.2.2}/tests/test_events.py +0 -0
  45. {mreg_api-0.2.0 → mreg_api-0.2.2}/tests/test_exceptions.py +0 -0
  46. {mreg_api-0.2.0 → mreg_api-0.2.2}/tests/test_types.py +0 -0
  47. {mreg_api-0.2.0 → mreg_api-0.2.2}/uv.lock +0 -0
@@ -80,13 +80,7 @@ jobs:
80
80
  ### uv
81
81
 
82
82
  ```bash
83
- uv tool install mreg-api==${{ github.ref_name }}
84
- ```
85
-
86
- ### pipx
87
-
88
- ```bash
89
- pipx install mreg-api==${{ github.ref_name }}
83
+ uv add mreg-api==${{ github.ref_name }}
90
84
  ```
91
85
 
92
86
  ### pip
@@ -7,6 +7,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  <!-- ## Unreleased -->
9
9
 
10
+ ## [0.2.2](https://github.com/unioslo/mreg-api/releases/tag/0.2.2) - 2026-04-23
11
+
12
+ ### Changed
13
+
14
+ - Removed nullability of `NAPTR` fields.
15
+
16
+ ### Removed
17
+
18
+ - Duplicate endpoint `Endpoints.NAPTRs`. Now only `Endpoints.Naptrs` exists.
19
+
20
+ ## [0.2.1](https://github.com/unioslo/mreg-api/releases/tag/0.2.1) - 2026-04-20
21
+
22
+ ### Added
23
+
24
+ - `APIMixin.endpoint_with_id` property for getting the endpoint for the object with its ID, used for operations on the object itself (PATCH, DELETE, etc.). Used by default in `APIMixin.patch()` and `APIMixin.delete()`. Subclasses can override `endpoint_with_id` to provide custom endpoint resolution for these operations.
25
+
26
+ ### Removed
27
+
28
+ - `Community.patch()`. Now uses `APIMixin.patch()`.
29
+ - `Community.delete()`. Now uses `APIMixin.delete()`.
30
+ - `APIMixin.patch()` response validation.
31
+
32
+ ### Deprecated
33
+
34
+ - `APIMixin.patch()` parameter `validate`. Will be removed in 0.3.0.
35
+
10
36
  ## [0.2.0](https://github.com/unioslo/mreg-api/releases/tag/0.2.0) - 2026-04-16
11
37
 
12
38
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mreg-api
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: MREG API
5
5
  Author-email: Terje Kvernes <terjekv@uio.no>
6
6
  Maintainer-email: Peder Hovdan Andresen <pederhan@uio.no>
@@ -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.0'
22
- __version_tuple__ = version_tuple = (0, 2, 0)
21
+ __version__ = version = '0.2.2'
22
+ __version_tuple__ = version_tuple = (0, 2, 2)
23
23
 
24
- __commit_id__ = commit_id = 'gab1432412'
24
+ __commit_id__ = commit_id = 'ge065b8b90'
@@ -23,7 +23,6 @@ class Endpoint(str, Enum):
23
23
  PTR_overrides = "/api/v1/ptroverrides/"
24
24
  Locs = "/api/v1/locs/"
25
25
  Mxs = "/api/v1/mxs/"
26
- NAPTRs = "/api/v1/naptrs/"
27
26
  Nameservers = "/api/v1/nameservers/"
28
27
 
29
28
  Hosts = "/api/v1/hosts/"
@@ -4,110 +4,25 @@ from __future__ import annotations
4
4
 
5
5
  from abc import ABC
6
6
  from abc import abstractmethod
7
- from collections.abc import Mapping
8
7
  from datetime import datetime
9
8
  from typing import Any
10
- from typing import Callable
11
9
  from typing import Self
12
- from typing import cast
10
+ from typing import overload
13
11
 
14
- from pydantic import AliasChoices
15
12
  from pydantic import BaseModel
16
13
  from pydantic import ConfigDict
17
- from pydantic.fields import FieldInfo
14
+ from typing_extensions import deprecated
18
15
 
19
16
  from mreg_api.endpoints import Endpoint
20
17
  from mreg_api.exceptions import EntityAlreadyExists
21
18
  from mreg_api.exceptions import EntityNotFound
22
19
  from mreg_api.exceptions import GetError
23
20
  from mreg_api.exceptions import InternalError
24
- from mreg_api.exceptions import PatchError
25
21
  from mreg_api.exceptions import PostError
26
22
  from mreg_api.types import JsonMapping
27
23
  from mreg_api.types import QueryParams
28
24
 
29
25
 
30
- def get_field_aliases(field_info: FieldInfo) -> set[str]:
31
- """Get all aliases for a Pydantic field."""
32
- aliases: set[str] = set()
33
-
34
- if field_info.alias:
35
- aliases.add(field_info.alias)
36
-
37
- if field_info.validation_alias:
38
- if isinstance(field_info.validation_alias, str):
39
- aliases.add(field_info.validation_alias)
40
- elif isinstance(field_info.validation_alias, AliasChoices):
41
- for choice in field_info.validation_alias.choices:
42
- if isinstance(choice, str):
43
- aliases.add(choice)
44
- return aliases
45
-
46
-
47
- def get_model_aliases(model: BaseModel) -> dict[str, str]:
48
- """Get a mapping of aliases to field names for a Pydantic model.
49
-
50
- Includes field names, alias, and validation alias(es).
51
- """
52
- fields: dict[str, str] = {}
53
- for field_name, field_info in model.model_fields.items():
54
- aliases = get_field_aliases(field_info)
55
- if model.model_config.get("populate_by_name"):
56
- aliases.add(field_name)
57
- # Assign aliases to field name in mapping
58
- for alias in aliases:
59
- fields[alias] = field_name
60
- return fields
61
-
62
-
63
- def validate_patched_model(model: BaseModel, fields: Mapping[str, Any]) -> None:
64
- """Validate that model fields were patched correctly."""
65
- aliases = get_model_aliases(model)
66
-
67
- validators: dict[type, Callable[[Any, Any], bool]] = {
68
- list: _validate_lists,
69
- dict: _validate_dicts,
70
- }
71
- for key, value in fields.items():
72
- field_name = key
73
- if key in aliases:
74
- field_name = aliases[key]
75
-
76
- try:
77
- nval = getattr(model, field_name)
78
- except AttributeError as e:
79
- raise PatchError(f"Could not get value for {field_name} in patched object.") from e
80
-
81
- # Ensure patched value is the one we tried to set
82
- validator = validators.get(
83
- type(nval), # pyright:ignore[reportUnknownArgumentType, reportAny] # dict.get call with unknown type (Any) is fine
84
- _validate_default,
85
- )
86
- if not validator(nval, value):
87
- raise PatchError(
88
- f"Patch failure! Tried to set {key} to {value!r}, but server returned {nval!r}."
89
- )
90
-
91
-
92
- def _validate_lists(new: list[Any], old: list[Any]) -> bool:
93
- """Validate that two lists are equal."""
94
- if len(new) != len(old):
95
- return False
96
- return all(x in old for x in new)
97
-
98
-
99
- def _validate_dicts(new: dict[str, Any], old: dict[str, Any]) -> bool:
100
- """Validate that two dictionaries are equal."""
101
- if len(new) != len(old):
102
- return False
103
- return all(old.get(k) == v for k, v in new.items())
104
-
105
-
106
- def _validate_default(new: Any, old: Any) -> bool:
107
- """Validate that two values are equal."""
108
- return str(new) == str(old)
109
-
110
-
111
26
  class FrozenModel(BaseModel):
112
27
  """Model for an immutable object."""
113
28
 
@@ -153,9 +68,17 @@ class APIMixin(ABC):
153
68
  @classmethod
154
69
  @abstractmethod
155
70
  def endpoint(cls) -> Endpoint:
156
- """Return the endpoint for the method."""
71
+ """Return the endpoint for the resource."""
157
72
  raise NotImplementedError("You must define an endpoint.")
158
73
 
74
+ @property
75
+ def endpoint_with_id(self) -> str:
76
+ """Return the endpoint for the object with its ID.
77
+
78
+ Used for operations on the object itself (PATCH, DELETE, etc.).
79
+ """
80
+ return self.endpoint().with_id(self.id_for_endpoint())
81
+
159
82
  @classmethod
160
83
  def get(cls, _id: int) -> Self | None:
161
84
  """Get an object.
@@ -526,8 +449,33 @@ class APIMixin(ABC):
526
449
  raise GetError(f"Could not refresh {self.__class__.__name__} with ID {identifier}.")
527
450
  return obj
528
451
 
452
+ @overload
453
+ @deprecated(
454
+ "APIMixin.patch() parameter 'validate' is deprecated and will be removed in a future version."
455
+ )
456
+ def patch(
457
+ self,
458
+ data: JsonMapping,
459
+ *,
460
+ params: QueryParams | None = None,
461
+ validate: bool,
462
+ ) -> Self: ...
463
+
464
+ @overload
465
+ def patch(
466
+ self,
467
+ data: JsonMapping,
468
+ *,
469
+ params: QueryParams | None = ...,
470
+ validate: None = ...,
471
+ ) -> Self: ...
472
+
529
473
  def patch(
530
- self, data: JsonMapping, *, params: QueryParams | None = None, validate: bool = False
474
+ self,
475
+ data: JsonMapping,
476
+ *,
477
+ params: QueryParams | None = None,
478
+ validate: bool | None = None, # noqa: ARG002 # pyright: ignore[reportUnusedParameter]
531
479
  ) -> Self:
532
480
  """Patch the object with the given values.
533
481
 
@@ -539,21 +487,16 @@ class APIMixin(ABC):
539
487
  Args:
540
488
  data: The values to patch.
541
489
  params: Optional query parameters.
542
- validate: Whether to validate the patched object.
490
+ validate: Whether to validate the response. (Deprecated and ignored)
543
491
 
544
492
  Returns:
545
493
  The object refetched from the server.
546
494
  """
547
495
  from mreg_api.client import MregClient # noqa: PLC0415
548
496
 
549
- MregClient().patch(self.endpoint().with_id(self.id_for_endpoint()), json=data, params=params)
497
+ MregClient().patch(self.endpoint_with_id, json=data, params=params)
550
498
  new_object = self.refetch()
551
499
 
552
- if validate:
553
- # __init_subclass__ guarantees we inherit from BaseModel
554
- # but we can't signal this to the type checker, so we cast here.
555
- validate_patched_model(cast(BaseModel, new_object), data) # pyright: ignore[reportInvalidCast] # we know what we are doing here (...?!)
556
-
557
500
  return new_object
558
501
 
559
502
  def delete(self) -> bool:
@@ -564,7 +507,7 @@ class APIMixin(ABC):
564
507
  """
565
508
  from mreg_api.client import MregClient # noqa: PLC0415
566
509
 
567
- response = MregClient().delete(self.endpoint().with_id(self.id_for_endpoint()))
510
+ response = MregClient().delete(self.endpoint_with_id)
568
511
 
569
512
  if response and response.is_success:
570
513
  return True
@@ -1,6 +1,6 @@
1
1
  """Custom field types for Pydantic models.
2
2
 
3
- The types validate to basic types like str, int, etc., but with additional
3
+ The types resolve to basic types like str, int, etc., but with additional
4
4
  validation added to them. The types are used in Pydantic models for consistent
5
5
  validation of common fields such as hostnames, MAC addresses, etc.
6
6
 
@@ -14,6 +14,7 @@ from pydantic import field_validator
14
14
 
15
15
  from mreg_api.endpoints import Endpoint
16
16
  from mreg_api.exceptions import EntityNotFound
17
+ from mreg_api.types import JsonMapping
17
18
  from mreg_api.types import QueryParams
18
19
  from mreg_api.types import parse_json_mapping_string
19
20
 
@@ -62,7 +63,7 @@ class HistoryItem(BaseModel):
62
63
  mid: int = Field(alias="model_id") # model_ is an internal pydantic namespace.
63
64
  model: str
64
65
  action: str
65
- data: dict[str, Any]
66
+ data: JsonMapping
66
67
 
67
68
  @field_validator("data", mode="before")
68
69
  def parse_json_data(cls, v: Any) -> Any:
@@ -891,7 +891,7 @@ class Zone(FrozenModelWithTimestamps, WithTTL, APIMixin):
891
891
 
892
892
  self.ensure_delegation_in_zone(name)
893
893
  cls = Delegation.type_by_zone(self)
894
- resp = MregClient().get(cls.endpoint_with_id(self, name), ok404=True)
894
+ resp = MregClient().get(cls.endpoint_with_name(self, name), ok404=True)
895
895
  if not resp:
896
896
  return None
897
897
  return cls.model_validate_json(resp.text)
@@ -951,7 +951,7 @@ class Zone(FrozenModelWithTimestamps, WithTTL, APIMixin):
951
951
  # Check if delegation exists
952
952
  self.ensure_delegation_in_zone(name) # check name
953
953
  delegation = self.get_delegation_or_raise(name)
954
- resp = MregClient().delete(delegation.endpoint_with_id(self, name))
954
+ resp = MregClient().delete(delegation.endpoint_with_name(self, name))
955
955
  return resp.is_success if resp else False
956
956
 
957
957
  def set_delegation_comment(self, name: str, comment: str) -> None:
@@ -966,7 +966,7 @@ class Zone(FrozenModelWithTimestamps, WithTTL, APIMixin):
966
966
  delegation = self.get_delegation_or_raise(name)
967
967
  try:
968
968
  MregClient().patch(
969
- delegation.endpoint_with_id(self, delegation.name), json={"comment": comment}
969
+ delegation.endpoint_with_name(self, delegation.name), json={"comment": comment}
970
970
  )
971
971
  except PatchError as e:
972
972
  # TODO: implement after mreg-cli parity
@@ -1087,7 +1087,7 @@ class Delegation(FrozenModelWithTimestamps, WithZone):
1087
1087
  return Endpoint.ForwardZonesDelegations
1088
1088
 
1089
1089
  @classmethod
1090
- def endpoint_with_id(cls, zone: Zone, name: str) -> str:
1090
+ def endpoint_with_name(cls, zone: Zone, name: str) -> str:
1091
1091
  """Return the path to a delegation in a specific zone."""
1092
1092
  if cls.is_reverse():
1093
1093
  endpoint = Endpoint.ReverseZonesDelegationsZone
@@ -2000,7 +2000,7 @@ class Network(FrozenModelWithTimestamps, APIMixin):
2000
2000
  Returns:
2001
2001
  The updated Network object.
2002
2002
  """
2003
- return self.patch({"policy": policy.id}, validate=False)
2003
+ return self.patch({"policy": policy.id})
2004
2004
 
2005
2005
  def set_max_communities(self, max_communities: int) -> Self:
2006
2006
  """Set the maximum number of communities for the network.
@@ -2011,7 +2011,7 @@ class Network(FrozenModelWithTimestamps, APIMixin):
2011
2011
  Returns:
2012
2012
  The updated Network object.
2013
2013
  """
2014
- return self.patch({"max_communities": max_communities}, validate=False)
2014
+ return self.patch({"max_communities": max_communities})
2015
2015
 
2016
2016
  def unset_policy(self) -> Self:
2017
2017
  """Unset the network policy of the network.
@@ -2019,7 +2019,7 @@ class Network(FrozenModelWithTimestamps, APIMixin):
2019
2019
  Returns:
2020
2020
  The updated Network object.
2021
2021
  """
2022
- return self.patch({"policy": None}, validate=False)
2022
+ return self.patch({"policy": None})
2023
2023
 
2024
2024
  def unset_max_communities(self) -> Self:
2025
2025
  """Unset the maximum number of communities for the network.
@@ -2027,7 +2027,7 @@ class Network(FrozenModelWithTimestamps, APIMixin):
2027
2027
  Returns:
2028
2028
  The updated Network object.
2029
2029
  """
2030
- return self.patch({"max_communities": None}, validate=False)
2030
+ return self.patch({"max_communities": None})
2031
2031
 
2032
2032
 
2033
2033
  class NetworkPolicyAttribute(FrozenModelWithTimestamps, WithName):
@@ -2068,6 +2068,7 @@ class Community(FrozenModelWithTimestamps, APIMixin):
2068
2068
  return Endpoint.NetworkCommunity
2069
2069
 
2070
2070
  @property
2071
+ @override
2071
2072
  def endpoint_with_id(self) -> str:
2072
2073
  """Return the endpoint with the community ID."""
2073
2074
  return self.endpoint().with_params(self.network_address, self.id)
@@ -2088,42 +2089,6 @@ class Community(FrozenModelWithTimestamps, APIMixin):
2088
2089
 
2089
2090
  return MregClient().get_typed(self.endpoint_with_id, self.__class__)
2090
2091
 
2091
- @override
2092
- def patch(
2093
- self,
2094
- data: JsonMapping,
2095
- *,
2096
- params: QueryParams | None = None,
2097
- validate: bool = False, # noqa: ARG002, E501
2098
- ) -> Self:
2099
- """Patch the community.
2100
-
2101
- Args:
2102
- data: The data to patch.
2103
- params: Optional query parameters.
2104
- validate: Whether to validate the response. (Not implemented)
2105
-
2106
- Returns:
2107
- The updated Community object.
2108
- """
2109
- from mreg_api.client import MregClient # noqa: PLC0415
2110
-
2111
- try:
2112
- MregClient().patch(self.endpoint_with_id, json=data, params=params)
2113
- except PatchError as e:
2114
- # TODO: implement after mreg-cli parity
2115
- # raise PatchError(f"Failed to patch community {self.name!r}", e.response) from e
2116
- raise e
2117
- new_object = self.refetch()
2118
- return new_object
2119
-
2120
- def delete(self) -> bool:
2121
- """Delete the community."""
2122
- from mreg_api.client import MregClient # noqa: PLC0415
2123
-
2124
- resp = MregClient().delete(self.endpoint_with_id)
2125
- return resp.is_success if resp else False
2126
-
2127
2092
  def get_hosts(self) -> list[Host]:
2128
2093
  """Get a list of hosts in the community.
2129
2094
 
@@ -2286,7 +2251,6 @@ class NetworkPolicy(FrozenModelWithTimestamps, WithName):
2286
2251
  """
2287
2252
  self.patch(
2288
2253
  {"attributes": [{"name": a.name, "value": a.value} for a in attrs]},
2289
- validate=False,
2290
2254
  )
2291
2255
  # NOTE: can return self.refetch() here if we need to refresh the object
2292
2256
 
@@ -2468,7 +2432,7 @@ class IPAddress(FrozenModelWithTimestamps, WithHost, APIMixin):
2468
2432
  A new IPAddress object fetched from the API with the MAC address removed.
2469
2433
  """
2470
2434
  # Model converts empty string to None so we must validate this ourselves.
2471
- patched = self.patch(data={"macaddress": ""}, validate=False)
2435
+ patched = self.patch(data={"macaddress": ""})
2472
2436
  if patched.macaddress:
2473
2437
  raise PatchError(f"Failed to disassociate MAC address from {self.ipaddress}")
2474
2438
  return patched
@@ -2639,9 +2603,9 @@ class NAPTR(FrozenModelWithTimestamps, WithHost, APIMixin):
2639
2603
  id: int # noqa: A003
2640
2604
  preference: int
2641
2605
  order: int
2642
- flag: str | None = None
2643
- service: str | None = None
2644
- regex: str | None = None
2606
+ flag: str
2607
+ service: str
2608
+ regex: str
2645
2609
  replacement: str
2646
2610
 
2647
2611
  @classmethod
@@ -2650,7 +2614,7 @@ class NAPTR(FrozenModelWithTimestamps, WithHost, APIMixin):
2650
2614
  return Endpoint.Naptrs
2651
2615
 
2652
2616
  @classmethod
2653
- def headers(cls) -> list[str]:
2617
+ def headers(cls) -> list[str]: # TODO: remove. Move to mreg-cli
2654
2618
  """Return the headers for the NAPTR record."""
2655
2619
  return [
2656
2620
  "NAPTRs:",
@@ -3282,7 +3246,7 @@ class Host(FrozenModelWithTimestamps, WithTTL, WithHistory, APIMixin):
3282
3246
  Host: Updated Host object.
3283
3247
  """
3284
3248
  # Uses non-atomic host update via PATCH to set the contacts list.
3285
- return self.patch(data={"contacts": contacts}, validate=False)
3249
+ return self.patch(data={"contacts": contacts})
3286
3250
 
3287
3251
  def add_contacts(self, contacts: list[str]) -> HostContactModification:
3288
3252
  """Add contacts to the host.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mreg-api
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: MREG API
5
5
  Author-email: Terje Kvernes <terjekv@uio.no>
6
6
  Maintainer-email: Peder Hovdan Andresen <pederhan@uio.no>
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes