string-schema 0.1.5__py3-none-any.whl → 0.1.6__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.
@@ -15,6 +15,7 @@ Key Functions:
15
15
 
16
16
  import functools
17
17
  import uuid
18
+ from datetime import datetime, timezone
18
19
  from typing import Any, Dict, Type, Union, Callable, Optional, List
19
20
  import logging
20
21
 
@@ -30,6 +31,48 @@ except ImportError:
30
31
  logger = logging.getLogger(__name__)
31
32
 
32
33
 
34
+ def _ensure_timezone_aware_dict(data: Dict[str, Any]) -> Dict[str, Any]:
35
+ """
36
+ Ensure all datetime values in a dictionary have timezone information.
37
+
38
+ This function recursively processes dictionaries and lists to add UTC timezone
39
+ information to naive datetime objects, ensuring consistent API responses.
40
+
41
+ Args:
42
+ data: Dictionary that may contain datetime values
43
+
44
+ Returns:
45
+ Dictionary with timezone-aware datetime values converted to ISO format
46
+ """
47
+ if not isinstance(data, dict):
48
+ return data
49
+
50
+ result = {}
51
+ for key, value in data.items():
52
+ if isinstance(value, datetime):
53
+ # Add UTC timezone to naive datetime objects
54
+ if value.tzinfo is None:
55
+ value = value.replace(tzinfo=timezone.utc)
56
+ # Convert to ISO format string for consistent API responses
57
+ result[key] = value.isoformat()
58
+ elif isinstance(value, dict):
59
+ # Recursively process nested dictionaries
60
+ result[key] = _ensure_timezone_aware_dict(value)
61
+ elif isinstance(value, list):
62
+ # Process lists that may contain dictionaries or datetime objects
63
+ result[key] = [
64
+ _ensure_timezone_aware_dict(item) if isinstance(item, dict)
65
+ else item.isoformat() if isinstance(item, datetime) and item.tzinfo is None
66
+ else item.replace(tzinfo=timezone.utc).isoformat() if isinstance(item, datetime)
67
+ else item
68
+ for item in value
69
+ ]
70
+ else:
71
+ result[key] = value
72
+
73
+ return result
74
+
75
+
33
76
  def string_to_model(schema_str: str, name: Optional[str] = None) -> Type[BaseModel]:
34
77
  """
35
78
  Create Pydantic model from string schema.
@@ -218,13 +261,21 @@ def validate_to_dict(data: Union[Dict[str, Any], Any], schema_str: str) -> Union
218
261
  try:
219
262
  # Try Pydantic v2 RootModel style
220
263
  validated_instance = TempModel(data)
221
- # Return the validated array data
222
- return validated_instance.model_dump() if hasattr(validated_instance, 'model_dump') else validated_instance.dict()
264
+ # Return the validated array data with timezone-aware conversion
265
+ result_data = validated_instance.model_dump() if hasattr(validated_instance, 'model_dump') else validated_instance.dict()
266
+ # Process array items for timezone-aware datetime conversion
267
+ if isinstance(result_data, list):
268
+ return [_ensure_timezone_aware_dict(item) if isinstance(item, dict) else item for item in result_data]
269
+ return result_data
223
270
  except:
224
271
  # Fallback to Pydantic v1 style
225
272
  validated_instance = TempModel(__root__=data)
226
- # Return the validated array data
227
- return validated_instance.model_dump()['__root__'] if hasattr(validated_instance, 'model_dump') else validated_instance.dict()['__root__']
273
+ # Return the validated array data with timezone-aware conversion
274
+ result_data = validated_instance.model_dump()['__root__'] if hasattr(validated_instance, 'model_dump') else validated_instance.dict()['__root__']
275
+ # Process array items for timezone-aware datetime conversion
276
+ if isinstance(result_data, list):
277
+ return [_ensure_timezone_aware_dict(item) if isinstance(item, dict) else item for item in result_data]
278
+ return result_data
228
279
  else:
229
280
  # Handle different input types for object schemas
230
281
  if isinstance(data, dict):
@@ -236,11 +287,14 @@ def validate_to_dict(data: Union[Dict[str, Any], Any], schema_str: str) -> Union
236
287
  # Try direct validation
237
288
  validated_instance = TempModel(data)
238
289
 
239
- # Return as dictionary (use model_dump for Pydantic v2, fallback to dict for v1)
290
+ # Return as dictionary with timezone-aware datetime handling
240
291
  if hasattr(validated_instance, 'model_dump'):
241
- return validated_instance.model_dump()
292
+ result_dict = validated_instance.model_dump()
242
293
  else:
243
- return validated_instance.dict()
294
+ result_dict = validated_instance.dict()
295
+
296
+ # Ensure timezone-aware datetime conversion for consistent API responses
297
+ return _ensure_timezone_aware_dict(result_dict)
244
298
 
245
299
  except ValidationError as e:
246
300
  # Re-raise the original validation error
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: string-schema
3
- Version: 0.1.5
3
+ Version: 0.1.6
4
4
  Summary: A simple, LLM-friendly schema definition library for converting string syntax to structured schemas
5
5
  Home-page: https://github.com/xychenmsn/string-schema
6
6
  Author: Michael Chen
@@ -151,6 +151,7 @@ String Schema takes human-readable text descriptions and converts them into stru
151
151
  - **🤖 LLM Data Extraction**: Define extraction schemas that LLMs can easily follow
152
152
  - **🔧 API Development**: Generate Pydantic models and OpenAPI docs from simple syntax
153
153
  - **✅ Data Validation**: Create robust validation schemas with minimal code
154
+ - **🌍 Timezone-Aware APIs**: Automatic UTC conversion for consistent datetime handling
154
155
  - **📋 Configuration**: Define and validate application configuration schemas
155
156
  - **🔄 Data Transformation**: Convert between different schema formats
156
157
 
@@ -175,6 +176,12 @@ print(user_dict) # {"name": "John Doe", "email": "john@example.com", "age": 25}
175
176
  user_model = validate_to_model(raw_data, "name:string, email:email, age:int?")
176
177
  print(user_model.name) # "John Doe" - Full type safety
177
178
  print(user_model.age) # 25 - Converted to int
179
+
180
+ # 🌍 Automatic timezone handling for datetime fields
181
+ from datetime import datetime
182
+ event_data = {"name": "Meeting", "start_time": datetime(2025, 8, 13, 14, 30)}
183
+ event_dict = validate_to_dict(event_data, "name:string, start_time:datetime")
184
+ print(event_dict) # {"name": "Meeting", "start_time": "2025-08-13T14:30:00+00:00"}
178
185
  ```
179
186
 
180
187
  ### 🎨 Function Decorators
@@ -1,6 +1,6 @@
1
1
  string_schema/__init__.py,sha256=J0_B0TNO0AK_piEcT5gFFHllywjx16DTP59ps_Fp-WU,4052
2
2
  string_schema/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
3
- string_schema/utilities.py,sha256=iLyqCKFd0qTL13xyZvt3Dia2-gjZCjHyDVVm59GxLK4,19918
3
+ string_schema/utilities.py,sha256=FjWKNHPVMFxUc04ITtt2eC4bI6ayLDYwr44fnBgN0-o,22351
4
4
  string_schema/core/__init__.py,sha256=jeukkZ1WoCSXrBafumHVH2GkCJ6QjnkH_jAr3DESFio,481
5
5
  string_schema/core/builders.py,sha256=AHDTqtCnSe5ZN-DwedisqXqktjgl6nypd-mebucjI3k,7809
6
6
  string_schema/core/fields.py,sha256=iLUR-w3pZCr7OkQHhb2DFkVLtObnpyJ_mEUdc0qAqXY,5534
@@ -17,8 +17,8 @@ string_schema/parsing/__init__.py,sha256=dFW68DqJIwP4w_aYaZMjjVK15X7tCv8A0SPqmIg
17
17
  string_schema/parsing/optimizer.py,sha256=Ofte8Tb7sKmdEv7RrVIEBQ4Qqr-Whanp1vh8BakcOgw,8479
18
18
  string_schema/parsing/string_parser.py,sha256=-a_143fjNkxcRu24JdpqA6GltR7a_2AUXPNgHsbwYv4,24989
19
19
  string_schema/parsing/syntax.py,sha256=RO3BIAnWfDBupowOnoJocHtAe-kwE-SgRWXKknVwGdg,8900
20
- string_schema-0.1.5.dist-info/licenses/LICENSE,sha256=wCD2KBeSlVSkJy0apl6zmVj04uw97UJhRRi-en_3Qfk,1065
21
- string_schema-0.1.5.dist-info/METADATA,sha256=W8XGHUtUAz-SlPW1Mw1Y_SHy1SjuntWS9AolofnE64E,18246
22
- string_schema-0.1.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
23
- string_schema-0.1.5.dist-info/top_level.txt,sha256=1uTmLPYIRrCDVxUW1fDFRMaWvGO48NRcGmbW4oq89I0,14
24
- string_schema-0.1.5.dist-info/RECORD,,
20
+ string_schema-0.1.6.dist-info/licenses/LICENSE,sha256=wCD2KBeSlVSkJy0apl6zmVj04uw97UJhRRi-en_3Qfk,1065
21
+ string_schema-0.1.6.dist-info/METADATA,sha256=L96Jgf9qVZ2K2LwLb5H7stwh684wy5vYFR2bze1yQII,18662
22
+ string_schema-0.1.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
23
+ string_schema-0.1.6.dist-info/top_level.txt,sha256=1uTmLPYIRrCDVxUW1fDFRMaWvGO48NRcGmbW4oq89I0,14
24
+ string_schema-0.1.6.dist-info/RECORD,,