stidapi 1.4.2__tar.gz → 1.4.3__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.
- {stidapi-1.4.2 → stidapi-1.4.3}/PKG-INFO +11 -14
- {stidapi-1.4.2 → stidapi-1.4.3}/README.md +6 -7
- stidapi-1.4.3/pyproject.toml +35 -0
- stidapi-1.4.3/pyproject.toml.orig +32 -0
- {stidapi-1.4.2 → stidapi-1.4.3/src}/stidapi/doc.py +117 -3
- stidapi-1.4.2/pyproject.toml +0 -24
- {stidapi-1.4.2 → stidapi-1.4.3/src}/stidapi/__init__.py +0 -0
- {stidapi-1.4.2 → stidapi-1.4.3/src}/stidapi/plant.py +0 -0
- {stidapi-1.4.2 → stidapi-1.4.3/src}/stidapi/system.py +0 -0
- {stidapi-1.4.2 → stidapi-1.4.3/src}/stidapi/tag.py +0 -0
- {stidapi-1.4.2 → stidapi-1.4.3/src}/stidapi/utils.py +0 -0
|
@@ -1,24 +1,22 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: stidapi
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.3
|
|
4
4
|
Summary: Python client for connecting to Equinor STIDapi
|
|
5
|
-
License: Proprietary
|
|
6
5
|
Author: Åsmund Våge Fannemel
|
|
7
|
-
Author-email: asmf@equinor.com
|
|
8
|
-
|
|
9
|
-
Classifier: License :: Other/Proprietary License
|
|
6
|
+
Author-email: Åsmund Våge Fannemel <asmf@equinor.com>
|
|
7
|
+
License-Expression: LicenseRef-Proprietary
|
|
10
8
|
Classifier: Programming Language :: Python :: 3
|
|
11
9
|
Classifier: Programming Language :: Python :: 3.10
|
|
12
10
|
Classifier: Programming Language :: Python :: 3.11
|
|
13
11
|
Classifier: Programming Language :: Python :: 3.12
|
|
14
12
|
Classifier: Programming Language :: Python :: 3.13
|
|
15
13
|
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
-
Requires-Dist: eq-api-connector
|
|
14
|
+
Requires-Dist: eq-api-connector>=1.1.0,<2
|
|
15
|
+
Requires-Python: >=3.10, <4
|
|
17
16
|
Project-URL: repository, https://github.com/equinor/STIDapi-python
|
|
18
17
|
Description-Content-Type: text/markdown
|
|
19
18
|
|
|
20
|
-
# STIDapi-python
|
|
21
|
-
|
|
19
|
+
# STIDapi-python
|
|
22
20
|
A simple wrapper package to interface Equinor [STIDapi](https://stidapi.equinor.com/) using python and get plant, system, tag and doc data.
|
|
23
21
|
|
|
24
22
|
|
|
@@ -46,14 +44,13 @@ Install package from pypi using `pip install stidapi`
|
|
|
46
44
|
|
|
47
45
|
## Developing / testing
|
|
48
46
|
|
|
49
|
-
|
|
50
|
-
`
|
|
47
|
+
Dependency manager uv is preferred for developers. Install with required packages for testing and coverage:
|
|
48
|
+
`uv sync`
|
|
51
49
|
|
|
52
|
-
Call `
|
|
50
|
+
Call `uv run pytest` to run tests.
|
|
53
51
|
|
|
54
|
-
To generate coverage report run `
|
|
52
|
+
To generate coverage report run `uv run pytest --cov=stidapi tests/ --cov-report=xml`
|
|
55
53
|
|
|
56
54
|
To compare coverage with master branch run
|
|
57
|
-
`
|
|
58
|
-
|
|
55
|
+
`uv run diff-cover coverage.xml --compare-branch master`
|
|
59
56
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
# STIDapi-python
|
|
2
|
-
|
|
1
|
+
# STIDapi-python
|
|
3
2
|
A simple wrapper package to interface Equinor [STIDapi](https://stidapi.equinor.com/) using python and get plant, system, tag and doc data.
|
|
4
3
|
|
|
5
4
|
|
|
@@ -27,13 +26,13 @@ Install package from pypi using `pip install stidapi`
|
|
|
27
26
|
|
|
28
27
|
## Developing / testing
|
|
29
28
|
|
|
30
|
-
|
|
31
|
-
`
|
|
29
|
+
Dependency manager uv is preferred for developers. Install with required packages for testing and coverage:
|
|
30
|
+
`uv sync`
|
|
32
31
|
|
|
33
|
-
Call `
|
|
32
|
+
Call `uv run pytest` to run tests.
|
|
34
33
|
|
|
35
|
-
To generate coverage report run `
|
|
34
|
+
To generate coverage report run `uv run pytest --cov=stidapi tests/ --cov-report=xml`
|
|
36
35
|
|
|
37
36
|
To compare coverage with master branch run
|
|
38
|
-
`
|
|
37
|
+
`uv run diff-cover coverage.xml --compare-branch master`
|
|
39
38
|
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "stidapi"
|
|
3
|
+
version = "1.4.3"
|
|
4
|
+
description = "Python client for connecting to Equinor STIDapi"
|
|
5
|
+
requires-python = ">=3.10,<4"
|
|
6
|
+
readme = "README.md"
|
|
7
|
+
license = "LicenseRef-Proprietary"
|
|
8
|
+
classifiers = [
|
|
9
|
+
"Programming Language :: Python :: 3",
|
|
10
|
+
"Programming Language :: Python :: 3.10",
|
|
11
|
+
"Programming Language :: Python :: 3.11",
|
|
12
|
+
"Programming Language :: Python :: 3.12",
|
|
13
|
+
"Programming Language :: Python :: 3.13",
|
|
14
|
+
"Programming Language :: Python :: 3.14",
|
|
15
|
+
]
|
|
16
|
+
dependencies = ["eq-api-connector>=1.1.0,<2"]
|
|
17
|
+
|
|
18
|
+
[[project.authors]]
|
|
19
|
+
name = "Åsmund Våge Fannemel"
|
|
20
|
+
email = "asmf@equinor.com"
|
|
21
|
+
|
|
22
|
+
[project.urls]
|
|
23
|
+
repository = "https://github.com/equinor/STIDapi-python"
|
|
24
|
+
|
|
25
|
+
[dependency-groups]
|
|
26
|
+
dev = [
|
|
27
|
+
"pytest>=9.0.0,<10",
|
|
28
|
+
"pytest-cov>=7.0.0,<8",
|
|
29
|
+
"black>=26.3.0,<27",
|
|
30
|
+
"diff-cover>=10.2.0,<11",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[build-system]
|
|
34
|
+
requires = ["uv_build>=0.11.16,<0.13.0"]
|
|
35
|
+
build-backend = "uv_build"
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "stidapi"
|
|
3
|
+
version = "1.4.3"
|
|
4
|
+
description = "Python client for connecting to Equinor STIDapi"
|
|
5
|
+
authors = [{ name = "Åsmund Våge Fannemel", email = "asmf@equinor.com" }]
|
|
6
|
+
requires-python = ">=3.10,<4"
|
|
7
|
+
readme = "README.md"
|
|
8
|
+
license = "LicenseRef-Proprietary"
|
|
9
|
+
classifiers = [
|
|
10
|
+
"Programming Language :: Python :: 3",
|
|
11
|
+
"Programming Language :: Python :: 3.10",
|
|
12
|
+
"Programming Language :: Python :: 3.11",
|
|
13
|
+
"Programming Language :: Python :: 3.12",
|
|
14
|
+
"Programming Language :: Python :: 3.13",
|
|
15
|
+
"Programming Language :: Python :: 3.14",
|
|
16
|
+
]
|
|
17
|
+
dependencies = ["eq-api-connector>=1.1.0,<2"]
|
|
18
|
+
|
|
19
|
+
[project.urls]
|
|
20
|
+
repository = "https://github.com/equinor/STIDapi-python"
|
|
21
|
+
|
|
22
|
+
[dependency-groups]
|
|
23
|
+
dev = [
|
|
24
|
+
"pytest>=9.0.0,<10",
|
|
25
|
+
"pytest-cov>=7.0.0,<8",
|
|
26
|
+
"black>=26.3.0,<27",
|
|
27
|
+
"diff-cover>=10.2.0,<11",
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
[build-system]
|
|
31
|
+
requires = ["uv_build>=0.11.16,<0.13.0"]
|
|
32
|
+
build-backend = "uv_build"
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import os
|
|
1
2
|
from typing import Any, Dict, List, Optional
|
|
2
3
|
from urllib.parse import urljoin
|
|
3
4
|
import stidapi.utils as u
|
|
@@ -54,6 +55,40 @@ class File:
|
|
|
54
55
|
"""Get object type."""
|
|
55
56
|
return getattr(self, "objectType", "")
|
|
56
57
|
|
|
58
|
+
def download_file(
|
|
59
|
+
self, destination: Optional[str] = None, overwrite: bool = False
|
|
60
|
+
) -> str:
|
|
61
|
+
"""Download this file from STID.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
destination: Optional local path for the downloaded file.
|
|
65
|
+
overwrite: Allow an existing destination file to be replaced.
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
Path returned by the API connector after downloading the file.
|
|
69
|
+
|
|
70
|
+
Raises:
|
|
71
|
+
ValueError: If no download URL or file name is available.
|
|
72
|
+
"""
|
|
73
|
+
download_url = getattr(self, "url", "")
|
|
74
|
+
if not download_url:
|
|
75
|
+
file_id = getattr(self, "id", None)
|
|
76
|
+
if file_id is None or not self.inst_code:
|
|
77
|
+
raise ValueError(
|
|
78
|
+
f"No download endpoint found for file {self.file_name}"
|
|
79
|
+
)
|
|
80
|
+
download_url = urljoin(u.get_api_url(), f"{self.inst_code}/file/{file_id}")
|
|
81
|
+
|
|
82
|
+
output_name = destination or self.file_name
|
|
83
|
+
if destination and os.path.isdir(destination):
|
|
84
|
+
output_name = os.path.join(destination, self.file_name)
|
|
85
|
+
if not output_name:
|
|
86
|
+
raise ValueError("A destination is required when the file has no name")
|
|
87
|
+
if os.path.exists(output_name) and not overwrite:
|
|
88
|
+
raise FileExistsError(f"Destination already exists: {output_name}")
|
|
89
|
+
|
|
90
|
+
return u.get_api_client().get_file(download_url, output_name)
|
|
91
|
+
|
|
57
92
|
def __str__(self) -> str:
|
|
58
93
|
return f"InstCode: {self.inst_code}, FileName: {self.file_name}, Description: {self.description}, ObjectType: {self.object_type}"
|
|
59
94
|
|
|
@@ -108,6 +143,27 @@ class Revision:
|
|
|
108
143
|
"""
|
|
109
144
|
return [File(x) for x in self._data.get("files", [])]
|
|
110
145
|
|
|
146
|
+
def download_files(
|
|
147
|
+
self, destination: Optional[str] = None, overwrite: bool = False
|
|
148
|
+
) -> List[str]:
|
|
149
|
+
"""Download all files in this revision.
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
destination: Optional destination directory for the downloaded files.
|
|
153
|
+
overwrite: Allow existing destination files to be replaced.
|
|
154
|
+
|
|
155
|
+
Returns:
|
|
156
|
+
Paths returned by the API connector for each downloaded file.
|
|
157
|
+
"""
|
|
158
|
+
if destination is None:
|
|
159
|
+
destination = os.path.join(os.getcwd(), self.rev_no)
|
|
160
|
+
os.makedirs(destination, exist_ok=True)
|
|
161
|
+
|
|
162
|
+
return [
|
|
163
|
+
file.download_file(destination, overwrite=overwrite)
|
|
164
|
+
for file in self.get_files()
|
|
165
|
+
]
|
|
166
|
+
|
|
111
167
|
def __str__(self) -> str:
|
|
112
168
|
return f"RevNo: {self.rev_no}, RevStatus: {self.rev_status}, RevDate: {self.rev_date}"
|
|
113
169
|
|
|
@@ -164,6 +220,7 @@ class Doc:
|
|
|
164
220
|
raise ValueError("doc_no must be a non-empty string")
|
|
165
221
|
|
|
166
222
|
self._data: Dict[str, Any] = {}
|
|
223
|
+
self._full_data_loaded = data is None or "currentRevision" in data
|
|
167
224
|
|
|
168
225
|
if data is not None:
|
|
169
226
|
self._data = data
|
|
@@ -187,19 +244,32 @@ class Doc:
|
|
|
187
244
|
"""Get document number."""
|
|
188
245
|
return self._data.get("docNo", "")
|
|
189
246
|
|
|
247
|
+
def _ensure_full_data(self) -> None:
|
|
248
|
+
"""Reload document data once when initialized from a partial reference."""
|
|
249
|
+
if self._full_data_loaded:
|
|
250
|
+
return
|
|
251
|
+
|
|
252
|
+
fetched_data = Doc.get(self.inst_code, self.no)
|
|
253
|
+
if isinstance(fetched_data, dict):
|
|
254
|
+
self._data = fetched_data
|
|
255
|
+
self._full_data_loaded = True
|
|
256
|
+
|
|
190
257
|
@property
|
|
191
258
|
def category(self) -> str:
|
|
192
259
|
"""Get document category description."""
|
|
260
|
+
self._ensure_full_data()
|
|
193
261
|
return self._data.get("docCategoryDescription", "")
|
|
194
262
|
|
|
195
263
|
@property
|
|
196
264
|
def discipline(self) -> str:
|
|
197
265
|
"""Get discipline code description."""
|
|
266
|
+
self._ensure_full_data()
|
|
198
267
|
return self._data.get("disciplineCodeDescription", "")
|
|
199
268
|
|
|
200
269
|
@property
|
|
201
270
|
def type(self) -> str:
|
|
202
271
|
"""Get document type description."""
|
|
272
|
+
self._ensure_full_data()
|
|
203
273
|
return self._data.get("docTypeDescription", "")
|
|
204
274
|
|
|
205
275
|
@property
|
|
@@ -207,13 +277,35 @@ class Doc:
|
|
|
207
277
|
"""Get document title."""
|
|
208
278
|
return self._data.get("docTitle", "")
|
|
209
279
|
|
|
210
|
-
|
|
280
|
+
@property
|
|
281
|
+
def current_revision(self) -> Revision:
|
|
211
282
|
"""Get the current revision of this document.
|
|
212
283
|
|
|
213
284
|
Returns:
|
|
214
285
|
Revision object for the current revision.
|
|
215
286
|
"""
|
|
216
|
-
|
|
287
|
+
self._ensure_full_data()
|
|
288
|
+
current_revision = self._data.get("currentRevision")
|
|
289
|
+
|
|
290
|
+
if isinstance(current_revision, dict) and current_revision:
|
|
291
|
+
return Revision(current_revision)
|
|
292
|
+
|
|
293
|
+
project_revisions = [
|
|
294
|
+
revision
|
|
295
|
+
for revision in self._data.get("projectRevisions", [])
|
|
296
|
+
if isinstance(revision, dict)
|
|
297
|
+
]
|
|
298
|
+
marked_current = next(
|
|
299
|
+
(revision for revision in project_revisions if revision.get("isCurrent")),
|
|
300
|
+
None,
|
|
301
|
+
)
|
|
302
|
+
return Revision(
|
|
303
|
+
marked_current or (project_revisions[0] if project_revisions else {})
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
def get_current_revision(self) -> Revision:
|
|
307
|
+
"""Backward-compatible alias for current_revision."""
|
|
308
|
+
return self.current_revision
|
|
217
309
|
|
|
218
310
|
def get_files(self) -> List[File]:
|
|
219
311
|
"""Get files from the current revision.
|
|
@@ -221,7 +313,29 @@ class Doc:
|
|
|
221
313
|
Returns:
|
|
222
314
|
List of File objects from the current revision.
|
|
223
315
|
"""
|
|
224
|
-
return self.
|
|
316
|
+
return self.current_revision.get_files()
|
|
317
|
+
|
|
318
|
+
def download_files(
|
|
319
|
+
self,
|
|
320
|
+
revision: Revision,
|
|
321
|
+
destination: Optional[str] = None,
|
|
322
|
+
overwrite: bool = False,
|
|
323
|
+
) -> List[str]:
|
|
324
|
+
"""Download all files from a specific revision.
|
|
325
|
+
|
|
326
|
+
Args:
|
|
327
|
+
revision: Revision whose files should be downloaded.
|
|
328
|
+
destination: Optional destination directory. Defaults to a
|
|
329
|
+
document/revision directory in the current working directory.
|
|
330
|
+
overwrite: Allow existing destination files to be replaced.
|
|
331
|
+
|
|
332
|
+
Returns:
|
|
333
|
+
Paths returned by the API connector for each downloaded file.
|
|
334
|
+
"""
|
|
335
|
+
if destination is None:
|
|
336
|
+
destination = os.path.join(os.getcwd(), self.no, revision.rev_no)
|
|
337
|
+
os.makedirs(destination, exist_ok=True)
|
|
338
|
+
return revision.download_files(destination, overwrite=overwrite)
|
|
225
339
|
|
|
226
340
|
def __str__(self) -> str:
|
|
227
341
|
return f"InstCode: {self.inst_code}, No: {self.no}, Title: {self.title}"
|
stidapi-1.4.2/pyproject.toml
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
[tool.poetry]
|
|
2
|
-
name = "stidapi"
|
|
3
|
-
version = "1.4.2"
|
|
4
|
-
description = "Python client for connecting to Equinor STIDapi"
|
|
5
|
-
authors = ["Åsmund Våge Fannemel <asmf@equinor.com>"]
|
|
6
|
-
license = "Proprietary"
|
|
7
|
-
readme = "README.md"
|
|
8
|
-
|
|
9
|
-
[tool.poetry.urls]
|
|
10
|
-
"repository" = "https://github.com/equinor/STIDapi-python"
|
|
11
|
-
|
|
12
|
-
[tool.poetry.dependencies]
|
|
13
|
-
python = "^3.10"
|
|
14
|
-
eq-api-connector = "^1.1.0"
|
|
15
|
-
|
|
16
|
-
[tool.poetry.group.dev.dependencies]
|
|
17
|
-
pytest = "^9.0.0"
|
|
18
|
-
pytest-cov = "^7.0.0"
|
|
19
|
-
black = "^25.10.0"
|
|
20
|
-
diff-cover = "^10.2.0"
|
|
21
|
-
|
|
22
|
-
[build-system]
|
|
23
|
-
requires = ["poetry-core"]
|
|
24
|
-
build-backend = "poetry.core.masonry.api"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|