langtrace-python-sdk 3.3.2__py3-none-any.whl → 3.3.3__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,61 @@
1
+ from langtrace_python_sdk import langtrace, with_langtrace_root_span
2
+ import pymongo
3
+ import os
4
+ from dotenv import load_dotenv
5
+ from openai import OpenAI
6
+
7
+ load_dotenv()
8
+ langtrace.init(write_spans_to_console=False, batch=False)
9
+ MODEL = "text-embedding-ada-002"
10
+ openai_client = OpenAI()
11
+ client = pymongo.MongoClient(os.environ["MONGO_URI"])
12
+
13
+
14
+ # Define a function to generate embeddings
15
+ def get_embedding(text):
16
+ """Generates vector embeddings for the given text."""
17
+ embedding = (
18
+ openai_client.embeddings.create(input=[text], model=MODEL).data[0].embedding
19
+ )
20
+ return embedding
21
+
22
+
23
+ @with_langtrace_root_span("mongo-vector-search")
24
+ def vector_query():
25
+ db = client["sample_mflix"]
26
+
27
+ embedded_movies_collection = db["embedded_movies"]
28
+ # define pipeline
29
+ pipeline = [
30
+ {
31
+ "$vectorSearch": {
32
+ "index": "vector_index",
33
+ "path": "plot_embedding",
34
+ "queryVector": get_embedding("time travel"),
35
+ "numCandidates": 150,
36
+ "limit": 10,
37
+ }
38
+ },
39
+ {
40
+ "$project": {
41
+ "_id": 0,
42
+ "plot": 1,
43
+ "title": 1,
44
+ "score": {"$meta": "vectorSearchScore"},
45
+ }
46
+ },
47
+ ]
48
+
49
+ result = embedded_movies_collection.aggregate(pipeline)
50
+ for doc in result:
51
+ # print(doc)
52
+ pass
53
+
54
+
55
+ if __name__ == "__main__":
56
+ try:
57
+ vector_query()
58
+ except Exception as e:
59
+ print("error", e)
60
+ finally:
61
+ client.close()
@@ -34,6 +34,7 @@ SERVICE_PROVIDERS = {
34
34
  "EMBEDCHAIN": "Embedchain",
35
35
  "AUTOGEN": "Autogen",
36
36
  "XAI": "XAI",
37
+ "MONGODB": "MongoDB",
37
38
  "AWS_BEDROCK": "AWS Bedrock",
38
39
  "CEREBRAS": "Cerebras",
39
40
  }
@@ -0,0 +1,8 @@
1
+ APIS = {
2
+ "AGGREGATE": {
3
+ "MODULE": "pymongo.collection",
4
+ "METHOD": "Collection.aggregate",
5
+ "OPERATION": "aggregate",
6
+ "SPAN_NAME": "MongoDB Aggregate",
7
+ },
8
+ }
@@ -21,6 +21,7 @@ from .mistral import MistralInstrumentation
21
21
  from .aws_bedrock import AWSBedrockInstrumentation
22
22
  from .embedchain import EmbedchainInstrumentation
23
23
  from .litellm import LiteLLMInstrumentation
24
+ from .pymongo import PyMongoInstrumentation
24
25
  from .cerebras import CerebrasInstrumentation
25
26
 
26
27
  __all__ = [
@@ -46,6 +47,7 @@ __all__ = [
46
47
  "VertexAIInstrumentation",
47
48
  "GeminiInstrumentation",
48
49
  "MistralInstrumentation",
50
+ "PyMongoInstrumentation",
49
51
  "AWSBedrockInstrumentation",
50
52
  "CerebrasInstrumentation",
51
53
  ]
@@ -27,6 +27,7 @@ from langtrace_python_sdk.utils.llm import (
27
27
  set_event_completion,
28
28
  StreamWrapper,
29
29
  set_span_attributes,
30
+ set_usage_attributes,
30
31
  )
31
32
  from langtrace_python_sdk.types import NOT_GIVEN
32
33
 
@@ -450,6 +451,14 @@ def embeddings_create(version: str, tracer: Tracer) -> Callable:
450
451
  span_attributes[SpanAttributes.LLM_REQUEST_EMBEDDING_INPUTS] = json.dumps(
451
452
  [kwargs.get("input", "")]
452
453
  )
454
+ span_attributes[SpanAttributes.LLM_PROMPTS] = json.dumps(
455
+ [
456
+ {
457
+ "role": "user",
458
+ "content": kwargs.get("input"),
459
+ }
460
+ ]
461
+ )
453
462
 
454
463
  attributes = LLMSpanAttributes(**filter_valid_attributes(span_attributes))
455
464
 
@@ -463,6 +472,11 @@ def embeddings_create(version: str, tracer: Tracer) -> Callable:
463
472
  try:
464
473
  # Attempt to call the original method
465
474
  result = wrapped(*args, **kwargs)
475
+ usage = getattr(result, "usage", None)
476
+ if usage:
477
+ set_usage_attributes(
478
+ span, {"prompt_tokens": getattr(usage, "prompt_tokens", 0)}
479
+ )
466
480
  span.set_status(StatusCode.OK)
467
481
  return result
468
482
  except Exception as err:
@@ -0,0 +1,5 @@
1
+ from .instrumentation import PyMongoInstrumentation
2
+
3
+ __all__ = [
4
+ "PyMongoInstrumentation",
5
+ ]
@@ -0,0 +1,47 @@
1
+ """
2
+ Copyright (c) 2024 Scale3 Labs
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ """
16
+
17
+ from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
18
+ from opentelemetry.trace import get_tracer
19
+
20
+ from typing import Collection
21
+ from importlib_metadata import version as v
22
+ from wrapt import wrap_function_wrapper as _W
23
+ from .patch import generic_patch
24
+ from langtrace_python_sdk.constants.instrumentation.pymongo import APIS
25
+
26
+
27
+ class PyMongoInstrumentation(BaseInstrumentor):
28
+ """
29
+ The PyMongoInstrumentation class represents the PyMongo instrumentation
30
+ """
31
+
32
+ def instrumentation_dependencies(self) -> Collection[str]:
33
+ return ["pymongo >= 4.0.0"]
34
+
35
+ def _instrument(self, **kwargs):
36
+ tracer_provider = kwargs.get("tracer_provider")
37
+ tracer = get_tracer(__name__, "", tracer_provider)
38
+ version = v("pymongo")
39
+ for api in APIS.values():
40
+ _W(
41
+ module=api["MODULE"],
42
+ name=api["METHOD"],
43
+ wrapper=generic_patch(api["SPAN_NAME"], version, tracer),
44
+ )
45
+
46
+ def _uninstrument(self, **kwargs):
47
+ pass
@@ -0,0 +1,66 @@
1
+ from langtrace_python_sdk.utils.llm import (
2
+ get_langtrace_attributes,
3
+ get_span_name,
4
+ set_span_attributes,
5
+ set_span_attribute,
6
+ )
7
+ from langtrace_python_sdk.utils import deduce_args_and_kwargs, handle_span_error
8
+ from opentelemetry.trace import SpanKind
9
+ from langtrace_python_sdk.constants.instrumentation.common import SERVICE_PROVIDERS
10
+ from langtrace.trace_attributes import DatabaseSpanAttributes
11
+
12
+ import json
13
+
14
+
15
+ def generic_patch(name, version, tracer):
16
+ def traced_method(wrapped, instance, args, kwargs):
17
+ database = instance.database.__dict__
18
+ span_attributes = {
19
+ **get_langtrace_attributes(
20
+ version=version,
21
+ service_provider=SERVICE_PROVIDERS["MONGODB"],
22
+ vendor_type="vectordb",
23
+ ),
24
+ "db.system": "mongodb",
25
+ "db.query": "aggregate",
26
+ }
27
+
28
+ attributes = DatabaseSpanAttributes(**span_attributes)
29
+
30
+ with tracer.start_as_current_span(
31
+ get_span_name(name), kind=SpanKind.CLIENT
32
+ ) as span:
33
+ if span.is_recording():
34
+ set_input_attributes(
35
+ span, deduce_args_and_kwargs(wrapped, *args, **kwargs)
36
+ )
37
+ set_span_attributes(span, attributes)
38
+
39
+ try:
40
+ result = wrapped(*args, **kwargs)
41
+ print(result)
42
+ for doc in result:
43
+ if span.is_recording():
44
+ span.add_event(
45
+ name="db.query.match",
46
+ attributes={**doc},
47
+ )
48
+ return result
49
+ except Exception as err:
50
+ handle_span_error(span, err)
51
+ raise
52
+
53
+ return traced_method
54
+
55
+
56
+ def set_input_attributes(span, args):
57
+ pipeline = args.get("pipeline", None)
58
+ for stage in pipeline:
59
+ for k, v in stage.items():
60
+ if k == "$vectorSearch":
61
+ set_span_attribute(span, "db.index", v.get("index", None))
62
+ set_span_attribute(span, "db.path", v.get("path", None))
63
+ set_span_attribute(span, "db.top_k", v.get("numCandidates"))
64
+ set_span_attribute(span, "db.limit", v.get("limit"))
65
+ else:
66
+ set_span_attribute(span, k, json.dumps(v))
@@ -64,6 +64,7 @@ from langtrace_python_sdk.instrumentation import (
64
64
  AutogenInstrumentation,
65
65
  VertexAIInstrumentation,
66
66
  WeaviateInstrumentation,
67
+ PyMongoInstrumentation,
67
68
  CerebrasInstrumentation,
68
69
  )
69
70
  from opentelemetry.util.re import parse_env_headers
@@ -281,6 +282,7 @@ def init(
281
282
  "mistralai": MistralInstrumentation(),
282
283
  "boto3": AWSBedrockInstrumentation(),
283
284
  "autogen": AutogenInstrumentation(),
285
+ "pymongo": PyMongoInstrumentation(),
284
286
  "cerebras-cloud-sdk": CerebrasInstrumentation(),
285
287
  }
286
288
 
@@ -1 +1 @@
1
- __version__ = "3.3.2"
1
+ __version__ = "3.3.3"
@@ -1,11 +1,9 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: langtrace-python-sdk
3
- Version: 3.3.2
3
+ Version: 3.3.3
4
4
  Summary: Python SDK for LangTrace
5
5
  Project-URL: Homepage, https://github.com/Scale3-Labs/langtrace-python-sdk
6
6
  Author-email: Scale3 Labs <engineering@scale3labs.com>
7
- License-Expression: Apache-2.0
8
- License-File: LICENSE
9
7
  Classifier: License :: OSI Approved :: Apache Software License
10
8
  Classifier: Operating System :: OS Independent
11
9
  Classifier: Programming Language :: Python :: 3
@@ -72,6 +72,7 @@ examples/mistral_example/__init__.py,sha256=4kMzYY7whzUFkT9LvqPp9wSdwNtk8pq28pmZ
72
72
  examples/mistral_example/complete.py,sha256=Ydf5iOCGM2tySSd5vzGvNh3Qz39aTpxcCItBii9b0ig,589
73
73
  examples/mistral_example/complete_async.py,sha256=-SVOLNLNi5JL3o4obBsCXKOt8A6b61j3otbrrYPOOtM,586
74
74
  examples/mistral_example/embeddings.py,sha256=LKq_k3Y-TS2SCkyFKw2tLiYreVRHqlY6z0Gfh1y_7u0,468
75
+ examples/mongo_vector_search_example/main.py,sha256=6bHOxR3LfAZwmGmv74jgNCciATS5h5e-Tb5z0cD0z3Q,1542
75
76
  examples/ollama_example/__init__.py,sha256=qOx0jGCPuSpRCPiqtDVm7F0z8hIZ8C75hDZ_C8Apz-s,399
76
77
  examples/ollama_example/basic.py,sha256=EPbsigOF4xBDBgLgAD0EzPo737ycVm7aXZr7F5Xt-A4,1062
77
78
  examples/openai_example/__init__.py,sha256=6faH7wTegSozKmS89sd1Tgv8AcEH0GfKkC7YaBWA8tg,849
@@ -102,8 +103,8 @@ examples/vertexai_example/main.py,sha256=gndId5X5ksD-ycxnAWMdEqIDbLc3kz5Vt8vm4YP
102
103
  examples/weaviate_example/__init__.py,sha256=8JMDBsRSEV10HfTd-YC7xb4txBjD3la56snk-Bbg2Kw,618
103
104
  examples/weaviate_example/query_text.py,sha256=wPHQTc_58kPoKTZMygVjTj-2ZcdrIuaausJfMxNQnQc,127162
104
105
  langtrace_python_sdk/__init__.py,sha256=VZM6i71NR7pBQK6XvJWRelknuTYUhqwqE7PlicKa5Wg,1166
105
- langtrace_python_sdk/langtrace.py,sha256=J8Iwn9l6AGOQps7SLkw8u9cQI2n_MzYMIecYK9cl_6k,12456
106
- langtrace_python_sdk/version.py,sha256=ljnJCYxaT-9Q47JZlNplo0KcLdOZrB0woIJhPq11pD0,22
106
+ langtrace_python_sdk/langtrace.py,sha256=rxd-Vn0hTqqd02E5S6KzwjiTdSMttNfhY63d74Xi_gk,12529
107
+ langtrace_python_sdk/version.py,sha256=Au2yR9CeJDYeCsUV7lIDllPVwz8EynN-QwVbxO3RWOM,22
107
108
  langtrace_python_sdk/constants/__init__.py,sha256=3CNYkWMdd1DrkGqzLUgNZXjdAlM6UFMlf_F-odAToyc,146
108
109
  langtrace_python_sdk/constants/exporter/langtrace_exporter.py,sha256=d-3Qn5C_NTy1NkmdavZvy-6vePwTC5curN6QMy2haHc,50
109
110
  langtrace_python_sdk/constants/instrumentation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -111,7 +112,7 @@ langtrace_python_sdk/constants/instrumentation/anthropic.py,sha256=YX3llt3zwDY6X
111
112
  langtrace_python_sdk/constants/instrumentation/aws_bedrock.py,sha256=f9eukqoxrPgPeaBJX2gpBUz1uu0dZIPahOpvoudfbH8,310
112
113
  langtrace_python_sdk/constants/instrumentation/chroma.py,sha256=hiPGYdHS0Yj4Kh3eaYBbuCAl_swqIygu80yFqkOgdak,955
113
114
  langtrace_python_sdk/constants/instrumentation/cohere.py,sha256=tf9sDfb5K3qOAHChEE5o8eYWPZ1io58VsOjZDCZPxfw,577
114
- langtrace_python_sdk/constants/instrumentation/common.py,sha256=gs7xupRbUW_4UjXFnmqiLGRktA8lllXHRcOLeQFKek4,1125
115
+ langtrace_python_sdk/constants/instrumentation/common.py,sha256=OJcZBJptWlZGmsdI47n9pqH4q-KkYB9xN0WvtQfeaoo,1151
115
116
  langtrace_python_sdk/constants/instrumentation/embedchain.py,sha256=HodCJvaFjILoOG50OwFObxfVxt_8VUaIAIqvgoN3tzo,278
116
117
  langtrace_python_sdk/constants/instrumentation/gemini.py,sha256=UAmfgg9FM7uNeOCdPfWlir6OIH-8BoxFGPRpdBd9ZZs,358
117
118
  langtrace_python_sdk/constants/instrumentation/groq.py,sha256=VFXmIl4aqGY_fS0PAmjPj_Qm7Tibxbx7Ur_e7rQpqXc,134
@@ -120,13 +121,14 @@ langtrace_python_sdk/constants/instrumentation/mistral.py,sha256=9PlmcC5P5_BHJ-z
120
121
  langtrace_python_sdk/constants/instrumentation/ollama.py,sha256=H_-S0xjqRsi5qSp7mAlK7Y9NlQ3BqOkG6ASogqqgdJY,212
121
122
  langtrace_python_sdk/constants/instrumentation/openai.py,sha256=uEOH5UXapU2DSf2AdgXTRhhJEHGWXUNFkUGD5QafflM,1164
122
123
  langtrace_python_sdk/constants/instrumentation/pinecone.py,sha256=0TityERbGWaHGSN8-vyYZtYCjVj8fQOKae8lng0O0Bk,478
124
+ langtrace_python_sdk/constants/instrumentation/pymongo.py,sha256=bZR3anvH2OjQCj6ZCLMmdJcWcmlHhEGezS_3sx9RyJ8,195
123
125
  langtrace_python_sdk/constants/instrumentation/qdrant.py,sha256=yL7BopNQTXW7L7Z-gVM2PdusKD7r9qqcATvczFd7NtQ,1999
124
126
  langtrace_python_sdk/constants/instrumentation/vertexai.py,sha256=0s2vX3Y0iwjOPkUg5lAKi-7o3LaNivDSBBbF-o695Ok,1266
125
127
  langtrace_python_sdk/constants/instrumentation/weaviate.py,sha256=gtv-JBxvNGClEMxClmRKzjJ1khgOonsli4D_k9IagSE,2601
126
128
  langtrace_python_sdk/extensions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
127
129
  langtrace_python_sdk/extensions/langtrace_exporter.py,sha256=UFupNL03zklVd5penpsfXjbWSb5qB39mEv2BY2wczSs,6307
128
130
  langtrace_python_sdk/extensions/langtrace_filesystem.py,sha256=34fZutG28EJ66l67OvTGsydAH3ZpXgikdE7hVLqBpG4,7863
129
- langtrace_python_sdk/instrumentation/__init__.py,sha256=0wSimp9RM2Z8OpGW-h-ftDCWjXDcer0UAWg-BYXyZ0s,1857
131
+ langtrace_python_sdk/instrumentation/__init__.py,sha256=sH9bZVQN9oHZHjGnIFLSue3jbkhvHTfb4D6x3nuChCQ,1931
130
132
  langtrace_python_sdk/instrumentation/anthropic/__init__.py,sha256=donrurJAGYlxrSRA3BIf76jGeUcAx9Tq8CVpah68S0Y,101
131
133
  langtrace_python_sdk/instrumentation/anthropic/instrumentation.py,sha256=ndXdruI0BG7n75rsuEpKjfzePxrZxg40gZ39ONmD_v4,1845
132
134
  langtrace_python_sdk/instrumentation/anthropic/patch.py,sha256=ztPN4VZujoxYOKhTbFnup7Ibms9NAzYCPAJY43NUgKw,4935
@@ -188,11 +190,14 @@ langtrace_python_sdk/instrumentation/ollama/instrumentation.py,sha256=jdsvkqUJAA
188
190
  langtrace_python_sdk/instrumentation/ollama/patch.py,sha256=7ETx0tQic5h_kH1f-IeptFwgNTBb4hSkTkWsB18Avm0,5375
189
191
  langtrace_python_sdk/instrumentation/openai/__init__.py,sha256=VPHRNCQEdkizIVP2d0Uw_a7t8XOTSTprEIB8oboJFbs,95
190
192
  langtrace_python_sdk/instrumentation/openai/instrumentation.py,sha256=PZxI0qfoud1VsKGmJu49YDp0Z9z9TzCR8qxR3uznOMA,2810
191
- langtrace_python_sdk/instrumentation/openai/patch.py,sha256=MacQoaqs5b3zgCkD6z2k6fP9mruRtLSLWNNBXuZ70m8,24431
193
+ langtrace_python_sdk/instrumentation/openai/patch.py,sha256=GINHfq5HHSfOzMr1HErwLuzOFx5pzmclE9Pwa4ziKBQ,24946
192
194
  langtrace_python_sdk/instrumentation/openai/types.py,sha256=aVkoa7tmAbYfyOhnyMrDaVjQuwhmRNLMthlNtKMtWX8,4311
193
195
  langtrace_python_sdk/instrumentation/pinecone/__init__.py,sha256=DzXyGh9_MGWveJvXULkFwdkf7PbG2s3bAWtT1Dmz7Ok,99
194
196
  langtrace_python_sdk/instrumentation/pinecone/instrumentation.py,sha256=HDXkRITrVPwdQEoOYJOfMzZE_2-vDDvuqHTlD8W1lQw,1845
195
197
  langtrace_python_sdk/instrumentation/pinecone/patch.py,sha256=MIbUcEsVzl4W_pfq81LP9QFVhwPB8rHF0Aod9pq_j-o,5249
198
+ langtrace_python_sdk/instrumentation/pymongo/__init__.py,sha256=Q_ecuvZ0j5TxOCdD69BfZhCPT6rj7w5lHbTuDSpLYD4,97
199
+ langtrace_python_sdk/instrumentation/pymongo/instrumentation.py,sha256=fG938JR2Be3zy19JUyvKxafYQPavnUV9eMtD7Vn0_fc,1597
200
+ langtrace_python_sdk/instrumentation/pymongo/patch.py,sha256=4K-_QWTXoWDzpYEgaWPkf6kvXGnAmHKvp8H2gMmPokA,2330
196
201
  langtrace_python_sdk/instrumentation/qdrant/__init__.py,sha256=TaIGSAEPysrL23KJ5FcEL1tfQogrKCtEQ75_u62eqso,95
197
202
  langtrace_python_sdk/instrumentation/qdrant/instrumentation.py,sha256=vl2eKSP55aqDo1JiRlvOUBrr6kddvG9Z5dCYew2OG08,1816
198
203
  langtrace_python_sdk/instrumentation/qdrant/patch.py,sha256=IgdozFyKqB8n72BjKvBDiMhYM4o75DReD0I8_uIQ7KY,5015
@@ -254,8 +259,8 @@ tests/pinecone/cassettes/test_query.yaml,sha256=b5v9G3ssUy00oG63PlFUR3JErF2Js-5A
254
259
  tests/pinecone/cassettes/test_upsert.yaml,sha256=neWmQ1v3d03V8WoLl8FoFeeCYImb8pxlJBWnFd_lITU,38607
255
260
  tests/qdrant/conftest.py,sha256=9n0uHxxIjWk9fbYc4bx-uP8lSAgLBVx-cV9UjnsyCHM,381
256
261
  tests/qdrant/test_qdrant.py,sha256=pzjAjVY2kmsmGfrI2Gs2xrolfuaNHz7l1fqGQCjp5_o,3353
257
- langtrace_python_sdk-3.3.2.dist-info/METADATA,sha256=9okCBfH1pQOf1Kwq0JspTVZ-NAeXy5aMUcvmbsHfKtE,15996
258
- langtrace_python_sdk-3.3.2.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
259
- langtrace_python_sdk-3.3.2.dist-info/entry_points.txt,sha256=1_b9-qvf2fE7uQNZcbUei9vLpFZBbbh9LrtGw95ssAo,70
260
- langtrace_python_sdk-3.3.2.dist-info/licenses/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
261
- langtrace_python_sdk-3.3.2.dist-info/RECORD,,
262
+ langtrace_python_sdk-3.3.3.dist-info/METADATA,sha256=dWEl_fFJz9n8MjBCDuafoksbyiaCxKRnphD8La5xtyM,15943
263
+ langtrace_python_sdk-3.3.3.dist-info/WHEEL,sha256=3U_NnUcV_1B1kPkYaPzN-irRckL5VW_lytn0ytO_kRY,87
264
+ langtrace_python_sdk-3.3.3.dist-info/entry_points.txt,sha256=1_b9-qvf2fE7uQNZcbUei9vLpFZBbbh9LrtGw95ssAo,70
265
+ langtrace_python_sdk-3.3.3.dist-info/licenses/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
266
+ langtrace_python_sdk-3.3.3.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.25.0
2
+ Generator: hatchling 1.26.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any