cpg-utils 5.2.1__tar.gz → 5.3.1__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.
- {cpg-utils-5.2.1 → cpg_utils-5.3.1}/PKG-INFO +22 -2
- {cpg-utils-5.2.1 → cpg_utils-5.3.1}/cpg_utils/cloud.py +54 -2
- {cpg-utils-5.2.1 → cpg_utils-5.3.1}/cpg_utils/config.py +32 -12
- {cpg-utils-5.2.1 → cpg_utils-5.3.1}/cpg_utils/cromwell.py +5 -7
- {cpg-utils-5.2.1 → cpg_utils-5.3.1}/cpg_utils.egg-info/PKG-INFO +22 -2
- {cpg-utils-5.2.1 → cpg_utils-5.3.1}/cpg_utils.egg-info/requires.txt +1 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.1}/setup.py +2 -1
- {cpg-utils-5.2.1 → cpg_utils-5.3.1}/LICENSE +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.1}/README.md +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.1}/cpg_utils/__init__.py +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.1}/cpg_utils/cloudpath_hail_az.py +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.1}/cpg_utils/constants.py +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.1}/cpg_utils/cromwell_model.py +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.1}/cpg_utils/dataproc.py +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.1}/cpg_utils/git.py +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.1}/cpg_utils/hail_batch.py +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.1}/cpg_utils/membership.py +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.1}/cpg_utils/py.typed +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.1}/cpg_utils/slack.py +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.1}/cpg_utils.egg-info/SOURCES.txt +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.1}/cpg_utils.egg-info/dependency_links.txt +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.1}/cpg_utils.egg-info/top_level.txt +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.1}/pyproject.toml +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.1}/setup.cfg +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.1}/test/__init__.py +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.1}/test/test_config.py +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.1}/test/test_cromwell.py +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.1}/test/test_doctests.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: cpg-utils
|
|
3
|
-
Version: 5.
|
|
3
|
+
Version: 5.3.1
|
|
4
4
|
Summary: Library of convenience functions specific to the CPG
|
|
5
5
|
Home-page: https://github.com/populationgenomics/cpg-utils
|
|
6
6
|
License: MIT
|
|
@@ -17,6 +17,26 @@ Classifier: Topic :: Scientific/Engineering
|
|
|
17
17
|
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
18
18
|
Description-Content-Type: text/markdown
|
|
19
19
|
License-File: LICENSE
|
|
20
|
+
Requires-Dist: boto3>=1.28.56
|
|
21
|
+
Requires-Dist: botocore>=1.31.56
|
|
22
|
+
Requires-Dist: cloudpathlib[all]
|
|
23
|
+
Requires-Dist: frozendict
|
|
24
|
+
Requires-Dist: google-auth>=1.27.0
|
|
25
|
+
Requires-Dist: google-cloud-artifact-registry
|
|
26
|
+
Requires-Dist: google-cloud-secret-manager
|
|
27
|
+
Requires-Dist: requests
|
|
28
|
+
Requires-Dist: tabulate
|
|
29
|
+
Requires-Dist: toml
|
|
30
|
+
Requires-Dist: deprecated
|
|
31
|
+
Dynamic: classifier
|
|
32
|
+
Dynamic: description
|
|
33
|
+
Dynamic: description-content-type
|
|
34
|
+
Dynamic: home-page
|
|
35
|
+
Dynamic: keywords
|
|
36
|
+
Dynamic: license
|
|
37
|
+
Dynamic: license-file
|
|
38
|
+
Dynamic: requires-dist
|
|
39
|
+
Dynamic: summary
|
|
20
40
|
|
|
21
41
|
# cpg-utils
|
|
22
42
|
|
|
@@ -5,7 +5,9 @@ import os
|
|
|
5
5
|
import re
|
|
6
6
|
import subprocess
|
|
7
7
|
import traceback
|
|
8
|
-
|
|
8
|
+
import urllib.parse
|
|
9
|
+
from collections import defaultdict
|
|
10
|
+
from typing import Any, NamedTuple
|
|
9
11
|
|
|
10
12
|
# pylint: disable=no-name-in-module
|
|
11
13
|
import google.api_core.exceptions
|
|
@@ -26,7 +28,7 @@ from google.auth._default import (
|
|
|
26
28
|
_SERVICE_ACCOUNT_TYPE,
|
|
27
29
|
)
|
|
28
30
|
from google.auth.transport import requests
|
|
29
|
-
from google.cloud import secretmanager
|
|
31
|
+
from google.cloud import artifactregistry, secretmanager
|
|
30
32
|
from google.oauth2 import credentials as oauth2_credentials
|
|
31
33
|
from google.oauth2 import service_account
|
|
32
34
|
|
|
@@ -123,6 +125,56 @@ def write_secret(project_id: str, secret_name: str, secret_value: str) -> None:
|
|
|
123
125
|
secret_manager.disable_secret_version(request={'name': version.name})
|
|
124
126
|
|
|
125
127
|
|
|
128
|
+
class DockerImage(NamedTuple):
|
|
129
|
+
name: str
|
|
130
|
+
uri: str
|
|
131
|
+
tag_uri: str
|
|
132
|
+
size: str
|
|
133
|
+
build_time: str
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
_repo_image_tags: dict[str, defaultdict[str, dict[str, DockerImage]]] = {}
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def _ensure_image_tags_loaded(project: str, location: str, repository: str) -> None:
|
|
140
|
+
"""Populate _repo_image_tags as a map-of-map-of-maps of 'repository' -> 'imagename' -> 'tag' -> image."""
|
|
141
|
+
if repository in _repo_image_tags:
|
|
142
|
+
return
|
|
143
|
+
|
|
144
|
+
image_tags: defaultdict[str, dict[str, DockerImage]] = defaultdict(dict)
|
|
145
|
+
|
|
146
|
+
request = artifactregistry.ListDockerImagesRequest(
|
|
147
|
+
parent=f'projects/{project}/locations/{location}/repositories/{repository}',
|
|
148
|
+
page_size=500, # Increase efficiency by making fewer requests
|
|
149
|
+
)
|
|
150
|
+
for image in artifactregistry.ArtifactRegistryClient().list_docker_images(request):
|
|
151
|
+
name_and_checksum = image.name.rpartition('/dockerImages/')[2]
|
|
152
|
+
name = urllib.parse.unquote(name_and_checksum).rpartition('@')[0]
|
|
153
|
+
base_uri = image.uri.rpartition('@')[0]
|
|
154
|
+
for tag in image.tags:
|
|
155
|
+
image_tags[name][tag] = DockerImage(
|
|
156
|
+
image.name,
|
|
157
|
+
image.uri,
|
|
158
|
+
f'{base_uri}@{tag}',
|
|
159
|
+
image.image_size_bytes,
|
|
160
|
+
image.build_time,
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
image_tags.default_factory = None
|
|
164
|
+
_repo_image_tags[repository] = image_tags
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def find_image(repository: str | None, name: str, version: str) -> DockerImage:
|
|
168
|
+
"""Returns image details or raises ValueError if the image or tag does not exist."""
|
|
169
|
+
repository = f'images-{repository}' if repository is not None else 'images'
|
|
170
|
+
_ensure_image_tags_loaded('cpg-common', 'australia-southeast1', repository)
|
|
171
|
+
try:
|
|
172
|
+
return _repo_image_tags[repository][name][version]
|
|
173
|
+
except KeyError as e:
|
|
174
|
+
message = f'Image {name}:{version} not found in {repository} repository ({e} not found)'
|
|
175
|
+
raise ValueError(message) from None
|
|
176
|
+
|
|
177
|
+
|
|
126
178
|
def get_google_identity_token(
|
|
127
179
|
target_audience: str | None,
|
|
128
180
|
request: google.auth.transport.Request | None = None,
|
|
@@ -9,6 +9,7 @@ import toml
|
|
|
9
9
|
from frozendict import frozendict
|
|
10
10
|
|
|
11
11
|
from cpg_utils import Path, to_path
|
|
12
|
+
from cpg_utils.cloud import find_image
|
|
12
13
|
|
|
13
14
|
AR_GUID_NAME = 'ar-guid'
|
|
14
15
|
|
|
@@ -474,33 +475,52 @@ def output_path(
|
|
|
474
475
|
)
|
|
475
476
|
|
|
476
477
|
|
|
477
|
-
def image_path(
|
|
478
|
+
def image_path(
|
|
479
|
+
key: str,
|
|
480
|
+
version: str | list[str] | None = None,
|
|
481
|
+
repository: str | None = None,
|
|
482
|
+
) -> str:
|
|
478
483
|
"""
|
|
479
|
-
Returns a path to a container image
|
|
484
|
+
Returns a path to a container image for the given key (i.e., image name)
|
|
485
|
+
and version.
|
|
480
486
|
|
|
481
487
|
Examples
|
|
482
488
|
--------
|
|
483
|
-
>> image_path('bcftools')
|
|
484
|
-
'australia-southeast1-docker.pkg.dev/cpg-common/images/bcftools:1.
|
|
485
|
-
|
|
486
|
-
Assuming config structure as follows:
|
|
487
|
-
|
|
488
|
-
```toml
|
|
489
|
-
[images]
|
|
490
|
-
bcftools = 'australia-southeast1-docker.pkg.dev/cpg-common/images/bcftools:1.10.2'
|
|
491
|
-
```
|
|
489
|
+
>> image_path('bcftools', '1.16-1')
|
|
490
|
+
'australia-southeast1-docker.pkg.dev/cpg-common/images/bcftools:1.16-1'
|
|
492
491
|
|
|
493
492
|
Parameters
|
|
494
493
|
----------
|
|
495
494
|
key : str
|
|
495
|
+
Specifies the image name.
|
|
496
|
+
When `version` is not specified:
|
|
496
497
|
Describes the key within the `images` config section. Can list sections
|
|
497
498
|
separated with '/'.
|
|
498
499
|
|
|
500
|
+
version : str or list[str], optional
|
|
501
|
+
Specifies the desired image version, e.g., '1.18-1', either directly as
|
|
502
|
+
a version number string or indirectly via a config key list which will
|
|
503
|
+
be used to retrieve a version number string via `config_retrieve`.
|
|
504
|
+
|
|
505
|
+
repository : str, optional
|
|
506
|
+
The suffix (e.g., 'dev' for images-dev) of an artifact registry repository
|
|
507
|
+
to be used instead of the default production images repository.
|
|
508
|
+
|
|
509
|
+
Using `image_path(key)` without giving `version` is deprecated. In future,
|
|
510
|
+
specifying it will be required.
|
|
511
|
+
|
|
499
512
|
Returns
|
|
500
513
|
-------
|
|
501
514
|
str
|
|
502
515
|
"""
|
|
503
|
-
|
|
516
|
+
if version is None:
|
|
517
|
+
return config_retrieve(['images', *key.strip('/').split('/')])
|
|
518
|
+
|
|
519
|
+
if isinstance(version, list):
|
|
520
|
+
version = config_retrieve(version)
|
|
521
|
+
|
|
522
|
+
assert isinstance(version, str)
|
|
523
|
+
return find_image(repository, key, version).tag_uri
|
|
504
524
|
|
|
505
525
|
|
|
506
526
|
def reference_path(key: str) -> str:
|
|
@@ -42,7 +42,7 @@ class CromwellBackend(Enum):
|
|
|
42
42
|
pipelines_api = 'papi'
|
|
43
43
|
|
|
44
44
|
|
|
45
|
-
DEFAULT_BACKEND = CromwellBackend.
|
|
45
|
+
DEFAULT_BACKEND = CromwellBackend.batch
|
|
46
46
|
|
|
47
47
|
|
|
48
48
|
class CromwellOutputType:
|
|
@@ -643,7 +643,8 @@ def watch_workflow_and_get_output(
|
|
|
643
643
|
array_length = output.array_length
|
|
644
644
|
if array_length is None:
|
|
645
645
|
# is single
|
|
646
|
-
j = b.
|
|
646
|
+
j = b.new_bash_job(f'{job_prefix}_collect_{output_name}')
|
|
647
|
+
j.image(driver_image)
|
|
647
648
|
if output.resource_group:
|
|
648
649
|
# is single resource group
|
|
649
650
|
out_file_map[oname] = _copy_resource_group_into_batch(
|
|
@@ -660,13 +661,13 @@ def watch_workflow_and_get_output(
|
|
|
660
661
|
output_name=output_name,
|
|
661
662
|
idx=None,
|
|
662
663
|
copy_file_into_batch=output.copy_file_into_batch,
|
|
663
|
-
driver_image=driver_image,
|
|
664
664
|
)
|
|
665
665
|
else:
|
|
666
666
|
# is array
|
|
667
667
|
outs: list[Resource] = []
|
|
668
668
|
for idx in range(array_length):
|
|
669
|
-
j = b.
|
|
669
|
+
j = b.new_bash_job(f'{job_prefix}_collect_{output_name}[{idx}]')
|
|
670
|
+
j.image(driver_image)
|
|
670
671
|
if output.resource_group:
|
|
671
672
|
# is array output group
|
|
672
673
|
outs.append(
|
|
@@ -685,7 +686,6 @@ def watch_workflow_and_get_output(
|
|
|
685
686
|
output_name=output_name,
|
|
686
687
|
idx=idx,
|
|
687
688
|
copy_file_into_batch=output.copy_file_into_batch,
|
|
688
|
-
driver_image=driver_image,
|
|
689
689
|
),
|
|
690
690
|
)
|
|
691
691
|
|
|
@@ -701,7 +701,6 @@ def _copy_basic_file_into_batch(
|
|
|
701
701
|
output_name: str,
|
|
702
702
|
idx: int | None,
|
|
703
703
|
copy_file_into_batch: bool,
|
|
704
|
-
driver_image: str,
|
|
705
704
|
) -> Resource:
|
|
706
705
|
"""
|
|
707
706
|
1. Take the file-pointer to the dictionary `rdict`,
|
|
@@ -725,7 +724,6 @@ def _copy_basic_file_into_batch(
|
|
|
725
724
|
jq_el = f'"{output_name}"[{idx}]'
|
|
726
725
|
|
|
727
726
|
# activate to gcloud storage cp
|
|
728
|
-
j.image(driver_image)
|
|
729
727
|
j.env('GOOGLE_APPLICATION_CREDENTIALS', '/gsa-key/key.json')
|
|
730
728
|
j.command(GCLOUD_ACTIVATE_AUTH)
|
|
731
729
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: cpg-utils
|
|
3
|
-
Version: 5.
|
|
3
|
+
Version: 5.3.1
|
|
4
4
|
Summary: Library of convenience functions specific to the CPG
|
|
5
5
|
Home-page: https://github.com/populationgenomics/cpg-utils
|
|
6
6
|
License: MIT
|
|
@@ -17,6 +17,26 @@ Classifier: Topic :: Scientific/Engineering
|
|
|
17
17
|
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
18
18
|
Description-Content-Type: text/markdown
|
|
19
19
|
License-File: LICENSE
|
|
20
|
+
Requires-Dist: boto3>=1.28.56
|
|
21
|
+
Requires-Dist: botocore>=1.31.56
|
|
22
|
+
Requires-Dist: cloudpathlib[all]
|
|
23
|
+
Requires-Dist: frozendict
|
|
24
|
+
Requires-Dist: google-auth>=1.27.0
|
|
25
|
+
Requires-Dist: google-cloud-artifact-registry
|
|
26
|
+
Requires-Dist: google-cloud-secret-manager
|
|
27
|
+
Requires-Dist: requests
|
|
28
|
+
Requires-Dist: tabulate
|
|
29
|
+
Requires-Dist: toml
|
|
30
|
+
Requires-Dist: deprecated
|
|
31
|
+
Dynamic: classifier
|
|
32
|
+
Dynamic: description
|
|
33
|
+
Dynamic: description-content-type
|
|
34
|
+
Dynamic: home-page
|
|
35
|
+
Dynamic: keywords
|
|
36
|
+
Dynamic: license
|
|
37
|
+
Dynamic: license-file
|
|
38
|
+
Dynamic: requires-dist
|
|
39
|
+
Dynamic: summary
|
|
20
40
|
|
|
21
41
|
# cpg-utils
|
|
22
42
|
|
|
@@ -8,7 +8,7 @@ with open('README.md') as f:
|
|
|
8
8
|
setup(
|
|
9
9
|
name='cpg-utils',
|
|
10
10
|
# This tag is automatically updated by bumpversion
|
|
11
|
-
version='5.
|
|
11
|
+
version='5.3.1',
|
|
12
12
|
description='Library of convenience functions specific to the CPG',
|
|
13
13
|
long_description=long_description,
|
|
14
14
|
long_description_content_type='text/markdown',
|
|
@@ -24,6 +24,7 @@ setup(
|
|
|
24
24
|
'cloudpathlib[all]',
|
|
25
25
|
'frozendict',
|
|
26
26
|
'google-auth>=1.27.0',
|
|
27
|
+
'google-cloud-artifact-registry',
|
|
27
28
|
'google-cloud-secret-manager',
|
|
28
29
|
'requests',
|
|
29
30
|
'tabulate',
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|