-
Notifications
You must be signed in to change notification settings - Fork 76
Expand file tree
/
Copy pathtypes.py
More file actions
93 lines (66 loc) · 3.05 KB
/
types.py
File metadata and controls
93 lines (66 loc) · 3.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
"""Contrib type classes for interfacing with Nautobot in SSoT."""
# pylint: disable=protected-access
# Diffsync relies on underscore-prefixed attributes quite heavily, which is why we disable this here.
from dataclasses import dataclass
from typing import Optional
from nautobot_ssot.contrib.enums import RelationshipSideEnum
class CustomAnnotation:
"""Base class used to identify custom annotations in SSoT operations."""
def __hash__(self):
"""Return a hash of the class instance."""
return hash(frozenset({"class": self.__class__} | self.__dict__))
@dataclass
class CustomRelationshipAnnotation(CustomAnnotation):
"""Map a model field to an arbitrary custom relationship.
For usage with `typing.Annotated`.
This exists to map model fields to their corresponding relationship fields. All different types of relationships
then work exactly the same as they normally do, just that you have to annotate the field(s) that belong(s) to the
relationship.
Example:
Given a custom relationship called "Circuit provider to tenant":
```python
class ProviderModel(NautobotModel):
_model: Provider
_identifiers = ("name",)
_attributes = ("tenant__name",)
tenant__name = Annotated[
str,
CustomRelationshipAnnotation(name="Circuit provider to tenant", side=RelationshipSideEnum.SOURCE)
]
This then identifies the tenant to relate the provider to through its `name` field as well as the relationship
name.
"""
name: str
side: RelationshipSideEnum
@dataclass
class CustomFieldAnnotation(CustomAnnotation):
"""Map a model field to an arbitrary custom field name.
For usage with `typing.Annotated`.
This exists to map model fields to their corresponding custom fields. This serves to explicitly differentiate
normal fields from custom fields.
Note that for backwards compatibility purposes it is also possible to use `CustomFieldAnnotation.name` instead of
`CustomFieldAnnotation.key`.
Example:
Given a boolean custom field with label "Is Global" and key "is_global" on the Provider model:
```python
class ProviderModel(NautobotModel):
_model: Provider
_identifiers = ("name",)
_attributes = ("is_global",)
name: str
is_global: Annotated[bool, CustomFieldAnnotation(key="is_global")
```
This then maps the model field 'is_global' to the custom field with the key 'is_global'.
"""
# TODO: Delete on 3.0, keep around for backwards compatibility for now
name: Optional[str] = None
key: Optional[str] = None
def __post_init__(self):
"""Compatibility layer with using 'name' instead of 'key'.
If `self.key` isn't set, fall back to the old behaviour.
"""
if not self.key:
if self.name:
self.key = self.name
else:
raise ValueError("The 'key' field on CustomFieldAnnotation needs to be set.")