commonlib-reader 1.0.0__py3-none-any.whl
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.
- commonlib_reader/__init__.py +25 -0
- commonlib_reader/facility.py +105 -0
- commonlib_reader/ims.py +126 -0
- commonlib_reader/tag.py +439 -0
- commonlib_reader/unit.py +44 -0
- commonlib_reader/utils.py +139 -0
- commonlib_reader-1.0.0.dist-info/METADATA +39 -0
- commonlib_reader-1.0.0.dist-info/RECORD +9 -0
- commonlib_reader-1.0.0.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from commonlib_reader.utils import (
|
|
2
|
+
get_code,
|
|
3
|
+
get_code_param,
|
|
4
|
+
get_disciplines,
|
|
5
|
+
get_library_names,
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
from .tag import TagType, TagCategory, TagFormat
|
|
10
|
+
from .ims import IMS
|
|
11
|
+
from .facility import Facility
|
|
12
|
+
from .unit import Unit
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"Facility",
|
|
16
|
+
"IMS",
|
|
17
|
+
"TagType",
|
|
18
|
+
"TagCategory",
|
|
19
|
+
"TagFormat",
|
|
20
|
+
"Unit",
|
|
21
|
+
"get_code",
|
|
22
|
+
"get_code_param",
|
|
23
|
+
"get_disciplines",
|
|
24
|
+
"get_library_names",
|
|
25
|
+
]
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
|
|
3
|
+
from commonlib_reader.utils import attributes_list_to_dict, get_code
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Facility:
|
|
7
|
+
"""
|
|
8
|
+
Facility class to encapsulate information.
|
|
9
|
+
|
|
10
|
+
Attributes:
|
|
11
|
+
identity (str) : A unique identifier for the facility (read from the data source).
|
|
12
|
+
name (str) : The name of the facility (read from the data source).
|
|
13
|
+
description (str) : A description of the facility (read from the data source).
|
|
14
|
+
SAPPlant (str) : SAP Plant code (if available).
|
|
15
|
+
Field (str) : Field identifier associated with the facility (if available).
|
|
16
|
+
ParentFacility (str) : Parent facility identifier (if available).
|
|
17
|
+
NPDID (str) : NPD ID (if available).
|
|
18
|
+
|
|
19
|
+
_cache (list of dict, optional):
|
|
20
|
+
Class level cache to store facility data, to minimize data source access.
|
|
21
|
+
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
_cache = None
|
|
25
|
+
|
|
26
|
+
def __init__(self, code):
|
|
27
|
+
"""
|
|
28
|
+
Initializes the Facility instance by retrieving data related to the given STID plant code.
|
|
29
|
+
|
|
30
|
+
Parameters:
|
|
31
|
+
code (str): The code used to retrieve facility data from the data source.
|
|
32
|
+
|
|
33
|
+
Raises:
|
|
34
|
+
ValueError: If no data is found for the provided code.
|
|
35
|
+
"""
|
|
36
|
+
self._data = Facility._get_facility(code=code)
|
|
37
|
+
self._attributes = attributes_list_to_dict(self._data["attributes"])
|
|
38
|
+
|
|
39
|
+
self.identity = self._data["identity"]
|
|
40
|
+
self.name = self._data["name"]
|
|
41
|
+
self.description = self._data["description"]
|
|
42
|
+
|
|
43
|
+
common_attributes = ["SAPPlant", "Field", "ParentFacility", "NPDID"]
|
|
44
|
+
for attr in common_attributes:
|
|
45
|
+
self.__setattr__(attr, "")
|
|
46
|
+
|
|
47
|
+
for key, val in self._attributes.items():
|
|
48
|
+
if key in common_attributes:
|
|
49
|
+
self.__setattr__(key, val)
|
|
50
|
+
|
|
51
|
+
def isSTID(self):
|
|
52
|
+
"""
|
|
53
|
+
Checks if the facility is marked for STID.
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
bool: True if the facility is marked for STID, False otherwise.
|
|
57
|
+
"""
|
|
58
|
+
if "IsForSTID" in self._attributes.keys():
|
|
59
|
+
if self._attributes["IsForSTID"] == "True":
|
|
60
|
+
return True
|
|
61
|
+
|
|
62
|
+
return False
|
|
63
|
+
|
|
64
|
+
@classmethod
|
|
65
|
+
def get_all_facilities(cls) -> List["Facility"]:
|
|
66
|
+
"""
|
|
67
|
+
Retrieves and returns a list of Facility instances for all known facilities.
|
|
68
|
+
|
|
69
|
+
Returns:
|
|
70
|
+
List[Facility]: A list of Facility instances.
|
|
71
|
+
"""
|
|
72
|
+
f = Facility._get_all_facilities()
|
|
73
|
+
return [Facility(x["identity"]) for x in f]
|
|
74
|
+
|
|
75
|
+
@classmethod
|
|
76
|
+
def _get_all_facilities(cls) -> List[dict]:
|
|
77
|
+
"""
|
|
78
|
+
Retrieves all facility data, using a class level cache.
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
List[dict]: A list of dictionaries, each representing facility data.
|
|
82
|
+
"""
|
|
83
|
+
if cls._cache is None:
|
|
84
|
+
cls._cache = get_code("Facility")
|
|
85
|
+
|
|
86
|
+
return cls._cache
|
|
87
|
+
|
|
88
|
+
@classmethod
|
|
89
|
+
def _get_facility(cls, code) -> dict:
|
|
90
|
+
"""
|
|
91
|
+
Retrieves the facility data for the given code.
|
|
92
|
+
|
|
93
|
+
Parameters:
|
|
94
|
+
code (str): The STID plant code corresponding to the facility.
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
dict: A dictionary containing data related to the facility.
|
|
98
|
+
|
|
99
|
+
Raises:
|
|
100
|
+
ValueError: If no data is found for the provided code.
|
|
101
|
+
"""
|
|
102
|
+
for f in cls._get_all_facilities():
|
|
103
|
+
if f["identity"] == code or f["name"] == code or f["description"] == code:
|
|
104
|
+
return f
|
|
105
|
+
raise ValueError(f"No data found for {code}")
|
commonlib_reader/ims.py
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
from typing import List, Union
|
|
2
|
+
from commonlib_reader.utils import attributes_list_to_dict, get_code
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class IMS:
|
|
6
|
+
_ims_codes = []
|
|
7
|
+
|
|
8
|
+
"""Class for IMS objects.
|
|
9
|
+
|
|
10
|
+
properties:
|
|
11
|
+
Facility (str) - Name of facility
|
|
12
|
+
IMSType (str) - Type of IMS
|
|
13
|
+
Alias (str) - Facility name aliases
|
|
14
|
+
isValid (bool) - True if IMS is in operation
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(self, data: Union[str, dict]):
|
|
18
|
+
"""Instance constructor for IMS object. End-users should use static method IMS.from_facility()
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
data (str,dict): Facility name or data dictionary to populate instance data attributes.
|
|
22
|
+
|
|
23
|
+
Raises:
|
|
24
|
+
ValueError: If input data is not a dict.
|
|
25
|
+
"""
|
|
26
|
+
if isinstance(data, str):
|
|
27
|
+
data = IMS.from_facility(data)._data
|
|
28
|
+
|
|
29
|
+
if not isinstance(data, dict):
|
|
30
|
+
raise ValueError("Input data must be a dict from codetable")
|
|
31
|
+
|
|
32
|
+
self._data = data
|
|
33
|
+
self._attributes = attributes_list_to_dict(self._data["attributes"])
|
|
34
|
+
|
|
35
|
+
self.isValid = data["isValid"]
|
|
36
|
+
|
|
37
|
+
self.Facility = ""
|
|
38
|
+
self.IMSType = ""
|
|
39
|
+
self.Alias = ""
|
|
40
|
+
|
|
41
|
+
for attr in self._data["attributes"]:
|
|
42
|
+
self.__setattr__(attr["definitionName"], attr["displayValue"])
|
|
43
|
+
|
|
44
|
+
@staticmethod
|
|
45
|
+
def from_facility(facility: str) -> "IMS":
|
|
46
|
+
"""Get IMS instance from STID code.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
facility (str): Facility code
|
|
50
|
+
|
|
51
|
+
Raises:
|
|
52
|
+
ValueError: Not able to instantiate IMS object from input facility code.
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
IMS: IMS instance
|
|
56
|
+
"""
|
|
57
|
+
if facility is None or len(facility) == 0:
|
|
58
|
+
raise ValueError(
|
|
59
|
+
"Facility must be provided. Empty strings are not allowed."
|
|
60
|
+
)
|
|
61
|
+
ims = IMS.get_ims_list(facility=facility)
|
|
62
|
+
if len(ims) == 1:
|
|
63
|
+
return ims[0]
|
|
64
|
+
|
|
65
|
+
raise ValueError(f"Not able to get IMS object for facility {facility}")
|
|
66
|
+
|
|
67
|
+
@classmethod
|
|
68
|
+
def _get_ims_codes(cls) -> List["IMS"]:
|
|
69
|
+
"""Get list of IMS instance of entries in code library ApplicationIMS. Caches locally in memory.
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
List[IMS]: list of IMS instance from entries in code library ApplicationIMS.
|
|
73
|
+
"""
|
|
74
|
+
if cls._ims_codes is None or len(cls._ims_codes) == 0:
|
|
75
|
+
cls._ims_codes = get_code("ApplicationIMS")
|
|
76
|
+
|
|
77
|
+
return [IMS(x) for x in cls._ims_codes]
|
|
78
|
+
|
|
79
|
+
@staticmethod
|
|
80
|
+
def get_ims_list(facility: str = "") -> List["IMS"]:
|
|
81
|
+
"""Get list of IMS objects.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
facility (str, optional): Facility. Defaults to "", which will get list of all entries defined in lib.
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
List[IMS]: list of IMS objects
|
|
88
|
+
"""
|
|
89
|
+
i = IMS._get_ims_codes()
|
|
90
|
+
if len(facility) > 0:
|
|
91
|
+
return [x for x in i if x.Facility == facility]
|
|
92
|
+
|
|
93
|
+
return i
|
|
94
|
+
|
|
95
|
+
@staticmethod
|
|
96
|
+
def get_source(facility: str) -> str:
|
|
97
|
+
"""Get IMS name for a facility.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
facility (str): Name of facility.
|
|
101
|
+
|
|
102
|
+
Raises:
|
|
103
|
+
ValueError: If facility input is invalid, i.e., empty.
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
str: Name of IMS
|
|
107
|
+
"""
|
|
108
|
+
|
|
109
|
+
l_ims = IMS.from_facility(facility=facility)
|
|
110
|
+
return l_ims.Alias
|
|
111
|
+
|
|
112
|
+
@staticmethod
|
|
113
|
+
def get_type(facility: str) -> str:
|
|
114
|
+
"""Get IMS type for a facility.
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
facility (str): Name of facility
|
|
118
|
+
|
|
119
|
+
Raises:
|
|
120
|
+
ValueError: If facility input is invalid, i.e., empty.
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
str: Type of IMS
|
|
124
|
+
"""
|
|
125
|
+
l_ims = IMS.from_facility(facility=facility)
|
|
126
|
+
return l_ims.IMSType
|
commonlib_reader/tag.py
ADDED
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
from typing import List, Union
|
|
2
|
+
from commonlib_reader.utils import get_code, get_code_param, query_sql
|
|
3
|
+
|
|
4
|
+
# from commonlib_reader.utils import attributes_list_to_dict
|
|
5
|
+
|
|
6
|
+
_cache = {}
|
|
7
|
+
_cache["TagType"] = {}
|
|
8
|
+
_cache["TagCategory"] = {}
|
|
9
|
+
_cache["TagFormat"] = {}
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class TagFormat:
|
|
13
|
+
"""
|
|
14
|
+
A class that represents the format of a tag within the context of a Facility.
|
|
15
|
+
|
|
16
|
+
Attributes:
|
|
17
|
+
inst_code (str): Installation code.
|
|
18
|
+
description (str): Description of the tag format.
|
|
19
|
+
tag_category (str): Tag category this format belongs to.
|
|
20
|
+
syntax (str): The syntax structure of the tag format.
|
|
21
|
+
regex (str): The regular expression pattern representing the tag format.
|
|
22
|
+
regex_grouped (str): Grouped regular expression pattern for the tag format.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(self, data: dict, inst_code: str):
|
|
26
|
+
"""
|
|
27
|
+
Initializes a TagFormat object.
|
|
28
|
+
|
|
29
|
+
Parameters:
|
|
30
|
+
data (dict): Data containing different properties of a tag format.
|
|
31
|
+
inst_code (str): Installation code for this tag format.
|
|
32
|
+
"""
|
|
33
|
+
self._data = data
|
|
34
|
+
# self._attributes = attributes_list_to_dict(self._data["attributes"])
|
|
35
|
+
|
|
36
|
+
self.inst_code = inst_code
|
|
37
|
+
self.description = data["description"]
|
|
38
|
+
|
|
39
|
+
self.tag_category = ""
|
|
40
|
+
self.syntax = ""
|
|
41
|
+
self.regex = ""
|
|
42
|
+
self.regex_grouped = ""
|
|
43
|
+
|
|
44
|
+
for attr in self._data["attributes"]:
|
|
45
|
+
if attr["definitionName"] == "TagCategory":
|
|
46
|
+
self.tag_category = attr["displayValue"]
|
|
47
|
+
elif attr["definitionName"] == "Syntax":
|
|
48
|
+
self.syntax = attr["displayValue"]
|
|
49
|
+
elif attr["definitionName"] == "Regex":
|
|
50
|
+
self.regex = attr["displayValue"]
|
|
51
|
+
elif attr["definitionName"] == "RegexGrouped":
|
|
52
|
+
self.regex_grouped = attr["displayValue"]
|
|
53
|
+
|
|
54
|
+
def __str__(self):
|
|
55
|
+
return f"{self.description} - {self.tag_category}"
|
|
56
|
+
|
|
57
|
+
@staticmethod
|
|
58
|
+
def get_tagformat(
|
|
59
|
+
description: str, inst_code: str, tag_category: str
|
|
60
|
+
) -> "TagFormat":
|
|
61
|
+
"""
|
|
62
|
+
Retrieve a tag format for a given description, installation code and tag category.
|
|
63
|
+
|
|
64
|
+
Parameters:
|
|
65
|
+
description (str): Description of the tag format to retrieve.
|
|
66
|
+
inst_code (str): Installation code of the requested tag format.
|
|
67
|
+
tag_category (str): Category of the requested tag format.
|
|
68
|
+
|
|
69
|
+
Returns:
|
|
70
|
+
TagFormat: The requested tag format object.
|
|
71
|
+
"""
|
|
72
|
+
t = TagCategory.get_category(inst_code=inst_code, name=tag_category)
|
|
73
|
+
return t[0].get_format(description)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class TagType:
|
|
77
|
+
"""
|
|
78
|
+
A class that represents a tag type, which is pertinent to a tag category and
|
|
79
|
+
associated with a particular facility.
|
|
80
|
+
|
|
81
|
+
Attributes:
|
|
82
|
+
inst_code (str): The facility code the tag type is associated with.
|
|
83
|
+
name (str): The name of the tag type.
|
|
84
|
+
description (str): A description of the tag type.
|
|
85
|
+
is_valid (bool): A flag indicating whether the tag type is valid.
|
|
86
|
+
tag_category (str): The category under which this tag type falls.
|
|
87
|
+
STID_tag_Count (int): The number of STID tags associated with this tag type.
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
def __init__(self, data: dict, inst_code: str):
|
|
91
|
+
"""
|
|
92
|
+
Initializes a TagType object with provided data and installation code.
|
|
93
|
+
|
|
94
|
+
Parameters:
|
|
95
|
+
data (dict): Data containing different properties of a tag type.
|
|
96
|
+
inst_code (str): Installation code for which this tag type applies.
|
|
97
|
+
"""
|
|
98
|
+
self._data = data
|
|
99
|
+
self.inst_code = inst_code
|
|
100
|
+
|
|
101
|
+
self.name = self._data["name"]
|
|
102
|
+
self.description = self._data["description"]
|
|
103
|
+
self.is_valid = self._data["isValid"]
|
|
104
|
+
self.tag_category = ""
|
|
105
|
+
|
|
106
|
+
for attr in self._data["attributes"]:
|
|
107
|
+
if attr["definitionName"] == "STIDTagCount":
|
|
108
|
+
self.STID_tag_Count = int(attr["displayValue"])
|
|
109
|
+
elif attr["definitionName"] == "TagCategory":
|
|
110
|
+
self.tag_category = attr["displayValue"]
|
|
111
|
+
|
|
112
|
+
def __str__(self):
|
|
113
|
+
return f"{self.name} - {self.description}"
|
|
114
|
+
|
|
115
|
+
@staticmethod
|
|
116
|
+
def get_tagtype(name: str, inst_code: str, tag_category: str) -> "TagType":
|
|
117
|
+
"""
|
|
118
|
+
Retrieve a tag type object based on the name, installation code, and tag category.
|
|
119
|
+
|
|
120
|
+
Parameters:
|
|
121
|
+
name (str): Name of the tag type to retrieve.
|
|
122
|
+
inst_code (str): Installation code specific to the tag type.
|
|
123
|
+
tag_category (str): Category to which the tag type belongs.
|
|
124
|
+
|
|
125
|
+
Returns:
|
|
126
|
+
TagType: The TagType object matching the criteria.
|
|
127
|
+
"""
|
|
128
|
+
t = TagCategory.get_category(inst_code=inst_code, name=tag_category)
|
|
129
|
+
return t[0].get_type(name)
|
|
130
|
+
|
|
131
|
+
@staticmethod
|
|
132
|
+
def get_tagtype_no_cache(
|
|
133
|
+
name: str, inst_code: str, tag_category: str = ""
|
|
134
|
+
) -> "TagType":
|
|
135
|
+
"""
|
|
136
|
+
Retrieve tag types for the given name and installation code without using the cache. Optionally filter by tag category.
|
|
137
|
+
|
|
138
|
+
Parameters:
|
|
139
|
+
name (str): The name of the tag type to retrieve.
|
|
140
|
+
inst_code (str): Installation code specific to the tag type.
|
|
141
|
+
tag_category (str, optional): Optional category to filter the tag types.
|
|
142
|
+
|
|
143
|
+
Returns:
|
|
144
|
+
List[TagType]: A list of TagType objects matching the criteria.
|
|
145
|
+
"""
|
|
146
|
+
|
|
147
|
+
params = {}
|
|
148
|
+
params["scope"] = inst_code
|
|
149
|
+
params["name"] = name
|
|
150
|
+
|
|
151
|
+
tag_types = [
|
|
152
|
+
TagType(x, inst_code=inst_code)
|
|
153
|
+
for x in get_code_param("TagType", params=params)
|
|
154
|
+
]
|
|
155
|
+
|
|
156
|
+
if tag_category:
|
|
157
|
+
tag_types = [x for x in tag_types if x.tag_category == tag_category]
|
|
158
|
+
|
|
159
|
+
return tag_types
|
|
160
|
+
|
|
161
|
+
@staticmethod
|
|
162
|
+
def get_master_tagtype(
|
|
163
|
+
name: str, tag_category: str = "", technology: str = "Oil&Gas"
|
|
164
|
+
) -> "TagType":
|
|
165
|
+
"""
|
|
166
|
+
Retrieve master tag types based on name, category, and technology. If name is empty,
|
|
167
|
+
sorts by name and returns all. If name is provided, filters by name.
|
|
168
|
+
|
|
169
|
+
Parameters:
|
|
170
|
+
name (str): The name of the master tag type to retrieve. Can be empty to retrieve all.
|
|
171
|
+
tag_category (str, optional): Category to filter the master tag types. Can be empty to not filter.
|
|
172
|
+
technology (str, optional): Technology to filter the master tag types, defaults to 'Oil&Gas'.
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
List[TagType]: A list of TagType objects matching the criteria.
|
|
176
|
+
"""
|
|
177
|
+
return_value = []
|
|
178
|
+
d = _get_master_type_data()
|
|
179
|
+
for k in range(0, len(d)):
|
|
180
|
+
for att in d[k]["attributes"]:
|
|
181
|
+
if att["definitionName"] == "Technology":
|
|
182
|
+
currTechnology = att["displayValue"]
|
|
183
|
+
break
|
|
184
|
+
|
|
185
|
+
include_technology = (
|
|
186
|
+
technology is None
|
|
187
|
+
or len(technology) == 0
|
|
188
|
+
or currTechnology == technology
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
include_category = tag_category is None or len(tag_category) == 0
|
|
192
|
+
if not include_category:
|
|
193
|
+
for att in d[k]["attributes"]:
|
|
194
|
+
if (
|
|
195
|
+
att["definitionName"] == "TagCategory"
|
|
196
|
+
and att["displayValue"] == tag_category
|
|
197
|
+
):
|
|
198
|
+
include_category = True
|
|
199
|
+
break
|
|
200
|
+
|
|
201
|
+
if include_category and include_technology:
|
|
202
|
+
return_value.append(TagType(d[k], currTechnology))
|
|
203
|
+
|
|
204
|
+
if not name:
|
|
205
|
+
return_value.sort(key=lambda x: x.name)
|
|
206
|
+
else:
|
|
207
|
+
return_value = [x for x in return_value if x.name == name]
|
|
208
|
+
|
|
209
|
+
return return_value
|
|
210
|
+
|
|
211
|
+
@staticmethod
|
|
212
|
+
def get_master_tagtype_mappings(
|
|
213
|
+
name: str, tag_category: str = "", technology: str = "Oil&Gas"
|
|
214
|
+
):
|
|
215
|
+
"""
|
|
216
|
+
Retrieve mappings of the master tag types based on name, category,
|
|
217
|
+
and technology. Raises a ValueError if no relevant mappings are found
|
|
218
|
+
or if more than one master tag type is matching name, tag category and technology input.
|
|
219
|
+
|
|
220
|
+
Parameters:
|
|
221
|
+
name (str): The name of the master tag type to search for mappings.
|
|
222
|
+
tag_category (str, optional): Category to filter the tag type mappings. Can be empty to not filter.
|
|
223
|
+
technology (str, optional): Technology to filter the tag type mappings, defaults to 'Oil&Gas'.
|
|
224
|
+
|
|
225
|
+
Returns:
|
|
226
|
+
List: A list of mapped tag types.
|
|
227
|
+
|
|
228
|
+
Raises:
|
|
229
|
+
ValueError: If no master tag type is found, or if multiple master tag types are found.
|
|
230
|
+
"""
|
|
231
|
+
mtt = TagType.get_master_tagtype(
|
|
232
|
+
name=name, tag_category=tag_category, technology=technology
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
if len(mtt) == 0:
|
|
236
|
+
raise ValueError("No master tag type found")
|
|
237
|
+
|
|
238
|
+
if len(mtt) > 1:
|
|
239
|
+
raise ValueError("Multiple master tag types found. Currently not supported")
|
|
240
|
+
|
|
241
|
+
sql = f"""SELECT tt.scope Facility,tt.Name LocalTagType, tt.tagcategory LocalTagCategory FROM MasterTagType mtt
|
|
242
|
+
inner join TagType tt on tt.MasterTagType_ID=mtt.id
|
|
243
|
+
where mtt.tagcategory='{mtt[0].tag_category}' and mtt.Name ='{mtt[0].name}' and mtt.Technology='{mtt[0].inst_code}' and tt.isValid='True'
|
|
244
|
+
order by tt.name, tt.scope"""
|
|
245
|
+
|
|
246
|
+
res = query_sql(sql=sql)
|
|
247
|
+
mapped_types = []
|
|
248
|
+
[
|
|
249
|
+
mapped_types.extend(
|
|
250
|
+
TagType.get_tagtype_no_cache(
|
|
251
|
+
x["LocalTagType"], x["Facility"], x["LocalTagCategory"]
|
|
252
|
+
)
|
|
253
|
+
)
|
|
254
|
+
for x in res
|
|
255
|
+
]
|
|
256
|
+
return mapped_types
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
class TagCategory:
|
|
260
|
+
"""
|
|
261
|
+
A class representing a Facility specific category of tag types.
|
|
262
|
+
|
|
263
|
+
Attributes:
|
|
264
|
+
inst_code (str): Installation code for the facilitye the TagCategory is associated with.
|
|
265
|
+
name (str): Name of the tag category.
|
|
266
|
+
description (str): Description of the tag category.
|
|
267
|
+
is_valid (bool): Flag indicating whether the tag category is considered valid.
|
|
268
|
+
TagCategoryId (int): Unique identifier of the tag category.
|
|
269
|
+
TagCategoryDlg (str): Additional dialog information associated with the tag category.
|
|
270
|
+
IndividFlag (str): A flag indicating individual characteristics for the category.
|
|
271
|
+
SapFlCategory (str): Corresponding SAP functional location category.
|
|
272
|
+
"""
|
|
273
|
+
|
|
274
|
+
def __init__(self, data, inst_code):
|
|
275
|
+
"""
|
|
276
|
+
Initializes a TagCategory object.
|
|
277
|
+
|
|
278
|
+
Parameters:
|
|
279
|
+
data (dict): Data containing different properties of a tag category.
|
|
280
|
+
inst_code (str): Installation code for which this tag category applies.
|
|
281
|
+
"""
|
|
282
|
+
self._data = data
|
|
283
|
+
self.inst_code = inst_code
|
|
284
|
+
|
|
285
|
+
self.name = self._data["name"]
|
|
286
|
+
self.description = self._data["description"]
|
|
287
|
+
self.is_valid = self._data["isValid"]
|
|
288
|
+
|
|
289
|
+
for attr in self._data["attributes"]:
|
|
290
|
+
if attr["definitionName"] == "TagCategoryId":
|
|
291
|
+
self.TagCategoryId = int(attr["displayValue"])
|
|
292
|
+
elif attr["definitionName"] == "TagCategoryDlg":
|
|
293
|
+
self.TagCategoryDlg = attr["displayValue"]
|
|
294
|
+
elif attr["definitionName"] == "IndividFlag":
|
|
295
|
+
self.IndividFlag = attr["displayValue"]
|
|
296
|
+
elif attr["definitionName"] == "SapFlCategory":
|
|
297
|
+
self.SapFlCategory = attr["displayValue"]
|
|
298
|
+
|
|
299
|
+
self._types = []
|
|
300
|
+
self._formats = []
|
|
301
|
+
|
|
302
|
+
def get_formats(self) -> List[TagFormat]:
|
|
303
|
+
"""Get tag formats for this specific tag category.
|
|
304
|
+
|
|
305
|
+
Returns:
|
|
306
|
+
List[TagType]: List of TagFormat objects belonging to this category.
|
|
307
|
+
"""
|
|
308
|
+
if self._formats is None or len(self._formats) == 0:
|
|
309
|
+
tag_formats = [
|
|
310
|
+
TagFormat(x, self.inst_code) for x in _get_format_data(self.inst_code)
|
|
311
|
+
]
|
|
312
|
+
self._formats = [x for x in tag_formats if x.tag_category == self.name]
|
|
313
|
+
|
|
314
|
+
return self._formats
|
|
315
|
+
|
|
316
|
+
def get_format(self, description: str) -> TagFormat:
|
|
317
|
+
"""Get single tag format for this specific tag category.
|
|
318
|
+
|
|
319
|
+
Args:
|
|
320
|
+
format (str): Description (name) of tag format.
|
|
321
|
+
|
|
322
|
+
Returns:
|
|
323
|
+
TagFormat: Tag format object
|
|
324
|
+
"""
|
|
325
|
+
for curr_type in self.get_formats():
|
|
326
|
+
if curr_type.description == description:
|
|
327
|
+
return curr_type
|
|
328
|
+
|
|
329
|
+
return None
|
|
330
|
+
|
|
331
|
+
def get_types(self) -> List[TagType]:
|
|
332
|
+
"""Get tag types for this specific tag category.
|
|
333
|
+
|
|
334
|
+
Returns:
|
|
335
|
+
List[TagType]: List of TagType objects belonging to this category.
|
|
336
|
+
"""
|
|
337
|
+
if self._types is None or len(self._types) == 0:
|
|
338
|
+
tag_types = [
|
|
339
|
+
TagType(x, self.inst_code) for x in _get_type_data(self.inst_code)
|
|
340
|
+
]
|
|
341
|
+
self._types = [x for x in tag_types if x.tag_category == self.name]
|
|
342
|
+
self._types.sort(key=lambda x: x.name)
|
|
343
|
+
|
|
344
|
+
return self._types
|
|
345
|
+
|
|
346
|
+
def get_type(self, type: str) -> Union[TagType, None]:
|
|
347
|
+
"""Get single type from this specific tag category.
|
|
348
|
+
|
|
349
|
+
Args:
|
|
350
|
+
type (str): Type name
|
|
351
|
+
|
|
352
|
+
Returns:
|
|
353
|
+
Union[TagType, None]: TagType if found, else None.
|
|
354
|
+
"""
|
|
355
|
+
for curr_type in self.get_types():
|
|
356
|
+
if curr_type.name == type:
|
|
357
|
+
return curr_type
|
|
358
|
+
|
|
359
|
+
return None
|
|
360
|
+
|
|
361
|
+
def __str__(self):
|
|
362
|
+
return f"{self.TagCategoryId}:{self.name} - {self.description}"
|
|
363
|
+
|
|
364
|
+
@staticmethod
|
|
365
|
+
def get_category(inst_code, name="") -> List["TagCategory"]:
|
|
366
|
+
categories = _get_category_data(inst_code=inst_code)
|
|
367
|
+
tc = [TagCategory(x, inst_code=inst_code) for x in categories]
|
|
368
|
+
tc.sort(key=lambda x: x.TagCategoryId)
|
|
369
|
+
if name is None:
|
|
370
|
+
pass
|
|
371
|
+
elif isinstance(name, str) and len(name) > 0:
|
|
372
|
+
tc = [x for x in tc if x.name == name or x.description == name]
|
|
373
|
+
|
|
374
|
+
return tc
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
def _get_category_data(inst_code) -> List[dict]:
|
|
378
|
+
"""Get code table of tag categories for a facility from commonlibapi.
|
|
379
|
+
|
|
380
|
+
Args:
|
|
381
|
+
inst_code (str): STID installation code.
|
|
382
|
+
|
|
383
|
+
Returns:
|
|
384
|
+
List[dict]: Data for each tag category.
|
|
385
|
+
"""
|
|
386
|
+
global _cache
|
|
387
|
+
|
|
388
|
+
if inst_code not in _cache["TagCategory"].keys():
|
|
389
|
+
_cache["TagCategory"][inst_code] = get_code("TagCategory", scope=inst_code)
|
|
390
|
+
|
|
391
|
+
return _cache["TagCategory"][inst_code]
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
def _get_type_data(inst_code: str) -> List[dict]:
|
|
395
|
+
"""Get code table of tag types for an installation from commonlibapi.
|
|
396
|
+
|
|
397
|
+
Args:
|
|
398
|
+
inst_code (str): STID installation code.
|
|
399
|
+
|
|
400
|
+
Returns:
|
|
401
|
+
List[dict]: Data for each tag type.
|
|
402
|
+
"""
|
|
403
|
+
global _cache
|
|
404
|
+
|
|
405
|
+
if inst_code not in _cache["TagType"].keys():
|
|
406
|
+
_cache["TagType"][inst_code] = get_code("TagType", scope=inst_code)
|
|
407
|
+
|
|
408
|
+
return _cache["TagType"][inst_code]
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
def _get_master_type_data(scope="") -> List[dict]:
|
|
412
|
+
"""Get code table of master tag types from commonlibapi.
|
|
413
|
+
|
|
414
|
+
Returns:
|
|
415
|
+
List[dict]: Data for each tag type.
|
|
416
|
+
"""
|
|
417
|
+
global _cache
|
|
418
|
+
|
|
419
|
+
if "MasterTagType" not in _cache.keys():
|
|
420
|
+
_cache["MasterTagType"] = get_code("MasterTagType")
|
|
421
|
+
|
|
422
|
+
return _cache["MasterTagType"]
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
def _get_format_data(inst_code: str) -> List[dict]:
|
|
426
|
+
"""Get code table of tag formats for an installation from commonlibapi.
|
|
427
|
+
|
|
428
|
+
Args:
|
|
429
|
+
inst_code (str): STID installation code.
|
|
430
|
+
|
|
431
|
+
Returns:
|
|
432
|
+
List[dict]: Data for each format.
|
|
433
|
+
"""
|
|
434
|
+
global _cache
|
|
435
|
+
|
|
436
|
+
if inst_code not in _cache["TagFormat"].keys():
|
|
437
|
+
_cache["TagFormat"][inst_code] = get_code("TagFormat", scope=inst_code)
|
|
438
|
+
|
|
439
|
+
return _cache["TagFormat"][inst_code]
|
commonlib_reader/unit.py
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
from commonlib_reader.utils import get_code
|
|
2
|
+
|
|
3
|
+
# from commonlib_reader.utils import attributes_list_to_dict
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Unit:
|
|
7
|
+
_units = []
|
|
8
|
+
|
|
9
|
+
def __init__(self, data):
|
|
10
|
+
self.name = ""
|
|
11
|
+
self.description = ""
|
|
12
|
+
|
|
13
|
+
self.identity = ""
|
|
14
|
+
self.quantity = ""
|
|
15
|
+
|
|
16
|
+
if isinstance(data, str):
|
|
17
|
+
s = [x for x in Unit.get_units() if x.name == data]
|
|
18
|
+
if len(s) > 0:
|
|
19
|
+
data = s[0]._data
|
|
20
|
+
else:
|
|
21
|
+
raise ValueError(f"No unit named {data} found.")
|
|
22
|
+
|
|
23
|
+
if isinstance(data, dict):
|
|
24
|
+
self._data = data
|
|
25
|
+
# self._attributes = attributes_list_to_dict(self._data["attributes"])
|
|
26
|
+
|
|
27
|
+
for key in data.keys():
|
|
28
|
+
if key == "attributes":
|
|
29
|
+
for attr in data["attributes"]:
|
|
30
|
+
self.__setattr__(attr["definitionName"], attr["displayValue"])
|
|
31
|
+
else:
|
|
32
|
+
self.__setattr__(key, data[key])
|
|
33
|
+
|
|
34
|
+
@classmethod
|
|
35
|
+
def get_units(cls):
|
|
36
|
+
"""Get list of Unit objects of entries in code library. Caches locally in memory.
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
List[IMS]: list of Unit objects from entries in code library.
|
|
40
|
+
"""
|
|
41
|
+
if cls._units is None or len(cls._units) == 0:
|
|
42
|
+
cls._units = get_code("UnitOfMeasure")
|
|
43
|
+
|
|
44
|
+
return [Unit(x) for x in cls._units]
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from typing import Dict, List
|
|
3
|
+
from urllib.parse import urljoin
|
|
4
|
+
|
|
5
|
+
import requests
|
|
6
|
+
from msal_bearer.BearerAuth import BearerAuth, get_login_name
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def get_library_names():
|
|
10
|
+
url = urljoin(get_api_url(), "api/Library/NameList")
|
|
11
|
+
library_names = get_json(url=url)
|
|
12
|
+
library_names.sort()
|
|
13
|
+
return library_names
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def get_disciplines():
|
|
17
|
+
return get_code("Discipline")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def get_code(code: str, scope: str = None, name: str = None):
|
|
21
|
+
params = {}
|
|
22
|
+
if scope is not None:
|
|
23
|
+
params["scope"] = scope
|
|
24
|
+
|
|
25
|
+
if name is not None:
|
|
26
|
+
params["name"] = name
|
|
27
|
+
return get_code_param(code=code, params=params)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def get_code_param(code, params=None):
|
|
31
|
+
if params is None:
|
|
32
|
+
params = {}
|
|
33
|
+
|
|
34
|
+
url = urljoin(get_api_url(), f"api/Code/{code}")
|
|
35
|
+
return get_json(url, params=params)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def query_sql(sql: str):
|
|
39
|
+
return post_sql(sql=sql, take=0, skip=0)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def get_api_url() -> str:
|
|
43
|
+
"""Get base url to api
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
str: Base url to api
|
|
47
|
+
"""
|
|
48
|
+
return "https://commonlibapi.equinor.com/"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def get_auth() -> BearerAuth:
|
|
52
|
+
"""Get Bearerauth object including token for accessing api.
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
BearerAuth: Object with access token for api.
|
|
56
|
+
"""
|
|
57
|
+
tenantID = "3aa4a235-b6e2-48d5-9195-7fcf05b459b0"
|
|
58
|
+
clientID = "728cfddd-b8e9-4ed7-b9a3-8f2fd5b8e79a"
|
|
59
|
+
scopes = ["37d598fc-da0f-46bd-949f-7107918d47a5/user_impersonation"]
|
|
60
|
+
auth = BearerAuth.get_auth(
|
|
61
|
+
tenantID=tenantID,
|
|
62
|
+
clientID=clientID,
|
|
63
|
+
scopes=scopes,
|
|
64
|
+
username=f"{get_login_name()}@equinor.com",
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
return auth
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def get_json(url: str, params=None) -> list:
|
|
71
|
+
"""Get json from api endpoint
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
url (str): Url to api endpoint to get.
|
|
75
|
+
params (dict, optional): Dictionary of parameters to pass. Defaults to None.
|
|
76
|
+
|
|
77
|
+
Returns:
|
|
78
|
+
list: List of response from api
|
|
79
|
+
"""
|
|
80
|
+
response = requests.get(url, auth=get_auth(), params=params)
|
|
81
|
+
# response.raise_for_status()
|
|
82
|
+
if response.status_code == 200:
|
|
83
|
+
try:
|
|
84
|
+
return response.json()
|
|
85
|
+
except json.JSONDecodeError:
|
|
86
|
+
print(
|
|
87
|
+
f"Warning: {str(url)} returned successfully, but not with a valid json response"
|
|
88
|
+
)
|
|
89
|
+
else:
|
|
90
|
+
print(f"Warning: {str(url)} returned status code {response.status_code}")
|
|
91
|
+
|
|
92
|
+
return []
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def post_sql(sql: str, take: int = 100, skip: int = 0) -> list:
|
|
96
|
+
"""Get json from api/sql endpoint accepting sql queries.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
sql (str): SQL query to run
|
|
100
|
+
take (int, optional): Number of results to return. Defaults to 100.
|
|
101
|
+
skip (int, optional): Number of results to skip. Defaults to 0.
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
list: List of response from api
|
|
105
|
+
"""
|
|
106
|
+
url = urljoin(get_api_url(), "api/sql")
|
|
107
|
+
response = requests.post(
|
|
108
|
+
url=url, json={"query": sql, "take": take, "skip": skip}, auth=get_auth()
|
|
109
|
+
)
|
|
110
|
+
if response.status_code == 200:
|
|
111
|
+
try:
|
|
112
|
+
return response.json()
|
|
113
|
+
except json.JSONDecodeError:
|
|
114
|
+
print(
|
|
115
|
+
f"Warning: {str(url)} returned successfully, but not with a valid json response"
|
|
116
|
+
)
|
|
117
|
+
else:
|
|
118
|
+
print(f"Warning: {str(url)} returned status code {response.status_code}")
|
|
119
|
+
|
|
120
|
+
return []
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def attributes_list_to_dict(attribute_list: List[Dict]) -> Dict:
|
|
124
|
+
"""Convert list of attributes typically returned from commonlib to a normal dictionary.
|
|
125
|
+
|
|
126
|
+
Args:
|
|
127
|
+
attribute_list (List[Dict]): List of attributes
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
Dict: Dictionary with attribute definitionName as keys.
|
|
131
|
+
"""
|
|
132
|
+
d = {}
|
|
133
|
+
for r in attribute_list:
|
|
134
|
+
try:
|
|
135
|
+
d[r["definitionName"]] = r["displayValue"]
|
|
136
|
+
except:
|
|
137
|
+
pass
|
|
138
|
+
|
|
139
|
+
return d
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: commonlib-reader
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Reader for Equinor commonlibapi.
|
|
5
|
+
Home-page: https://github.com/equinor/commonlib-reader.git
|
|
6
|
+
Author: Åsmund Våge Fannemel
|
|
7
|
+
Author-email: asmf@equinor.com
|
|
8
|
+
Requires-Python: >=3.9,<4.0
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Requires-Dist: msal_bearer (>0.2.1)
|
|
15
|
+
Requires-Dist: pandas (>=2.1.4,<3.0.0)
|
|
16
|
+
Requires-Dist: requests (>=2.31.0,<3.0.0)
|
|
17
|
+
Project-URL: Repository, https://github.com/equinor/commonlib-reader.git
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
|
|
20
|
+
# commonlib-python
|
|
21
|
+
Connector package for Equinor Commonlib api. Used for getting code tables.
|
|
22
|
+
|
|
23
|
+
Some additional functionality for asset specific Tag categories and tag types is also included.
|
|
24
|
+
|
|
25
|
+
## Use
|
|
26
|
+
Try it out by running the [demo](examples/demo.py).
|
|
27
|
+
|
|
28
|
+
## Installing
|
|
29
|
+
|
|
30
|
+
Install package from pypi using `pip install commonlib_reader`
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
## Developing / testing
|
|
34
|
+
|
|
35
|
+
Poetry is preferred for developers. Clone and install with required packages for testing and coverage:
|
|
36
|
+
`poetry install`
|
|
37
|
+
|
|
38
|
+
For testing with coverage run:
|
|
39
|
+
`poetry run pytest --cov --cov-report=html`
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
commonlib_reader/__init__.py,sha256=tpUVIRqbBqlyWj8iqxnUCzrpLr63OKB89fcwCogCk20,434
|
|
2
|
+
commonlib_reader/facility.py,sha256=V2XCUi_2gfZSiiUtA3ll9_15NXrWJeDcUq0Ux3l5S6Y,3486
|
|
3
|
+
commonlib_reader/ims.py,sha256=qyHBS9ar-e-6IPoldE-almAOsBMamgkf86EGya7tK9Q,3600
|
|
4
|
+
commonlib_reader/tag.py,sha256=x8OEQJ0XpLiixCZOz_0zp6hh513byAzxNr5HQFjNzQc,15543
|
|
5
|
+
commonlib_reader/unit.py,sha256=NDIJA2A2m7ZzsKUmza5EQLZQQXhHW9p_DzYUrPhu3OY,1346
|
|
6
|
+
commonlib_reader/utils.py,sha256=sjYYI8HpmFCYyMQ1nEMsBMBsODdicdSZkxNDJ_VBdO8,3685
|
|
7
|
+
commonlib_reader-1.0.0.dist-info/METADATA,sha256=Yz7L0aH1XjV5Ifeug6-OVbMKALoVGAUYx-hh2f0Ea-w,1290
|
|
8
|
+
commonlib_reader-1.0.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
9
|
+
commonlib_reader-1.0.0.dist-info/RECORD,,
|