pycharter 0.0.20__py3-none-any.whl → 0.0.22__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.
Files changed (222) hide show
  1. api/dependencies/__init__.py +2 -1
  2. api/dependencies/database.py +71 -5
  3. api/main.py +47 -8
  4. api/models/contracts.py +6 -4
  5. api/models/metadata.py +11 -7
  6. api/models/schemas.py +16 -10
  7. api/routes/v1/contracts.py +498 -226
  8. api/routes/v1/metadata.py +52 -211
  9. api/routes/v1/schemas.py +1 -1
  10. api/routes/v1/settings.py +88 -1
  11. api/utils.py +224 -0
  12. pycharter/__init__.py +149 -93
  13. pycharter/data/templates/template_transform_advanced.yaml +50 -0
  14. pycharter/data/templates/template_transform_simple.yaml +59 -0
  15. pycharter/db/models/base.py +1 -2
  16. pycharter/etl_generator/orchestrator.py +463 -487
  17. pycharter/metadata_store/postgres.py +16 -191
  18. pycharter/metadata_store/sqlite.py +12 -41
  19. {pycharter-0.0.20.dist-info → pycharter-0.0.22.dist-info}/METADATA +284 -62
  20. pycharter-0.0.22.dist-info/RECORD +358 -0
  21. ui/static/404/index.html +1 -1
  22. ui/static/404.html +1 -1
  23. ui/static/__next.__PAGE__.txt +1 -1
  24. ui/static/__next._full.txt +2 -2
  25. ui/static/__next._head.txt +1 -1
  26. ui/static/__next._index.txt +2 -2
  27. ui/static/__next._tree.txt +2 -2
  28. ui/static/_next/static/chunks/13d4a0fbd74c1ee4.js +1 -0
  29. ui/static/_next/static/chunks/2edb43b48432ac04.js +441 -0
  30. ui/static/_next/static/chunks/c4fa4f4114b7c352.js +1 -0
  31. ui/static/_next/static/chunks/d2363397e1b2bcab.css +1 -0
  32. ui/static/_next/static/chunks/f7d1a90dd75d2572.js +1 -0
  33. ui/static/_not-found/__next._full.txt +2 -2
  34. ui/static/_not-found/__next._head.txt +1 -1
  35. ui/static/_not-found/__next._index.txt +2 -2
  36. ui/static/_not-found/__next._not-found.__PAGE__.txt +1 -1
  37. ui/static/_not-found/__next._not-found.txt +1 -1
  38. ui/static/_not-found/__next._tree.txt +2 -2
  39. ui/static/_not-found/index.html +1 -1
  40. ui/static/_not-found/index.txt +2 -2
  41. ui/static/contracts/__next._full.txt +3 -3
  42. ui/static/contracts/__next._head.txt +1 -1
  43. ui/static/contracts/__next._index.txt +2 -2
  44. ui/static/contracts/__next._tree.txt +2 -2
  45. ui/static/contracts/__next.contracts.__PAGE__.txt +2 -2
  46. ui/static/contracts/__next.contracts.txt +1 -1
  47. ui/static/contracts/index.html +1 -1
  48. ui/static/contracts/index.txt +3 -3
  49. ui/static/documentation/__next._full.txt +3 -3
  50. ui/static/documentation/__next._head.txt +1 -1
  51. ui/static/documentation/__next._index.txt +2 -2
  52. ui/static/documentation/__next._tree.txt +2 -2
  53. ui/static/documentation/__next.documentation.__PAGE__.txt +2 -2
  54. ui/static/documentation/__next.documentation.txt +1 -1
  55. ui/static/documentation/index.html +2 -2
  56. ui/static/documentation/index.txt +3 -3
  57. ui/static/index.html +1 -1
  58. ui/static/index.txt +2 -2
  59. ui/static/metadata/__next._full.txt +2 -2
  60. ui/static/metadata/__next._head.txt +1 -1
  61. ui/static/metadata/__next._index.txt +2 -2
  62. ui/static/metadata/__next._tree.txt +2 -2
  63. ui/static/metadata/__next.metadata.__PAGE__.txt +1 -1
  64. ui/static/metadata/__next.metadata.txt +1 -1
  65. ui/static/metadata/index.html +1 -1
  66. ui/static/metadata/index.txt +2 -2
  67. ui/static/quality/__next._full.txt +2 -2
  68. ui/static/quality/__next._head.txt +1 -1
  69. ui/static/quality/__next._index.txt +2 -2
  70. ui/static/quality/__next._tree.txt +2 -2
  71. ui/static/quality/__next.quality.__PAGE__.txt +1 -1
  72. ui/static/quality/__next.quality.txt +1 -1
  73. ui/static/quality/index.html +2 -2
  74. ui/static/quality/index.txt +2 -2
  75. ui/static/rules/__next._full.txt +2 -2
  76. ui/static/rules/__next._head.txt +1 -1
  77. ui/static/rules/__next._index.txt +2 -2
  78. ui/static/rules/__next._tree.txt +2 -2
  79. ui/static/rules/__next.rules.__PAGE__.txt +1 -1
  80. ui/static/rules/__next.rules.txt +1 -1
  81. ui/static/rules/index.html +1 -1
  82. ui/static/rules/index.txt +2 -2
  83. ui/static/schemas/__next._full.txt +2 -2
  84. ui/static/schemas/__next._head.txt +1 -1
  85. ui/static/schemas/__next._index.txt +2 -2
  86. ui/static/schemas/__next._tree.txt +2 -2
  87. ui/static/schemas/__next.schemas.__PAGE__.txt +1 -1
  88. ui/static/schemas/__next.schemas.txt +1 -1
  89. ui/static/schemas/index.html +1 -1
  90. ui/static/schemas/index.txt +2 -2
  91. ui/static/settings/__next._full.txt +2 -2
  92. ui/static/settings/__next._head.txt +1 -1
  93. ui/static/settings/__next._index.txt +2 -2
  94. ui/static/settings/__next._tree.txt +2 -2
  95. ui/static/settings/__next.settings.__PAGE__.txt +1 -1
  96. ui/static/settings/__next.settings.txt +1 -1
  97. ui/static/settings/index.html +1 -1
  98. ui/static/settings/index.txt +2 -2
  99. ui/static/static/.gitkeep +0 -0
  100. ui/static/static/404/index.html +1 -0
  101. ui/static/static/404.html +1 -0
  102. ui/static/static/__next.__PAGE__.txt +10 -0
  103. ui/static/static/__next._full.txt +30 -0
  104. ui/static/static/__next._head.txt +7 -0
  105. ui/static/static/__next._index.txt +9 -0
  106. ui/static/static/__next._tree.txt +2 -0
  107. ui/static/static/_next/static/chunks/222442f6da32302a.js +1 -0
  108. ui/static/static/_next/static/chunks/247eb132b7f7b574.js +1 -0
  109. ui/static/static/_next/static/chunks/297d55555b71baba.js +1 -0
  110. ui/static/static/_next/static/chunks/2ab439ce003cd691.js +1 -0
  111. ui/static/static/_next/static/chunks/414e77373f8ff61c.js +1 -0
  112. ui/static/static/_next/static/chunks/49ca65abd26ae49e.js +1 -0
  113. ui/static/static/_next/static/chunks/5e04d10c4a7b58a3.js +1 -0
  114. ui/static/static/_next/static/chunks/652ad0aa26265c47.js +2 -0
  115. ui/static/static/_next/static/chunks/75d88a058d8ffaa6.js +1 -0
  116. ui/static/static/_next/static/chunks/8c89634cf6bad76f.js +1 -0
  117. ui/static/static/_next/static/chunks/9667e7a3d359eb39.js +1 -0
  118. ui/static/static/_next/static/chunks/9c23f44fff36548a.js +1 -0
  119. ui/static/static/_next/static/chunks/a6dad97d9634a72d.js +1 -0
  120. ui/static/static/_next/static/chunks/b32a0963684b9933.js +4 -0
  121. ui/static/static/_next/static/chunks/c69f6cba366bd988.js +1 -0
  122. ui/static/static/_next/static/chunks/db913959c675cea6.js +1 -0
  123. ui/static/static/_next/static/chunks/f061a4be97bfc3b3.js +1 -0
  124. ui/static/static/_next/static/chunks/f2e7afeab1178138.js +1 -0
  125. ui/static/static/_next/static/chunks/ff1a16fafef87110.js +1 -0
  126. ui/static/static/_next/static/chunks/turbopack-ffcb7ab6794027ef.js +3 -0
  127. ui/static/static/_next/static/tNTkVW6puVXC4bAm4WrHl/_buildManifest.js +11 -0
  128. ui/static/static/_next/static/tNTkVW6puVXC4bAm4WrHl/_ssgManifest.js +1 -0
  129. ui/static/static/_not-found/__next._full.txt +17 -0
  130. ui/static/static/_not-found/__next._head.txt +7 -0
  131. ui/static/static/_not-found/__next._index.txt +9 -0
  132. ui/static/static/_not-found/__next._not-found.__PAGE__.txt +5 -0
  133. ui/static/static/_not-found/__next._not-found.txt +4 -0
  134. ui/static/static/_not-found/__next._tree.txt +2 -0
  135. ui/static/static/_not-found/index.html +1 -0
  136. ui/static/static/_not-found/index.txt +17 -0
  137. ui/static/static/contracts/__next._full.txt +21 -0
  138. ui/static/static/contracts/__next._head.txt +7 -0
  139. ui/static/static/contracts/__next._index.txt +9 -0
  140. ui/static/static/contracts/__next._tree.txt +2 -0
  141. ui/static/static/contracts/__next.contracts.__PAGE__.txt +9 -0
  142. ui/static/static/contracts/__next.contracts.txt +4 -0
  143. ui/static/static/contracts/index.html +1 -0
  144. ui/static/static/contracts/index.txt +21 -0
  145. ui/static/static/documentation/__next._full.txt +21 -0
  146. ui/static/static/documentation/__next._head.txt +7 -0
  147. ui/static/static/documentation/__next._index.txt +9 -0
  148. ui/static/static/documentation/__next._tree.txt +2 -0
  149. ui/static/static/documentation/__next.documentation.__PAGE__.txt +9 -0
  150. ui/static/static/documentation/__next.documentation.txt +4 -0
  151. ui/static/static/documentation/index.html +93 -0
  152. ui/static/static/documentation/index.txt +21 -0
  153. ui/static/static/index.html +1 -0
  154. ui/static/static/index.txt +30 -0
  155. ui/static/static/metadata/__next._full.txt +21 -0
  156. ui/static/static/metadata/__next._head.txt +7 -0
  157. ui/static/static/metadata/__next._index.txt +9 -0
  158. ui/static/static/metadata/__next._tree.txt +2 -0
  159. ui/static/static/metadata/__next.metadata.__PAGE__.txt +9 -0
  160. ui/static/static/metadata/__next.metadata.txt +4 -0
  161. ui/static/static/metadata/index.html +1 -0
  162. ui/static/static/metadata/index.txt +21 -0
  163. ui/static/static/quality/__next._full.txt +21 -0
  164. ui/static/static/quality/__next._head.txt +7 -0
  165. ui/static/static/quality/__next._index.txt +9 -0
  166. ui/static/static/quality/__next._tree.txt +2 -0
  167. ui/static/static/quality/__next.quality.__PAGE__.txt +9 -0
  168. ui/static/static/quality/__next.quality.txt +4 -0
  169. ui/static/static/quality/index.html +2 -0
  170. ui/static/static/quality/index.txt +21 -0
  171. ui/static/static/rules/__next._full.txt +21 -0
  172. ui/static/static/rules/__next._head.txt +7 -0
  173. ui/static/static/rules/__next._index.txt +9 -0
  174. ui/static/static/rules/__next._tree.txt +2 -0
  175. ui/static/static/rules/__next.rules.__PAGE__.txt +9 -0
  176. ui/static/static/rules/__next.rules.txt +4 -0
  177. ui/static/static/rules/index.html +1 -0
  178. ui/static/static/rules/index.txt +21 -0
  179. ui/static/static/schemas/__next._full.txt +21 -0
  180. ui/static/static/schemas/__next._head.txt +7 -0
  181. ui/static/static/schemas/__next._index.txt +9 -0
  182. ui/static/static/schemas/__next._tree.txt +2 -0
  183. ui/static/static/schemas/__next.schemas.__PAGE__.txt +9 -0
  184. ui/static/static/schemas/__next.schemas.txt +4 -0
  185. ui/static/static/schemas/index.html +1 -0
  186. ui/static/static/schemas/index.txt +21 -0
  187. ui/static/static/settings/__next._full.txt +21 -0
  188. ui/static/static/settings/__next._head.txt +7 -0
  189. ui/static/static/settings/__next._index.txt +9 -0
  190. ui/static/static/settings/__next._tree.txt +2 -0
  191. ui/static/static/settings/__next.settings.__PAGE__.txt +9 -0
  192. ui/static/static/settings/__next.settings.txt +4 -0
  193. ui/static/static/settings/index.html +1 -0
  194. ui/static/static/settings/index.txt +21 -0
  195. ui/static/static/validation/__next._full.txt +21 -0
  196. ui/static/static/validation/__next._head.txt +7 -0
  197. ui/static/static/validation/__next._index.txt +9 -0
  198. ui/static/static/validation/__next._tree.txt +2 -0
  199. ui/static/static/validation/__next.validation.__PAGE__.txt +9 -0
  200. ui/static/static/validation/__next.validation.txt +4 -0
  201. ui/static/static/validation/index.html +1 -0
  202. ui/static/static/validation/index.txt +21 -0
  203. ui/static/validation/__next._full.txt +2 -2
  204. ui/static/validation/__next._head.txt +1 -1
  205. ui/static/validation/__next._index.txt +2 -2
  206. ui/static/validation/__next._tree.txt +2 -2
  207. ui/static/validation/__next.validation.__PAGE__.txt +1 -1
  208. ui/static/validation/__next.validation.txt +1 -1
  209. ui/static/validation/index.html +1 -1
  210. ui/static/validation/index.txt +2 -2
  211. pycharter/db/schemas/.ipynb_checkpoints/data_contract-checkpoint.py +0 -160
  212. pycharter-0.0.20.dist-info/RECORD +0 -247
  213. {pycharter-0.0.20.dist-info → pycharter-0.0.22.dist-info}/WHEEL +0 -0
  214. {pycharter-0.0.20.dist-info → pycharter-0.0.22.dist-info}/entry_points.txt +0 -0
  215. {pycharter-0.0.20.dist-info → pycharter-0.0.22.dist-info}/licenses/LICENSE +0 -0
  216. {pycharter-0.0.20.dist-info → pycharter-0.0.22.dist-info}/top_level.txt +0 -0
  217. /ui/static/_next/static/{tNTkVW6puVXC4bAm4WrHl → 0rYA78L88aUyD2Uh38hhX}/_buildManifest.js +0 -0
  218. /ui/static/_next/static/{tNTkVW6puVXC4bAm4WrHl → 0rYA78L88aUyD2Uh38hhX}/_ssgManifest.js +0 -0
  219. /ui/static/{_next → static/_next}/static/chunks/4e310fe5005770a3.css +0 -0
  220. /ui/static/{_next → static/_next}/static/chunks/5fc14c00a2779dc5.js +0 -0
  221. /ui/static/{_next → static/_next}/static/chunks/b584574fdc8ab13e.js +0 -0
  222. /ui/static/{_next → static/_next}/static/chunks/d5989c94d3614b3a.js +0 -0
@@ -4,6 +4,7 @@ Dependencies for API routes.
4
4
  This module provides FastAPI dependency injection for shared resources.
5
5
  """
6
6
 
7
+ from api.dependencies.database import get_db_session
7
8
  from api.dependencies.store import get_metadata_store
8
9
 
9
- __all__ = ["get_metadata_store"]
10
+ __all__ = ["get_db_session", "get_metadata_store"]
@@ -4,7 +4,7 @@ Database session dependency for API routes.
4
4
 
5
5
  import os
6
6
  from pathlib import Path
7
- from typing import Optional
7
+ from typing import Generator, Optional
8
8
 
9
9
  from fastapi import Depends, HTTPException, status
10
10
  from sqlalchemy import create_engine, inspect
@@ -99,36 +99,102 @@ def _ensure_sqlite_initialized(db_url: str) -> None:
99
99
  logger.warning(f"Could not auto-initialize SQLite database: {e}")
100
100
 
101
101
 
102
- def get_db_session() -> Session:
102
+ def get_db_session() -> Generator[Session, None, None]:
103
103
  """
104
104
  FastAPI dependency to get database session.
105
105
 
106
106
  Defaults to SQLite (sqlite:///pycharter.db) if no database URL is configured.
107
107
  Automatically initializes SQLite database if it doesn't exist or is uninitialized.
108
108
 
109
- Returns:
109
+ **Important**: This dependency properly manages session lifecycle using yield,
110
+ ensuring sessions are closed after request completion.
111
+
112
+ Yields:
110
113
  SQLAlchemy session
111
114
 
112
115
  Raises:
113
116
  HTTPException: If database connection fails
114
117
  """
118
+ import logging
119
+
120
+ logger = logging.getLogger(__name__)
121
+
115
122
  db_url = get_database_url()
116
123
 
117
124
  # Default to SQLite if no database URL is configured
118
125
  if not db_url:
119
126
  default_db_path = Path.cwd() / "pycharter.db"
120
127
  db_url = f"sqlite:///{default_db_path}"
128
+ logger.warning(
129
+ f"No database URL configured. Using default SQLite: {db_url}\n"
130
+ f"To use PostgreSQL, set PYCHARTER_DATABASE_URL environment variable:\n"
131
+ f" export PYCHARTER_DATABASE_URL='postgresql://user:password@localhost:5432/pycharter'"
132
+ )
133
+ else:
134
+ # Mask password in logs
135
+ masked_url = db_url
136
+ if "@" in db_url and "://" in db_url:
137
+ parts = db_url.split("@", 1)
138
+ if ":" in parts[0]:
139
+ user_pass = parts[0].split("://", 1)[1]
140
+ if ":" in user_pass:
141
+ user, _ = user_pass.split(":", 1)
142
+ masked_url = db_url.split(":", 2)[0] + "://" + user + ":****@" + parts[1]
143
+ logger.info(f"Using database: {masked_url}")
121
144
 
122
145
  # Auto-initialize SQLite if needed
123
146
  _ensure_sqlite_initialized(db_url)
124
147
 
148
+ session = None
125
149
  try:
126
150
  session = get_session(db_url)
127
- return session
151
+ # Test the connection by executing a simple query
152
+ from sqlalchemy import text
153
+ session.execute(text("SELECT 1"))
154
+ yield session
128
155
  except Exception as e:
156
+ if session:
157
+ try:
158
+ session.rollback()
159
+ except Exception:
160
+ pass
161
+ logger.error(f"Database session error: {e}", exc_info=True)
162
+
163
+ # Provide more helpful error messages
164
+ error_detail = "Failed to connect to database"
165
+ error_msg = str(e).lower()
166
+
167
+ # Check for common issues
168
+ if "no such table" in error_msg or "table" in error_msg and "doesn't exist" in error_msg:
169
+ error_detail = (
170
+ "Database tables not found. Please initialize the database:\n"
171
+ f" pycharter db init {db_url}"
172
+ )
173
+ elif "database is locked" in error_msg:
174
+ error_detail = (
175
+ "Database is locked. Another process may be using it.\n"
176
+ "Close other connections or wait a moment and try again."
177
+ )
178
+ elif "permission denied" in error_msg or "access denied" in error_msg:
179
+ error_detail = (
180
+ "Database permission denied. Check file permissions:\n"
181
+ f" chmod 644 {db_url.split(':///')[-1] if 'sqlite' in db_url else 'database file'}"
182
+ )
183
+ else:
184
+ # Show detailed error in development mode
185
+ is_development = os.getenv("ENVIRONMENT") == "development" or not os.getenv("ENVIRONMENT")
186
+ if is_development:
187
+ error_detail = f"Failed to connect to database: {str(e)}"
188
+
129
189
  raise HTTPException(
130
190
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
131
- detail=f"Failed to connect to database: {str(e)}",
191
+ detail=error_detail,
132
192
  )
193
+ finally:
194
+ if session:
195
+ try:
196
+ session.close()
197
+ except Exception:
198
+ pass
133
199
 
134
200
 
api/main.py CHANGED
@@ -59,11 +59,35 @@ def create_application() -> FastAPI:
59
59
  )
60
60
 
61
61
  # Add CORS middleware
62
+ import os
63
+ # Get CORS origins from environment variable
64
+ cors_origins_env = os.getenv("CORS_ORIGINS", "").strip()
65
+ cors_origins = [origin.strip() for origin in cors_origins_env.split(",") if origin.strip()] if cors_origins_env else []
66
+
67
+ # Default behavior: In development (or when ENVIRONMENT not set), allow localhost origins
68
+ # This makes development easier without requiring environment variables
69
+ is_development = os.getenv("ENVIRONMENT") == "development"
70
+ is_production = os.getenv("ENVIRONMENT") == "production"
71
+
72
+ # If no explicit CORS origins set and not in production, allow localhost for development
73
+ if not cors_origins and not is_production:
74
+ cors_origins = [
75
+ "http://localhost:3000",
76
+ "http://localhost:3001",
77
+ "http://127.0.0.1:3000",
78
+ "http://127.0.0.1:3001",
79
+ ]
80
+
81
+ # Configure CORS middleware
82
+ # Note: Can't use allow_credentials=True with allow_origins=["*"]
83
+ # So we use specific origins for development, or "*" without credentials for production
84
+ use_credentials = bool(cors_origins and "*" not in cors_origins)
85
+
62
86
  app.add_middleware(
63
87
  CORSMiddleware,
64
- allow_origins=["*"], # Configure appropriately for production
65
- allow_credentials=True,
66
- allow_methods=["*"],
88
+ allow_origins=cors_origins if cors_origins else ["*"], # Fallback to "*" if explicitly empty
89
+ allow_credentials=use_credentials,
90
+ allow_methods=["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"],
67
91
  allow_headers=["*"],
68
92
  )
69
93
 
@@ -179,13 +203,28 @@ def create_application() -> FastAPI:
179
203
  @app.exception_handler(Exception)
180
204
  async def global_exception_handler(request: Request, exc: Exception) -> JSONResponse:
181
205
  """Global exception handler for unhandled errors."""
182
- return JSONResponse(
183
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
184
- content={
185
- "error": "Internal server error",
206
+ import logging
207
+ import os
208
+
209
+ logger = logging.getLogger(__name__)
210
+ logger.error(f"Unhandled exception: {exc}", exc_info=True)
211
+
212
+ # In production, don't expose internal error details
213
+ is_development = os.getenv("ENVIRONMENT") == "development"
214
+
215
+ error_detail = {
216
+ "error": "Internal server error",
217
+ }
218
+
219
+ if is_development:
220
+ error_detail.update({
186
221
  "message": str(exc),
187
222
  "type": type(exc).__name__,
188
- },
223
+ })
224
+
225
+ return JSONResponse(
226
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
227
+ content=error_detail,
189
228
  )
190
229
 
191
230
  # Override openapi() method to handle schema generation errors gracefully
api/models/contracts.py CHANGED
@@ -4,7 +4,7 @@ Request/Response models for contract endpoints.
4
4
 
5
5
  from typing import Any, Dict, List, Optional
6
6
 
7
- from pydantic import BaseModel, Field, field_validator, model_validator
7
+ from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
8
8
 
9
9
  from pycharter.shared.name_validator import validate_name
10
10
 
@@ -37,7 +37,7 @@ class ContractParseRequest(BaseModel):
37
37
  class ContractParseResponse(BaseModel):
38
38
  """Response model for parsed contract."""
39
39
 
40
- schema: Dict[str, Any] = Field(..., description="JSON Schema definition")
40
+ schema: Dict[str, Any] = Field(..., description="JSON Schema definition", alias="schema")
41
41
  metadata: Optional[Dict[str, Any]] = Field(None, description="Metadata information")
42
42
  ownership: Optional[Dict[str, Any]] = Field(None, description="Ownership information")
43
43
  governance_rules: Optional[Dict[str, Any]] = Field(None, description="Governance rules")
@@ -45,8 +45,9 @@ class ContractParseResponse(BaseModel):
45
45
  validation_rules: Optional[Dict[str, Any]] = Field(None, description="Validation rules")
46
46
  versions: Optional[Dict[str, str]] = Field(None, description="Component versions")
47
47
 
48
- class Config:
49
- json_schema_extra = {
48
+ model_config = ConfigDict(
49
+ populate_by_name=True,
50
+ json_schema_extra={
50
51
  "example": {
51
52
  "schema": {
52
53
  "type": "object",
@@ -65,6 +66,7 @@ class ContractParseResponse(BaseModel):
65
66
  }
66
67
  }
67
68
  }
69
+ )
68
70
 
69
71
 
70
72
  class ContractBuildRequest(BaseModel):
api/models/metadata.py CHANGED
@@ -4,7 +4,7 @@ Request/Response models for metadata store endpoints.
4
4
 
5
5
  from typing import Any, Dict, List, Optional
6
6
 
7
- from pydantic import BaseModel, Field, field_validator
7
+ from pydantic import BaseModel, ConfigDict, Field, field_validator
8
8
 
9
9
  from pycharter.shared.name_validator import validate_name
10
10
 
@@ -13,7 +13,7 @@ class SchemaStoreRequest(BaseModel):
13
13
  """Request model for storing a schema."""
14
14
 
15
15
  schema_name: str = Field(..., description="Schema name/identifier")
16
- schema: Dict[str, Any] = Field(..., description="JSON Schema definition")
16
+ schema: Dict[str, Any] = Field(..., description="JSON Schema definition", alias="schema")
17
17
  version: str = Field(..., description="Schema version")
18
18
 
19
19
  @field_validator('schema_name')
@@ -30,8 +30,9 @@ class SchemaStoreRequest(BaseModel):
30
30
  v['title'] = validate_name(str(v['title']), field_name="schema.title")
31
31
  return v
32
32
 
33
- class Config:
34
- json_schema_extra = {
33
+ model_config = ConfigDict(
34
+ populate_by_name=True,
35
+ json_schema_extra={
35
36
  "example": {
36
37
  "schema_name": "user_schema",
37
38
  "schema": {
@@ -44,6 +45,7 @@ class SchemaStoreRequest(BaseModel):
44
45
  "version": "1.0.0"
45
46
  }
46
47
  }
48
+ )
47
49
 
48
50
 
49
51
  class SchemaStoreResponse(BaseModel):
@@ -81,11 +83,12 @@ class SchemaGetRequest(BaseModel):
81
83
  class SchemaGetResponse(BaseModel):
82
84
  """Response model for retrieved schema."""
83
85
 
84
- schema: Dict[str, Any] = Field(..., description="JSON Schema definition")
86
+ schema: Dict[str, Any] = Field(..., description="JSON Schema definition", alias="schema")
85
87
  version: Optional[str] = Field(None, description="Schema version")
86
88
 
87
- class Config:
88
- json_schema_extra = {
89
+ model_config = ConfigDict(
90
+ populate_by_name=True,
91
+ json_schema_extra={
89
92
  "example": {
90
93
  "schema": {
91
94
  "type": "object",
@@ -97,6 +100,7 @@ class SchemaGetResponse(BaseModel):
97
100
  "version": "1.0.0"
98
101
  }
99
102
  }
103
+ )
100
104
 
101
105
 
102
106
  class MetadataStoreRequest(BaseModel):
api/models/schemas.py CHANGED
@@ -4,17 +4,18 @@ Request/Response models for schema generation and conversion endpoints.
4
4
 
5
5
  from typing import Any, Dict, Optional
6
6
 
7
- from pydantic import BaseModel, Field
7
+ from pydantic import BaseModel, ConfigDict, Field
8
8
 
9
9
 
10
10
  class SchemaGenerateRequest(BaseModel):
11
11
  """Request model for generating a Pydantic model from JSON Schema."""
12
12
 
13
- schema: Dict[str, Any] = Field(..., description="JSON Schema definition")
13
+ schema: Dict[str, Any] = Field(..., description="JSON Schema definition", alias="schema")
14
14
  model_name: Optional[str] = Field("DynamicModel", description="Name for the generated model")
15
15
 
16
- class Config:
17
- json_schema_extra = {
16
+ model_config = ConfigDict(
17
+ populate_by_name=True,
18
+ json_schema_extra={
18
19
  "example": {
19
20
  "schema": {
20
21
  "type": "object",
@@ -27,17 +28,19 @@ class SchemaGenerateRequest(BaseModel):
27
28
  "model_name": "User"
28
29
  }
29
30
  }
31
+ )
30
32
 
31
33
 
32
34
  class SchemaGenerateResponse(BaseModel):
33
35
  """Response model for generated schema."""
34
36
 
35
37
  model_name: str = Field(..., description="Name of the generated model")
36
- schema_json: Dict[str, Any] = Field(..., description="JSON Schema representation of the model")
38
+ schema_definition: Dict[str, Any] = Field(..., description="JSON Schema representation of the model", alias="schema_json")
37
39
  message: str = Field(..., description="Success message")
38
40
 
39
- class Config:
40
- json_schema_extra = {
41
+ model_config = ConfigDict(
42
+ populate_by_name=True,
43
+ json_schema_extra={
41
44
  "example": {
42
45
  "model_name": "User",
43
46
  "schema_json": {
@@ -51,6 +54,7 @@ class SchemaGenerateResponse(BaseModel):
51
54
  "message": "Model generated successfully"
52
55
  }
53
56
  }
57
+ )
54
58
 
55
59
 
56
60
  class SchemaConvertRequest(BaseModel):
@@ -71,12 +75,13 @@ class SchemaConvertRequest(BaseModel):
71
75
  class SchemaConvertResponse(BaseModel):
72
76
  """Response model for converted schema."""
73
77
 
74
- schema: Dict[str, Any] = Field(..., description="JSON Schema definition")
78
+ schema: Dict[str, Any] = Field(..., description="JSON Schema definition", alias="schema")
75
79
  title: Optional[str] = Field(None, description="Schema title")
76
80
  version: Optional[str] = Field(None, description="Schema version")
77
81
 
78
- class Config:
79
- json_schema_extra = {
82
+ model_config = ConfigDict(
83
+ populate_by_name=True,
84
+ json_schema_extra={
80
85
  "example": {
81
86
  "schema": {
82
87
  "type": "object",
@@ -89,4 +94,5 @@ class SchemaConvertResponse(BaseModel):
89
94
  "version": "1.0.0"
90
95
  }
91
96
  }
97
+ )
92
98