clarifai 11.2.0__py3-none-any.whl → 11.2.1__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.
clarifai/__init__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "11.2.0"
1
+ __version__ = "11.2.1"
clarifai/cli/base.py CHANGED
@@ -43,17 +43,10 @@ def cli(ctx):
43
43
  """Clarifai CLI"""
44
44
  ctx.ensure_object(dict)
45
45
  config_path = f"{os.getenv('HOME')}/.clarifai/config.yaml"
46
- config_dir = os.path.dirname(config_path)
47
46
  if os.path.exists(config_path):
48
47
  ctx.obj = from_yaml(config_path)
49
48
  else:
50
49
  ctx.obj = {}
51
- if ctx.invoked_subcommand != 'login':
52
- logger.error("Error getting config: CLI config file missing")
53
- logger.info("Running `login` to set up the CLI configuration.")
54
- if not os.path.exists(config_dir):
55
- os.makedirs(config_dir)
56
- ctx.invoke(login)
57
50
 
58
51
 
59
52
  @cli.command()
@@ -74,16 +67,16 @@ def login(ctx, config, env, user_id):
74
67
 
75
68
  if 'pat' in ctx.obj:
76
69
  os.environ["CLARIFAI_PAT"] = ctx.obj['pat']
77
- click.echo("Loaded PAT from config file.")
70
+ logger.info("Loaded PAT from config file.")
78
71
  elif 'CLARIFAI_PAT' in os.environ:
79
72
  ctx.obj['pat'] = os.environ["CLARIFAI_PAT"]
80
- click.echo("Loaded PAT from environment variable.")
73
+ logger.info("Loaded PAT from environment variable.")
81
74
  else:
82
75
  _pat = click.prompt(
83
76
  "Get your PAT from https://clarifai.com/settings/security and pass it here", type=str)
84
77
  os.environ["CLARIFAI_PAT"] = _pat
85
78
  ctx.obj['pat'] = _pat
86
- click.echo("PAT saved successfully.")
79
+ logger.info("PAT saved successfully.")
87
80
 
88
81
  if user_id:
89
82
  ctx.obj['user_id'] = user_id
@@ -97,7 +90,7 @@ def login(ctx, config, env, user_id):
97
90
  user_id = click.prompt("Pass the User ID here", type=str)
98
91
  os.environ["CLARIFAI_USER_ID"] = user_id
99
92
  ctx.obj['user_id'] = user_id
100
- click.echo("User ID saved successfully.")
93
+ logger.info("User ID saved successfully.")
101
94
 
102
95
  if env:
103
96
  ctx.obj['env'] = env
@@ -113,9 +106,14 @@ def login(ctx, config, env, user_id):
113
106
  ctx.obj['env'] = 'prod'
114
107
  ctx.obj['base_url'] = set_base_url(ctx.obj['env'])
115
108
  os.environ["CLARIFAI_API_BASE"] = ctx.obj['base_url']
116
- click.echo("Base URL saved successfully.")
109
+ logger.info("Base URL saved successfully.")
110
+
111
+ config_path = f"{os.getenv('HOME')}/.clarifai/config.yaml"
112
+ config_dir = os.path.dirname(config_path)
113
+ if not os.path.exists(config_dir):
114
+ os.makedirs(config_dir)
117
115
 
118
- dump_yaml(ctx.obj, f"{os.getenv('HOME')}/.clarifai/config.yaml")
116
+ dump_yaml(ctx.obj, config_path)
119
117
 
120
118
 
121
119
  # Import the CLI commands to register them
@@ -1,7 +1,8 @@
1
1
  import click
2
+
2
3
  from clarifai.cli.base import cli
3
4
  from clarifai.client.user import User
4
- from clarifai.utils.cli import display_co_resources
5
+ from clarifai.utils.cli import display_co_resources, validate_context
5
6
 
6
7
 
7
8
  @cli.group(['computecluster', 'cc'])
@@ -24,6 +25,8 @@ def computecluster():
24
25
  @click.pass_context
25
26
  def create(ctx, config, compute_cluster_id):
26
27
  """Create a new Compute Cluster with the given config file."""
28
+
29
+ validate_context(ctx)
27
30
  user = User(user_id=ctx.obj['user_id'], pat=ctx.obj['pat'], base_url=ctx.obj['base_url'])
28
31
  if compute_cluster_id:
29
32
  user.create_compute_cluster(config, compute_cluster_id=compute_cluster_id)
@@ -37,6 +40,8 @@ def create(ctx, config, compute_cluster_id):
37
40
  @click.pass_context
38
41
  def list(ctx, page_no, per_page):
39
42
  """List all compute clusters for the user."""
43
+
44
+ validate_context(ctx)
40
45
  user = User(user_id=ctx.obj['user_id'], pat=ctx.obj['pat'], base_url=ctx.obj['base_url'])
41
46
  response = user.list_compute_clusters(page_no, per_page)
42
47
  display_co_resources(response, "Compute Cluster")
@@ -47,5 +52,7 @@ def list(ctx, page_no, per_page):
47
52
  @click.pass_context
48
53
  def delete(ctx, compute_cluster_id):
49
54
  """Deletes a compute cluster for the user."""
55
+
56
+ validate_context(ctx)
50
57
  user = User(user_id=ctx.obj['user_id'], pat=ctx.obj['pat'], base_url=ctx.obj['base_url'])
51
58
  user.delete_compute_clusters([compute_cluster_id])
@@ -1,7 +1,7 @@
1
1
  import click
2
2
  from clarifai.cli.base import cli
3
3
  from clarifai.client.nodepool import Nodepool
4
- from clarifai.utils.cli import display_co_resources, from_yaml
4
+ from clarifai.utils.cli import display_co_resources, from_yaml, validate_context
5
5
 
6
6
 
7
7
  @cli.group(['deployment', 'dpl'])
@@ -29,6 +29,8 @@ def deployment():
29
29
  @click.pass_context
30
30
  def create(ctx, nodepool_id, config, deployment_id):
31
31
  """Create a new Deployment with the given config file."""
32
+
33
+ validate_context(ctx)
32
34
  if not nodepool_id:
33
35
  deployment_config = from_yaml(config)
34
36
  nodepool_id = deployment_config['deployment']['nodepools'][0]['id']
@@ -56,6 +58,7 @@ def create(ctx, nodepool_id, config, deployment_id):
56
58
  def list(ctx, nodepool_id, page_no, per_page):
57
59
  """List all deployments for the nodepool."""
58
60
 
61
+ validate_context(ctx)
59
62
  nodepool = Nodepool(
60
63
  nodepool_id=nodepool_id,
61
64
  user_id=ctx.obj['user_id'],
@@ -76,6 +79,7 @@ def list(ctx, nodepool_id, page_no, per_page):
76
79
  def delete(ctx, nodepool_id, deployment_id):
77
80
  """Deletes a deployment for the nodepool."""
78
81
 
82
+ validate_context(ctx)
79
83
  nodepool = Nodepool(
80
84
  nodepool_id=nodepool_id,
81
85
  user_id=ctx.obj['user_id'],
clarifai/cli/model.py CHANGED
@@ -96,11 +96,14 @@ def download_checkpoints(model_path, out_path, stage):
96
96
  help=
97
97
  'Keep the Docker image after testing the model locally (applicable for container mode). Defaults to False.'
98
98
  )
99
- def test_locally(model_path, keep_env=False, keep_image=False, mode='env'):
100
- """Test model locally.
101
-
102
- MODEL_PATH: Path to the model directory. If not specified, the current directory is used by default.
103
- """
99
+ @click.option(
100
+ '--skip_dockerfile',
101
+ is_flag=True,
102
+ help=
103
+ 'Flag to skip generating a dockerfile so that you can manually edit an already created dockerfile. Apply for `--mode conatainer`.',
104
+ )
105
+ def test_locally(model_path, keep_env=False, keep_image=False, mode='env', skip_dockerfile=False):
106
+ """Test model locally."""
104
107
  try:
105
108
  from clarifai.runners.models import model_run_locally
106
109
  if mode == 'env' and keep_image:
@@ -114,7 +117,11 @@ def test_locally(model_path, keep_env=False, keep_image=False, mode='env'):
114
117
  elif mode == "container":
115
118
  click.echo("Testing model locally inside a container...")
116
119
  model_run_locally.main(
117
- model_path, inside_container=True, run_model_server=False, keep_image=keep_image)
120
+ model_path,
121
+ inside_container=True,
122
+ run_model_server=False,
123
+ keep_image=keep_image,
124
+ skip_dockerfile=skip_dockerfile)
118
125
  click.echo("Model tested successfully.")
119
126
  except Exception as e:
120
127
  click.echo(f"Failed to test model locally: {e}", err=True)
@@ -154,11 +161,14 @@ def test_locally(model_path, keep_env=False, keep_image=False, mode='env'):
154
161
  help=
155
162
  'Keep the Docker image after testing the model locally (applicable for container mode). Defaults to False.'
156
163
  )
157
- def run_locally(model_path, port, mode, keep_env, keep_image):
158
- """Run the model locally and start a gRPC server to serve the model.
159
-
160
- MODEL_PATH: Path to the model directory. If not specified, the current directory is used by default.
161
- """
164
+ @click.option(
165
+ '--skip_dockerfile',
166
+ is_flag=True,
167
+ help=
168
+ 'Flag to skip generating a dockerfile so that you can manually edit an already created dockerfile. Apply for `--mode conatainer`.',
169
+ )
170
+ def run_locally(model_path, port, mode, keep_env, keep_image, skip_dockerfile=False):
171
+ """Run the model locally and start a gRPC server to serve the model."""
162
172
  try:
163
173
  from clarifai.runners.models import model_run_locally
164
174
  if mode == 'env' and keep_image:
@@ -176,7 +186,8 @@ def run_locally(model_path, port, mode, keep_env, keep_image):
176
186
  inside_container=True,
177
187
  run_model_server=True,
178
188
  port=port,
179
- keep_image=keep_image)
189
+ keep_image=keep_image,
190
+ skip_dockerfile=skip_dockerfile)
180
191
  click.echo(f"Model server started locally from {model_path} in {mode} mode.")
181
192
  except Exception as e:
182
193
  click.echo(f"Failed to starts model server locally: {e}", err=True)
@@ -230,7 +241,8 @@ def predict(ctx, config, model_id, user_id, app_id, model_url, file_path, url, b
230
241
  import json
231
242
 
232
243
  from clarifai.client.model import Model
233
- from clarifai.utils.cli import from_yaml
244
+ from clarifai.utils.cli import from_yaml, validate_context
245
+ validate_context(ctx)
234
246
  if config:
235
247
  config = from_yaml(config)
236
248
  model_id, user_id, app_id, model_url, file_path, url, bytes, input_type, compute_cluster_id, nodepool_id, deployment_id, inference_params, output_config = (
clarifai/cli/nodepool.py CHANGED
@@ -1,7 +1,7 @@
1
1
  import click
2
2
  from clarifai.cli.base import cli
3
3
  from clarifai.client.compute_cluster import ComputeCluster
4
- from clarifai.utils.cli import display_co_resources, dump_yaml, from_yaml
4
+ from clarifai.utils.cli import display_co_resources, dump_yaml, from_yaml, validate_context
5
5
 
6
6
 
7
7
  @cli.group(['nodepool', 'np'])
@@ -27,6 +27,7 @@ def nodepool():
27
27
  def create(ctx, compute_cluster_id, config, nodepool_id):
28
28
  """Create a new Nodepool with the given config file."""
29
29
 
30
+ validate_context(ctx)
30
31
  nodepool_config = from_yaml(config)
31
32
  if not compute_cluster_id:
32
33
  if 'compute_cluster' not in nodepool_config['nodepool']:
@@ -63,6 +64,7 @@ def create(ctx, compute_cluster_id, config, nodepool_id):
63
64
  def list(ctx, compute_cluster_id, page_no, per_page):
64
65
  """List all nodepools for the user."""
65
66
 
67
+ validate_context(ctx)
66
68
  compute_cluster = ComputeCluster(
67
69
  compute_cluster_id=compute_cluster_id,
68
70
  user_id=ctx.obj['user_id'],
@@ -83,6 +85,7 @@ def list(ctx, compute_cluster_id, page_no, per_page):
83
85
  def delete(ctx, compute_cluster_id, nodepool_id):
84
86
  """Deletes a nodepool for the user."""
85
87
 
88
+ validate_context(ctx)
86
89
  compute_cluster = ComputeCluster(
87
90
  compute_cluster_id=compute_cluster_id,
88
91
  user_id=ctx.obj['user_id'],
@@ -473,7 +473,8 @@ def main(model_path,
473
473
  inside_container=False,
474
474
  port=8080,
475
475
  keep_env=False,
476
- keep_image=False):
476
+ keep_image=False,
477
+ skip_dockerfile: bool = False):
477
478
 
478
479
  manager = ModelRunLocally(model_path)
479
480
  # get whatever stage is in config.yaml to force download now
@@ -484,10 +485,13 @@ def main(model_path,
484
485
  if inside_container:
485
486
  if not manager.is_docker_installed():
486
487
  sys.exit(1)
487
- manager.builder.create_dockerfile()
488
+ if not skip_dockerfile:
489
+ manager.builder.create_dockerfile()
488
490
  image_tag = manager._docker_hash()
489
- image_name = f"{manager.config['model']['id']}:{image_tag}"
490
- container_name = manager.config['model']['id']
491
+ model_id = manager.config['model']['id'].lower()
492
+ # must be in lowercase
493
+ image_name = f"{model_id}:{image_tag}"
494
+ container_name = model_id
491
495
  if not manager.docker_image_exists(image_name):
492
496
  manager.build_docker_image(image_name=image_name)
493
497
  try:
clarifai/utils/cli.py CHANGED
@@ -1,6 +1,7 @@
1
1
  import importlib
2
2
  import os
3
3
  import pkgutil
4
+ import sys
4
5
 
5
6
  import click
6
7
  import yaml
@@ -10,6 +11,8 @@ from rich.panel import Panel
10
11
  from rich.style import Style
11
12
  from rich.text import Text
12
13
 
14
+ from clarifai.utils.logging import logger
15
+
13
16
 
14
17
  def from_yaml(filename: str):
15
18
  try:
@@ -68,3 +71,9 @@ def display_co_resources(response, resource_type):
68
71
  border_style="green",
69
72
  width=60)
70
73
  console.print(panel)
74
+
75
+
76
+ def validate_context(ctx):
77
+ if ctx.obj == {}:
78
+ logger.error("CLI config file missing. Run `clarifai login` to set up the CLI config.")
79
+ sys.exit(1)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: clarifai
3
- Version: 11.2.0
3
+ Version: 11.2.1
4
4
  Summary: Clarifai Python SDK
5
5
  Home-page: https://github.com/Clarifai/clarifai-python
6
6
  Author: Clarifai
@@ -20,7 +20,7 @@ Classifier: Operating System :: OS Independent
20
20
  Requires-Python: >=3.8
21
21
  Description-Content-Type: text/markdown
22
22
  License-File: LICENSE
23
- Requires-Dist: clarifai-grpc>=11.2.5
23
+ Requires-Dist: clarifai-grpc>=11.2.6
24
24
  Requires-Dist: clarifai-protocol>=0.0.20
25
25
  Requires-Dist: numpy>=1.22.0
26
26
  Requires-Dist: tqdm>=4.65.0
@@ -1,15 +1,15 @@
1
- clarifai/__init__.py,sha256=VIaU72qq7Ra35KV6zKPuIujD7yQXELMsD6Ypm1ZDIMU,23
1
+ clarifai/__init__.py,sha256=R3NVFNSpKk1o0N9GhBBuvfPhVFPrY5oLJJk5xhzNpGY,23
2
2
  clarifai/cli.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  clarifai/errors.py,sha256=RwzTajwds51wLD0MVlMC5kcpBnzRpreDLlazPSBZxrg,2605
4
4
  clarifai/versions.py,sha256=jctnczzfGk_S3EnVqb2FjRKfSREkNmvNEwAAa_VoKiQ,222
5
5
  clarifai/cli/README.md,sha256=YGApHfeUyu5P0Pdth-mqQCQftWHDxz6bugDlvDXDhOE,1942
6
6
  clarifai/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
7
  clarifai/cli/__main__.py,sha256=utJ2F40cl0jPHcYdTlGZRqpPfZ0CtVYB-8Ft0b2fWD4,72
8
- clarifai/cli/base.py,sha256=OL8VAaxnCXLf1IMsn4_Ewx0CVEjWGh2qr9Yt-3bvo74,4031
9
- clarifai/cli/compute_cluster.py,sha256=N2dNQNJEPg9nxsb8x2igEzYuGRzjn7l4kNttjFIxmhI,1827
10
- clarifai/cli/deployment.py,sha256=sUEuz5-rtozMx8deVcJXLi6lHsP2jc8x3y2MpUAVfqY,2506
11
- clarifai/cli/model.py,sha256=9tSR_IiyZcSdTwrXOfv36MqaQ_61wLltpwsggh3yE4w,11677
12
- clarifai/cli/nodepool.py,sha256=yihxS_rIFoBBKzRlqBX8Ab42iPpBMJrJFsk8saph6ms,3049
8
+ clarifai/cli/base.py,sha256=SOAic4T6Hg7VJJ-UDdjTuTNI1Hu_YANmzW_giUjK24o,3853
9
+ clarifai/cli/compute_cluster.py,sha256=v77YUbZjmXbTq0wCmcUJ8TzYSfFEtB1na87-iZuG21Q,1921
10
+ clarifai/cli/deployment.py,sha256=Vv92Qo7Q3UmMiCdrGQ4qNVNVzfcDyl-GB6B7kx8gyFw,2597
11
+ clarifai/cli/model.py,sha256=PR-A7V3D78iAjNx2hNeputiWuIyINrx2SJmjKtfMoQ4,12079
12
+ clarifai/cli/nodepool.py,sha256=eYo3l9NMSwjeFzsuwKSYVkR1FdZ7_NcCdNvzGsBBMzY,3139
13
13
  clarifai/client/__init__.py,sha256=xI1U0l5AZdRThvQAXCLsd9axxyFzXXJ22m8LHqVjQRU,662
14
14
  clarifai/client/app.py,sha256=6pckYme1urV2YJjLIYfeZ-vH0Z5YSQa51jzIMcEfwug,38342
15
15
  clarifai/client/base.py,sha256=hSHOqkXbSKyaRDeylMMnkhUHCAHhEqno4KI0CXGziBA,7536
@@ -68,7 +68,7 @@ clarifai/runners/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG
68
68
  clarifai/runners/models/base_typed_model.py,sha256=0QCWxch8CcyJSKvE1D4PILd2RSnQZHTmx4DXlQQ6dpo,7856
69
69
  clarifai/runners/models/model_builder.py,sha256=YCnZsAIE0CB-M0c2cvdEzY4O11I80STshd36dqDAN2Q,32565
70
70
  clarifai/runners/models/model_class.py,sha256=9JSPAr4U4K7xI0kSl-q0mHB06zknm2OR-8XIgBCto94,1611
71
- clarifai/runners/models/model_run_locally.py,sha256=BNzn4h6ma6qA_7yeaPheJRoylssHx9ow5NeFRBWXuYg,20442
71
+ clarifai/runners/models/model_run_locally.py,sha256=hSkXrln4q1_EEtRyGH5g0nMg-ieGWmamD7cI5YV_qIk,20550
72
72
  clarifai/runners/models/model_runner.py,sha256=PyxwK-33hLlhkD07tTXkjWZ_iNlZHl9_8AZ2W7WfExI,6097
73
73
  clarifai/runners/models/model_servicer.py,sha256=jtQmtGeQlvQ5ttMvVw7CMnNzq-rLkTaxR2IWF9SnHwk,2808
74
74
  clarifai/runners/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -80,7 +80,7 @@ clarifai/runners/utils/url_fetcher.py,sha256=v_8JOWmkyFAzsBulsieKX7Nfjy1Yg7wGSZe
80
80
  clarifai/schema/search.py,sha256=JjTi8ammJgZZ2OGl4K6tIA4zEJ1Fr2ASZARXavI1j5c,2448
81
81
  clarifai/urls/helper.py,sha256=tjoMGGHuWX68DUB0pk4MEjrmFsClUAQj2jmVEM_Sy78,4751
82
82
  clarifai/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
83
- clarifai/utils/cli.py,sha256=CdcLsF00KdfA-BgMIbO-u88gUF9Ts1n0TDDZS-oImp8,1949
83
+ clarifai/utils/cli.py,sha256=P29JalmKQLQBWqbW2_bumCLNSUUo8APtLXD8zS0dcIk,2160
84
84
  clarifai/utils/constants.py,sha256=MG_iHnSwNEyUZOpvsrTicNwaT4CIjmlK_Ixk_qqEX8g,142
85
85
  clarifai/utils/logging.py,sha256=CVy8OsLrlbg-b8qe88kb1yO_9wi9wRYfF-QkIaN9xE8,11936
86
86
  clarifai/utils/misc.py,sha256=4aNOHPTNdX-WGxuNab8qKePoCMUnscd-aN_dQEIVSWk,2933
@@ -93,9 +93,9 @@ clarifai/workflows/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuF
93
93
  clarifai/workflows/export.py,sha256=vICRhIreqDSShxLKjHNM2JwzKsf1B4fdXB0ciMcA70k,1945
94
94
  clarifai/workflows/utils.py,sha256=nGeB_yjVgUO9kOeKTg4OBBaBz-AwXI3m-huSVj-9W18,1924
95
95
  clarifai/workflows/validate.py,sha256=yJq03MaJqi5AK3alKGJJBR89xmmjAQ31sVufJUiOqY8,2556
96
- clarifai-11.2.0.dist-info/licenses/LICENSE,sha256=mUqF_d12-qE2n41g7C5_sq-BMLOcj6CNN-jevr15YHU,555
97
- clarifai-11.2.0.dist-info/METADATA,sha256=RqwiHt12kWum-svcHdU-cy18o_ie4zH8JYKNtysR0FY,22472
98
- clarifai-11.2.0.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
99
- clarifai-11.2.0.dist-info/entry_points.txt,sha256=X9FZ4Z-i_r2Ud1RpZ9sNIFYuu_-9fogzCMCRUD9hyX0,51
100
- clarifai-11.2.0.dist-info/top_level.txt,sha256=wUMdCQGjkxaynZ6nZ9FAnvBUCgp5RJUVFSy2j-KYo0s,9
101
- clarifai-11.2.0.dist-info/RECORD,,
96
+ clarifai-11.2.1.dist-info/licenses/LICENSE,sha256=mUqF_d12-qE2n41g7C5_sq-BMLOcj6CNN-jevr15YHU,555
97
+ clarifai-11.2.1.dist-info/METADATA,sha256=te276wArqCAEYdsF-LYLQSTxMZiPtAVO_a2lEQngFNU,22472
98
+ clarifai-11.2.1.dist-info/WHEEL,sha256=DK49LOLCYiurdXXOXwGJm6U4DkHkg4lcxjhqwRa0CP4,91
99
+ clarifai-11.2.1.dist-info/entry_points.txt,sha256=X9FZ4Z-i_r2Ud1RpZ9sNIFYuu_-9fogzCMCRUD9hyX0,51
100
+ clarifai-11.2.1.dist-info/top_level.txt,sha256=wUMdCQGjkxaynZ6nZ9FAnvBUCgp5RJUVFSy2j-KYo0s,9
101
+ clarifai-11.2.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (77.0.3)
2
+ Generator: setuptools (78.0.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5