chalkpy 2.95.3__py3-none-any.whl → 2.95.4__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.
chalk/_version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "2.95.3"
1
+ __version__ = "2.95.4"
@@ -1311,7 +1311,7 @@ def _process_class(
1311
1311
  )
1312
1312
  cls_cast = cast(Type, cls)
1313
1313
  if not f_i.is_typ_set():
1314
- f_i.typ = ParsedAnnotation(cls_cast, f.name)
1314
+ f_i.typ = ParsedAnnotation(cls_cast, f.attribute_name)
1315
1315
 
1316
1316
  f_i.features_cls = cls_cast
1317
1317
  f_i.attribute_name = f"{f.attribute_name}_v{i}"
@@ -1329,9 +1329,18 @@ def _process_class(
1329
1329
  class_cache_strategy=cache_strategy,
1330
1330
  error_builder=error_builder,
1331
1331
  )
1332
+
1333
+ # copy over expressions for default version
1334
+ if i == f.version.default:
1335
+ if f.underscore_expression is None and f_i.underscore_expression is not None:
1336
+ f.underscore_expression = f_i.underscore_expression
1337
+ if f.offline_underscore_expression is None and f_i.offline_underscore_expression is not None:
1338
+ f.offline_underscore_expression = f_i.offline_underscore_expression
1339
+
1332
1340
  f.version.reference[i] = f_i
1333
1341
  # The default feature already exists.
1334
1342
  f_i.no_display = i == f.version.default
1343
+ cls_fields.append(f_i)
1335
1344
  continue
1336
1345
 
1337
1346
  for i in range(1, f.version.maximum + 1):
chalk/utils/tracing.py CHANGED
@@ -5,7 +5,7 @@ import os
5
5
  import threading
6
6
  import time
7
7
  import types
8
- from typing import TYPE_CHECKING, Any, Mapping, Union, cast
8
+ from typing import TYPE_CHECKING, Any, Callable, Mapping, Union, cast
9
9
 
10
10
  from chalk.utils._ddtrace_version import can_use_datadog_statsd, can_use_ddtrace
11
11
  from chalk.utils._otel_version import can_use_otel_trace
@@ -16,6 +16,41 @@ if TYPE_CHECKING:
16
16
  import ddtrace.context
17
17
  from opentelemetry import trace as otel_trace
18
18
 
19
+
20
+ class Once:
21
+ """Execute a function exactly once and block all callers until the function returns
22
+
23
+ Same as golang's `sync.Once <https://pkg.go.dev/sync#Once>`_
24
+ """
25
+
26
+ def __init__(self) -> None:
27
+ self._lock = threading.Lock()
28
+ self._done = False
29
+ super().__init__()
30
+
31
+ def do_once(self, func: Callable[[], None]) -> bool:
32
+ """Execute ``func`` if it hasn't been executed or return.
33
+
34
+ Will block until ``func`` has been called by one thread.
35
+
36
+ Returns:
37
+ Whether or not ``func`` was executed in this call
38
+ """
39
+
40
+ # fast path, try to avoid locking
41
+ if self._done:
42
+ return False
43
+
44
+ with self._lock:
45
+ if not self._done:
46
+ func()
47
+ self._done = True
48
+ return True
49
+ return False
50
+
51
+
52
+ _TRACING_CONFIGURED = Once()
53
+
19
54
  _logger = get_logger(__name__)
20
55
 
21
56
  if can_use_otel_trace:
@@ -27,6 +62,7 @@ if can_use_otel_trace:
27
62
 
28
63
  @contextlib.contextmanager
29
64
  def safe_trace(span_id: str, attributes: Mapping[str, str] | None = None): # pyright: ignore[reportRedeclaration]
65
+ configure_tracing("chalkpy")
30
66
  if attributes is None:
31
67
  attributes = {}
32
68
  attributes = dict(attributes)
@@ -36,14 +72,17 @@ if can_use_otel_trace:
36
72
  yield span
37
73
 
38
74
  def safe_add_metrics(metrics: Mapping[str, Union[int, float]]): # pyright: ignore[reportRedeclaration]
75
+ configure_tracing("chalkpy")
39
76
  current_span = otel_trace.get_current_span()
40
77
  current_span.set_attributes(dict(metrics))
41
78
 
42
79
  def safe_add_tags(tags: Mapping[str, str]):
80
+ configure_tracing("chalkpy")
43
81
  current_span = otel_trace.get_current_span()
44
82
  current_span.set_attributes(dict(tags))
45
83
 
46
84
  def safe_current_trace_context() -> ddtrace.context.Context | otel_trace.SpanContext | None: # pyright: ignore[reportRedeclaration]
85
+ configure_tracing("chalkpy")
47
86
  return otel_trace.get_current_span().get_span_context()
48
87
 
49
88
  @contextlib.contextmanager
@@ -53,6 +92,7 @@ if can_use_otel_trace:
53
92
  | otel_trace.SpanContext
54
93
  | None, # pyright: ignore[reportPrivateImportUsage]
55
94
  ):
95
+ configure_tracing("chalkpy")
56
96
  if isinstance(ctx, otel_trace.SpanContext):
57
97
  new_span = otel_trace.NonRecordingSpan(ctx)
58
98
  new_context = otel_trace.set_span_in_context(new_span)
@@ -65,6 +105,7 @@ if can_use_otel_trace:
65
105
  def add_trace_headers( # pyright: ignore[reportRedeclaration]
66
106
  input_headers: None | dict[str, str]
67
107
  ) -> dict[str, str]:
108
+ configure_tracing("chalkpy")
68
109
  current_span_ctx = otel_trace.get_current_span().get_span_context()
69
110
  new_span_ctx = otel_trace.SpanContext(
70
111
  trace_id=current_span_ctx.trace_id,
@@ -86,6 +127,7 @@ elif can_use_ddtrace:
86
127
 
87
128
  @contextlib.contextmanager
88
129
  def safe_trace(span_id: str, attributes: Mapping[str, str] | None = None): # pyright: ignore[reportRedeclaration]
130
+ configure_tracing("chalkpy")
89
131
  if not ddtrace.tracer.enabled:
90
132
  yield
91
133
  return
@@ -106,16 +148,19 @@ elif can_use_ddtrace:
106
148
  yield
107
149
 
108
150
  def safe_add_metrics(metrics: Mapping[str, Union[int, float]]): # pyright: ignore[reportRedeclaration]
151
+ configure_tracing("chalkpy")
109
152
  span = ddtrace.tracer.current_span()
110
153
  if span:
111
154
  span.set_metrics(cast(Any, metrics))
112
155
 
113
156
  def safe_add_tags(tags: Mapping[str, str]): # pyright: ignore[reportRedeclaration]
157
+ configure_tracing("chalkpy")
114
158
  span = ddtrace.tracer.current_span()
115
159
  if span:
116
160
  span.set_tags(cast(Any, tags))
117
161
 
118
162
  def safe_current_trace_context() -> ddtrace.context.Context | otel_trace.SpanContext | None: # pyright: ignore[reportRedeclaration]
163
+ configure_tracing("chalkpy")
119
164
  return ddtrace.tracer.current_trace_context()
120
165
 
121
166
  @contextlib.contextmanager
@@ -125,6 +170,7 @@ elif can_use_ddtrace:
125
170
  | otel_trace.SpanContext
126
171
  | None, # pyright: ignore[reportPrivateImportUsage]
127
172
  ):
173
+ configure_tracing("chalkpy")
128
174
  if isinstance(ctx, ddtrace.context.Context) or isinstance(ctx, ddtrace.Span):
129
175
  ddtrace.tracer.context_provider.activate(ctx)
130
176
  yield
@@ -132,6 +178,7 @@ elif can_use_ddtrace:
132
178
  def add_trace_headers( # pyright: ignore[reportRedeclaration]
133
179
  input_headers: None | dict[str, str]
134
180
  ) -> dict[str, str]:
181
+ configure_tracing("chalkpy")
135
182
  headers: dict[str, str] = dict(input_headers if input_headers is not None else {})
136
183
  span = ddtrace.tracer.current_span()
137
184
  if span:
@@ -223,74 +270,74 @@ class PerfTimer:
223
270
 
224
271
 
225
272
  def configure_tracing(default_service_name: str):
226
- from chalk.utils.log_with_context import get_logger
227
-
228
- _logger = get_logger(__name__)
229
-
230
- if can_use_otel_trace:
231
- from opentelemetry import trace as otel_trace
232
- from opentelemetry.sdk.resources import Resource
233
- from opentelemetry.sdk.trace import TracerProvider
234
-
235
- provider = TracerProvider(
236
- resource=Resource.create(
237
- {
238
- "service.name": default_service_name,
239
- }
240
- ),
241
- )
242
- otel_trace.set_tracer_provider(provider)
243
-
244
- elif can_use_ddtrace:
245
- import ddtrace
246
- from ddtrace.filters import FilterRequestsOnUrl
247
-
248
- if ddtrace.config.service is None:
249
- ddtrace.config.service = default_service_name
250
- # Re-configuring the global tracer to capture any setting changes from environs from a .dotenv file
251
- # which might be loaded after the first ddtrace import
252
-
253
- ddtrace.tracer.configure(
254
- enabled=None if "DD_TRACE_ENABLED" not in os.environ else env_var_bool("DD_TRACE_ENABLED"),
255
- hostname=os.getenv("DD_AGENT_HOST") or os.getenv("DD_TRACE_AGENT_URL"),
256
- uds_path=os.getenv("DD_TRACE_AGENT_URL"),
257
- dogstatsd_url=os.getenv("DD_DOGSTATSD_URL"),
258
- api_version=os.getenv("DD_TRACE_API_VERSION"),
259
- compute_stats_enabled=env_var_bool("DD_TRACE_COMPUTE_STATS"),
260
- iast_enabled=None if "DD_IAST_ENABLED" not in os.environ else env_var_bool("DD_IAST_ENABLED"),
261
- # exclude healthcheck url from apm trace collection
262
- settings={
263
- "FILTERS": [
264
- FilterRequestsOnUrl(
265
- [
266
- r"^http://.*/healthcheck$",
267
- r"^http://.*/ready$",
268
- r"^http://[^/]*/$", # exclude "/"
269
- ]
270
- )
271
- ]
272
- },
273
- )
274
- if ddtrace.tracer.enabled:
275
- ddtrace.patch(
276
- asyncio=True,
277
- databricks=False,
278
- fastapi=True,
279
- futures=True,
280
- httplib=True,
281
- httpx=True,
282
- psycopg=True,
283
- redis=True,
284
- requests=True,
285
- sqlalchemy=False,
286
- urllib3=True,
273
+ def do_configure_tracing():
274
+ from chalk.utils.log_with_context import get_logger
275
+
276
+ _logger = get_logger(__name__)
277
+
278
+ if can_use_otel_trace:
279
+ from opentelemetry import trace as otel_trace
280
+ from opentelemetry.sdk.resources import Resource
281
+ from opentelemetry.sdk.trace import TracerProvider
282
+
283
+ provider = TracerProvider(
284
+ resource=Resource.create(
285
+ {
286
+ "service.name": default_service_name,
287
+ }
288
+ ),
287
289
  )
290
+ otel_trace.set_tracer_provider(provider)
291
+
292
+ elif can_use_ddtrace:
293
+ import ddtrace
294
+ from ddtrace.filters import FilterRequestsOnUrl
295
+
296
+ if ddtrace.config.service is None:
297
+ ddtrace.config.service = default_service_name
298
+ # Re-configuring the global tracer to capture any setting changes from environs from a .dotenv file
299
+ # which might be loaded after the first ddtrace import
300
+
301
+ ddtrace.tracer.configure(
302
+ enabled=None if "DD_TRACE_ENABLED" not in os.environ else env_var_bool("DD_TRACE_ENABLED"),
303
+ hostname=os.getenv("DD_AGENT_HOST") or os.getenv("DD_TRACE_AGENT_URL"),
304
+ uds_path=os.getenv("DD_TRACE_AGENT_URL"),
305
+ dogstatsd_url=os.getenv("DD_DOGSTATSD_URL"),
306
+ api_version=os.getenv("DD_TRACE_API_VERSION"),
307
+ compute_stats_enabled=env_var_bool("DD_TRACE_COMPUTE_STATS"),
308
+ iast_enabled=None if "DD_IAST_ENABLED" not in os.environ else env_var_bool("DD_IAST_ENABLED"),
309
+ # exclude healthcheck url from apm trace collection
310
+ settings={
311
+ "FILTERS": [
312
+ FilterRequestsOnUrl(
313
+ [
314
+ r"^http://.*/healthcheck$",
315
+ r"^http://.*/ready$",
316
+ r"^http://[^/]*/$", # exclude "/"
317
+ ]
318
+ )
319
+ ]
320
+ },
321
+ )
322
+ if ddtrace.tracer.enabled:
323
+ ddtrace.patch(
324
+ asyncio=True,
325
+ databricks=False,
326
+ fastapi=True,
327
+ futures=True,
328
+ httplib=True,
329
+ httpx=True,
330
+ psycopg=True,
331
+ redis=True,
332
+ requests=True,
333
+ sqlalchemy=False,
334
+ urllib3=True,
335
+ )
288
336
 
289
- _logger.info(
290
- f"Configuring DDtrace tracing: enabled={ddtrace.tracer.enabled}, service={ddtrace.config.service}, env={ddtrace.config.env}, trace_agent_url: {ddtrace.config._trace_agent_url}, effective trace agent: {ddtrace.tracer._agent_url}" # pyright: ignore [reportAttributeAccessIssue, reportPrivateUsage]
291
- )
292
- else:
293
- _logger.warning("neither opentelemetry nor ddtrace are installed")
294
-
337
+ _logger.info(
338
+ f"Configuring DDtrace tracing: enabled={ddtrace.tracer.enabled}, service={ddtrace.config.service}, env={ddtrace.config.env}, trace_agent_url: {ddtrace.config._trace_agent_url}, effective trace agent: {ddtrace.tracer._agent_url}" # pyright: ignore [reportAttributeAccessIssue, reportPrivateUsage]
339
+ )
340
+ else:
341
+ _logger.warning("neither opentelemetry nor ddtrace are installed")
295
342
 
296
- configure_tracing("chalkpy")
343
+ _TRACING_CONFIGURED.do_once(do_configure_tracing)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: chalkpy
3
- Version: 2.95.3
3
+ Version: 2.95.4
4
4
  Summary: Python SDK for Chalk
5
5
  Author: Chalk AI, Inc.
6
6
  Project-URL: Homepage, https://chalk.ai
@@ -1,5 +1,5 @@
1
1
  chalk/__init__.py,sha256=vKsx9-cl5kImlVWGHVRYO6bweBm79NAzGs3l36u71wM,2657
2
- chalk/_version.py,sha256=3mOL1q8f2weUXXobYqEuH_DLckY1SaBw45iZJ106Qa0,23
2
+ chalk/_version.py,sha256=806ZJ4Nmzvk8iZwepGS8Gxx4y0klotQk8lkbn8S8CIo,23
3
3
  chalk/cli.py,sha256=ckqqfOI-A2mT23-rnZzDMmblYj-2x1VBX8ebHlIEn9A,5873
4
4
  chalk/importer.py,sha256=m4lMn1lSYj_euDq8CS7LYTBnek9JOcjGJf9-82dJHbA,64441
5
5
  chalk/prompts.py,sha256=2H9UomLAamdfRTNUdKs9i3VTpiossuyRhntqsAXUhhg,16117
@@ -641,7 +641,7 @@ chalk/features/_vector.py,sha256=jtJmUTtCaUFru4Fw17PYWozl3pPEdIOCYAuZOqIaN3Y,720
641
641
  chalk/features/feature_cache_strategy.py,sha256=bXV-tjHfPzUotMpZ3h_D9Xxq-V1CLj_UcVtGIGMpMkI,4942
642
642
  chalk/features/feature_field.py,sha256=x-B8CIt086xMOjtfpRMGcmfysS6G2vA_whsLZgGQeqI,93759
643
643
  chalk/features/feature_set.py,sha256=yNi0_J4CylAVkVp1Y67qV6i8vHMdE0p99DnyLPABPHI,12406
644
- chalk/features/feature_set_decorator.py,sha256=e5yp1FHObicrXPlNUxXQf4iwq4RdWuP-qe0cboDT2QI,65060
644
+ chalk/features/feature_set_decorator.py,sha256=u92jAk0iVqdy3u-h_t6ieMDYpF-AWZRVpHaNrC33iqQ,65594
645
645
  chalk/features/feature_time.py,sha256=iUk8NDelig81jP7QT3tguyzx5eOZ-YC84OVgJRRKVwo,1639
646
646
  chalk/features/feature_wrapper.py,sha256=OolNWGGX67IAEMHCObFvOCpH5EmwjbMvMygRSBJJtu0,19259
647
647
  chalk/features/filter.py,sha256=2ldMbqvXC-nJ0jc-OZ36qHtrej-Jkx4TNQ1W_NZodAs,11177
@@ -814,12 +814,12 @@ chalk/utils/storage_client.py,sha256=cK5KH8DVAt4Okk3X4jNMCkMiZgfUJE9Sq3zn4HkaBQo
814
814
  chalk/utils/string.py,sha256=mHciu1FR1NdXiE0GjiCOOs_Q3JBVpaNnjUQPorE5cJg,4268
815
815
  chalk/utils/stubgen.py,sha256=-mKIWFeiZojtfPwaTd9o3h4m4RvTmMTk6i-bI9JpU6c,21580
816
816
  chalk/utils/threading.py,sha256=dacvfFCpDs9GDWdRrE2mmM3Ex5DKOIaj5rCYDTqGshk,5305
817
- chalk/utils/tracing.py,sha256=ye5z6UCEsrxXC3ofXUNCDdUCf8ydPahEO92qQTd0AIA,11383
817
+ chalk/utils/tracing.py,sha256=qAyMRdFBkL4Q2_Bn-C31atDfJirUtBvcSjkYC2R51sM,13005
818
818
  chalk/utils/weak_set_by_identity.py,sha256=VmikA_laYwFeOphCwXJIuyOIkrdlQe0bSzaXq7onoQw,953
819
819
  chalk/utils/pydanticutil/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
820
820
  chalk/utils/pydanticutil/pydantic_compat.py,sha256=O575lLYJ5GvZC4HMzR9yATxf9XwjC6NrDUXbNwZidlE,3031
821
- chalkpy-2.95.3.dist-info/METADATA,sha256=QZ1kTTPKmvBN0BhPkMwZrRQ2-F1rquRkTtW7MBM0Pq0,27494
822
- chalkpy-2.95.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
823
- chalkpy-2.95.3.dist-info/entry_points.txt,sha256=Vg23sd8icwq-morJrljVFr-kQnMbm95rZfZj5wsZGis,42
824
- chalkpy-2.95.3.dist-info/top_level.txt,sha256=1Q6_19IGYfNxSw50W8tYKEJ2t5HKQ3W9Wiw4ia5yg2c,6
825
- chalkpy-2.95.3.dist-info/RECORD,,
821
+ chalkpy-2.95.4.dist-info/METADATA,sha256=KWZ99My6RPafBho_fntwsoMUHCFT5oaLH2qaD6zDVm0,27494
822
+ chalkpy-2.95.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
823
+ chalkpy-2.95.4.dist-info/entry_points.txt,sha256=Vg23sd8icwq-morJrljVFr-kQnMbm95rZfZj5wsZGis,42
824
+ chalkpy-2.95.4.dist-info/top_level.txt,sha256=1Q6_19IGYfNxSw50W8tYKEJ2t5HKQ3W9Wiw4ia5yg2c,6
825
+ chalkpy-2.95.4.dist-info/RECORD,,