dcicutils 7.4.2__tar.gz → 7.4.2.1b0__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of dcicutils might be problematic. Click here for more details.
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/PKG-INFO +1 -1
- dcicutils-7.4.2.1b0/dcicutils/project_utils.py +257 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/pyproject.toml +1 -1
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/setup.py +1 -1
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/LICENSE.txt +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/README.rst +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/__init__.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/base.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/beanstalk_utils.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/cloudformation_utils.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/codebuild_utils.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/command_utils.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/common.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/creds_utils.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/data_utils.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/deployment_utils.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/diff_utils.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/docker_utils.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/ecr_scripts.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/ecr_utils.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/ecs_utils.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/env_base.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/env_manager.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/env_scripts.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/env_utils.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/env_utils_legacy.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/es_utils.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/exceptions.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/ff_mocks.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/ff_utils.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/function_cache_decorator.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/glacier_utils.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/jh_utils.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/kibana/dashboards.json +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/kibana/readme.md +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/lang_utils.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/log_utils.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/misc_utils.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/obfuscation_utils.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/opensearch_utils.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/qa_checkers.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/qa_utils.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/redis_tools.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/redis_utils.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/s3_utils.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/scripts/publish_to_pypi.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/secrets_utils.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/snapshot_utils.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/ssl_certificate_utils.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/task_utils.py +0 -0
- {dcicutils-7.4.2 → dcicutils-7.4.2.1b0}/dcicutils/trace_utils.py +0 -0
@@ -0,0 +1,257 @@
|
|
1
|
+
import os
|
2
|
+
import toml
|
3
|
+
|
4
|
+
from pkg_resources import resource_filename
|
5
|
+
from typing import Optional
|
6
|
+
from .env_utils import EnvUtils
|
7
|
+
from .misc_utils import classproperty
|
8
|
+
|
9
|
+
|
10
|
+
def project_filename(filename):
|
11
|
+
# TODO: In fact we should do this based on the working dir so that when this is imported to another repo,
|
12
|
+
# it gets the inserts out of that repo's tests, not our own.
|
13
|
+
return resource_filename(Project.PACKAGE_NAME, filename)
|
14
|
+
|
15
|
+
|
16
|
+
class ProjectRegistry:
|
17
|
+
|
18
|
+
SHOW_HERALD_WHEN_INITIALIZED = True
|
19
|
+
|
20
|
+
REGISTERED_PROJECTS = {}
|
21
|
+
|
22
|
+
# All of these might never be other than None so be careful when accessing them.
|
23
|
+
APPLICATION_PROJECT_HOME = None
|
24
|
+
PYPROJECT_TOML_FILE = None
|
25
|
+
PYPROJECT_TOML = None
|
26
|
+
POETRY_DATA = None
|
27
|
+
# This is expected to ultimately be set properly.
|
28
|
+
_PYPROJECT_NAME = None
|
29
|
+
|
30
|
+
@classproperty
|
31
|
+
def PYPROJECT_NAME(cls) -> str: # noQA - PyCharm thinks this should be 'self'
|
32
|
+
if cls._PYPROJECT_NAME is None:
|
33
|
+
cls.initialize_pyproject_name()
|
34
|
+
result: Optional[str] = cls._PYPROJECT_NAME
|
35
|
+
if result is None:
|
36
|
+
raise ValueError(f"ProjectRegistry.PROJECT_NAME not initialized properly.")
|
37
|
+
return result
|
38
|
+
|
39
|
+
@classmethod
|
40
|
+
def initialize_pyproject_name(cls, project_home=None, pyproject_toml_file=None):
|
41
|
+
if cls._PYPROJECT_NAME is None:
|
42
|
+
# This isn't the home of snovault, but the home of the snovault-based application.
|
43
|
+
# So in CGAP, for example, this would want to be the home of the CGAP application.
|
44
|
+
# If not set, it will be assumed that the current working directory is that.
|
45
|
+
if not project_home:
|
46
|
+
project_home = os.environ.get("APPLICATION_PROJECT_HOME", os.path.abspath(os.curdir))
|
47
|
+
cls.APPLICATION_PROJECT_HOME = project_home
|
48
|
+
if not pyproject_toml_file:
|
49
|
+
expected_pyproject_toml_file = os.path.join(project_home, "pyproject.toml")
|
50
|
+
pyproject_toml_file = (expected_pyproject_toml_file
|
51
|
+
if os.path.exists(expected_pyproject_toml_file)
|
52
|
+
else None)
|
53
|
+
cls.PYPROJECT_TOML_FILE = pyproject_toml_file
|
54
|
+
cls.PYPROJECT_TOML = pyproject_toml = (toml.load(cls.PYPROJECT_TOML_FILE)
|
55
|
+
if cls.PYPROJECT_TOML_FILE
|
56
|
+
else None)
|
57
|
+
cls.POETRY_DATA = (pyproject_toml['tool']['poetry']
|
58
|
+
if pyproject_toml
|
59
|
+
else None)
|
60
|
+
|
61
|
+
declared_pyproject_name = os.environ.get("APPLICATION_PYPROJECT_NAME")
|
62
|
+
inferred_pyproject_name = cls.POETRY_DATA['name'] if cls.POETRY_DATA else None
|
63
|
+
if (declared_pyproject_name and inferred_pyproject_name
|
64
|
+
and declared_pyproject_name != inferred_pyproject_name):
|
65
|
+
raise RuntimeError(f"APPLICATION_PYPROJECT_NAME={declared_pyproject_name!r},"
|
66
|
+
f" but {pyproject_toml_file} says it should be {inferred_pyproject_name!r}")
|
67
|
+
|
68
|
+
cls._PYPROJECT_NAME = declared_pyproject_name or inferred_pyproject_name
|
69
|
+
|
70
|
+
@classmethod
|
71
|
+
def register(cls, name):
|
72
|
+
"""
|
73
|
+
Registers a class to be used based on the name in the top of pyproject.toml.
|
74
|
+
Note that this means that cgap-portal and fourfront will both register as 'encoded',
|
75
|
+
as in:
|
76
|
+
|
77
|
+
@Project.register('encoded')
|
78
|
+
class FourfrontProject(EncodedCoreProject):
|
79
|
+
PRETTY_NAME = "Fourfront"
|
80
|
+
|
81
|
+
Since fourfront and cgap-portal don't occupy the same space, no confusion should result.
|
82
|
+
"""
|
83
|
+
def _wrap_class(the_class):
|
84
|
+
the_class_name = the_class.__name__
|
85
|
+
if not issubclass(the_class, Project):
|
86
|
+
raise ValueError(f"The class {the_class_name} must inherit from Project.")
|
87
|
+
lower_registry_name = name.lower()
|
88
|
+
for x in ['cgap-portal', 'fourfront', 'smaht']:
|
89
|
+
if x in lower_registry_name:
|
90
|
+
# It's an easy error to make, but the name of the project from which we're gaining foothold
|
91
|
+
# in pyproject.toml is 'encoded', not 'cgap-portal', etc., so the name 'encoded' will be
|
92
|
+
# needed for bootstrapping. So it should look like
|
93
|
+
# -kmp 15-May-2023
|
94
|
+
raise ValueError(f"Please use ProjectRegistry.register('encoded'),"
|
95
|
+
f" not ProjectRegistry.register({name!r})."
|
96
|
+
f" This registration is just for bootstrapping."
|
97
|
+
f" The class can still be {the_class_name}.")
|
98
|
+
cls.REGISTERED_PROJECTS[name] = the_class
|
99
|
+
return the_class
|
100
|
+
return _wrap_class
|
101
|
+
|
102
|
+
@classmethod
|
103
|
+
def _lookup(cls, name):
|
104
|
+
"""
|
105
|
+
Returns the project object with the given name.
|
106
|
+
|
107
|
+
:param name: a string name that was used in a ProjectRegistry.register decorator
|
108
|
+
|
109
|
+
NOTE: There is no need for this function to be called outside of this class except for testing.
|
110
|
+
Really only one of these should be instantiated per running application, and that's
|
111
|
+
done automatically by this class.
|
112
|
+
"""
|
113
|
+
project_class = cls.REGISTERED_PROJECTS.get(name)
|
114
|
+
return project_class
|
115
|
+
|
116
|
+
@classmethod
|
117
|
+
def _make_project(cls):
|
118
|
+
"""
|
119
|
+
Creates and returns an instantiated project object for the current project.
|
120
|
+
|
121
|
+
The project to use can be specified by setting the environment variable APPLICATION_PROJECT_HOME
|
122
|
+
to a particular directory that contains the pyproject.toml file to use.
|
123
|
+
If no such variable is set, the current working directory is used.
|
124
|
+
|
125
|
+
NOTE: There is no need for this function to be called outside of this class except for testing.
|
126
|
+
Really only one of these should be instantiated per running application, and that's
|
127
|
+
done automatically by this class.
|
128
|
+
"""
|
129
|
+
project_class = cls._lookup(cls.PYPROJECT_NAME)
|
130
|
+
assert issubclass(project_class, Project)
|
131
|
+
project: Project = project_class()
|
132
|
+
return project # instantiate and return
|
133
|
+
|
134
|
+
_app_project = None
|
135
|
+
_initialized = False
|
136
|
+
|
137
|
+
@classmethod
|
138
|
+
def initialize(cls):
|
139
|
+
if cls._initialized:
|
140
|
+
raise RuntimeError(f"{cls.__name__}.initialize() was called more than once.")
|
141
|
+
cls._app_project = cls._make_project()
|
142
|
+
cls._initalized = True
|
143
|
+
if cls.SHOW_HERALD_WHEN_INITIALIZED:
|
144
|
+
cls.show_herald()
|
145
|
+
app_project: Project = cls.app_project
|
146
|
+
return app_project # It's initialized now, so we use the proper interface
|
147
|
+
|
148
|
+
@classmethod
|
149
|
+
def show_herald(cls):
|
150
|
+
app_project = cls.app_project_maker()
|
151
|
+
|
152
|
+
print("=" * 80)
|
153
|
+
print(f"APPLICATION_PROJECT_HOME == {cls.APPLICATION_PROJECT_HOME!r}")
|
154
|
+
print(f"PYPROJECT_TOML_FILE == {cls.PYPROJECT_TOML_FILE!r}")
|
155
|
+
print(f"PYPROJECT_NAME == {cls.PYPROJECT_NAME!r}")
|
156
|
+
the_app_project = Project.app_project
|
157
|
+
the_app_project_class = the_app_project.__class__
|
158
|
+
the_app_project_class_name = the_app_project_class.__name__
|
159
|
+
assert (Project.app_project
|
160
|
+
== app_project()
|
161
|
+
== the_app_project_class.app_project
|
162
|
+
== the_app_project.app_project), (
|
163
|
+
"Project consistency check failed."
|
164
|
+
)
|
165
|
+
print(f"{the_app_project_class_name}.app_project == Project.app_project == app_project() == {app_project()!r}")
|
166
|
+
print(f"app_project().NAME == {app_project().NAME!r}")
|
167
|
+
print(f"app_project().PRETTY_NAME == {app_project().PRETTY_NAME!r}")
|
168
|
+
print(f"app_project().PACKAGE_NAME == {app_project().PACKAGE_NAME!r}")
|
169
|
+
print(f"app_project().APP_NAME == {app_project().APP_NAME!r}")
|
170
|
+
print(f"app_project().APP_PRETTY_NAME == {app_project().APP_PRETTY_NAME!r}")
|
171
|
+
print("=" * 80)
|
172
|
+
|
173
|
+
@classproperty
|
174
|
+
def app_project(cls): # noQA - PyCharm thinks we should use 'self'
|
175
|
+
"""
|
176
|
+
Once the project is initialized, ProjectRegistry.app_project returns the application object
|
177
|
+
that should be used to dispatch project-dependent behavior.
|
178
|
+
"""
|
179
|
+
if cls._app_project is None:
|
180
|
+
# You need to put a call to
|
181
|
+
raise RuntimeError(f"Attempt to access {cls.__name__}.project before .initialize() called.")
|
182
|
+
return cls._app_project
|
183
|
+
|
184
|
+
@classmethod
|
185
|
+
def app_project_maker(cls):
|
186
|
+
|
187
|
+
def app_project(initialize=False, initialization_options: Optional[dict] = None):
|
188
|
+
if initialize:
|
189
|
+
Project.initialize_app_project(**(initialization_options or {}))
|
190
|
+
return ProjectRegistry.app_project
|
191
|
+
|
192
|
+
return app_project
|
193
|
+
|
194
|
+
|
195
|
+
class Project:
|
196
|
+
"""
|
197
|
+
A class that should be a superclass of all classes registered using ProjectRegistry.register
|
198
|
+
|
199
|
+
All such classes have these names:
|
200
|
+
.NAME - The name of the project in pyproject.toml
|
201
|
+
.PACKAGE_NAME - The pypi name of the project, useful for pkg_resources, for example.
|
202
|
+
.PRETTY_NAME - The pretty name of the package name
|
203
|
+
.APP_NAME - The ame of the project application (see dcicutils.common and the orchestrated app in EnvUtils)
|
204
|
+
.APP_PRETTY_NAME - The pretty name of the project application.
|
205
|
+
|
206
|
+
Some sample usess of pre-defined attributes of a Project that may help motivate the choice of attribute names:
|
207
|
+
|
208
|
+
registered |
|
209
|
+
name | NAME | PACKAGE_NAME | PRETTY NAME | APP_NAME | APP_PRETTY_NAME
|
210
|
+
-------------+--------------+----------------+--------------+-----------+----------------
|
211
|
+
snovault | dcicsnovault | snovault | Snovault | snovault | Snovault
|
212
|
+
encoded-core | encoded-core | encoded-core | Encoded Core | core | Core
|
213
|
+
encoded | cgap-portal | cgap-portal | CGAP Portal | cgap | CGAP
|
214
|
+
encoded | fourfront | fourfront | Fourfront | fourfront | Fourfront
|
215
|
+
encoded | smaht-portal | smaht-portal | SMaHT Portal | smaht | SMaHT
|
216
|
+
|
217
|
+
The registered name is the one used with the ProjectRegistry.register() decorator.
|
218
|
+
"""
|
219
|
+
|
220
|
+
NAME = 'project'
|
221
|
+
|
222
|
+
@classmethod
|
223
|
+
def _prettify(cls, name):
|
224
|
+
return name.title().replace("Cgap", "CGAP").replace("Smaht", "SMaHT").replace("-", " ")
|
225
|
+
|
226
|
+
@classproperty
|
227
|
+
def PACKAGE_NAME(cls): # noQA - PyCharm wants the variable name to be self
|
228
|
+
return cls.NAME.replace('dcic', '')
|
229
|
+
|
230
|
+
@classproperty
|
231
|
+
def PRETTY_NAME(cls): # noQA - PyCharm wants the variable name to be self
|
232
|
+
return cls._prettify(cls.PACKAGE_NAME)
|
233
|
+
|
234
|
+
@classproperty
|
235
|
+
def APP_NAME(cls): # noQA - PyCharm wants the variable name to be self
|
236
|
+
return cls.PACKAGE_NAME.replace('-portal', '').replace('encoded-', '')
|
237
|
+
|
238
|
+
@classproperty
|
239
|
+
def APP_PRETTY_NAME(cls): # noQA - PyCharm wants the variable name to be self
|
240
|
+
return cls._prettify(cls.APP_NAME)
|
241
|
+
|
242
|
+
@classproperty
|
243
|
+
def app_project(cls): # noQA - PyCharm wants the variable name to be self
|
244
|
+
"""
|
245
|
+
Project.app_project returns the actual instantiated project for app-specific behavior,
|
246
|
+
which might be of this class or one of its subclasses.
|
247
|
+
|
248
|
+
This access will fail if the project has not been initialized.
|
249
|
+
"""
|
250
|
+
return ProjectRegistry.app_project
|
251
|
+
|
252
|
+
@classmethod
|
253
|
+
def initialize_app_project(cls, initialize_env_utils=True):
|
254
|
+
if initialize_env_utils:
|
255
|
+
EnvUtils.init()
|
256
|
+
project: Project = ProjectRegistry.initialize()
|
257
|
+
return project
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[tool.poetry]
|
2
2
|
name = "dcicutils"
|
3
|
-
version = "7.4.2"
|
3
|
+
version = "7.4.2.1b0" # to become 7.5.0
|
4
4
|
description = "Utility package for interacting with the 4DN Data Portal and other 4DN resources"
|
5
5
|
authors = ["4DN-DCIC Team <support@4dnucleome.org>"]
|
6
6
|
license = "MIT"
|
@@ -38,7 +38,7 @@ entry_points = \
|
|
38
38
|
|
39
39
|
setup_kwargs = {
|
40
40
|
'name': 'dcicutils',
|
41
|
-
'version': '7.4.2',
|
41
|
+
'version': '7.4.2.1b0',
|
42
42
|
'description': 'Utility package for interacting with the 4DN Data Portal and other 4DN resources',
|
43
43
|
'long_description': '=====\nutils\n=====\n\nCheck out our full documentation `here <https://dcic-utils.readthedocs.io/en/latest/>`_\n\nThis repository contains various utility modules shared amongst several projects in the 4DN-DCIC. It is meant to be used internally by the DCIC team and externally as a Python API to `Fourfront <https://data.4dnucleome.org>`_\\ , the 4DN data portal.\n\npip installable as the ``dcicutils`` package with: ``pip install dcicutils``\n\nSee `this document <https://dcic-utils.readthedocs.io/en/latest/getting_started.html>`_ for tips on getting started. `Go here <https://dcic-utils.readthedocs.io/en/latest/examples.html>`_ for examples of some of the most useful functions.\n\n\n.. image:: https://travis-ci.org/4dn-dcic/utils.svg?branch=master\n :target: https://travis-ci.org/4dn-dcic/utils\n :alt: Build Status\n\n\n.. image:: https://coveralls.io/repos/github/4dn-dcic/utils/badge.svg?branch=master\n :target: https://coveralls.io/github/4dn-dcic/utils?branch=master\n :alt: Coverage\n\n.. image:: https://readthedocs.org/projects/dcic-utils/badge/?version=latest\n :target: https://dcic-utils.readthedocs.io/en/latest/?badge=latest\n :alt: Documentation Status\n',
|
44
44
|
'author': '4DN-DCIC Team',
|
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
|
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
|
File without changes
|
File without changes
|
File without changes
|