cpg-utils 5.2.1__tar.gz → 5.3.0__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.0}/PKG-INFO +22 -2
- {cpg-utils-5.2.1 → cpg_utils-5.3.0}/cpg_utils/cloud.py +54 -2
- {cpg-utils-5.2.1 → cpg_utils-5.3.0}/cpg_utils/config.py +32 -12
- {cpg-utils-5.2.1 → cpg_utils-5.3.0}/cpg_utils.egg-info/PKG-INFO +22 -2
- {cpg-utils-5.2.1 → cpg_utils-5.3.0}/cpg_utils.egg-info/requires.txt +1 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.0}/setup.py +2 -1
- {cpg-utils-5.2.1 → cpg_utils-5.3.0}/LICENSE +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.0}/README.md +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.0}/cpg_utils/__init__.py +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.0}/cpg_utils/cloudpath_hail_az.py +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.0}/cpg_utils/constants.py +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.0}/cpg_utils/cromwell.py +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.0}/cpg_utils/cromwell_model.py +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.0}/cpg_utils/dataproc.py +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.0}/cpg_utils/git.py +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.0}/cpg_utils/hail_batch.py +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.0}/cpg_utils/membership.py +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.0}/cpg_utils/py.typed +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.0}/cpg_utils/slack.py +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.0}/cpg_utils.egg-info/SOURCES.txt +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.0}/cpg_utils.egg-info/dependency_links.txt +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.0}/cpg_utils.egg-info/top_level.txt +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.0}/pyproject.toml +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.0}/setup.cfg +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.0}/test/__init__.py +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.0}/test/test_config.py +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.0}/test/test_cromwell.py +0 -0
- {cpg-utils-5.2.1 → cpg_utils-5.3.0}/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.0
|
|
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:
|
|
@@ -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.0
|
|
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.0',
|
|
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
|
|
File without changes
|