geniespec 0.1.2.dev8__tar.gz → 0.1.2.dev11__tar.gz

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 (22) hide show
  1. {geniespec-0.1.2.dev8 → geniespec-0.1.2.dev11}/PKG-INFO +2 -1
  2. {geniespec-0.1.2.dev8 → geniespec-0.1.2.dev11}/README.md +1 -0
  3. {geniespec-0.1.2.dev8 → geniespec-0.1.2.dev11}/pyproject.toml +2 -6
  4. {geniespec-0.1.2.dev8 → geniespec-0.1.2.dev11}/pyproject.toml.orig +2 -7
  5. {geniespec-0.1.2.dev8 → geniespec-0.1.2.dev11}/src/geniespec/api_schema.yaml +11 -0
  6. {geniespec-0.1.2.dev8 → geniespec-0.1.2.dev11}/src/geniespec/genie.py +21 -7
  7. {geniespec-0.1.2.dev8 → geniespec-0.1.2.dev11}/src/geniespec/types.py +5 -0
  8. {geniespec-0.1.2.dev8 → geniespec-0.1.2.dev11}/src/geniespec/__init__.py +0 -0
  9. {geniespec-0.1.2.dev8 → geniespec-0.1.2.dev11}/src/geniespec/cli.py +0 -0
  10. {geniespec-0.1.2.dev8 → geniespec-0.1.2.dev11}/src/geniespec/languages.py +0 -0
  11. {geniespec-0.1.2.dev8 → geniespec-0.1.2.dev11}/src/geniespec/renderable_types.py +0 -0
  12. {geniespec-0.1.2.dev8 → geniespec-0.1.2.dev11}/src/geniespec/templates/python-server/{service}/__init__.py.j2 +0 -0
  13. {geniespec-0.1.2.dev8 → geniespec-0.1.2.dev11}/src/geniespec/templates/python-server/{service}/v{version}/__init__.py.j2 +0 -0
  14. {geniespec-0.1.2.dev8 → geniespec-0.1.2.dev11}/src/geniespec/templates/python-server/{service}/v{version}/api.py.j2 +0 -0
  15. {geniespec-0.1.2.dev8 → geniespec-0.1.2.dev11}/src/geniespec/templates/python-server/{service}/v{version}/endpoints.py.j2 +0 -0
  16. {geniespec-0.1.2.dev8 → geniespec-0.1.2.dev11}/src/geniespec/templates/python-server/{service}/v{version}/exceptions.py.j2 +0 -0
  17. {geniespec-0.1.2.dev8 → geniespec-0.1.2.dev11}/src/geniespec/templates/python-server/{service}/v{version}/internal.py.j2 +0 -0
  18. {geniespec-0.1.2.dev8 → geniespec-0.1.2.dev11}/src/geniespec/templates/python-server/{service}/v{version}/resources.py.j2 +0 -0
  19. {geniespec-0.1.2.dev8 → geniespec-0.1.2.dev11}/src/geniespec/templates/typescript-client/{service}/v{version}/client.ts.j2 +0 -0
  20. {geniespec-0.1.2.dev8 → geniespec-0.1.2.dev11}/src/geniespec/templates/typescript-client/{service}/v{version}/endpoints.ts.j2 +0 -0
  21. {geniespec-0.1.2.dev8 → geniespec-0.1.2.dev11}/src/geniespec/templates/typescript-client/{service}/v{version}/index.ts.j2 +0 -0
  22. {geniespec-0.1.2.dev8 → geniespec-0.1.2.dev11}/src/geniespec/templates/typescript-client/{service}/v{version}/resources.ts.j2 +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: geniespec
3
- Version: 0.1.2.dev8
3
+ Version: 0.1.2.dev11
4
4
  Summary: Generate API code from an api.yaml spec
5
5
  License-Expression: MIT
6
6
  Requires-Dist: jinja2>=3.1.6
@@ -124,6 +124,7 @@ resources:
124
124
  `overrides` keep an API that existed before genie working the same way once it moves to genie. They are meant to be dropped in the next major version of that API.
125
125
 
126
126
  - `shouldPrefixParentName: false` on a child resource names it without its parent's name: `Agent` under `User` stays `Agent` (not `UserAgent`), so its primary attribute is `agent-id` rather than `user-agent-id` and its fields keep their names. Its path is unchanged (`/users/{userId}/agents/{agentId}`).
127
+ - `responseFieldName` on a `GET`, `LIST`, `CREATE` or `UPDATE` transition renames the field its response puts the resource in (for example `memories` instead of `agentMemories`). Custom transitions name it with `responseField`.
127
128
 
128
129
  # Development
129
130
 
@@ -110,6 +110,7 @@ resources:
110
110
  `overrides` keep an API that existed before genie working the same way once it moves to genie. They are meant to be dropped in the next major version of that API.
111
111
 
112
112
  - `shouldPrefixParentName: false` on a child resource names it without its parent's name: `Agent` under `User` stays `Agent` (not `UserAgent`), so its primary attribute is `agent-id` rather than `user-agent-id` and its fields keep their names. Its path is unchanged (`/users/{userId}/agents/{agentId}`).
113
+ - `responseFieldName` on a `GET`, `LIST`, `CREATE` or `UPDATE` transition renames the field its response puts the resource in (for example `memories` instead of `agentMemories`). Custom transitions name it with `responseField`.
113
114
 
114
115
  # Development
115
116
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "geniespec"
3
- version = "0.1.2.dev8"
3
+ version = "0.1.2.dev11"
4
4
  description = "Generate API code from an api.yaml spec"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -21,7 +21,7 @@ repository = "https://github.com/kibalabs/genie"
21
21
 
22
22
  [dependency-groups]
23
23
  dev = [
24
- "kiba-build==0.1.11.dev15",
24
+ "kiba-build==0.1.11.dev24",
25
25
  "kiba-core[core-api,requester]>=0.5.3.dev87,<0.5.4",
26
26
  ]
27
27
 
@@ -31,7 +31,3 @@ build-backend = "uv_build"
31
31
 
32
32
  [tool.pytest.ini_options]
33
33
  pythonpath = ["src"]
34
-
35
- [tool.bumpversion]
36
- search = 'version = "{current_version}"'
37
- replace = 'version = "{new_version}"'
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "geniespec"
3
- version = "0.1.2.dev8"
3
+ version = "0.1.2.dev11"
4
4
  description = "Generate API code from an api.yaml spec"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -21,7 +21,7 @@ repository = "https://github.com/kibalabs/genie"
21
21
 
22
22
  [dependency-groups]
23
23
  dev = [
24
- "kiba-build==0.1.11.dev15",
24
+ "kiba-build==0.1.11.dev24",
25
25
  "kiba-core[core-api,requester]>=0.5.3.dev87,<0.5.4",
26
26
  ]
27
27
 
@@ -31,8 +31,3 @@ build-backend = "uv_build"
31
31
 
32
32
  [tool.pytest.ini_options]
33
33
  pythonpath = ["src"]
34
-
35
- # NOTE(krishan711): without this, bumping the version also rewrites dependency pins that contain it (e.g. 0.1.1 inside kiba-build==0.1.11.dev15)
36
- [tool.bumpversion]
37
- search = "version = \"{current_version}\""
38
- replace = "version = \"{new_version}\""
@@ -263,6 +263,8 @@ definitions:
263
263
  type: string
264
264
  extensions:
265
265
  type: object
266
+ overrides:
267
+ $ref: '#/definitions/TransitionOverrides'
266
268
  Transition:
267
269
  type: object
268
270
  additionalProperties: false
@@ -319,6 +321,15 @@ definitions:
319
321
  type: string
320
322
  extensions:
321
323
  type: object
324
+ overrides:
325
+ $ref: '#/definitions/TransitionOverrides'
326
+ TransitionOverrides:
327
+ type: object
328
+ additionalProperties: false
329
+ properties:
330
+ responseFieldName:
331
+ type: string
332
+ pattern: '^[a-z][A-Za-z0-9-]*$'
322
333
  RootTransition:
323
334
  type: object
324
335
  allOf:
@@ -264,6 +264,15 @@ class Renderer:
264
264
  def _operation_documentation(transition: BaseTransition) -> dict[str, object]:
265
265
  return {'operationId': transition.operationId, 'summary': transition.summary, 'description': transition.description, 'tags': transition.tags, 'extensions': transition.extensions}
266
266
 
267
+ def _with_transition_fields(self, operation: RenderableOperation, transition: BaseTransition, isStandard: bool) -> RenderableOperation:
268
+ update = self._operation_documentation(transition=transition)
269
+ responseFieldName = transition.overrides.responseFieldName
270
+ if responseFieldName is not None:
271
+ if not isStandard or not operation.responseFields:
272
+ raise SemanticValidationException(message=f'Only GET, LIST, CREATE and UPDATE transitions can override responseFieldName: {transition.action}')
273
+ update['responseFields'] = [field.model_copy(update={'name': RenderableString.from_kebab_case_string(string=responseFieldName)}) for field in operation.responseFields]
274
+ return operation.model_copy(update=update)
275
+
267
276
  @staticmethod
268
277
  def _resource_full_name(resource: Resource, name: str) -> str:
269
278
  return f'{resource.parentResource or ""}{name}' if resource.overrides.shouldPrefixParentName else name
@@ -462,13 +471,17 @@ class Renderer:
462
471
  if resourceErrors:
463
472
  raise SemanticValidationException(message='\n'.join(resourceErrors))
464
473
  renderableOperations = [
465
- self._action_operation(
474
+ self._with_transition_fields(
475
+ operation=self._action_operation(
476
+ transition=transition,
477
+ endpoint=RenderableEndpoint(components=[ActionEndpointComponent(actionName=RenderableString.from_separated_string(string=transition.action, separator='-'))]),
478
+ knownTypeNames=knownTypeNames,
479
+ defaultAuthentication=api.defaultAuthentication,
480
+ defaultRateLimit=api.defaultRateLimit,
481
+ ),
466
482
  transition=transition,
467
- endpoint=RenderableEndpoint(components=[ActionEndpointComponent(actionName=RenderableString.from_separated_string(string=transition.action, separator='-'))]),
468
- knownTypeNames=knownTypeNames,
469
- defaultAuthentication=api.defaultAuthentication,
470
- defaultRateLimit=api.defaultRateLimit,
471
- ).model_copy(update=self._operation_documentation(transition=transition))
483
+ isStandard=False,
484
+ )
472
485
  for transition in api.transitions
473
486
  ]
474
487
  renderableExceptions = [
@@ -574,7 +587,8 @@ class Renderer:
574
587
  for endpoint in customEndpoints:
575
588
  customEndpoint = RenderableEndpoint(components=[*endpoint.components, ActionEndpointComponent(actionName=RenderableString.from_separated_string(string=transition.action, separator='-'))])
576
589
  renderableApi.operations.append(self._action_operation(transition=transition, endpoint=customEndpoint, knownTypeNames=knownTypeNames, defaultAuthentication=api.defaultAuthentication, defaultRateLimit=api.defaultRateLimit, isIndirectAction=transition.isIndirectAction))
577
- renderableApi.operations[operationCount:] = [operation.model_copy(update=self._operation_documentation(transition=transition)) for operation in renderableApi.operations[operationCount:]]
590
+ isStandard = transition.action.upper() in {'CREATE', 'UPDATE', 'GET', 'LIST'}
591
+ renderableApi.operations[operationCount:] = [self._with_transition_fields(operation=operation, transition=transition, isStandard=isStandard) for operation in renderableApi.operations[operationCount:]]
578
592
  if len(renderableApi.operations) == operationCount:
579
593
  uncoveredTransitions.append(f'{renderableResource.singleName.pascalCaseString} {transition.action}')
580
594
  if uncoveredTransitions:
@@ -117,6 +117,10 @@ class RequestField(BaseModel):
117
117
  description: str | None = None
118
118
 
119
119
 
120
+ class TransitionOverrides(BaseModel):
121
+ responseFieldName: str | None = None
122
+
123
+
120
124
  class BaseTransition(BaseModel):
121
125
  action: str
122
126
  method: str | None = None
@@ -130,6 +134,7 @@ class BaseTransition(BaseModel):
130
134
  description: str | None = None
131
135
  tags: list[str] = []
132
136
  extensions: dict[str, pydantic.JsonValue] = {}
137
+ overrides: TransitionOverrides = TransitionOverrides()
133
138
 
134
139
 
135
140
  class Transition(BaseTransition):