data_pipeline_api 0.9.0__tar.gz → 0.9.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,22 +1,24 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: data_pipeline_api
3
- Version: 0.9.0
3
+ Version: 0.9.2
4
4
  Summary: Python api to interact with the Fair Data Pipeline
5
- Home-page: https://www.fairdatapipeline.org/
6
5
  License: GNU General Public License v3.0
6
+ License-File: LICENSE
7
7
  Keywords: FAIR Data Pipeline,FAIR,Data Management,Provenance
8
8
  Author: Ryan J Field
9
9
  Author-email: ryan.field@glasgow.ac.uk
10
- Requires-Python: >=3.9,<4.0
10
+ Requires-Python: >=3.10,<4.0
11
11
  Classifier: License :: Other/Proprietary License
12
12
  Classifier: Programming Language :: Python :: 3
13
- Classifier: Programming Language :: Python :: 3.9
14
13
  Classifier: Programming Language :: Python :: 3.10
15
14
  Classifier: Programming Language :: Python :: 3.11
16
15
  Classifier: Programming Language :: Python :: 3.12
17
16
  Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Programming Language :: Python :: 3.14
18
+ Classifier: Programming Language :: Python :: 3.15
18
19
  Requires-Dist: PyYAML (>=6.0,<7.0)
19
20
  Requires-Dist: requests (>=2.23.0,<3.0.0)
21
+ Project-URL: Homepage, https://www.fairdatapipeline.org/
20
22
  Project-URL: Issue Tracker, https://github.com/FAIRDataPipeline/pyDataPipeline/issues
21
23
  Project-URL: Repository, https://github.com/FAIRDataPipeline/pyDataPipeline
22
24
  Description-Content-Type: text/markdown
@@ -163,7 +163,9 @@ def post_entry(
163
163
  return existing_entry[0]
164
164
 
165
165
  if response.status_code != 201:
166
- raise ValueError(SERVER_RESPONSE_STR + str(response.status_code))
166
+ raise ValueError(
167
+ f"{SERVER_RESPONSE_STR}{response.status_code}: {response.text}"
168
+ )
167
169
 
168
170
  return response.json()
169
171
 
@@ -188,7 +190,9 @@ def patch_entry(
188
190
 
189
191
  response = requests.patch(url, data_json, headers=headers)
190
192
  if response.status_code != 200:
191
- raise ValueError(SERVER_RESPONSE_STR + str(response.status_code))
193
+ raise ValueError(
194
+ f"{SERVER_RESPONSE_STR}{response.status_code}: {response.text}"
195
+ )
192
196
 
193
197
  return response.json()
194
198
 
@@ -347,6 +347,47 @@ def finalise(token: str, handle: dict) -> None:
347
347
  datastore = handle["yaml"]["run_metadata"]["write_data_store"]
348
348
  api_version = handle["yaml"]["run_metadata"]["api_version"]
349
349
 
350
+ # Refuse outputs whose data product version is already registered before
351
+ # anything is posted or moved: the registry allows one producing code run
352
+ # per object, so the existing object cannot be claimed by this run
353
+ for output in handle.get("output", {}):
354
+ if "${{RUN_ID}}" in handle["output"][output]["use_data_product"]:
355
+ handle["output"][output]["use_data_product"] = handle["output"][
356
+ output
357
+ ]["use_data_product"].replace("${{RUN_ID}}", handle["code_run_uuid"])
358
+
359
+ namespace_name = handle["output"][output]["use_namespace"]
360
+ data_product_name = handle["output"][output]["use_data_product"]
361
+ version = handle["output"][output]["use_version"]
362
+
363
+ existing_namespace = fdp_utils.get_entry(
364
+ url=registry_url,
365
+ endpoint="namespace",
366
+ query={"name": namespace_name},
367
+ api_version=api_version,
368
+ )
369
+ if not existing_namespace:
370
+ continue
371
+
372
+ data_product_exists = fdp_utils.get_entry(
373
+ url=registry_url,
374
+ endpoint="data_product",
375
+ query={
376
+ "name": data_product_name,
377
+ "version": version,
378
+ "namespace": fdp_utils.get_first_entry(existing_namespace)[
379
+ "url"
380
+ ],
381
+ },
382
+ api_version=api_version,
383
+ )
384
+ if data_product_exists:
385
+ raise ValueError(
386
+ f"Data product {namespace_name}:{data_product_name}@{version} "
387
+ "already exists; bump the version in the write block of your "
388
+ "config"
389
+ )
390
+
350
391
  datastore = fdp_utils.remove_local_from_root(datastore)
351
392
  datastore_root = fdp_utils.get_entry(
352
393
  url=registry_url,
@@ -372,13 +413,6 @@ def finalise(token: str, handle: dict) -> None:
372
413
 
373
414
  if "output" in handle:
374
415
  for output in handle["output"]:
375
-
376
- if "${RUN_ID}" in handle["output"][output]["use_data_product"]:
377
- handle["output"][output]["use_data_product"] = handle[
378
- "output"
379
- ][output]["use_data_product"].replace(
380
- "${RUN_ID}", handle["code_run_uuid"]
381
- )
382
416
  write_namespace = fdp_utils.get_entry(
383
417
  url=registry_url,
384
418
  endpoint="namespace",
@@ -492,82 +526,56 @@ def finalise(token: str, handle: dict) -> None:
492
526
  api_version=api_version,
493
527
  )["url"]
494
528
 
495
- data_product_exists = fdp_utils.get_entry(
529
+ object_url = fdp_utils.post_entry(
530
+ token=token,
496
531
  url=registry_url,
497
- endpoint="data_product",
498
- query={
499
- "name": handle["output"][output]["use_data_product"],
500
- "version": handle["output"][output]["use_version"],
501
- "namespace": write_namespace_url,
532
+ endpoint="object",
533
+ data={
534
+ "description": handle["output"][output][
535
+ "data_product_description"
536
+ ],
537
+ "storage_location": storage_location_url,
538
+ "authors": [handle["author"]],
539
+ "file_type": file_type_url,
502
540
  },
503
541
  api_version=api_version,
504
- )
542
+ )["url"]
505
543
 
506
- if data_product_exists:
507
- data_product_exists_dict = fdp_utils.get_first_entry(
508
- data_product_exists
509
- )
510
- data_product_url = data_product_exists_dict["url"]
511
- object_url = data_product_exists_dict["object"]
512
- obj = fdp_utils.get_entity(
513
- url=registry_url,
514
- endpoint="object",
515
- id=int(fdp_utils.extract_id(object_url)),
516
- api_version=api_version,
517
- )
518
- component_url = obj["components"][0]
544
+ component_url = None
519
545
 
520
- else:
521
- object_url = fdp_utils.post_entry(
546
+ if handle["output"][output]["use_component"]:
547
+ component_url = fdp_utils.post_entry(
522
548
  token=token,
523
549
  url=registry_url,
524
- endpoint="object",
550
+ endpoint="object_component",
525
551
  data={
526
- "description": handle["output"][output][
527
- "data_product_description"
528
- ],
529
- "storage_location": storage_location_url,
530
- "authors": [handle["author"]],
531
- "file_type": file_type_url,
552
+ "object": object_url,
553
+ "name": handle["output"][output]["use_component"],
532
554
  },
533
555
  api_version=api_version,
534
556
  )["url"]
535
-
536
- component_url = None
537
-
538
- if handle["output"][output]["use_component"]:
539
- component_url = fdp_utils.post_entry(
540
- token=token,
541
- url=registry_url,
542
- endpoint="object_component",
543
- data={
544
- "object": object_url,
545
- "name": handle["output"][output]["use_component"],
546
- },
547
- api_version=api_version,
548
- )["url"]
549
- else:
550
- component_url = fdp_utils.get_entry(
551
- url=registry_url,
552
- endpoint="object_component",
553
- query={
554
- "object": fdp_utils.extract_id(object_url),
555
- },
556
- api_version=api_version,
557
- )[0]["url"]
558
-
559
- data_product_url = fdp_utils.post_entry(
560
- token=token,
557
+ else:
558
+ component_url = fdp_utils.get_entry(
561
559
  url=registry_url,
562
- endpoint="data_product",
563
- data={
564
- "name": handle["output"][output]["use_data_product"],
565
- "version": handle["output"][output]["use_version"],
566
- "object": object_url,
567
- "namespace": write_namespace_url,
560
+ endpoint="object_component",
561
+ query={
562
+ "object": fdp_utils.extract_id(object_url),
568
563
  },
569
564
  api_version=api_version,
570
- )["url"]
565
+ )[0]["url"]
566
+
567
+ data_product_url = fdp_utils.post_entry(
568
+ token=token,
569
+ url=registry_url,
570
+ endpoint="data_product",
571
+ data={
572
+ "name": handle["output"][output]["use_data_product"],
573
+ "version": handle["output"][output]["use_version"],
574
+ "object": object_url,
575
+ "namespace": write_namespace_url,
576
+ },
577
+ api_version=api_version,
578
+ )["url"]
571
579
 
572
580
  handle["output"][output]["component_url"] = component_url
573
581
  handle["output"][output]["data_product_url"] = data_product_url
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "data_pipeline_api"
3
- version = "0.9.0"
3
+ version = "0.9.2"
4
4
  description = "Python api to interact with the Fair Data Pipeline"
5
5
  authors = [
6
6
  "Ryan J Field <ryan.field@glasgow.ac.uk>",
@@ -31,7 +31,7 @@ keywords = [
31
31
  ]
32
32
 
33
33
  [tool.poetry.dependencies]
34
- python = ">=3.9,<4.0"
34
+ python = ">=3.10,<4.0"
35
35
  requests = "^2.23.0"
36
36
  PyYAML = "^6.0"
37
37
 
@@ -40,12 +40,12 @@ pytest = "^8.3.4"
40
40
  black = "*"
41
41
  mypy = "*"
42
42
  flake8 = "*"
43
- poetry = "^1.1.12"
43
+ poetry = "^2.0.0"
44
44
  pytest-mock = "*"
45
45
  pytest-dependency = "*"
46
46
  pytest-cov = "*"
47
47
  pre-commit = "^4.0.1"
48
- isort = "^5.10.1"
48
+ isort = "^6.0.0"
49
49
  Sphinx = "*"
50
50
  sphinx-rtd-theme = "*"
51
51