hmd-cli-python 0.2.74__py3-none-any.whl

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.
File without changes
@@ -0,0 +1,121 @@
1
+ import json
2
+ import os
3
+ from importlib.metadata import version
4
+
5
+ from cement import Controller, ex
6
+
7
+ from hmd_cli_tools.hmd_cli_tools import get_standard_parameters
8
+
9
+
10
+ VERSION_BANNER = """
11
+ hmd docker version: {}
12
+ """
13
+
14
+
15
+ class LocalController(Controller):
16
+ class Meta:
17
+ label = "python"
18
+
19
+ stacked_type = "nested"
20
+ stacked_on = "base"
21
+
22
+ # text displayed at the top of --help output
23
+ description = "Build and deploy python packages"
24
+
25
+ arguments = (
26
+ (
27
+ ["-v", "--version"],
28
+ {
29
+ "help": "Display the version of the python command.",
30
+ "action": "version",
31
+ "version": VERSION_BANNER.format(version("hmd_cli_python")),
32
+ },
33
+ ),
34
+ )
35
+
36
+ def _default(self):
37
+ """Default action if no sub-command is passed."""
38
+
39
+ self.app.args.print_help()
40
+
41
+ @ex(
42
+ help="login into multiple registries and edit pip config",
43
+ arguments=get_standard_parameters(["account"]),
44
+ )
45
+ def login(self):
46
+ from .hmd_cli_python import login as do_login
47
+
48
+ registries = os.environ.get("PYTHON_REGISTRIES", "{}")
49
+ default_username = os.environ.get("PIP_USERNAME")
50
+ default_password = os.environ.get("PIP_PASSWORD")
51
+ default_url = os.environ.get("PIP_EXTRA_INDEX_URL")
52
+
53
+ do_login(
54
+ hmd_region=self.app.pargs.hmd_region,
55
+ profile=self.app.pargs.profile,
56
+ registries=json.loads(registries),
57
+ default_username=default_username,
58
+ default_password=default_password,
59
+ default_url=default_url,
60
+ )
61
+
62
+ @ex(help="deploy a python package", arguments=[])
63
+ def publish(self):
64
+ from .hmd_cli_python import publish as do_publish
65
+
66
+ do_publish(repo_name=self.app.pargs.repo_name)
67
+
68
+ @ex(
69
+ label="build",
70
+ help="Execute unit tests and build package.",
71
+ arguments=[
72
+ (
73
+ ["-pco", "--pip-compile-only"],
74
+ {
75
+ "action": "store_true",
76
+ "dest": "pip_compile_only",
77
+ "default": False,
78
+ "required": False,
79
+ },
80
+ ),
81
+ (
82
+ ["-ur", "--upload-results"],
83
+ {
84
+ "action": "store_true",
85
+ "dest": "upload_results",
86
+ "default": False,
87
+ "required": False,
88
+ },
89
+ ),
90
+ ],
91
+ )
92
+ def build(self):
93
+ if not hasattr(self.app.pargs, "upload_results"):
94
+ self.app.pargs.upload_results = False
95
+ if not hasattr(self.app.pargs, "pip_compile_only"):
96
+ self.app.pargs.pip_compile_only = False
97
+
98
+ args = {
99
+ "repo_name": self.app.pargs.repo_name,
100
+ "command_name": self.Meta.label,
101
+ "upload_results": self.app.pargs.upload_results,
102
+ "pip_compile_only": self.app.pargs.pip_compile_only,
103
+ }
104
+
105
+ from .hmd_cli_python import build as do_build
106
+
107
+ do_build(**args)
108
+
109
+ @ex(label="install-local", help="Install Python package into local environment")
110
+ def install_local(self):
111
+ from .hmd_cli_python import install_local as do_install_local
112
+
113
+ do_install_local(repo_name=self.app.pargs.repo_name)
114
+
115
+ @ex(label="release", help="release a project to PyPI")
116
+ def release(self):
117
+ from .hmd_cli_python import release as do_release
118
+
119
+ do_release(
120
+ repo_name=self.app.pargs.repo_name, repo_version=self.app.pargs.repo_version
121
+ )
@@ -0,0 +1,329 @@
1
+ import os
2
+ from pathlib import Path
3
+ from base64 import b64decode
4
+ import shutil
5
+ from typing import Any, Dict, List
6
+ from urllib.parse import urlparse, urlunparse
7
+
8
+ from cement.utils import shell
9
+ from setuptools import find_packages
10
+
11
+ from hmd_cli_tools import cd, get_version
12
+ from hmd_cli_tools.build_tools import build_dir
13
+ from hmd_cli_tools.hmd_cli_tools import get_cloud_region, get_session
14
+
15
+
16
+ def publish(repo_name: str):
17
+ with build_dir(repo_name):
18
+ with cd("./src/python"):
19
+ exitcode = shell.exec_cmd2(
20
+ ["twine", "upload", "-r", "neuronsphere", "dist/*"]
21
+ )
22
+ if exitcode != 0:
23
+ raise Exception("Error uploading distribution.")
24
+
25
+
26
+ def update_setup_py(requirements: List[str]):
27
+ with open("setup.py", "r") as setup:
28
+ setup_data = setup.read().splitlines()
29
+
30
+ output = []
31
+ found = False
32
+ for line in setup_data:
33
+ if line.strip().startswith("install_requires=[]"):
34
+ found = True
35
+ indent = line.index("install")
36
+ output.append((" " * indent) + "install_requires=[")
37
+ for req in requirements:
38
+ if not req.strip().startswith("#"):
39
+ output.append((" " * (indent + 4)) + f'"{req}",')
40
+ output.append((" " * indent) + "]")
41
+ else:
42
+ output.append(line)
43
+ if not found:
44
+ raise Exception("setup.py doesn't contain an empty 'install_requires' line.")
45
+ with open("setup.py", "w") as setup:
46
+ setup.writelines(f"{line}\n" for line in output)
47
+
48
+
49
+ def compile_requirements():
50
+ compiled_deps = None
51
+ if os.path.exists("requirements.in"):
52
+ req_file = Path(os.getcwd()) / "requirements.in"
53
+ command = [
54
+ "pip-compile-multi",
55
+ "-d",
56
+ os.getcwd(),
57
+ "-t",
58
+ req_file,
59
+ "--no-upgrade",
60
+ "--no-annotate-index",
61
+ "-c",
62
+ "hmd-*",
63
+ ]
64
+
65
+ compiled_deps, stderr, exitcode = shell.exec_cmd(command)
66
+ if exitcode != 0:
67
+ raise Exception(f"Error evaluating dependencies. ({stderr.decode()})")
68
+
69
+ with open("requirements.txt", "r") as fl:
70
+ compiled_deps = fl.read().splitlines()
71
+
72
+ return compiled_deps
73
+
74
+
75
+ def fetch_codeartifact_token(
76
+ hmd_region: str, profile: str, domain: str, account: str, repository: str
77
+ ):
78
+ aws_region = get_cloud_region(hmd_region)
79
+ session = get_session(aws_region, profile)
80
+ client = session.client("codeartifact")
81
+
82
+ response = client.get_authorization_token(domain=domain, domainOwner=account)
83
+ token = response["authorizationToken"]
84
+ return token
85
+
86
+
87
+ def login(
88
+ hmd_region: str,
89
+ profile: str,
90
+ registries: Dict[str, Any],
91
+ default_username: str,
92
+ default_password: str,
93
+ default_url: str,
94
+ ):
95
+ pip_conf_name = Path.home() / ".config" / "pip" / "pip.conf"
96
+
97
+ if os.name == "nt":
98
+ pip_conf_name = Path.home() / ".pip" / "pip.ini"
99
+
100
+ pip_conf_name = Path(os.environ.get("PIP_CONFIG_FILE", pip_conf_name))
101
+
102
+ if not os.path.exists(pip_conf_name):
103
+ pip_conf_name.parent.mkdir(parents=True, exist_ok=True)
104
+
105
+ extra_index_urls = []
106
+ registry_urls = []
107
+ twine_urls = []
108
+
109
+ for registry, config in registries.items():
110
+ registry_type = config.get("type", None)
111
+
112
+ if "url" not in config:
113
+ raise Exception(f"Invalid configuration in PYTHON_REGISTRIES: {registry}")
114
+
115
+ url_parts = urlparse(config["url"])
116
+ registry_urls.append(url_parts.hostname)
117
+ print(config["url"], url_parts)
118
+
119
+ if registry_type == "codeartifact":
120
+ token = fetch_codeartifact_token(
121
+ hmd_region,
122
+ profile,
123
+ config["domain"],
124
+ config["account"],
125
+ config["repository"],
126
+ )
127
+
128
+ if config.get("publish", False):
129
+ twine_urls.append(
130
+ (
131
+ urlunparse(
132
+ url_parts._replace(
133
+ path=url_parts.path.replace("simple/", "")
134
+ )
135
+ ),
136
+ "aws",
137
+ token,
138
+ )
139
+ )
140
+
141
+ url_parts = url_parts._replace(netloc=f"aws:{token}@{url_parts.hostname}")
142
+ extra_index_urls.append(urlunparse(url_parts))
143
+ else:
144
+ username = config["username"]
145
+ password = config["password"]
146
+
147
+ if config.get("publish", False):
148
+ twine_urls.append(
149
+ (
150
+ urlunparse(
151
+ url_parts._replace(
152
+ path=url_parts.path.replace("simple/", "")
153
+ )
154
+ ),
155
+ username,
156
+ password,
157
+ )
158
+ )
159
+
160
+ url_parts = url_parts._replace(
161
+ netloc=f"{username}:{password}@{url_parts.hostname}"
162
+ )
163
+ extra_index_urls.append(urlunparse(url_parts))
164
+
165
+ data = []
166
+ if os.path.exists(pip_conf_name):
167
+ with open(pip_conf_name, "r") as pc:
168
+ data = pc.readlines()
169
+
170
+ extra_urls = []
171
+ extra_urls_line = False
172
+ for line in data:
173
+ if line.startswith("extra-index-url"):
174
+ _, urls = line.split("=")
175
+ extra_urls_str = urls.strip()
176
+ extra_urls_line = True
177
+
178
+ if len(extra_urls_str) > 0:
179
+ extra_urls = extra_urls_str.split(",")
180
+
181
+ if len(extra_urls) > 0:
182
+ break
183
+ else:
184
+ continue
185
+
186
+ if extra_urls_line:
187
+ url = line.strip()
188
+
189
+ if len(url) == 0 or url.startswith("["):
190
+ break
191
+ extra_urls.append(url)
192
+
193
+ existing_urls = list(
194
+ filter(lambda u: urlparse(u).hostname not in registry_urls, extra_urls)
195
+ )
196
+ extra_index_urls = [*existing_urls, *extra_index_urls]
197
+ extra_str = "\n ".join(extra_index_urls)
198
+ pip_conf = f"""
199
+ [global]
200
+ extra-index-url =
201
+ {extra_str}
202
+
203
+ """
204
+
205
+ with open(pip_conf_name, "w") as pc:
206
+ pc.write(pip_conf)
207
+
208
+ if len(twine_urls) > 0:
209
+ if not os.path.exists(Path.home() / ".pypirc"):
210
+ with open(Path.home() / ".pypirc", "w") as twine:
211
+ cfg = f"""
212
+ [distutils]
213
+ index-servers =
214
+ neuronsphere
215
+
216
+ [neuronsphere]
217
+ repository = {twine_urls[0][0]}
218
+ username = {twine_urls[0][1]}
219
+ password = {twine_urls[0][2]}
220
+ """
221
+ twine.write(cfg)
222
+
223
+
224
+ def build(
225
+ command_name: str, repo_name: str, upload_results: bool, pip_compile_only: bool
226
+ ):
227
+ version = get_version()
228
+ if os.name == "nt":
229
+ py_cmd = "python"
230
+ else:
231
+ py_cmd = "python3"
232
+
233
+ repo_dir = os.getcwd()
234
+ with build_dir(repo_name):
235
+ with cd("./src/python"):
236
+ compiled_deps = compile_requirements()
237
+ reqs_txt_path = os.path.abspath("requirements.txt")
238
+ if os.path.exists(reqs_txt_path):
239
+ shutil.copy2(
240
+ reqs_txt_path,
241
+ os.path.join(repo_dir, "./src/python/requirements.txt"),
242
+ )
243
+
244
+ if pip_compile_only:
245
+ return
246
+
247
+ if compiled_deps:
248
+ update_setup_py(compiled_deps)
249
+
250
+ if os.path.exists("test"):
251
+ shell.exec_cmd2(["pip3", "install", "--force-reinstall", "-e", "."])
252
+ packages = find_packages()
253
+
254
+ command = [py_cmd, "-m", "pytest"]
255
+ for pkg in packages:
256
+ command += ["--cov", pkg]
257
+
258
+ command += ["--cov-report", "term"]
259
+ command += ["--cov-report", "html:coverage"]
260
+
261
+ exitcode = shell.exec_cmd2(command)
262
+
263
+ if exitcode != 0:
264
+ raise Exception("Error running unit tests.")
265
+
266
+ exitcode = shell.exec_cmd2([py_cmd, "setup.py", "bdist_wheel"])
267
+ if exitcode != 0:
268
+ raise Exception("Error creating distribution.")
269
+
270
+
271
+ def install_local(repo_name: str):
272
+ version = get_version()
273
+ if os.name == "nt":
274
+ py_cmd = "python"
275
+ else:
276
+ py_cmd = "python3"
277
+
278
+ with cd("./src/python"):
279
+ compiled_deps = compile_requirements()
280
+
281
+ print("Building python distribution...")
282
+ exitcode = shell.exec_cmd2([py_cmd, "setup.py", "sdist", "bdist_wheel"])
283
+ if exitcode != 0:
284
+ raise Exception("Error creating distribution.")
285
+
286
+ deps_install = ["pip3", "install", "-r", "requirements.txt"]
287
+ exitcode = shell.exec_cmd2(deps_install)
288
+
289
+ if exitcode != 0:
290
+ raise Exception("Error installing local Python package dependencies")
291
+
292
+ install_cmd = [
293
+ "pip3",
294
+ "install",
295
+ "--no-index",
296
+ "--no-deps",
297
+ "--force-reinstall",
298
+ "--find-links=./dist",
299
+ repo_name,
300
+ ]
301
+ print("Installing local package...")
302
+ exitcode = shell.exec_cmd2(install_cmd)
303
+
304
+ if exitcode != 0:
305
+ raise Exception("Error installing local Python package")
306
+
307
+
308
+ def release(repo_name: str, repo_version: str):
309
+ download_cmd = ["pip3", "download", f"{repo_name}=={repo_version}", "--no-deps"]
310
+
311
+ exitcode = shell.exec_cmd2(download_cmd)
312
+
313
+ if exitcode != 0:
314
+ raise Exception("Error downloading Python package")
315
+
316
+ wheels = list(Path(".").rglob(f"{repo_name.replace('-','_')}-{repo_version}-*.whl"))
317
+
318
+ whl = wheels[0]
319
+
320
+ upload_cmd = [
321
+ "twine",
322
+ "upload",
323
+ str(whl),
324
+ ]
325
+
326
+ exitcode = shell.exec_cmd2(upload_cmd)
327
+
328
+ if exitcode != 0:
329
+ raise Exception("Error uploading Python package")
@@ -0,0 +1,76 @@
1
+ Metadata-Version: 2.1
2
+ Name: hmd-cli-python
3
+ Version: 0.2.74
4
+ Summary: Implementation for python cli command
5
+ Home-page: UNKNOWN
6
+ Author: Jim Majure
7
+ Author-email: jim.majure@hmdlabs.io
8
+ License: Apache 2.0
9
+ Platform: UNKNOWN
10
+ Requires-Dist: attrs (==21.4.0)
11
+ Requires-Dist: aws-secretsmanager-caching (==1.1.1.5)
12
+ Requires-Dist: bleach (==4.1.0)
13
+ Requires-Dist: boto3 (==1.21.7)
14
+ Requires-Dist: botocore (==1.24.9)
15
+ Requires-Dist: cachetools (==5.2.0)
16
+ Requires-Dist: cement (==3.0.6)
17
+ Requires-Dist: certifi (==2022.12.7)
18
+ Requires-Dist: cffi (==1.15.0)
19
+ Requires-Dist: charset-normalizer (==2.0.12)
20
+ Requires-Dist: colorama (==0.4.4)
21
+ Requires-Dist: colorlog (==6.6.0)
22
+ Requires-Dist: coverage[toml] (==6.3.2)
23
+ Requires-Dist: cryptography (==39.0.1)
24
+ Requires-Dist: docutils (==0.18.1)
25
+ Requires-Dist: google-auth (==2.9.1)
26
+ Requires-Dist: hmd-cli-app (~=1.1.595)
27
+ Requires-Dist: hmd-cli-tools (~=1.1.227)
28
+ Requires-Dist: idna (==3.3)
29
+ Requires-Dist: importlib-metadata (==4.11.2)
30
+ Requires-Dist: iniconfig (==1.1.1)
31
+ Requires-Dist: inquirerpy (==0.3.4)
32
+ Requires-Dist: jeepney (==0.8.0)
33
+ Requires-Dist: jinja2 (==3.0.3)
34
+ Requires-Dist: jmespath (==0.10.0)
35
+ Requires-Dist: keyring (==23.5.0)
36
+ Requires-Dist: kubernetes (==24.2.0)
37
+ Requires-Dist: markupsafe (==2.1.0)
38
+ Requires-Dist: oauthlib (==3.2.2)
39
+ Requires-Dist: packaging (==21.3)
40
+ Requires-Dist: pfzy (==0.3.4)
41
+ Requires-Dist: pkginfo (==1.8.2)
42
+ Requires-Dist: pluggy (==1.0.0)
43
+ Requires-Dist: prompt-toolkit (==3.0.38)
44
+ Requires-Dist: py (==1.11.0)
45
+ Requires-Dist: pyasn1 (==0.4.8)
46
+ Requires-Dist: pyasn1-modules (==0.2.8)
47
+ Requires-Dist: pycparser (==2.21)
48
+ Requires-Dist: pygments (==2.14.0)
49
+ Requires-Dist: pyopenssl (==23.0.0)
50
+ Requires-Dist: pyparsing (==3.0.7)
51
+ Requires-Dist: pytest (==7.0.1)
52
+ Requires-Dist: pytest-cov (==3.0.0)
53
+ Requires-Dist: python-dateutil (==2.8.2)
54
+ Requires-Dist: python-dotenv (==0.19.2)
55
+ Requires-Dist: pyyaml (==6.0)
56
+ Requires-Dist: readme-renderer (==32.0)
57
+ Requires-Dist: requests (==2.28.2)
58
+ Requires-Dist: requests-oauthlib (==1.3.1)
59
+ Requires-Dist: requests-toolbelt (==0.9.1)
60
+ Requires-Dist: rfc3986 (==2.0.0)
61
+ Requires-Dist: rsa (==4.8)
62
+ Requires-Dist: s3transfer (==0.5.2)
63
+ Requires-Dist: secretstorage (==3.3.3)
64
+ Requires-Dist: six (==1.16.0)
65
+ Requires-Dist: tomli (==2.0.1)
66
+ Requires-Dist: tqdm (==4.63.0)
67
+ Requires-Dist: twine (==3.8.0)
68
+ Requires-Dist: urllib3 (==1.26.8)
69
+ Requires-Dist: wcwidth (==0.2.6)
70
+ Requires-Dist: webencodings (==0.5.1)
71
+ Requires-Dist: websocket-client (==1.3.3)
72
+ Requires-Dist: wheel (==0.38.0)
73
+ Requires-Dist: zipp (==3.7.0)
74
+
75
+ UNKNOWN
76
+
@@ -0,0 +1,7 @@
1
+ hmd_cli_python/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ hmd_cli_python/controller.py,sha256=VHaY1zMnTssbznWWkOWsq2PTZpovd4krDgwH_l3HJGI,3624
3
+ hmd_cli_python/hmd_cli_python.py,sha256=AmgT4OBX2qAnEAJ-Zgz7NQbV0bB0oZp646l7mgUTxw0,9749
4
+ hmd_cli_python-0.2.74.dist-info/METADATA,sha256=7X4utCWueIK6rPXO4SoP174ZOIv2f4YzFSu5L4T6GPs,2496
5
+ hmd_cli_python-0.2.74.dist-info/WHEEL,sha256=Ni9JGQXk2T4q02tFVwTZ-iAb8m9R1cjnSLMaE4VH1rg,92
6
+ hmd_cli_python-0.2.74.dist-info/top_level.txt,sha256=i2ZCGVJeOkzYWeWmczts0Y8Yv2QsTWcueX0_qWGbs7M,15
7
+ hmd_cli_python-0.2.74.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: bdist_wheel (0.38.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ hmd_cli_python