vectorwave 0.1.0__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.
@@ -0,0 +1,100 @@
1
+ import weaviate
2
+ import weaviate.classes as wvc
3
+ from typing import Dict, Any, Optional, List
4
+
5
+ from weaviate.collections.classes.filters import _Filters
6
+
7
+ from ..models.db_config import get_weaviate_settings, WeaviateSettings
8
+ from .db import get_cached_client
9
+ from ..exception.exceptions import WeaviateConnectionError
10
+
11
+ import uuid
12
+ from datetime import datetime
13
+
14
+
15
+ def _build_weaviate_filters(filters: Optional[Dict[str, Any]]) -> _Filters | None:
16
+ if not filters:
17
+ return None
18
+ filter_list = [
19
+ wvc.query.Filter.by_property(key).equal(value)
20
+ for key, value in filters.items()
21
+ ]
22
+ if not filter_list:
23
+ return None
24
+ return wvc.query.Filter.all_of(filter_list)
25
+
26
+
27
+ def search_functions(query: str, limit: int = 5, filters: Optional[Dict[str, Any]] = None) -> List[Dict[str, Any]]:
28
+ """
29
+ Searches function definitions from the [VectorWaveFunctions] collection using natural language (nearText).
30
+ """
31
+ try:
32
+ settings: WeaviateSettings = get_weaviate_settings()
33
+ client: weaviate.WeaviateClient = get_cached_client()
34
+
35
+ collection = client.collections.get(settings.COLLECTION_NAME)
36
+ weaviate_filter = _build_weaviate_filters(filters)
37
+
38
+ response = collection.query.near_text(
39
+ query=query,
40
+ limit=limit,
41
+ filters=weaviate_filter,
42
+ return_metadata=wvc.query.MetadataQuery(distance=True)
43
+ )
44
+
45
+ #todo expand custom range needed
46
+ results = [
47
+ {
48
+ "properties": obj.properties,
49
+ "metadata": obj.metadata, # This contains the distance
50
+ "uuid": obj.uuid # Add uuid separately here
51
+ }
52
+ for obj in response.objects
53
+ ]
54
+ return results
55
+
56
+ except Exception as e:
57
+ print(f"Error during Weaviate search: {e}")
58
+ raise WeaviateConnectionError(f"Failed to execute 'search_functions': {e}")
59
+
60
+
61
+ def search_executions(
62
+ limit: int = 10,
63
+ filters: Optional[Dict[str, Any]] = None,
64
+ sort_by: Optional[str] = "timestamp_utc",
65
+ sort_ascending: bool = False
66
+ ) -> List[Dict[str, Any]]:
67
+ """
68
+ Searches execution logs from the [VectorWaveExecutions] collection using filtering and sorting.
69
+ """
70
+ try:
71
+ settings: WeaviateSettings = get_weaviate_settings()
72
+ client: weaviate.WeaviateClient = get_cached_client()
73
+
74
+ collection = client.collections.get(settings.EXECUTION_COLLECTION_NAME)
75
+ weaviate_filter = _build_weaviate_filters(filters)
76
+ weaviate_sort = None
77
+
78
+ if sort_by:
79
+ weaviate_sort = wvc.query.Sort.by_property(
80
+ name=sort_by,
81
+ ascending=sort_ascending
82
+ )
83
+
84
+ response = collection.query.fetch_objects(
85
+ limit=limit,
86
+ filters=weaviate_filter,
87
+ sort=weaviate_sort
88
+ )
89
+ results = []
90
+ for obj in response.objects:
91
+ props = obj.properties.copy()
92
+ for key, value in props.items():
93
+ if isinstance(value, uuid.UUID) or isinstance(value, datetime):
94
+ props[key] = str(value)
95
+ results.append(props)
96
+
97
+ return results
98
+
99
+ except Exception as e:
100
+ raise WeaviateConnectionError(f"Failed to execute 'search_executions': {e}")
File without changes
@@ -0,0 +1,22 @@
1
+ """
2
+ Defines custom exceptions for the VectorWave project.
3
+ """
4
+
5
+ class VectorWaveError(Exception):
6
+ """Base exception class for the VectorWave library."""
7
+ pass
8
+
9
+
10
+ class WeaviateConnectionError(VectorWaveError):
11
+ """Raised when an error occurs while attempting to connect to the Weaviate server."""
12
+ pass
13
+
14
+
15
+ class WeaviateNotReadyError(VectorWaveError):
16
+ """Raised when connected to Weaviate, but the server is not in a ready state."""
17
+ pass
18
+
19
+
20
+ class SchemaCreationError(VectorWaveError):
21
+ """Raised when an error occurs during Weaviate collection schema creation."""
22
+ pass
File without changes
@@ -0,0 +1,82 @@
1
+ from pydantic_settings import BaseSettings, SettingsConfigDict
2
+ from functools import lru_cache
3
+ from typing import Dict, Optional, Any
4
+ import json
5
+ import os
6
+
7
+
8
+ class WeaviateSettings(BaseSettings):
9
+ """
10
+ Manages Weaviate database connection settings.
11
+
12
+ Reads values from environment variables or a .env file.
13
+ (e.g., WEAVIATE_HOST=10.0.0.1)
14
+ """
15
+ # If environment variables are not set, these default values will be used.
16
+ WEAVIATE_HOST: str = "localhost"
17
+ WEAVIATE_PORT: int = 8080
18
+ WEAVIATE_GRPC_PORT: int = 50051
19
+ COLLECTION_NAME: str = "VectorWaveFunctions"
20
+ EXECUTION_COLLECTION_NAME: str = "VectorWaveExecutions"
21
+ IS_VECTORIZE_COLLECTION_NAME: bool = True
22
+
23
+ # Configure to read from a .env file (optional)
24
+
25
+ VECTORIZER_CONFIG: str = "text2vec-openai"
26
+ GENERATIVE_CONFIG: str = "generative-openai"
27
+
28
+ CUSTOM_PROPERTIES_FILE_PATH: str = ".weaviate_properties"
29
+ custom_properties: Optional[Dict[str, Dict[str, Any]]] = None
30
+ global_custom_values: Optional[Dict[str, Any]] = None
31
+ model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8",extra='ignore')
32
+
33
+
34
+ # @lru_cache ensures this function creates the Settings object only once (Singleton pattern)
35
+ # and reuses the cached object on subsequent calls.
36
+ @lru_cache()
37
+ def get_weaviate_settings() -> WeaviateSettings:
38
+ """
39
+ Factory function that returns the settings object.
40
+ """
41
+ settings = WeaviateSettings()
42
+
43
+ file_path = settings.CUSTOM_PROPERTIES_FILE_PATH
44
+
45
+ if file_path and os.path.exists(file_path):
46
+ print(f"Loading custom properties schema from '{file_path}'...")
47
+ try:
48
+ with open(file_path, 'r', encoding='utf-8') as f:
49
+ loaded_data = json.load(f)
50
+
51
+ if isinstance(loaded_data, dict):
52
+ settings.custom_properties = loaded_data
53
+ else:
54
+ print(
55
+ f"Warning: Content in '{file_path}' is not a valid dictionary (JSON root). "
56
+ f"Custom properties will not be loaded."
57
+ )
58
+ settings.custom_properties = None
59
+
60
+ except json.JSONDecodeError as e:
61
+ print(f"Warning: Could not parse JSON from '{file_path}'. File might be malformed. {e}")
62
+ settings.custom_properties = None
63
+ except Exception as e:
64
+ print(f"Warning: Could not read file '{file_path}': {e}")
65
+ settings.custom_properties = None
66
+
67
+ elif file_path:
68
+ print(f"Note: Custom properties file not found at '{file_path}'. Skipping schema.")
69
+
70
+ if settings.custom_properties:
71
+ settings.global_custom_values = {}
72
+ print(f"Loading global custom values from environment variables...")
73
+
74
+ for prop_name in settings.custom_properties.keys():
75
+ env_var_name = prop_name.upper()
76
+ value = os.environ.get(env_var_name)
77
+
78
+ if value:
79
+ settings.global_custom_values[prop_name] = value
80
+ print(f"Loaded global value for '{prop_name}' from env var '{env_var_name}'.")
81
+
82
+ return settings
File without changes
File without changes
@@ -0,0 +1,128 @@
1
+ import inspect
2
+ import time
3
+ import traceback
4
+ from functools import wraps
5
+ from contextvars import ContextVar
6
+ from typing import Optional, List, Dict, Any, Callable
7
+ from uuid import uuid4
8
+ from datetime import datetime, timezone
9
+
10
+ from ..batch.batch import get_batch_manager
11
+ from ..models.db_config import get_weaviate_settings, WeaviateSettings
12
+
13
+
14
+ class TraceCollector:
15
+ def __init__(self, trace_id: str):
16
+ self.trace_id = trace_id
17
+ self.settings: WeaviateSettings = get_weaviate_settings()
18
+ self.batch = get_batch_manager()
19
+
20
+
21
+ current_tracer_var: ContextVar[Optional[TraceCollector]] = ContextVar('current_tracer', default=None)
22
+
23
+
24
+ def trace_root() -> Callable:
25
+ """
26
+ Decorator factory for the workflow's entry point function.
27
+ Creates and sets the TraceCollector in ContextVar.
28
+ """
29
+
30
+ def decorator(func: Callable) -> Callable:
31
+ @wraps(func)
32
+ def wrapper(*args, **kwargs):
33
+ if current_tracer_var.get() is not None:
34
+ return func(*args, **kwargs)
35
+
36
+ trace_id = kwargs.pop('trace_id', str(uuid4()))
37
+ tracer = TraceCollector(trace_id=trace_id)
38
+ token = current_tracer_var.set(tracer)
39
+
40
+ try:
41
+ # ⭐️ Key: Here, func is the wrapper of @trace_span.
42
+ return func(*args, **kwargs)
43
+ finally:
44
+ current_tracer_var.reset(token)
45
+
46
+ return wrapper
47
+
48
+ return decorator
49
+
50
+
51
+ def trace_span(
52
+ _func: Optional[Callable] = None,
53
+ *,
54
+ attributes_to_capture: Optional[List[str]] = None
55
+ ) -> Callable:
56
+ """
57
+ Decorator to capture function execution as a 'span'.
58
+ Can be used as @trace_span or @trace_span(attributes_to_capture=[...]).
59
+ """
60
+
61
+ def decorator(func: Callable) -> Callable:
62
+ @wraps(func)
63
+ def wrapper(*args, **kwargs):
64
+ tracer = current_tracer_var.get()
65
+ if not tracer:
66
+ return func(*args, **kwargs)
67
+
68
+ start_time = time.perf_counter()
69
+ status = "SUCCESS"
70
+ error_msg = None
71
+ result = None
72
+
73
+ captured_attributes = {}
74
+ if attributes_to_capture:
75
+ try:
76
+ # Directly checks the kwargs dictionary.
77
+ for attr_name in attributes_to_capture:
78
+ if attr_name in kwargs:
79
+ value = kwargs[attr_name]
80
+ if not isinstance(value, (str, int, float, bool, list, dict, type(None))):
81
+ value = str(value)
82
+ captured_attributes[attr_name] = value
83
+ except Exception as e:
84
+ print(f"Warning: Failed to capture attributes for {func.__name__}: {e}")
85
+
86
+ try:
87
+ result = func(*args, **kwargs)
88
+ except Exception as e:
89
+ status = "ERROR"
90
+ error_msg = traceback.format_exc()
91
+ raise e
92
+ finally:
93
+ duration_ms = (time.perf_counter() - start_time) * 1000
94
+
95
+ span_properties = {
96
+ "trace_id": tracer.trace_id,
97
+ "span_id": str(uuid4()),
98
+ "function_name": func.__name__,
99
+ "timestamp_utc": datetime.now(timezone.utc).isoformat(),
100
+ "duration_ms": duration_ms,
101
+ "status": status,
102
+ "error_message": error_msg,
103
+ }
104
+
105
+ # 1. Apply global tags first.
106
+ if tracer.settings.global_custom_values:
107
+ span_properties.update(tracer.settings.global_custom_values)
108
+
109
+ # 2. Apply captured attributes second (overriding global values if necessary).
110
+ # (If 'run_id' was captured, this value (e.g., override-run-xyz) overrides the global value.)
111
+ span_properties.update(captured_attributes)
112
+
113
+ try:
114
+ tracer.batch.add_object(
115
+ collection=tracer.settings.EXECUTION_COLLECTION_NAME,
116
+ properties=span_properties
117
+ )
118
+ except Exception as e:
119
+ print(f"Error: Failed to log span for {func.__name__} (trace_id: {tracer.trace_id}): {e}")
120
+
121
+ return result
122
+
123
+ return wrapper
124
+
125
+ if _func is None:
126
+ return decorator
127
+ else:
128
+ return decorator(_func)
File without changes
File without changes
@@ -0,0 +1,280 @@
1
+ Metadata-Version: 2.4
2
+ Name: vectorwave
3
+ Version: 0.1.0
4
+ Summary: VectorWave: Seamless Auto-Vectorization Framework
5
+ Author-email: junyeonggim <junyeonggim5@gmail.com>
6
+ Classifier: Programming Language :: Python :: 3
7
+ Classifier: Operating System :: OS Independent
8
+ Requires-Python: >=3.8
9
+ Description-Content-Type: text/markdown
10
+ Requires-Dist: weaviate-client>=4.0.0
11
+ Requires-Dist: pydantic-settings>=2.0.0
12
+
13
+
14
+ # VectorWave: Seamless Auto-Vectorization Framework
15
+
16
+ [](https://www.google.com/search?q=LICENSE)
17
+
18
+ ## 🌟 Overview
19
+
20
+ **VectorWave** is an innovative framework that uses a **decorator** to automatically save and manage the output of Python functions/methods in a **Vector Database (Vector DB)**. Developers can convert function outputs into intelligent vector data with a single line of code (`@vectorize`), without worrying about the complex processes of data collection, embedding generation, or storage in a Vector DB.
21
+
22
+ ---
23
+
24
+ ## ✨ Features
25
+
26
+ * **`@vectorize` Decorator:**
27
+ 1. **Static Data Collection:** Saves the function's source code, docstring, and metadata to the `VectorWaveFunctions` collection once when the script is loaded.
28
+ 2. **Dynamic Data Logging:** Records the execution time, success/failure status, error logs, and 'dynamic tags' to the `VectorWaveExecutions` collection every time the function is called.
29
+ * **Distributed Tracing:** By combining the `@vectorize` and `@trace_span` decorators, you can analyze the execution of complex multi-step workflows, grouped under a single **`trace_id`**.
30
+ * **Search Interface:** Provides `search_functions` (for vector search) and `search_executions` (for log filtering) to facilitate the construction of RAG and monitoring systems.
31
+
32
+ ---
33
+
34
+ ## 🚀 Usage
35
+
36
+ VectorWave consists of 'storing' via decorators and 'searching' via functions, and now includes **execution flow tracing**.
37
+
38
+ ### 1. (Required) Initialize the Database and Configuration
39
+
40
+ ```python
41
+ import time
42
+ from vectorwave import (
43
+ vectorize,
44
+ initialize_database,
45
+ search_functions,
46
+ search_executions
47
+ )
48
+ # [ADDITION] Import trace_span separately for distributed tracing.
49
+ from vectorwave.monitoring.tracer import trace_span
50
+
51
+ # This only needs to be called once when the script starts.
52
+ try:
53
+ client = initialize_database()
54
+ print("VectorWave DB initialized successfully.")
55
+ except Exception as e:
56
+ print(f"DB initialization failed: {e}")
57
+ exit()
58
+ ````
59
+
60
+ ### 2\. [Store] Use `@vectorize` with Distributed Tracing
61
+
62
+ The `@vectorize` acts as the **Root** for tracing, and `@trace_span` is used on internal functions to group the execution flow under a single `trace_id`.
63
+
64
+ ```python
65
+ # --- Child Span Function: Captures arguments ---
66
+ @trace_span(attributes_to_capture=['user_id', 'amount'])
67
+ def step_1_validate_payment(user_id: str, amount: int):
68
+ """(Span) Payment validation. Records user_id and amount in the log."""
69
+ print(f" [SPAN 1] Validating payment for {user_id}...")
70
+ time.sleep(0.1)
71
+ return True
72
+
73
+ @trace_span(attributes_to_capture=['user_id', 'receipt_id'])
74
+ def step_2_send_receipt(user_id: str, receipt_id: str):
75
+ """(Span) Sends the receipt."""
76
+ print(f" [SPAN 2] Sending receipt {receipt_id}...")
77
+ time.sleep(0.2)
78
+
79
+
80
+ # --- Root Function (@trace_root role) ---
81
+ @vectorize(
82
+ search_description="Charges a user in the payment system.",
83
+ sequence_narrative="Returns a receipt ID upon successful payment.",
84
+ team="billing", # <-- Custom Tag (recorded in all execution logs)
85
+ priority=1 # <-- Custom Tag (execution priority)
86
+ )
87
+ def process_payment(user_id: str, amount: int):
88
+ """(Root Span) Executes the user payment workflow."""
89
+ print(f" [ROOT EXEC] process_payment: Starting workflow for {user_id}...")
90
+
91
+ # When calling child functions, the same trace_id is automatically inherited via ContextVar.
92
+ step_1_validate_payment(user_id=user_id, amount=amount)
93
+
94
+ receipt_id = f"receipt_{user_id}_{amount}"
95
+ step_2_send_receipt(user_id=user_id, receipt_id=receipt_id)
96
+
97
+ print(f" [ROOT DONE] process_payment")
98
+ return {"status": "success", "receipt_id": receipt_id}
99
+
100
+ # --- Execute the Function ---
101
+ print("Now calling 'process_payment'...")
102
+ # This single call records 3 execution logs (spans) in the DB,
103
+ # all grouped under one 'trace_id'.
104
+ process_payment("user_789", 5000)
105
+ ```
106
+
107
+ ### 3\. [Search ①] Function Definition Search (for RAG)
108
+
109
+ ```python
110
+ # Search for functions related to 'payment' using natural language (vector search).
111
+ print("\n--- Searching for 'payment' functions ---")
112
+ payment_funcs = search_functions(
113
+ query="user payment processing",
114
+ limit=3
115
+ )
116
+ for func in payment_funcs:
117
+ print(f" - Function: {func['properties']['function_name']}")
118
+ print(f" - Description: {func['properties']['search_description']}")
119
+ print(f" - Similarity (Distance): {func['metadata'].distance:.4f}")
120
+ ```
121
+
122
+ ### 4\. [Search ②] Execution Log Search (Monitoring and Tracing)
123
+
124
+ The `search_executions` function can now search for all related execution logs (spans) based on the `trace_id`.
125
+
126
+ ```python
127
+ # 1. Find the Trace ID of a specific workflow (process_payment).
128
+ latest_payment_span = search_executions(
129
+ limit=1,
130
+ filters={"function_name": "process_payment"},
131
+ sort_by="timestamp_utc",
132
+ sort_ascending=False
133
+ )
134
+ trace_id = latest_payment_span[0]["trace_id"]
135
+
136
+ # 2. Search all spans belonging to that Trace ID, sorted chronologically.
137
+ print(f"\n--- Full Trace for ID ({trace_id[:8]}...) ---")
138
+ trace_spans = search_executions(
139
+ limit=10,
140
+ filters={"trace_id": trace_id},
141
+ sort_by="timestamp_utc",
142
+ sort_ascending=True # Ascending sort for workflow flow analysis
143
+ )
144
+
145
+ for i, span in enumerate(trace_spans):
146
+ print(f" - [Span {i+1}] {span['function_name']} ({span['duration_ms']:.2f}ms)")
147
+ # Captured arguments (user_id, amount, etc.) are displayed for the child spans.
148
+
149
+ # Example Output:
150
+ # - [Span 1] step_1_validate_payment (100.81ms)
151
+ # - [Span 2] step_2_send_receipt (202.06ms)
152
+ # - [Span 3] process_payment (333.18ms)
153
+ ```
154
+
155
+ -----
156
+
157
+ ## ⚙️ Configuration
158
+
159
+ VectorWave automatically reads Weaviate database connection information from **environment variables** or a `.env` file.
160
+
161
+ Create a `.env` file in the root directory of your project (e.g., where `main.py` is located) and set the required values.
162
+
163
+ ### .env File Example
164
+
165
+ ```ini
166
+ # .env
167
+ # --- Basic Weaviate Connection Settings ---
168
+ WEAVIATE_HOST=localhost
169
+ WEAVIATE_PORT=8080
170
+ WEAVIATE_GRPC_PORT=50051
171
+
172
+ # --- Vectorizer , Generative Module Config ---
173
+ # (default: text2vec-openai) Set to 'none' to disable vectorization.
174
+ VECTORIZER_CONFIG=text2vec-openai
175
+ # (default: generative-openai)
176
+ GENERATIVE_CONFIG=generative-openai
177
+ # An OpenAI API key is required if using modules like text2vec-openai.
178
+ # OPENAI_API_KEY=sk-your-key-here
179
+
180
+ # --- [Advanced] Custom Property Settings ---
181
+ # 1. The path to the JSON file defining custom properties to add to the schema.
182
+ CUSTOM_PROPERTIES_FILE_PATH=.weaviate_properties
183
+
184
+ # 2. Environment variables to be used for 'Global Dynamic Tagging'.
185
+ # ("run_id" must be defined in the .weaviate_properties file)
186
+ RUN_ID=test-run-001
187
+ EXPERIMENT_ID=exp-abc
188
+ ```
189
+
190
+ -----
191
+
192
+ ### Custom Properties and Dynamic Execution Tagging
193
+
194
+ VectorWave can store user-defined metadata in both static definitions (`VectorWaveFunctions`) and dynamic logs (`VectorWaveExecutions`). This works in two steps.
195
+
196
+ #### Step 1: Define Custom Schema (The "Allow-List")
197
+
198
+ Create a JSON file at the path specified by `CUSTOM_PROPERTIES_FILE_PATH` (default: `.weaviate_properties`).
199
+
200
+ This file instructs VectorWave to add **new properties (columns)** to the Weaviate collections. This file acts as an **"allow-list"** for all custom tags.
201
+
202
+ **`.weaviate_properties` Example:**
203
+
204
+ ```json
205
+ {
206
+ "run_id": {
207
+ "data_type": "TEXT",
208
+ "description": "The ID of the specific test run"
209
+ },
210
+ "experiment_id": {
211
+ "data_type": "TEXT",
212
+ "description": "Identifier for the experiment"
213
+ },
214
+ "team": {
215
+ "data_type": "TEXT",
216
+ "description": "The team responsible for this function"
217
+ },
218
+ "priority": {
219
+ "data_type": "INT",
220
+ "description": "Execution priority level"
221
+ }
222
+ }
223
+ ```
224
+
225
+ * Defining these will add `run_id`, `experiment_id`, `team`, and `priority` properties to *both* collections.
226
+
227
+ #### Step 2: Dynamic Execution Tagging (Adding Values)
228
+
229
+ When a function executes, VectorWave adds tags to the `VectorWaveExecutions` log. It does this in two ways, which are then merged:
230
+
231
+ **1. Global Tags (from Environment Variables)**
232
+ VectorWave searches for environment variables whose names match the **uppercase** keys from Step 1 (e.g., `RUN_ID`, `EXPERIMENT_ID`) and uses these for run-wide metadata.
233
+
234
+ **2. Function-Specific Tags (from Decorator)**
235
+ You can pass tags directly to the `@vectorize` decorator as keyword arguments (`**execution_tags`). This is ideal for function-specific metadata.
236
+
237
+ ```python
238
+ # --- .env file ---
239
+ # RUN_ID=global-run-abc
240
+ # TEAM=default-team
241
+
242
+ @vectorize(
243
+ search_description="Process a payment",
244
+ sequence_narrative="...",
245
+ team="billing", # <-- Function-specific tag
246
+ priority=1 # <-- Function-specific tag
247
+ )
248
+ def process_payment():
249
+ pass
250
+
251
+ @vectorize(
252
+ search_description="Another function",
253
+ sequence_narrative="...",
254
+ run_id="override-run-xyz" # <-- Overrides the global tag
255
+ )
256
+ def other_function():
257
+ pass
258
+ ```
259
+
260
+ **Tag Merging and Validation Rules**
261
+
262
+ 1. **Validation (Most Important):** A tag (either global or specific) will **only** be saved to Weaviate if its key (e.g., `run_id`, `team`, `priority`) was first defined in your `.weaviate_properties` file (Step 1). Tags not defined in the schema will be **ignored**, and a warning will be printed on startup.
263
+
264
+ 2. **Priority (Override):** If a tag key is defined in both places (e.g., a global `RUN_ID` in `.env` and a specific `run_id="override-run-xyz"` on the decorator), the **function-specific tag from the decorator will always win**.
265
+
266
+ **Resulting Logs:**
267
+
268
+ * `process_payment()` log will have: `{"run_id": "global-run-abc", "team": "billing", "priority": 1}`
269
+ * `other_function()` log will have: `{"run_id": "override-run-xyz", "team": "default-team"}`
270
+
271
+ -----
272
+
273
+ ## 🤝 Contributing
274
+
275
+ All forms of contribution are welcome, including bug reports, feature requests, and code contributions. For details, please refer to [CONTRIBUTING.md](https://www.google.com/search?q=httpsS://www.google.com/search%3Fq%3DCONTRIBUTING.md).
276
+
277
+ ## 📜 License
278
+
279
+ This project is distributed under the MIT License. See the [LICENSE](https://www.google.com/search?q=httpsS://www.google.com/search%3Fq%3DLICENSE) file for details.
280
+
@@ -0,0 +1,35 @@
1
+ tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ tests/batch/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ tests/batch/test_batch.py,sha256=vDP-W4KTH6f6XfTof-EYgRtz5MlKSRC1kwGrQ5Z4v0k,3315
4
+ tests/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ tests/core/test_decorator.py,sha256=uLlqBoGJ83Emu5qCdBmhvR12jd5tfDhWUzfCchgL6l8,12852
6
+ tests/database/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ tests/database/test_db.py,sha256=m_xuEBt2EzCX-o3UuY79xQdVvpTA3k05RvVahu4bP1k,16615
8
+ tests/database/test_db_search.py,sha256=fM75zvHhJ06meMbRN_T9cMoXVdcFaC5dwzjHu0nc3-g,5456
9
+ tests/exception/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ tests/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
+ tests/models/test_db_config.py,sha256=wdWTF4ZL9zieSMnfwUhsBtAmsJsVDC2YQbuYW0Tw-28,4823
12
+ tests/monitoring/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
+ tests/prediction/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
+ vectorwave/__init__.py,sha256=6EC-i4Ty_H_mZb4ZdsyryQpj_uobRf84mp8fPMNui3w,318
15
+ vectorwave/batch/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
+ vectorwave/batch/batch.py,sha256=gSfRjxF0Z5pCIvJndAWleMas5Ms78FkURfGVYqvtD8E,2225
17
+ vectorwave/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
+ vectorwave/core/core.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
+ vectorwave/core/decorator.py,sha256=rX9GSpMN76aki_0y7bm-ZpQt3pJrUcqGMuDTWevp5AI,3796
20
+ vectorwave/database/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
+ vectorwave/database/db.py,sha256=OP8LxJSFGbeArSatLzKXBhFHTzVydBuBfVyRHO6rpd0,10963
22
+ vectorwave/database/db_search.py,sha256=iN7m8jYsIM-h-qTnPcp-1grDOQtnM3xt1Fq3TEhaz4g,3319
23
+ vectorwave/exception/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
+ vectorwave/exception/exceptions.py,sha256=A7NuY3NyctYlQRtDhU4uvDjdSWormddf-Pk-kR0vMsQ,592
25
+ vectorwave/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
+ vectorwave/models/db_config.py,sha256=fcijRdX6Lh_vRRWGGvxS2Zn-eQ7ukwq68OeuUeSp3DA,3106
27
+ vectorwave/monitoring/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
+ vectorwave/monitoring/monitoring.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
+ vectorwave/monitoring/tracer.py,sha256=SH54QfGPosYzHmnz8SSEeZ08LQ9XUYscCIZuSp5pU3I,4431
30
+ vectorwave/prediction/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
+ vectorwave/prediction/predictor.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
32
+ vectorwave-0.1.0.dist-info/METADATA,sha256=dBb61UixAxREuoUHR9pS4uSo2SmPDnplIudYknshxJk,10518
33
+ vectorwave-0.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
34
+ vectorwave-0.1.0.dist-info/top_level.txt,sha256=Nce880E2pZRKbWF9XpB-FT5iZL9ETMDqSUVKF-_0m78,17
35
+ vectorwave-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ tests
2
+ vectorwave