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

1from abc import ABCMeta, abstractmethod 

2from .exceptions import * 

3 

4 

5ORN_SCHEME = "orn" 

6 

7class MetaRID(ABCMeta): 

8 """Defines class properties for all RID types.""" 

9 

10 @property 

11 def context(cls): 

12 if cls.scheme is None: 

13 raise RIDTypeError(f"Scheme undefined for RID type {repr(cls)}") 

14 

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)}") 

18 

19 return cls.scheme + ":" + cls.namespace 

20 else: 

21 return cls.scheme 

22 

23 

24class RID(metaclass=MetaRID): 

25 scheme: str = None 

26 namespace: str | None = None 

27 

28 # populated at runtime 

29 _context_table = {} 

30 _provisional_context_table = {} 

31 

32 _ProvisionalContext = None 

33 

34 @property 

35 def context(self): 

36 return self.__class__.context 

37 

38 def __str__(self): 

39 return self.context + ":" + self.reference 

40 

41 def __repr__(self): 

42 return f"<{self.__class__.__name__} RID '{str(self)}'>" 

43 

44 def __eq__(self, other): 

45 if isinstance(other, self.__class__): 

46 return str(self) == str(other) 

47 else: 

48 return False 

49 

50 @classmethod 

51 def register_context(cls, Class): 

52 cls._context_table[Class.context] = Class 

53 

54 @classmethod 

55 def from_string(cls, rid_string: str, allow_prov_ctx=False): 

56 if not isinstance(rid_string, str): raise Exception() 

57 

58 i = rid_string.find(":") 

59 

60 if i < 0: 

61 raise InvalidRIDError(f"Failed to parse RID string '{rid_string}', missing context delimeter ':'") 

62 

63 scheme = rid_string[0:i].lower() 

64 namespace = None 

65 

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 ':'") 

70 

71 namespace = rid_string[i+1:j] 

72 

73 context = rid_string[0:j].lower() 

74 reference = rid_string[j+1:] 

75 

76 else: 

77 context = rid_string[0:i].lower() 

78 reference = rid_string[i+1:] 

79 

80 

81 if context in cls._context_table: 

82 ContextClass = cls._context_table[context] 

83 

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] 

88 

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() 

97 

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`)") 

106 

107 return ContextClass.from_reference(reference) 

108 

109 @classmethod 

110 @abstractmethod 

111 def from_reference(cls, reference): 

112 pass 

113 

114 @property 

115 @abstractmethod 

116 def reference(self): 

117 pass 

118 

119 

120class ProvisionalContext(RID): 

121 def __init__(self, reference): 

122 self._reference = reference 

123 

124 @property 

125 def reference(self): 

126 return self._reference 

127 

128 @classmethod 

129 def from_reference(cls, reference): 

130 return cls(reference) 

131 

132RID._ProvisionalContext = ProvisionalContext 

133 

134 

135class ORN(RID): 

136 scheme = ORN_SCHEME