stidapi 1.4.0__tar.gz → 1.4.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: stidapi
3
- Version: 1.4.0
3
+ Version: 1.4.2
4
4
  Summary: Python client for connecting to Equinor STIDapi
5
5
  License: Proprietary
6
6
  Author: Åsmund Våge Fannemel
@@ -13,7 +13,7 @@ Classifier: Programming Language :: Python :: 3.11
13
13
  Classifier: Programming Language :: Python :: 3.12
14
14
  Classifier: Programming Language :: Python :: 3.13
15
15
  Classifier: Programming Language :: Python :: 3.14
16
- Requires-Dist: eq-api-connector (>=1.0.1,<2.0.0)
16
+ Requires-Dist: eq-api-connector (>=1.1.0,<2.0.0)
17
17
  Project-URL: repository, https://github.com/equinor/STIDapi-python
18
18
  Description-Content-Type: text/markdown
19
19
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "stidapi"
3
- version = "1.4.0"
3
+ version = "1.4.2"
4
4
  description = "Python client for connecting to Equinor STIDapi"
5
5
  authors = ["Åsmund Våge Fannemel <asmf@equinor.com>"]
6
6
  license = "Proprietary"
@@ -11,12 +11,12 @@ readme = "README.md"
11
11
 
12
12
  [tool.poetry.dependencies]
13
13
  python = "^3.10"
14
- eq-api-connector = "^1.0.1"
14
+ eq-api-connector = "^1.1.0"
15
15
 
16
16
  [tool.poetry.group.dev.dependencies]
17
- pytest = "^7.4.4"
18
- pytest-cov = "^5.0.0"
19
- black = "^24.10.0"
17
+ pytest = "^9.0.0"
18
+ pytest-cov = "^7.0.0"
19
+ black = "^25.10.0"
20
20
  diff-cover = "^10.2.0"
21
21
 
22
22
  [build-system]
@@ -0,0 +1,260 @@
1
+ from typing import Any, Dict, List, Optional
2
+ from urllib.parse import urljoin
3
+ import stidapi.utils as u
4
+
5
+
6
+ class File:
7
+ """Class for internal use. Copy of File as returned by document endpoint."""
8
+
9
+ # "id": 0,
10
+ # "instCode": "string",
11
+ # "fileName": "string",
12
+ # "objectType": "string",
13
+ # "description": "string",
14
+ # "fileOrder": 0,
15
+ # "prodViewCode": "string",
16
+ # "insertedDate": "2024-04-09T11:46:07.501Z",
17
+ # "thumbnail": "string",
18
+ # "fileSize": 0,
19
+ # "blobId": "string"
20
+
21
+ def __init__(self, data: Dict[str, Any]) -> None:
22
+ """Initialize File object from data dictionary.
23
+
24
+ Args:
25
+ data: Dictionary containing file properties.
26
+ """
27
+ self._description: str = ""
28
+
29
+ for prop in data.keys():
30
+ self.__setattr__(prop, data[prop])
31
+
32
+ @property
33
+ def inst_code(self) -> str:
34
+ """Get installation code."""
35
+ return getattr(self, "instCode", "")
36
+
37
+ @property
38
+ def file_name(self) -> str:
39
+ """Get file name."""
40
+ return getattr(self, "fileName", "")
41
+
42
+ @property
43
+ def description(self) -> str:
44
+ """Get file description."""
45
+ return self._description
46
+
47
+ @description.setter
48
+ def description(self, value: str) -> None:
49
+ """Set file description."""
50
+ self._description = value
51
+
52
+ @property
53
+ def object_type(self) -> str:
54
+ """Get object type."""
55
+ return getattr(self, "objectType", "")
56
+
57
+ def __str__(self) -> str:
58
+ return f"InstCode: {self.inst_code}, FileName: {self.file_name}, Description: {self.description}, ObjectType: {self.object_type}"
59
+
60
+
61
+ class Revision:
62
+ """Class for internal use. Copy of Revision as returned by document endpoint."""
63
+
64
+ # "revNo": "string",
65
+ # "revStatus": "string",
66
+ # "revStatusDescription": "string",
67
+ # "revDate": "2024-04-09T11:46:07.501Z",
68
+ # "isCurrent": true,
69
+ # "projectCode": "string",
70
+ # "projectCodeDescription": "string",
71
+ # "reasonForIssue": "string",
72
+ # "acceptanceCode": 0,
73
+ # "acceptanceCodeDescription": "string",
74
+ # "files": [File objects]
75
+
76
+ def __init__(self, data: Dict[str, Any]) -> None:
77
+ """Initialize Revision object from data dictionary.
78
+
79
+ Args:
80
+ data: Dictionary containing revision properties.
81
+ """
82
+ self._data: Dict[str, Any] = data
83
+ for prop in data.keys():
84
+ if prop == "files":
85
+ continue
86
+ self.__setattr__(prop, data[prop])
87
+
88
+ @property
89
+ def rev_date(self) -> str:
90
+ """Get revision date."""
91
+ return self._data.get("revDate", "")
92
+
93
+ @property
94
+ def rev_no(self) -> str:
95
+ """Get revision number."""
96
+ return self._data.get("revNo", "")
97
+
98
+ @property
99
+ def rev_status(self) -> str:
100
+ """Get revision status."""
101
+ return self._data.get("revStatus", "")
102
+
103
+ def get_files(self) -> List[File]:
104
+ """Get list of files in this revision.
105
+
106
+ Returns:
107
+ List of File objects.
108
+ """
109
+ return [File(x) for x in self._data.get("files", [])]
110
+
111
+ def __str__(self) -> str:
112
+ return f"RevNo: {self.rev_no}, RevStatus: {self.rev_status}, RevDate: {self.rev_date}"
113
+
114
+
115
+ class Doc:
116
+ """Represents a technical document in STID."""
117
+
118
+ # "instCode": "string", "instCodeDescription": "string",
119
+ # "docNo": "string", "docTitle": "string",
120
+ # "docCategory": "string", "docCategoryDescription": "string",
121
+ # "docType": "string", "docTypeDescription": "string",
122
+ # "projectCode": "string", "projectCodeDescription": "string",
123
+ # "contrCode": "string", "contrCodeDescription": "string",
124
+ # "disciplineCode": "string","disciplineCodeDescription": "string",
125
+ # "locationCode": "string","locationCodeDescription": "string",
126
+ # "docClass": "string","docClassName": "string", "docClassDescription": "string",
127
+ # "poNo": "string","poNoDescription": "string",
128
+ # "system": "string","systemDescription": "string",
129
+ # "remark": "string",
130
+ # "supplDocNo": "string",
131
+ # "companyCode": "string",
132
+ # "source": "string",
133
+ # "size": "string",
134
+ # "priority": "string", "priorityDescription": "string",
135
+ # "weightBearing": "string",
136
+ # "productCode": "string",
137
+ # "insulationClass": "string", "insulationClassDescription": "string",
138
+ # "tagRefCount": 0, "docRefCount": 0,
139
+ # "currentRevision": { Revision object },
140
+ # "projectRevisions": [ { Revision object }],
141
+ # "additionalFields": [{"type": "string","typeDescription": "string","value": "string","description": "string"}],
142
+ # "projects": [{"instCode": "string","projectCode": "string","description": "string","stidDeliveryCode": "string",
143
+ # "insertedDate": "2024-04-09T11:46:07.501Z","isPrimary": true,"isValid": true,}],
144
+ # "purchaseOrders": [
145
+ # {"instCode": "string","poNo": "string","description": "string","insertedDate": "2024-04-09T11:46:07.501Z","isPrimary": true,"isValid": true}],
146
+ # "apiResponseTime": "string",
147
+
148
+ def __init__(
149
+ self, inst_code: str, doc_no: str, data: Optional[Dict[str, Any]] = None
150
+ ) -> None:
151
+ """Initialize Doc object.
152
+
153
+ Args:
154
+ inst_code: STID installation code.
155
+ doc_no: Document number as found in STID.
156
+ data: (Optional) Dictionary of data as returned from Doc.get().
157
+
158
+ Raises:
159
+ ValueError: If inst_code or doc_no are empty/invalid.
160
+ """
161
+ if not inst_code or not isinstance(inst_code, str):
162
+ raise ValueError("inst_code must be a non-empty string")
163
+ if not doc_no or not isinstance(doc_no, str):
164
+ raise ValueError("doc_no must be a non-empty string")
165
+
166
+ self._data: Dict[str, Any] = {}
167
+
168
+ if data is not None:
169
+ self._data = data
170
+ else:
171
+ fetched_data = Doc.get(inst_code=inst_code, doc_no=doc_no)
172
+ if fetched_data:
173
+ self._data = fetched_data
174
+ else:
175
+ raise ValueError(f"No document found for {inst_code}/{doc_no}")
176
+
177
+ self.docNo = self.no
178
+ self.description = self.title
179
+
180
+ @property
181
+ def inst_code(self) -> str:
182
+ """Get installation code."""
183
+ return self._data.get("instCode", "")
184
+
185
+ @property
186
+ def no(self) -> str:
187
+ """Get document number."""
188
+ return self._data.get("docNo", "")
189
+
190
+ @property
191
+ def category(self) -> str:
192
+ """Get document category description."""
193
+ return self._data.get("docCategoryDescription", "")
194
+
195
+ @property
196
+ def discipline(self) -> str:
197
+ """Get discipline code description."""
198
+ return self._data.get("disciplineCodeDescription", "")
199
+
200
+ @property
201
+ def type(self) -> str:
202
+ """Get document type description."""
203
+ return self._data.get("docTypeDescription", "")
204
+
205
+ @property
206
+ def title(self) -> str:
207
+ """Get document title."""
208
+ return self._data.get("docTitle", "")
209
+
210
+ def get_current_revision(self) -> Revision:
211
+ """Get the current revision of this document.
212
+
213
+ Returns:
214
+ Revision object for the current revision.
215
+ """
216
+ return Revision(self._data.get("currentRevision", {}))
217
+
218
+ def get_files(self) -> List[File]:
219
+ """Get files from the current revision.
220
+
221
+ Returns:
222
+ List of File objects from the current revision.
223
+ """
224
+ return self.get_current_revision().get_files()
225
+
226
+ def __str__(self) -> str:
227
+ return f"InstCode: {self.inst_code}, No: {self.no}, Title: {self.title}"
228
+
229
+ @staticmethod
230
+ def get(inst_code: str, doc_no: str) -> Optional[Dict[str, Any]]:
231
+ """Get data from STID for a single document.
232
+
233
+ Args:
234
+ inst_code: STID installation code.
235
+ doc_no: STID document number.
236
+
237
+ Returns:
238
+ Dictionary of data from STID for the document, or None if not found.
239
+ """
240
+ if not inst_code or not doc_no:
241
+ return None
242
+
243
+ url = urljoin(
244
+ u.get_api_url(), str(inst_code) + "/document?docNo=" + str(doc_no)
245
+ )
246
+ return u.get_json(url)
247
+
248
+ @staticmethod
249
+ def from_data(data: Dict[str, Any]) -> "Doc":
250
+ """Create Doc object from data dictionary.
251
+
252
+ Args:
253
+ data: Dictionary of data for document.
254
+
255
+ Returns:
256
+ Doc object created from data.
257
+ """
258
+ return Doc(
259
+ inst_code=data.get("instCode", ""), doc_no=data.get("docNo", ""), data=data
260
+ )
@@ -0,0 +1,69 @@
1
+ from typing import Any, Dict, List, Optional
2
+ from urllib.parse import urljoin
3
+
4
+ import stidapi.utils as u
5
+
6
+
7
+ class System:
8
+ """Represents a system within a STID plant."""
9
+
10
+ def __init__(self, data: Optional[Dict[str, Any]] = None) -> None:
11
+ """Initialize System object.
12
+
13
+ Args:
14
+ inst_code: Installation code.
15
+ data: (Optional) Dictionary of system data.
16
+ """
17
+ self._data: Dict[str, Any] = {}
18
+
19
+ if isinstance(data, dict) and len(data) > 0:
20
+ self._data = data
21
+
22
+ @property
23
+ def inst_code(self) -> str:
24
+ """Get installation code."""
25
+ return self._data.get("instCode", "")
26
+
27
+ @property
28
+ def no(self) -> str:
29
+ """Get system number."""
30
+ return self._data.get("system", "")
31
+
32
+ @property
33
+ def description(self) -> str:
34
+ """Get system description."""
35
+ return self._data.get("description", "")
36
+
37
+ @property
38
+ def valid(self) -> bool:
39
+ """Get system validity flag."""
40
+ return self._data.get("validFlg", False)
41
+
42
+ @staticmethod
43
+ def get_all_data(inst_code: str, is_valid: bool = False) -> List[Dict[str, Any]]:
44
+ """Get all system data for an installation.
45
+
46
+ Args:
47
+ inst_code: Installation code.
48
+ is_valid: If True, return only valid systems.
49
+
50
+ Returns:
51
+ List of dictionaries containing system data.
52
+ """
53
+ url = urljoin(u.get_api_url(), f"{inst_code}/system?isValid={is_valid}")
54
+ parsed_json = u.get_json(url)
55
+ return parsed_json if isinstance(parsed_json, list) else []
56
+
57
+ @staticmethod
58
+ def get_system(inst_code: str, get_statistics: bool = False) -> List["System"]:
59
+ """Get all System objects for an installation.
60
+
61
+ Args:
62
+ inst_code: Installation code.
63
+ get_statistics: (Unused) Placeholder for future extension.
64
+
65
+ Returns:
66
+ List of System objects.
67
+ """
68
+ plant_data = System.get_all_data(inst_code, get_statistics)
69
+ return [System(x) for x in plant_data if isinstance(x, dict)]
@@ -1,4 +1,4 @@
1
- from typing import List, Optional, Tuple, Union
1
+ from typing import Any, Dict, List, Optional, Tuple, Union
2
2
  from urllib.parse import urljoin
3
3
 
4
4
  from stidapi import Doc
@@ -6,18 +6,38 @@ import stidapi.utils as u
6
6
 
7
7
 
8
8
  class Tag:
9
- def __init__(self, inst_code: str, tag_no: str, data: Optional[dict] = None):
10
- """
11
- Object initializer for Tag
12
- :param inst_code: STID installation code
13
- :param tag_no: Tag number as found in STID
14
- :param data: (Optional) dictionary of data as returned from Tag.get or Tag.search
9
+ """Represents an instrumentation tag in STID."""
10
+
11
+ def __init__(
12
+ self,
13
+ inst_code: str = "",
14
+ tag_no: str = "",
15
+ data: Optional[Dict[str, Any]] = None,
16
+ ) -> None:
17
+ """Initialize Tag object.
18
+
19
+ Args:
20
+ inst_code: (Optional) STID installation code.
21
+ tag_no: (Optional) Tag number as found in STID.
22
+ data: (Optional) Dictionary of data as returned from Tag.get() or Tag.search().
15
23
 
16
- Initializes object and gets data from STID if available.
24
+ Raises:
25
+ ValueError: If neither data nor valid combination of inst_code and tag_no is provided.
17
26
  """
18
27
 
28
+ self._data: Dict[str, Any] = {}
29
+
19
30
  if not data:
20
- self._data = Tag.get(inst_code=inst_code, tag_no=tag_no)
31
+ if not inst_code or not isinstance(inst_code, str):
32
+ raise ValueError("inst_code must be a non-empty string")
33
+ if not tag_no or not isinstance(tag_no, str):
34
+ raise ValueError("tag_no must be a non-empty string")
35
+
36
+ fetched_data = Tag.get(inst_code=inst_code, tag_no=tag_no)
37
+ if fetched_data:
38
+ self._data = fetched_data
39
+ else:
40
+ raise ValueError(f"No tag found for {inst_code}/{tag_no}")
21
41
  else:
22
42
  self._data = data
23
43
 
@@ -44,54 +64,65 @@ class Tag:
44
64
  self.__setattr__(prop[1], self._data[prop[0]])
45
65
 
46
66
  @property
47
- def data(self) -> dict:
67
+ def data(self) -> Dict[str, Any]:
68
+ """Get the tag data dictionary."""
48
69
  if hasattr(self, "_data"):
49
70
  return self._data
50
71
  return {}
51
72
 
52
73
  @property
53
74
  def tag_no(self) -> str:
75
+ """Get tag number."""
54
76
  return self.no
55
77
 
56
78
  @property
57
79
  def inst_code(self) -> str:
80
+ """Get installation code."""
58
81
  return str(self.data.get("instCode", ""))
59
82
 
60
83
  @property
61
- def no(self):
84
+ def no(self) -> str:
85
+ """Get tag number."""
62
86
  return str(self.data.get("tagNo", ""))
63
87
 
64
88
  @property
65
89
  def description(self) -> str:
90
+ """Get tag description."""
66
91
  return str(self.data.get("description", ""))
67
92
 
68
93
  @property
69
- def category(self):
94
+ def category(self) -> str:
95
+ """Get tag category."""
70
96
  return self.data.get("tagCategory", "")
71
97
 
72
98
  @property
73
99
  def category_description(self) -> str:
100
+ """Get tag category description."""
74
101
  return str(self.data.get("tagCategoryDescription", "")).upper()
75
102
 
76
103
  @property
77
- def discipline_description(self):
104
+ def discipline_description(self) -> str:
105
+ """Get discipline code description."""
78
106
  return self.data.get("disciplineCodeDescription", "")
79
107
 
80
108
  @property
81
109
  def is_function(self) -> bool:
110
+ """Check if tag is a function block."""
82
111
  return bool(
83
112
  self.data.get("isFunction", self.category_description == "FUNCTION")
84
113
  )
85
114
 
86
115
  @property
87
116
  def is_signal(self) -> bool:
117
+ """Check if tag is a signal."""
88
118
  return bool(self.data.get("isSignal", self.category_description == "SIGNAL"))
89
119
 
90
120
  @property
91
- def status(self):
121
+ def status(self) -> str:
122
+ """Get tag status."""
92
123
  return str(self.data.get("tagStatus", ""))
93
124
 
94
- def get_addition_field(self, field: str = "") -> List[dict]:
125
+ def get_addition_field(self, field: str = "") -> List[Dict[str, Any]]:
95
126
  """Get list of additional fields. Optionally filter by type.
96
127
 
97
128
  Args:
@@ -102,7 +133,7 @@ class Tag:
102
133
  """
103
134
  return self.get_additional_field(field=field)
104
135
 
105
- def get_additional_field(self, field: Optional[str] = "") -> List[dict]:
136
+ def get_additional_field(self, field: Optional[str] = "") -> List[Dict[str, Any]]:
106
137
  """Get list of additional fields. Optionally filter by type.
107
138
 
108
139
  Args:
@@ -112,12 +143,14 @@ class Tag:
112
143
  List[dict]: List of additional fields.
113
144
  """
114
145
  if field is None or len(field) == 0:
115
- return self._data["additionalFields"]
146
+ return self._data.get("additionalFields", [])
116
147
 
117
- return [x for x in self._data["additionalFields"] if x["type"] == field]
148
+ return [
149
+ x for x in self._data.get("additionalFields", []) if x.get("type") == field
150
+ ]
118
151
 
119
152
  def get_additional_field_value(self, field: str) -> List[Tuple[str, str]]:
120
- """Get list of tuples of value and description for additional field of a given type
153
+ """Get list of tuples of value and description for additional field of a given type.
121
154
 
122
155
  Args:
123
156
  field (str): Name of additional field to get
@@ -127,21 +160,32 @@ class Tag:
127
160
  """
128
161
  f = self.get_additional_field(field=field)
129
162
  if len(f) > 0:
130
- return [(x["value"], x["description"]) for x in f]
163
+ return [(x.get("value", ""), x.get("description", "")) for x in f]
131
164
 
132
165
  return []
133
166
 
134
- def get_doc(self) -> List["Doc"]:
167
+ def get_ims(self) -> dict[str, str]:
168
+ """Get IMS tags related to tag if available.
169
+
170
+ Returns:
171
+ str: IMS code or empty string if not available.
172
+ """
173
+ fields = self.get_additional_field_value(field="IMS")
174
+ d = {}
175
+ [d.update({v: k}) for k, v in fields if k is not None and v is not None]
176
+
177
+ return d
178
+
179
+ def get_doc(self) -> List[Doc]:
135
180
  """Get list of documents that tag refers to.
136
181
 
137
182
  Returns:
138
183
  List[Doc]: List of referred Documents
139
184
  """
185
+ return [Doc.from_data(x) for x in self.get_doc_references()]
140
186
 
141
- return [Doc(x["instCode"], x["docNo"]) for x in self.get_doc_references()]
142
-
143
- def get_doc_references(self) -> List[dict]:
144
- """Get doc references of tag from stidapi as dicts.
187
+ def get_doc_references(self) -> List[Dict[str, Any]]:
188
+ """Get doc references of tag from STID API as dictionaries.
145
189
 
146
190
  Returns:
147
191
  List[dict]: List of dicts describing document references.
@@ -150,8 +194,8 @@ class Tag:
150
194
  u.get_api_url(),
151
195
  f"{str(self.inst_code)}/tag/document-refs?tagNo={str(self.tag_no)}&noContentAs200=true",
152
196
  )
153
- json = u.get_json(url)
154
- return json
197
+ json_data = u.get_json(url)
198
+ return json_data if isinstance(json_data, list) else []
155
199
 
156
200
  def get_functional_location(self) -> str:
157
201
  """Get functional location of Tagged item or empty string if it does not have a functional location.
@@ -159,32 +203,26 @@ class Tag:
159
203
  Returns:
160
204
  str: Functional location or empty string if tagged item does not have a functional location.
161
205
  """
162
-
163
206
  url = urljoin(
164
207
  u.get_api_url(),
165
208
  f"portal/{self.inst_code}/tag/sap-tag?tagNo={self.tag_no}",
166
209
  )
167
- json = u.get_json(url)
210
+ json_data = u.get_json(url)
168
211
 
169
- if isinstance(json, dict) and "functionalLocation" in json.keys():
170
- return json["functionalLocation"]
212
+ if isinstance(json_data, dict) and "functionalLocation" in json_data:
213
+ return json_data.get("functionalLocation", "")
171
214
  else:
172
215
  return ""
173
216
 
174
- def __str__(self):
175
- """
176
- Overload string representation of object.
177
- :return: Pretty-print string describing Tag object
178
- """
217
+ def __str__(self) -> str:
218
+ """Get string representation of Tag object."""
179
219
  if isinstance(self._data, dict) and len(self._data) > 0:
180
220
  return str(self.tag_no) + "@" + str(self.inst_code) + " with data"
181
221
  else:
182
222
  return str(self.tag_no) + "@" + str(self.inst_code) + " with no data"
183
223
 
184
- def prune_empty_data(self):
185
- """
186
- Remove all empty, i.e., containing None, entries in data dictionary.
187
- """
224
+ def prune_empty_data(self) -> None:
225
+ """Remove all empty (None) entries from data dictionary."""
188
226
  if isinstance(self._data, dict) and len(self._data) > 0:
189
227
  self._data = {k: v for k, v in self._data.items() if v is not None}
190
228
 
@@ -196,6 +234,8 @@ class Tag:
196
234
  :param tag_no: STID tag number
197
235
  :return: Dictionary of data from STID for tag.
198
236
  """
237
+ if not inst_code or not tag_no:
238
+ return {}
199
239
 
200
240
  url = urljoin(u.get_api_url(), str(inst_code) + "/tag?tagNo=" + str(tag_no))
201
241
  data = u.get_json(url)
@@ -206,7 +246,7 @@ class Tag:
206
246
  if isinstance(data, dict):
207
247
  return data
208
248
 
209
- raise ValueError("Did not receive a dictionary from server.")
249
+ return {}
210
250
 
211
251
  @staticmethod
212
252
  def search(
@@ -239,8 +279,7 @@ class Tag:
239
279
  List[Tag]: List of Tag objects with a bit less data than when getting
240
280
  """
241
281
 
242
- # string subSystem, string mainSystem, string projectCode, string poNo,
243
- # string contrCode, string locationCode, string plantId,
282
+ # Build query parameters
244
283
  if len(tag_no) > 0:
245
284
  tag_no = "tagNo=" + tag_no + "&"
246
285
 
@@ -283,7 +322,10 @@ class Tag:
283
322
  + str(take_string),
284
323
  )
285
324
 
286
- return [Tag(x["instCode"], x["tagNo"], x) for x in u.get_json(url)]
325
+ result = u.get_json(url)
326
+ if isinstance(result, list):
327
+ return [Tag(data=x) for x in result]
328
+ return []
287
329
 
288
330
  @staticmethod
289
331
  def search_additional_field(
@@ -306,7 +348,8 @@ class Tag:
306
348
  res = u.get_json(url)
307
349
 
308
350
  if isinstance(res, list):
309
- return [Tag(inst_code=inst_code, tag_no=x["tagNo"]) for x in res]
351
+ return [Tag(inst_code=inst_code, tag_no=x["tagNo"], data=x) for x in res]
352
+ return []
310
353
 
311
354
  raise ValueError(f"Invalid data {res} returned from query {url}")
312
355
 
@@ -4,7 +4,6 @@ from typing import List, Optional, Union
4
4
  from eq_api_connector import APIConnector
5
5
  from types import SimpleNamespace
6
6
 
7
-
8
7
  logger = logging.getLogger(__name__)
9
8
 
10
9
  _client = None
@@ -29,7 +28,7 @@ class STIDApiClient(APIConnector):
29
28
  user_name=user_name,
30
29
  user_assertion=user_assertion,
31
30
  )
32
- self.set_url_prod("https://stidapi.equinor.com/")
31
+ self.url_prod = "https://stidapi.equinor.com/"
33
32
  # todo: set dev url
34
33
 
35
34
 
@@ -49,7 +48,7 @@ def set_api_client(client: STIDApiClient):
49
48
 
50
49
 
51
50
  def get_api_url():
52
- return get_api_client().get_url()
51
+ return get_api_client().url
53
52
 
54
53
 
55
54
  def get_object_from_json(text: str):
@@ -62,6 +61,6 @@ def get_object_from_json(text: str):
62
61
 
63
62
  def get_json(url: str, raise_for_status=False):
64
63
  c = get_api_client()
65
- c.set_raise_for_status(raise_for_status=raise_for_status)
64
+ c.raise_for_status = raise_for_status
66
65
 
67
66
  return c.get_json(url=url)
@@ -1,152 +0,0 @@
1
- from typing import List
2
- from urllib.parse import urljoin
3
- import stidapi.utils as u
4
-
5
-
6
- class File:
7
- """Class for internal use. Copy of File as returned by document endpoint."""
8
-
9
- # "id": 0,
10
- # "instCode": "string",
11
- # "fileName": "string",
12
- # "objectType": "string",
13
- # "description": "string",
14
- # "fileOrder": 0,
15
- # "prodViewCode": "string",
16
- # "insertedDate": "2024-04-09T11:46:07.501Z",
17
- # "thumbnail": "string",
18
- # "fileSize": 0,
19
- # "blobId": "string"
20
-
21
- def __init__(self, data: dict):
22
- for prop in data.keys():
23
- self.__setattr__(prop, data[prop])
24
-
25
- def __str__(self):
26
- return f"InstCode: {self.instCode}, FileName: {self.fileName}, Description: {self.description}, ObjectType: {self.objectType}"
27
-
28
-
29
- class Revision:
30
- """Class for internal use. Copy of Revision as returned by document endpoint."""
31
-
32
- # "revNo": "string",
33
- # "revStatus": "string",
34
- # "revStatusDescription": "string",
35
- # "revDate": "2024-04-09T11:46:07.501Z",
36
- # "isCurrent": true,
37
- # "projectCode": "string",
38
- # "projectCodeDescription": "string",
39
- # "reasonForIssue": "string",
40
- # "acceptanceCode": 0,
41
- # "acceptanceCodeDescription": "string",
42
- # "files": [File objects]
43
-
44
- def __init__(self, data: dict):
45
- self._data = data
46
- for prop in data.keys():
47
- if prop == "files":
48
- continue
49
- self.__setattr__(prop, data[prop])
50
-
51
- def get_files(self):
52
- return [File(x) for x in self._data["files"]]
53
-
54
- def __str__(self):
55
- return (
56
- f"RevNo: {self.revNo}, RevStatus: {self.revStatus}, RevDate: {self.revDate}"
57
- )
58
-
59
-
60
- class Doc:
61
- def __init__(self, inst_code: str, doc_no: str):
62
- """
63
- Object initializer for Doc
64
- :param inst_code: STID installation code
65
- :param doc_no: Doc number as found in STID
66
-
67
- Initializes object and gets data from STID if available.
68
- """
69
- self.inst_code = ""
70
- self.no = ""
71
- self.title = ""
72
-
73
- self.category = ""
74
- self.discipline = ""
75
- self.type = ""
76
-
77
- self._data = Doc.get(inst_code=inst_code, doc_no=doc_no)
78
-
79
- common_prop = [
80
- ("instCode", "inst_code"),
81
- ("docNo", "no"),
82
- ("docTitle", "title"),
83
- ("docCategoryDescription", "category"),
84
- ("disciplineCodeDescription", "discipline"),
85
- ("docTypeDescription", "type"),
86
- ]
87
- for prop in common_prop:
88
- if prop[0] in self._data:
89
- self.__setattr__(prop[1], self._data[prop[0]])
90
- else:
91
- self.__setattr__(prop[1], "")
92
-
93
- self.docNo = self.no
94
- self.description = self.title
95
-
96
- optional_prop = []
97
- for prop in optional_prop:
98
- if prop[0] in self._data and self._data[prop[0]] is not None:
99
- self.__setattr__(prop[1], self._data[prop[0]])
100
-
101
- def get_current_revision(self) -> Revision:
102
- return Revision(self._data["currentRevision"])
103
-
104
- def get_files(self) -> List[File]:
105
- return self.get_current_revision().get_files()
106
-
107
- def __str__(self):
108
- return f"InstCode: {self.inst_code}, No: {self.no}, Title: {self.title}"
109
-
110
- # "instCode": "string", "instCodeDescription": "string",
111
- # "docNo": "string", "docTitle": "string",
112
- # "docCategory": "string", "docCategoryDescription": "string",
113
- # "docType": "string", "docTypeDescription": "string",
114
- # "projectCode": "string", "projectCodeDescription": "string",
115
- # "contrCode": "string", "contrCodeDescription": "string",
116
- # "disciplineCode": "string","disciplineCodeDescription": "string",
117
- # "locationCode": "string","locationCodeDescription": "string",
118
- # "docClass": "string","docClassName": "string", "docClassDescription": "string",
119
- # "poNo": "string","poNoDescription": "string",
120
- # "system": "string","systemDescription": "string",
121
- # "remark": "string",
122
- # "supplDocNo": "string",
123
- # "companyCode": "string",
124
- # "source": "string",
125
- # "size": "string",
126
- # "priority": "string", "priorityDescription": "string",
127
- # "weightBearing": "string",
128
- # "productCode": "string",
129
- # "insulationClass": "string", "insulationClassDescription": "string",
130
- # "tagRefCount": 0, "docRefCount": 0,
131
- # "currentRevision": { Revision object },
132
- # "projectRevisions": [ { Revision object }],
133
- # "additionalFields": [{"type": "string","typeDescription": "string","value": "string","description": "string"}],
134
- # "projects": [{"instCode": "string","projectCode": "string","description": "string","stidDeliveryCode": "string",
135
- # "insertedDate": "2024-04-09T11:46:07.501Z","isPrimary": true,"isValid": true,}],
136
- # "purchaseOrders": [
137
- # {"instCode": "string","poNo": "string","description": "string","insertedDate": "2024-04-09T11:46:07.501Z","isPrimary": true,"isValid": true}],
138
- # "apiResponseTime": "string",
139
-
140
- @staticmethod
141
- def get(inst_code: str, doc_no: str):
142
- """
143
- Get data from STID for a single doc.
144
- :param inst_code: STID installation code
145
- :param doc_no: STID doc number
146
- :return: Dictionary of data from STID for doc.
147
- """
148
-
149
- url = urljoin(
150
- u.get_api_url(), str(inst_code) + "/document?docNo=" + str(doc_no)
151
- )
152
- return u.get_json(url)
@@ -1,40 +0,0 @@
1
- from urllib.parse import urljoin
2
-
3
- import stidapi.utils as u
4
-
5
-
6
- class System:
7
- def __init__(self, inst_code: str = "", data=None):
8
- if isinstance(inst_code, str) and len(inst_code) > 0:
9
- self.inst_code = inst_code
10
-
11
- self._data = {}
12
- self.no = ""
13
- self.description = ""
14
- self.inst_code = ""
15
- self.valid = None
16
-
17
- if isinstance(data, dict) and len(data) > 0:
18
- self._data = data
19
- self.inst_code = data["instCode"]
20
- self.no = data["system"]
21
- self.description = data["description"]
22
- self.valid = data["validFlg"]
23
-
24
- @staticmethod
25
- def get_all_data(inst_code, is_valid: bool = False):
26
- """
27
-
28
- :param get_statistics:
29
- :return:
30
- """
31
-
32
- url = urljoin(u.get_api_url(), f"{inst_code}/system?isValid={is_valid}")
33
- parsed_json = u.get_json(url)
34
-
35
- return parsed_json
36
-
37
- @staticmethod
38
- def get_system(inst_code: str, get_statistics: bool = False):
39
- plant_data = System.get_all_data(inst_code, get_statistics)
40
- return [System(inst_code, x) for x in plant_data]
File without changes
File without changes
File without changes