agentr 0.1.0__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.
@@ -0,0 +1,10 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
@@ -0,0 +1 @@
1
+ 3.13
agentr-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,8 @@
1
+ Metadata-Version: 2.4
2
+ Name: agentr
3
+ Version: 0.1.0
4
+ Summary: Add your description here
5
+ Author-email: Manoj Bajaj <manojbajaj95@gmail.com>
6
+ Requires-Python: >=3.13
7
+ Requires-Dist: pyyaml>=6.0.2
8
+ Requires-Dist: typer>=0.15.2
agentr-0.1.0/README.md ADDED
File without changes
@@ -0,0 +1,727 @@
1
+ openapi: 3.1.0
2
+ info:
3
+ title: Petstore - OpenAPI 3.1
4
+ description: |-
5
+ This is a sample Pet Store Server based on the OpenAPI 3.1 specification.
6
+
7
+ Some useful links:
8
+ - [OpenAPI Reference](https://www.speakeasy.com/openapi)
9
+ - [The Pet Store repository](https://github.com/swagger-api/swagger-petstore)
10
+ - [The source API definition for the Pet Store](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml)
11
+ termsOfService: http://swagger.io/terms/
12
+ contact:
13
+ email: support@speakeasy.com
14
+ license:
15
+ name: Apache 2.0
16
+ url: http://www.apache.org/licenses/LICENSE-2.0.html
17
+ version: 1.0.0
18
+ externalDocs:
19
+ description: Find out more about Swagger
20
+ url: http://swagger.io
21
+ security:
22
+ - api_key: []
23
+ servers:
24
+ - url: https://{environment}.petstore.io
25
+ description: A per-environment API.
26
+ variables:
27
+ environment:
28
+ description: The environment name. Defaults to the production environment.
29
+ default: prod
30
+ enum:
31
+ - prod
32
+ - staging
33
+ - dev
34
+ tags:
35
+ - name: pet
36
+ description: Everything about your Pets
37
+ externalDocs:
38
+ description: Find out more
39
+ url: http://swagger.io
40
+ - name: store
41
+ description: Access to Petstore orders
42
+ externalDocs:
43
+ description: Find out more about our store
44
+ url: http://swagger.io
45
+ - name: user
46
+ description: Operations about user
47
+ paths:
48
+ "/pet":
49
+ put:
50
+ tags:
51
+ - pet
52
+ summary: Update an existing pet
53
+ description: Update an existing pet by Id
54
+ operationId: updatePet
55
+ requestBody:
56
+ description: Update an existent pet in the store
57
+ content:
58
+ application/json:
59
+ schema:
60
+ "$ref": "#/components/schemas/Pet"
61
+ required: true
62
+ responses:
63
+ '200':
64
+ description: Successful operation
65
+ content:
66
+ application/json:
67
+ schema:
68
+ "$ref": "#/components/schemas/Pet"
69
+ '400':
70
+ $ref: '#/components/responses/InvalidInput'
71
+ '401':
72
+ $ref: '#/components/responses/Unauthorized'
73
+ '404':
74
+ $ref: '#/components/responses/NotFound'
75
+
76
+ post:
77
+ tags:
78
+ - pet
79
+ summary: Add a new pet to the store
80
+ description: Add a new pet to the store
81
+ operationId: addPet
82
+ requestBody:
83
+ description: Create a new pet in the store
84
+ content:
85
+ application/json:
86
+ schema:
87
+ "$ref": "#/components/schemas/Pet"
88
+ required: true
89
+ responses:
90
+ '200':
91
+ description: Successful operation
92
+ content:
93
+ application/json:
94
+ schema:
95
+ "$ref": "#/components/schemas/Pet"
96
+ '405':
97
+ description: Invalid input
98
+
99
+ "/pet/findByStatus":
100
+ get:
101
+ tags:
102
+ - pet
103
+ summary: Finds Pets by status
104
+ description: Multiple status values can be provided with comma separated strings
105
+ operationId: findPetsByStatus
106
+ parameters:
107
+ - name: status
108
+ in: query
109
+ description: Status values that need to be considered for filter
110
+ required: false
111
+ explode: true
112
+ schema:
113
+ type: string
114
+ default: available
115
+ enum:
116
+ - available
117
+ - pending
118
+ - sold
119
+ responses:
120
+ '200':
121
+ description: successful operation
122
+ content:
123
+ application/json:
124
+ schema:
125
+ type: array
126
+ items:
127
+ "$ref": "#/components/schemas/Pet"
128
+ '400':
129
+ $ref: '#/components/responses/InvalidInput'
130
+ '401':
131
+ $ref: '#/components/responses/Unauthorized'
132
+ '404':
133
+ $ref: '#/components/responses/NotFound'
134
+
135
+ "/pet/findByTags":
136
+ get:
137
+ tags:
138
+ - pet
139
+ summary: Finds Pets by tags
140
+ description: Multiple tags can be provided with comma separated strings. Use
141
+ tag1, tag2, tag3 for testing.
142
+ operationId: findPetsByTags
143
+ parameters:
144
+ - name: tags
145
+ in: query
146
+ description: Tags to filter by
147
+ required: false
148
+ explode: true
149
+ schema:
150
+ type: array
151
+ items:
152
+ type: string
153
+ responses:
154
+ '200':
155
+ description: successful operation
156
+ content:
157
+ application/json:
158
+ schema:
159
+ type: array
160
+ items:
161
+ "$ref": "#/components/schemas/Pet"
162
+ '400':
163
+ $ref: '#/components/responses/InvalidInput'
164
+ '401':
165
+ $ref: '#/components/responses/Unauthorized'
166
+ '404':
167
+ $ref: '#/components/responses/NotFound'
168
+
169
+ "/pet/{petId}":
170
+ get:
171
+ tags:
172
+ - pet
173
+ summary: Find pet by ID
174
+ description: Returns a single pet
175
+ operationId: getPetById
176
+ parameters:
177
+ - name: petId
178
+ in: path
179
+ description: ID of pet to return
180
+ required: true
181
+ schema:
182
+ type: integer
183
+ format: int64
184
+ responses:
185
+ '200':
186
+ description: successful operation
187
+ content:
188
+ application/json:
189
+ schema:
190
+ "$ref": "#/components/schemas/Pet"
191
+ '400':
192
+ $ref: '#/components/responses/InvalidInput'
193
+ '401':
194
+ $ref: '#/components/responses/Unauthorized'
195
+ '404':
196
+ $ref: '#/components/responses/NotFound'
197
+
198
+ delete:
199
+ tags:
200
+ - pet
201
+ summary: Deletes a pet
202
+ description: ''
203
+ operationId: deletePet
204
+ parameters:
205
+ - name: api_key
206
+ in: header
207
+ description: ''
208
+ required: false
209
+ schema:
210
+ type: string
211
+ - name: petId
212
+ in: path
213
+ description: Pet id to delete
214
+ required: true
215
+ schema:
216
+ type: integer
217
+ format: int64
218
+ responses:
219
+ '200':
220
+ description: Pet deleted
221
+ content:
222
+ application/json:
223
+ schema:
224
+ $ref: '#/components/schemas/Pet'
225
+ '400':
226
+ $ref: '#/components/responses/InvalidInput'
227
+ '401':
228
+ $ref: '#/components/responses/Unauthorized'
229
+ '404':
230
+ $ref: '#/components/responses/NotFound'
231
+
232
+ "/pet/{petId}/uploadImage":
233
+ post:
234
+ tags:
235
+ - pet
236
+ summary: uploads an image
237
+ description: ''
238
+ operationId: uploadFile
239
+ parameters:
240
+ - name: petId
241
+ in: path
242
+ description: ID of pet to update
243
+ required: true
244
+ schema:
245
+ type: integer
246
+ format: int64
247
+ - name: additionalMetadata
248
+ in: query
249
+ description: Additional Metadata
250
+ required: false
251
+ schema:
252
+ type: string
253
+ requestBody:
254
+ content:
255
+ application/octet-stream:
256
+ schema:
257
+ type: string
258
+ format: binary
259
+ responses:
260
+ '200':
261
+ description: successful operation
262
+ content:
263
+ application/json:
264
+ schema:
265
+ "$ref": "#/components/schemas/ApiResponse"
266
+
267
+ "/store/inventory":
268
+ get:
269
+ tags:
270
+ - store
271
+ summary: Returns pet inventories by status
272
+ description: Returns a map of status codes to quantities
273
+ operationId: getInventory
274
+ responses:
275
+ '200':
276
+ description: successful operation
277
+ content:
278
+ application/json:
279
+ schema:
280
+ type: object
281
+ additionalProperties:
282
+ type: integer
283
+ format: int32
284
+ '401':
285
+ $ref: '#/components/responses/Unauthorized'
286
+ '404':
287
+ $ref: '#/components/responses/NotFound'
288
+
289
+ "/store/order":
290
+ post:
291
+ tags:
292
+ - store
293
+ summary: Place an order for a pet
294
+ description: Place a new order in the store
295
+ operationId: placeOrder
296
+ requestBody:
297
+ content:
298
+ application/json:
299
+ schema:
300
+ "$ref": "#/components/schemas/Order"
301
+ responses:
302
+ '200':
303
+ description: successful operation
304
+ content:
305
+ application/json:
306
+ schema:
307
+ "$ref": "#/components/schemas/Order"
308
+ '405':
309
+ description: Invalid input
310
+ '401':
311
+ $ref: '#/components/responses/Unauthorized'
312
+ '404':
313
+ $ref: '#/components/responses/NotFound'
314
+ "/store/order/{orderId}":
315
+ get:
316
+ tags:
317
+ - store
318
+ summary: Find purchase order by ID
319
+ description: For valid response try integer IDs with value <= 5 or > 10. Other
320
+ values will generate exceptions.
321
+ operationId: getOrderById
322
+ parameters:
323
+ - name: orderId
324
+ in: path
325
+ description: ID of order that needs to be fetched
326
+ required: true
327
+ schema:
328
+ type: integer
329
+ format: int64
330
+ responses:
331
+ '200':
332
+ description: successful operation
333
+ content:
334
+ application/json:
335
+ schema:
336
+ "$ref": "#/components/schemas/Order"
337
+ '400':
338
+ $ref: '#/components/responses/InvalidInput'
339
+ '401':
340
+ $ref: '#/components/responses/Unauthorized'
341
+ '404':
342
+ $ref: '#/components/responses/NotFound'
343
+ delete:
344
+ tags:
345
+ - store
346
+ summary: Delete purchase order by ID
347
+ description: For valid response try integer IDs with value < 1000. Anything
348
+ above 1000 or nonintegers will generate API errors
349
+ operationId: deleteOrder
350
+ parameters:
351
+ - name: orderId
352
+ in: path
353
+ description: ID of the order that needs to be deleted
354
+ required: true
355
+ schema:
356
+ type: integer
357
+ format: int64
358
+ responses:
359
+ '200':
360
+ description: Order deleted
361
+ content:
362
+ application/json:
363
+ schema:
364
+ $ref: '#/components/schemas/Order'
365
+ '400':
366
+ $ref: '#/components/responses/InvalidInput'
367
+ '401':
368
+ $ref: '#/components/responses/Unauthorized'
369
+ '404':
370
+ $ref: '#/components/responses/NotFound'
371
+ "/user":
372
+ post:
373
+ tags:
374
+ - user
375
+ summary: Create user
376
+ description: This can only be done by the logged in user.
377
+ operationId: createUser
378
+ requestBody:
379
+ description: Created user object
380
+ content:
381
+ application/json:
382
+ schema:
383
+ "$ref": "#/components/schemas/User"
384
+ responses:
385
+ '200':
386
+ description: Successful operation
387
+ content:
388
+ application/json:
389
+ schema:
390
+ "$ref": "#/components/schemas/User"
391
+ "/user/createWithList":
392
+ post:
393
+ tags:
394
+ - user
395
+ summary: Creates list of users with given input array
396
+ description: Creates list of users with given input array
397
+ operationId: createUsersWithListInput
398
+ requestBody:
399
+ content:
400
+ application/json:
401
+ schema:
402
+ type: array
403
+ items:
404
+ "$ref": "#/components/schemas/User"
405
+ responses:
406
+ '200':
407
+ description: Successful operation
408
+ content:
409
+ application/json:
410
+ schema:
411
+ "$ref": "#/components/schemas/User"
412
+ "/user/login":
413
+ get:
414
+ tags:
415
+ - user
416
+ summary: Logs user into the system
417
+ description: ''
418
+ operationId: loginUser
419
+ parameters:
420
+ - name: username
421
+ in: query
422
+ description: The user name for login
423
+ required: false
424
+ schema:
425
+ type: string
426
+ - name: password
427
+ in: query
428
+ description: The password for login in clear text
429
+ required: false
430
+ schema:
431
+ type: string
432
+ responses:
433
+ '200':
434
+ description: successful operation
435
+ headers:
436
+ X-Rate-Limit:
437
+ description: calls per hour allowed by the user
438
+ schema:
439
+ type: integer
440
+ format: int32
441
+ X-Expires-After:
442
+ description: date in UTC when token expires
443
+ schema:
444
+ type: string
445
+ format: date-time
446
+ content:
447
+ application/json:
448
+ schema:
449
+ type: string
450
+ '400':
451
+ $ref: '#/components/responses/InvalidInput'
452
+ '401':
453
+ $ref: '#/components/responses/Unauthorized'
454
+ '404':
455
+ $ref: '#/components/responses/NotFound'
456
+ "/user/logout":
457
+ get:
458
+ tags:
459
+ - user
460
+ summary: Logs out current logged in user session
461
+ description: ''
462
+ operationId: logoutUser
463
+ parameters: []
464
+ responses:
465
+ '200':
466
+ description: successful operation
467
+ "/user/{username}":
468
+ get:
469
+ tags:
470
+ - user
471
+ summary: Get user by user name
472
+ description: ''
473
+ operationId: getUserByName
474
+ parameters:
475
+ - name: username
476
+ in: path
477
+ description: 'The name that needs to be fetched. Use user1 for testing. '
478
+ required: true
479
+ schema:
480
+ type: string
481
+ responses:
482
+ '200':
483
+ description: successful operation
484
+ content:
485
+ application/json:
486
+ schema:
487
+ "$ref": "#/components/schemas/User"
488
+ '400':
489
+ $ref: '#/components/responses/InvalidInput'
490
+ '401':
491
+ $ref: '#/components/responses/Unauthorized'
492
+ '404':
493
+ $ref: '#/components/responses/NotFound'
494
+ put:
495
+ tags:
496
+ - user
497
+ summary: Update user
498
+ description: This can only be done by the logged in user.
499
+ operationId: updateUser
500
+ parameters:
501
+ - name: username
502
+ in: path
503
+ description: name that needs to be updated
504
+ required: true
505
+ schema:
506
+ type: string
507
+ requestBody:
508
+ description: Update an existent user in the store
509
+ content:
510
+ application/json:
511
+ schema:
512
+ "$ref": "#/components/schemas/User"
513
+ responses:
514
+ '200':
515
+ description: successful operation
516
+ delete:
517
+ tags:
518
+ - user
519
+ summary: Delete user
520
+ description: This can only be done by the logged in user.
521
+ operationId: deleteUser
522
+ parameters:
523
+ - name: username
524
+ in: path
525
+ description: The name that needs to be deleted
526
+ required: true
527
+ schema:
528
+ type: string
529
+ responses:
530
+ '200':
531
+ description: User deleted
532
+ content:
533
+ application/json:
534
+ schema:
535
+ $ref: '#/components/schemas/User'
536
+ '400':
537
+ $ref: '#/components/responses/InvalidInput'
538
+ '401':
539
+ $ref: '#/components/responses/Unauthorized'
540
+ '404':
541
+ $ref: '#/components/responses/NotFound'
542
+ components:
543
+ securitySchemes:
544
+ api_key:
545
+ type: apiKey
546
+ name: api_key
547
+ in: header
548
+ schemas:
549
+ Order:
550
+ type: object
551
+ properties:
552
+ id:
553
+ type: integer
554
+ format: int64
555
+ example: 10
556
+ petId:
557
+ type: integer
558
+ format: int64
559
+ example: 198772
560
+ quantity:
561
+ type: integer
562
+ format: int32
563
+ example: 7
564
+ shipDate:
565
+ type: string
566
+ format: date-time
567
+ status:
568
+ type: string
569
+ description: Order Status
570
+ example: approved
571
+ enum:
572
+ - placed
573
+ - approved
574
+ - delivered
575
+ complete:
576
+ type: boolean
577
+ Category:
578
+ type: object
579
+ properties:
580
+ id:
581
+ type: integer
582
+ format: int64
583
+ example: 1
584
+ name:
585
+ type: string
586
+ example: Dogs
587
+ User:
588
+ type: object
589
+ properties:
590
+ id:
591
+ type: integer
592
+ format: int64
593
+ example: 10
594
+ username:
595
+ type: string
596
+ example: theUser
597
+ firstName:
598
+ type: string
599
+ example: John
600
+ lastName:
601
+ type: string
602
+ example: James
603
+ email:
604
+ type: string
605
+ example: john@email.com
606
+ password:
607
+ type: string
608
+ example: '12345'
609
+ phone:
610
+ type: string
611
+ example: '12345'
612
+ userStatus:
613
+ type: integer
614
+ description: User Status
615
+ format: int32
616
+ example: 1
617
+ Tag:
618
+ type: object
619
+ properties:
620
+ id:
621
+ type: integer
622
+ format: int64
623
+ name:
624
+ type: string
625
+ Pet:
626
+ required:
627
+ - name
628
+ - photoUrls
629
+ type: object
630
+ properties:
631
+ id:
632
+ type: integer
633
+ format: int64
634
+ example: 10
635
+ name:
636
+ type: string
637
+ example: doggie
638
+ category:
639
+ "$ref": "#/components/schemas/Category"
640
+ photoUrls:
641
+ type: array
642
+ items:
643
+ type: string
644
+ tags:
645
+ type: array
646
+ items:
647
+ "$ref": "#/components/schemas/Tag"
648
+ status:
649
+ type: string
650
+ description: pet status in the store
651
+ enum:
652
+ - available
653
+ - pending
654
+ - sold
655
+ ApiResponse:
656
+ type: object
657
+ properties:
658
+ code:
659
+ type: integer
660
+ format: int32
661
+ type:
662
+ type: string
663
+ message:
664
+ type: string
665
+ ApiErrorInvalidInput:
666
+ type: object
667
+ required:
668
+ - status
669
+ - error
670
+ properties:
671
+ status:
672
+ type: integer
673
+ format: int32
674
+ example: 400
675
+ error:
676
+ type: string
677
+ example: Bad request
678
+ ApiErrorNotFound:
679
+ type: object
680
+ required:
681
+ - status
682
+ - error
683
+ - code
684
+ properties:
685
+ status:
686
+ type: integer
687
+ format: int32
688
+ example: 404
689
+ error:
690
+ type: string
691
+ example: Not Found
692
+ code:
693
+ type: string
694
+ example: object_not_found
695
+ ApiErrorUnauthorized:
696
+ type: object
697
+ required:
698
+ - status
699
+ - error
700
+ properties:
701
+ status:
702
+ type: integer
703
+ format: int32
704
+ example: 401
705
+ error:
706
+ type: string
707
+ example: Unauthorized
708
+ responses:
709
+ Unauthorized:
710
+ description: Unauthorized error
711
+ content:
712
+ application/json:
713
+ schema:
714
+ $ref: '#/components/schemas/ApiErrorUnauthorized'
715
+ NotFound:
716
+ description: Not Found error
717
+ content:
718
+ application/json:
719
+ schema:
720
+ $ref: '#/components/schemas/ApiErrorNotFound'
721
+ InvalidInput:
722
+ description: Not Found error
723
+ content:
724
+ application/json:
725
+ schema:
726
+ $ref: '#/components/schemas/ApiErrorInvalidInput'
727
+
@@ -0,0 +1,21 @@
1
+ [project]
2
+ name = "agentr"
3
+ version = "0.1.0"
4
+ description = "Add your description here"
5
+ readme = "README.md"
6
+ authors = [
7
+ { name = "Manoj Bajaj", email = "manojbajaj95@gmail.com" }
8
+ ]
9
+ requires-python = ">=3.13"
10
+ dependencies = [
11
+ "pyyaml>=6.0.2",
12
+ "typer>=0.15.2",
13
+ ]
14
+
15
+ [project.scripts]
16
+ agentr = "agentr.cli:app"
17
+
18
+
19
+ [build-system]
20
+ requires = ["hatchling"]
21
+ build-backend = "hatchling.build"
@@ -0,0 +1,2 @@
1
+ def main():
2
+ print("hello")
@@ -0,0 +1,29 @@
1
+ import typer
2
+ import yaml
3
+ from pathlib import Path
4
+
5
+ app = typer.Typer()
6
+
7
+ @app.command()
8
+ def version():
9
+ """Show the version of the CLI"""
10
+ print("agentr version 0.1.0")
11
+
12
+ @app.command()
13
+ def generate(schema_path: Path = typer.Option(..., "--schema", "-s")):
14
+ """Generate API client from OpenAPI schema"""
15
+ if not schema_path.exists():
16
+ typer.echo(f"Error: Schema file {schema_path} does not exist", err=True)
17
+ raise typer.Exit(1)
18
+ from .utils.openapi import generate_api_client, load_schema
19
+
20
+ try:
21
+ schema = load_schema(schema_path)
22
+ except Exception as e:
23
+ typer.echo(f"Error loading schema: {e}", err=True)
24
+ raise typer.Exit(1)
25
+ code = generate_api_client(schema)
26
+ print(code)
27
+
28
+ if __name__ == "__main__":
29
+ app()
File without changes
File without changes
@@ -0,0 +1,185 @@
1
+ import json
2
+ import yaml
3
+ from pathlib import Path
4
+
5
+ def load_schema(path: Path):
6
+ if path.suffix == '.yaml':
7
+ type = 'yaml'
8
+ else:
9
+ type = 'json'
10
+ with open(path, 'r') as f:
11
+ if type == 'yaml':
12
+ return yaml.safe_load(f)
13
+ else:
14
+ return json.load(f)
15
+
16
+ def generate_api_client(schema):
17
+ """
18
+ Generate a Python API client class from an OpenAPI schema.
19
+
20
+ Args:
21
+ schema (dict): The OpenAPI schema as a dictionary.
22
+
23
+ Returns:
24
+ str: A string containing the Python code for the API client class.
25
+ """
26
+ methods = []
27
+
28
+ # Iterate over paths and their operations
29
+ for path, path_info in schema.get('paths', {}).items():
30
+ for method in path_info:
31
+ if method in ['get', 'post', 'put', 'delete', 'patch', 'options', 'head']:
32
+ operation = path_info[method]
33
+ method_code = generate_method_code(path, method, operation)
34
+ methods.append(method_code)
35
+
36
+ # Construct the class code
37
+ class_code = (
38
+ "import requests\n\n"
39
+ "class APIClient:\n"
40
+ " def __init__(self, base_url):\n"
41
+ " self.base_url = base_url\n\n" +
42
+ '\n\n'.join(methods)
43
+ )
44
+ return class_code
45
+
46
+ def generate_method_code(path, method, operation):
47
+ """
48
+ Generate the code for a single API method.
49
+
50
+ Args:
51
+ path (str): The API path (e.g., '/users/{user_id}').
52
+ method (str): The HTTP method (e.g., 'get').
53
+ operation (dict): The operation details from the schema.
54
+
55
+ Returns:
56
+ str: The Python code for the method.
57
+ """
58
+ # Determine function name
59
+ if 'operationId' in operation:
60
+ func_name = operation['operationId']
61
+ else:
62
+ # Generate name from path and method
63
+ path_parts = path.strip('/').split('/')
64
+ name_parts = [method]
65
+ for part in path_parts:
66
+ if part.startswith('{') and part.endswith('}'):
67
+ name_parts.append('by_' + part[1:-1])
68
+ else:
69
+ name_parts.append(part)
70
+ func_name = '_'.join(name_parts).replace('-', '_').lower()
71
+
72
+ # Get parameters and request body
73
+ parameters = operation.get('parameters', [])
74
+ has_body = 'requestBody' in operation
75
+ body_required = has_body and operation['requestBody'].get('required', False)
76
+
77
+ # Build function arguments
78
+ args = []
79
+ for param in parameters:
80
+ if param.get('required', False):
81
+ args.append(param['name'])
82
+ else:
83
+ args.append(f"{param['name']}=None")
84
+ if has_body:
85
+ args.append('body' if body_required else 'body=None')
86
+ signature = f"def {func_name}(self, {', '.join(args)}):"
87
+
88
+ # Build method body
89
+ body_lines = []
90
+
91
+ # Path parameters
92
+ path_params = [p for p in parameters if p['in'] == 'path']
93
+ path_params_dict = ', '.join([f"'{p['name']}': {p['name']}" for p in path_params])
94
+ body_lines.append(f" path_params = {{{path_params_dict}}}")
95
+
96
+ # Query parameters
97
+ query_params = [p for p in parameters if p['in'] == 'query']
98
+ query_params_items = ', '.join([f"('{p['name']}', {p['name']})" for p in query_params])
99
+ body_lines.append(
100
+ f" query_params = {{k: v for k, v in [{query_params_items}] if v is not None}}"
101
+ )
102
+
103
+ # Format URL
104
+ body_lines.append(f" url = f\"{{self.base_url}}{path}\".format_map(path_params)")
105
+
106
+ # Make HTTP request
107
+ method_func = method.lower()
108
+ if has_body:
109
+ body_lines.append(" if body is not None:")
110
+ body_lines.append(f" response = requests.{method_func}(url, params=query_params, json=body)")
111
+ body_lines.append(" else:")
112
+ body_lines.append(f" response = requests.{method_func}(url, params=query_params)")
113
+ else:
114
+ body_lines.append(f" response = requests.{method_func}(url, params=query_params)")
115
+
116
+ # Handle response
117
+ body_lines.append(" response.raise_for_status()")
118
+ body_lines.append(" return response.json()")
119
+
120
+ return signature + '\n' + '\n'.join(body_lines)
121
+
122
+ # Example usage
123
+ if __name__ == "__main__":
124
+ # Sample OpenAPI schema
125
+ schema = {
126
+ "paths": {
127
+ "/users": {
128
+ "get": {
129
+ "summary": "Get a list of users",
130
+ "parameters": [
131
+ {
132
+ "name": "limit",
133
+ "in": "query",
134
+ "required": False,
135
+ "schema": {"type": "integer"}
136
+ }
137
+ ],
138
+ "responses": {
139
+ "200": {
140
+ "description": "A list of users",
141
+ "content": {"application/json": {"schema": {"type": "array"}}}
142
+ }
143
+ }
144
+ },
145
+ "post": {
146
+ "summary": "Create a user",
147
+ "requestBody": {
148
+ "required": True,
149
+ "content": {
150
+ "application/json": {
151
+ "schema": {
152
+ "type": "object",
153
+ "properties": {"name": {"type": "string"}}
154
+ }
155
+ }
156
+ }
157
+ },
158
+ "responses": {
159
+ "201": {"description": "User created"}
160
+ }
161
+ }
162
+ },
163
+ "/users/{user_id}": {
164
+ "get": {
165
+ "summary": "Get a user by ID",
166
+ "parameters": [
167
+ {
168
+ "name": "user_id",
169
+ "in": "path",
170
+ "required": True,
171
+ "schema": {"type": "string"}
172
+ }
173
+ ],
174
+ "responses": {
175
+ "200": {"description": "User details"}
176
+ }
177
+ }
178
+ }
179
+ }
180
+ }
181
+
182
+
183
+ schema = load_schema('openapi.yaml')
184
+ code = generate_api_client(schema)
185
+ print(code)
agentr-0.1.0/uv.lock ADDED
@@ -0,0 +1,132 @@
1
+ version = 1
2
+ revision = 1
3
+ requires-python = ">=3.13"
4
+
5
+ [[package]]
6
+ name = "agentr"
7
+ version = "0.1.0"
8
+ source = { editable = "." }
9
+ dependencies = [
10
+ { name = "pyyaml" },
11
+ { name = "typer" },
12
+ ]
13
+
14
+ [package.metadata]
15
+ requires-dist = [
16
+ { name = "pyyaml", specifier = ">=6.0.2" },
17
+ { name = "typer", specifier = ">=0.15.2" },
18
+ ]
19
+
20
+ [[package]]
21
+ name = "click"
22
+ version = "8.1.8"
23
+ source = { registry = "https://pypi.org/simple" }
24
+ dependencies = [
25
+ { name = "colorama", marker = "sys_platform == 'win32'" },
26
+ ]
27
+ sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593 }
28
+ wheels = [
29
+ { url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188 },
30
+ ]
31
+
32
+ [[package]]
33
+ name = "colorama"
34
+ version = "0.4.6"
35
+ source = { registry = "https://pypi.org/simple" }
36
+ sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 }
37
+ wheels = [
38
+ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 },
39
+ ]
40
+
41
+ [[package]]
42
+ name = "markdown-it-py"
43
+ version = "3.0.0"
44
+ source = { registry = "https://pypi.org/simple" }
45
+ dependencies = [
46
+ { name = "mdurl" },
47
+ ]
48
+ sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596 }
49
+ wheels = [
50
+ { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 },
51
+ ]
52
+
53
+ [[package]]
54
+ name = "mdurl"
55
+ version = "0.1.2"
56
+ source = { registry = "https://pypi.org/simple" }
57
+ sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 }
58
+ wheels = [
59
+ { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 },
60
+ ]
61
+
62
+ [[package]]
63
+ name = "pygments"
64
+ version = "2.19.1"
65
+ source = { registry = "https://pypi.org/simple" }
66
+ sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581 }
67
+ wheels = [
68
+ { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293 },
69
+ ]
70
+
71
+ [[package]]
72
+ name = "pyyaml"
73
+ version = "6.0.2"
74
+ source = { registry = "https://pypi.org/simple" }
75
+ sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631 }
76
+ wheels = [
77
+ { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309 },
78
+ { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679 },
79
+ { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428 },
80
+ { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361 },
81
+ { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523 },
82
+ { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660 },
83
+ { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597 },
84
+ { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527 },
85
+ { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446 },
86
+ ]
87
+
88
+ [[package]]
89
+ name = "rich"
90
+ version = "13.9.4"
91
+ source = { registry = "https://pypi.org/simple" }
92
+ dependencies = [
93
+ { name = "markdown-it-py" },
94
+ { name = "pygments" },
95
+ ]
96
+ sdist = { url = "https://files.pythonhosted.org/packages/ab/3a/0316b28d0761c6734d6bc14e770d85506c986c85ffb239e688eeaab2c2bc/rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", size = 223149 }
97
+ wheels = [
98
+ { url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424 },
99
+ ]
100
+
101
+ [[package]]
102
+ name = "shellingham"
103
+ version = "1.5.4"
104
+ source = { registry = "https://pypi.org/simple" }
105
+ sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310 }
106
+ wheels = [
107
+ { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755 },
108
+ ]
109
+
110
+ [[package]]
111
+ name = "typer"
112
+ version = "0.15.2"
113
+ source = { registry = "https://pypi.org/simple" }
114
+ dependencies = [
115
+ { name = "click" },
116
+ { name = "rich" },
117
+ { name = "shellingham" },
118
+ { name = "typing-extensions" },
119
+ ]
120
+ sdist = { url = "https://files.pythonhosted.org/packages/8b/6f/3991f0f1c7fcb2df31aef28e0594d8d54b05393a0e4e34c65e475c2a5d41/typer-0.15.2.tar.gz", hash = "sha256:ab2fab47533a813c49fe1f16b1a370fd5819099c00b119e0633df65f22144ba5", size = 100711 }
121
+ wheels = [
122
+ { url = "https://files.pythonhosted.org/packages/7f/fc/5b29fea8cee020515ca82cc68e3b8e1e34bb19a3535ad854cac9257b414c/typer-0.15.2-py3-none-any.whl", hash = "sha256:46a499c6107d645a9c13f7ee46c5d5096cae6f5fc57dd11eccbbb9ae3e44ddfc", size = 45061 },
123
+ ]
124
+
125
+ [[package]]
126
+ name = "typing-extensions"
127
+ version = "4.12.2"
128
+ source = { registry = "https://pypi.org/simple" }
129
+ sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321 }
130
+ wheels = [
131
+ { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 },
132
+ ]