Coverage for venv\Lib\site-packages\rid_lib\core.py: 95%
82 statements
« prev ^ index » next coverage.py v7.6.7, created at 2024-11-20 16:40 +0800
« prev ^ index » next coverage.py v7.6.7, created at 2024-11-20 16:40 +0800
1from abc import ABCMeta, abstractmethod
2from .exceptions import *
5ORN_SCHEME = "orn"
7class MetaRID(ABCMeta):
8 """Defines class properties for all RID types."""
10 @property
11 def context(cls):
12 if cls.scheme is None:
13 raise RIDTypeError(f"Scheme undefined for RID type {repr(cls)}")
15 elif cls.scheme == ORN_SCHEME:
16 if cls.namespace is None:
17 raise RIDTypeError(f"Namespace undefined for ORN based RID type {repr(cls)}")
19 return cls.scheme + ":" + cls.namespace
20 else:
21 return cls.scheme
24class RID(metaclass=MetaRID):
25 scheme: str = None
26 namespace: str | None = None
28 # populated at runtime
29 _context_table = {}
30 _provisional_context_table = {}
32 _ProvisionalContext = None
34 @property
35 def context(self):
36 return self.__class__.context
38 def __str__(self):
39 return self.context + ":" + self.reference
41 def __repr__(self):
42 return f"<{self.__class__.__name__} RID '{str(self)}'>"
44 def __eq__(self, other):
45 if isinstance(other, self.__class__):
46 return str(self) == str(other)
47 else:
48 return False
50 @classmethod
51 def register_context(cls, Class):
52 cls._context_table[Class.context] = Class
54 @classmethod
55 def from_string(cls, rid_string: str, allow_prov_ctx=False):
56 if not isinstance(rid_string, str): raise Exception()
58 i = rid_string.find(":")
60 if i < 0:
61 raise InvalidRIDError(f"Failed to parse RID string '{rid_string}', missing context delimeter ':'")
63 scheme = rid_string[0:i].lower()
64 namespace = None
66 if scheme == ORN_SCHEME:
67 j = rid_string.find(":", i+1)
68 if j < 0:
69 raise InvalidRIDError(f"Failed to parse ORN RID string '{rid_string}', missing namespace delimeter ':'")
71 namespace = rid_string[i+1:j]
73 context = rid_string[0:j].lower()
74 reference = rid_string[j+1:]
76 else:
77 context = rid_string[0:i].lower()
78 reference = rid_string[i+1:]
81 if context in cls._context_table:
82 ContextClass = cls._context_table[context]
84 elif allow_prov_ctx:
85 if context in cls._provisional_context_table:
86 # use existing provisional context class
87 ContextClass = cls._provisional_context_table[context]
89 else:
90 # create new provisional context class
91 if scheme == ORN_SCHEME:
92 prov_context_classname = "".join([
93 s.capitalize() for s in namespace.split(".")
94 ])
95 else:
96 prov_context_classname = scheme.capitalize()
98 ContextClass = type(
99 prov_context_classname,
100 (cls._ProvisionalContext,),
101 dict(scheme=scheme, namespace=namespace)
102 )
103 cls._provisional_context_table[context] = ContextClass
104 else:
105 raise InvalidRIDError(f"Context '{context}' undefined for RID string '{rid_string}' (enable provisional contexts to avoid this error with `allow_prov_ctx=True`)")
107 return ContextClass.from_reference(reference)
109 @classmethod
110 @abstractmethod
111 def from_reference(cls, reference):
112 pass
114 @property
115 @abstractmethod
116 def reference(self):
117 pass
120class ProvisionalContext(RID):
121 def __init__(self, reference):
122 self._reference = reference
124 @property
125 def reference(self):
126 return self._reference
128 @classmethod
129 def from_reference(cls, reference):
130 return cls(reference)
132RID._ProvisionalContext = ProvisionalContext
135class ORN(RID):
136 scheme = ORN_SCHEME