mseep-agentops 0.4.18__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.
- agentops/__init__.py +488 -0
- agentops/client/__init__.py +5 -0
- agentops/client/api/__init__.py +71 -0
- agentops/client/api/base.py +162 -0
- agentops/client/api/types.py +21 -0
- agentops/client/api/versions/__init__.py +10 -0
- agentops/client/api/versions/v3.py +65 -0
- agentops/client/api/versions/v4.py +104 -0
- agentops/client/client.py +211 -0
- agentops/client/http/__init__.py +0 -0
- agentops/client/http/http_adapter.py +116 -0
- agentops/client/http/http_client.py +215 -0
- agentops/config.py +268 -0
- agentops/enums.py +36 -0
- agentops/exceptions.py +38 -0
- agentops/helpers/__init__.py +44 -0
- agentops/helpers/dashboard.py +54 -0
- agentops/helpers/deprecation.py +50 -0
- agentops/helpers/env.py +52 -0
- agentops/helpers/serialization.py +137 -0
- agentops/helpers/system.py +178 -0
- agentops/helpers/time.py +11 -0
- agentops/helpers/version.py +36 -0
- agentops/instrumentation/__init__.py +598 -0
- agentops/instrumentation/common/__init__.py +82 -0
- agentops/instrumentation/common/attributes.py +278 -0
- agentops/instrumentation/common/instrumentor.py +147 -0
- agentops/instrumentation/common/metrics.py +100 -0
- agentops/instrumentation/common/objects.py +26 -0
- agentops/instrumentation/common/span_management.py +176 -0
- agentops/instrumentation/common/streaming.py +218 -0
- agentops/instrumentation/common/token_counting.py +177 -0
- agentops/instrumentation/common/version.py +71 -0
- agentops/instrumentation/common/wrappers.py +235 -0
- agentops/legacy/__init__.py +277 -0
- agentops/legacy/event.py +156 -0
- agentops/logging/__init__.py +4 -0
- agentops/logging/config.py +86 -0
- agentops/logging/formatters.py +34 -0
- agentops/logging/instrument_logging.py +91 -0
- agentops/sdk/__init__.py +27 -0
- agentops/sdk/attributes.py +151 -0
- agentops/sdk/core.py +607 -0
- agentops/sdk/decorators/__init__.py +51 -0
- agentops/sdk/decorators/factory.py +486 -0
- agentops/sdk/decorators/utility.py +216 -0
- agentops/sdk/exporters.py +87 -0
- agentops/sdk/processors.py +71 -0
- agentops/sdk/types.py +21 -0
- agentops/semconv/__init__.py +36 -0
- agentops/semconv/agent.py +29 -0
- agentops/semconv/core.py +19 -0
- agentops/semconv/enum.py +11 -0
- agentops/semconv/instrumentation.py +13 -0
- agentops/semconv/langchain.py +63 -0
- agentops/semconv/message.py +61 -0
- agentops/semconv/meters.py +24 -0
- agentops/semconv/resource.py +52 -0
- agentops/semconv/span_attributes.py +118 -0
- agentops/semconv/span_kinds.py +50 -0
- agentops/semconv/status.py +11 -0
- agentops/semconv/tool.py +15 -0
- agentops/semconv/workflow.py +69 -0
- agentops/validation.py +357 -0
- mseep_agentops-0.4.18.dist-info/METADATA +49 -0
- mseep_agentops-0.4.18.dist-info/RECORD +94 -0
- mseep_agentops-0.4.18.dist-info/WHEEL +5 -0
- mseep_agentops-0.4.18.dist-info/licenses/LICENSE +21 -0
- mseep_agentops-0.4.18.dist-info/top_level.txt +2 -0
- tests/__init__.py +0 -0
- tests/conftest.py +10 -0
- tests/unit/__init__.py +0 -0
- tests/unit/client/__init__.py +1 -0
- tests/unit/client/test_http_adapter.py +221 -0
- tests/unit/client/test_http_client.py +206 -0
- tests/unit/conftest.py +54 -0
- tests/unit/sdk/__init__.py +1 -0
- tests/unit/sdk/instrumentation_tester.py +207 -0
- tests/unit/sdk/test_attributes.py +392 -0
- tests/unit/sdk/test_concurrent_instrumentation.py +468 -0
- tests/unit/sdk/test_decorators.py +763 -0
- tests/unit/sdk/test_exporters.py +241 -0
- tests/unit/sdk/test_factory.py +1188 -0
- tests/unit/sdk/test_internal_span_processor.py +397 -0
- tests/unit/sdk/test_resource_attributes.py +35 -0
- tests/unit/test_config.py +82 -0
- tests/unit/test_context_manager.py +777 -0
- tests/unit/test_events.py +27 -0
- tests/unit/test_host_env.py +54 -0
- tests/unit/test_init_py.py +501 -0
- tests/unit/test_serialization.py +433 -0
- tests/unit/test_session.py +676 -0
- tests/unit/test_user_agent.py +34 -0
- tests/unit/test_validation.py +405 -0
@@ -0,0 +1,49 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: mseep-agentops
|
3
|
+
Version: 0.4.18
|
4
|
+
Summary: Observability and DevTool Platform for AI Agents
|
5
|
+
Home-page: https://github.com/mseep
|
6
|
+
Author: mseep
|
7
|
+
Author-email: support@skydeck.ai
|
8
|
+
Maintainer: mseep
|
9
|
+
Maintainer-email: support@skydeck.ai
|
10
|
+
Keywords: mseep
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
13
|
+
Classifier: Operating System :: OS Independent
|
14
|
+
Requires-Python: >=3.6
|
15
|
+
Description-Content-Type: text/plain
|
16
|
+
License-File: LICENSE
|
17
|
+
Requires-Dist: requests<3.0.0,>=2.0.0
|
18
|
+
Requires-Dist: psutil<7.0.1,>=5.9.8
|
19
|
+
Requires-Dist: termcolor<2.5.0,>=2.3.0
|
20
|
+
Requires-Dist: PyYAML<7.0,>=5.3
|
21
|
+
Requires-Dist: packaging<25.0,>=21.0
|
22
|
+
Requires-Dist: httpx<0.29.0,>=0.24.0
|
23
|
+
Requires-Dist: opentelemetry-sdk==1.29.0; python_version < "3.10"
|
24
|
+
Requires-Dist: opentelemetry-sdk>1.29.0; python_version >= "3.10"
|
25
|
+
Requires-Dist: opentelemetry-api==1.29.0; python_version < "3.10"
|
26
|
+
Requires-Dist: opentelemetry-api>1.29.0; python_version >= "3.10"
|
27
|
+
Requires-Dist: opentelemetry-exporter-otlp-proto-http==1.29.0; python_version < "3.10"
|
28
|
+
Requires-Dist: opentelemetry-exporter-otlp-proto-http>1.29.0; python_version >= "3.10"
|
29
|
+
Requires-Dist: ordered-set<5.0.0,>=4.0.0
|
30
|
+
Requires-Dist: wrapt<2.0.0,>=1.0.0
|
31
|
+
Requires-Dist: opentelemetry-instrumentation==0.50b0; python_version < "3.10"
|
32
|
+
Requires-Dist: opentelemetry-instrumentation>=0.50b0; python_version >= "3.10"
|
33
|
+
Requires-Dist: opentelemetry-semantic-conventions==0.50b0; python_version < "3.10"
|
34
|
+
Requires-Dist: opentelemetry-semantic-conventions>=0.50b0; python_version >= "3.10"
|
35
|
+
Dynamic: author
|
36
|
+
Dynamic: author-email
|
37
|
+
Dynamic: classifier
|
38
|
+
Dynamic: description
|
39
|
+
Dynamic: description-content-type
|
40
|
+
Dynamic: home-page
|
41
|
+
Dynamic: keywords
|
42
|
+
Dynamic: license-file
|
43
|
+
Dynamic: maintainer
|
44
|
+
Dynamic: maintainer-email
|
45
|
+
Dynamic: requires-dist
|
46
|
+
Dynamic: requires-python
|
47
|
+
Dynamic: summary
|
48
|
+
|
49
|
+
Package managed by MseeP.ai
|
@@ -0,0 +1,94 @@
|
|
1
|
+
agentops/__init__.py,sha256=YvY0zsWTEpAhAZOrcb2T2dDs2PxJv-q8rUPuqgdpY0k,18788
|
2
|
+
agentops/config.py,sha256=7eu3crglngSeKK0fQ_pFsHGiOjr1gPCaqual8VP0hCA,10090
|
3
|
+
agentops/enums.py,sha256=mRvxU_EFzcfXAmlc0vEj2RBe8An0FnIF-3jZdw3ZMa0,980
|
4
|
+
agentops/exceptions.py,sha256=HjHLvB20ZadA4ZGsmMlQxh-SVhPYQLFzKv0Q_1Ujbx8,1177
|
5
|
+
agentops/validation.py,sha256=Dsxsoa7RbRagcXK56fCWWqgQ5OyUdbM2KjIQjHUp5XA,13294
|
6
|
+
agentops/client/__init__.py,sha256=9ot9lZs-zqk50W3zT87Bgql9Cb77mvCaXNpl2x3IhPs,120
|
7
|
+
agentops/client/client.py,sha256=jaqzPYSi2Jyyd0Nxjzo97aerN9gsGTIqG4Gjgam0vXQ,10667
|
8
|
+
agentops/client/api/__init__.py,sha256=LJJfrjVmm7weWrIRkc28WcV0iogSxU6XR49rOGv7wfI,1906
|
9
|
+
agentops/client/api/base.py,sha256=-SkPZyfR1W0KsCpn05u2F0cMfyc5OXEuRkE859DL66g,4439
|
10
|
+
agentops/client/api/types.py,sha256=GOhpOPnZF1QCYJ-_qZudbHayD8l6hebJDImZFJGYElk,407
|
11
|
+
agentops/client/api/versions/__init__.py,sha256=nyZyYD0dY2I8B7opmIxExlBQnH26lVGWgVXc1zDwi3I,254
|
12
|
+
agentops/client/api/versions/v3.py,sha256=MvClQ6_G2DiXCUNIFv36d_wNidKtIQsAt-rRv8Yng0M,2067
|
13
|
+
agentops/client/api/versions/v4.py,sha256=PsexNJ5h_AwJXbaKn-6ftoW480ZkHMM3u7ow0vocRfg,3532
|
14
|
+
agentops/client/http/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
15
|
+
agentops/client/http/http_adapter.py,sha256=M4LHvj8LFFptHSy-60LHLi_oTBWl1D7Y4_Bsq5W0P4U,4351
|
16
|
+
agentops/client/http/http_client.py,sha256=O9fggGMgqs5eyKF9jEUAgSoBlbPHvxk0lWQTiOQpuxw,8661
|
17
|
+
agentops/helpers/__init__.py,sha256=0YVuyl6CVYUiL5mpkPbsADj_Z_4rgSE8XzCK4OuE0p0,1075
|
18
|
+
agentops/helpers/dashboard.py,sha256=T80flB8GlB4ubPj61mB-seAuDTj4lYTa_U-WDstDg4Q,1552
|
19
|
+
agentops/helpers/deprecation.py,sha256=Ndv0FVa52OznNUu_lAOrF698IrIFL-EF_alrRqXtDpw,1573
|
20
|
+
agentops/helpers/env.py,sha256=cENhgB4QBSG-aZuENI15wUajskT4xLbSZ4NSQj5_tF0,1215
|
21
|
+
agentops/helpers/serialization.py,sha256=1XSCfkZGl51R1FQ4NXYu9ceYuDa4Almp0n7ECgHKI5o,3896
|
22
|
+
agentops/helpers/system.py,sha256=4DEnWHMu6ulgIAzSt6bzNFa_O7nzwcCp8Me5zVWD3bg,4872
|
23
|
+
agentops/helpers/time.py,sha256=XyCknaPCgDBI-FM-n-2lfKJwXUsMPvHzWlK8hc5RPaU,301
|
24
|
+
agentops/helpers/version.py,sha256=3kErXu8dtC27L_3BVG1RFbfO4OKtHMgusHxLz-5s5uI,1056
|
25
|
+
agentops/instrumentation/__init__.py,sha256=084qkc1Kggo4PPVc5q2GpUbYk-2RoX5O0nLsd7EoN20,25486
|
26
|
+
agentops/instrumentation/common/__init__.py,sha256=CYgIOTPUbxpLh47kjeLwLxhLZVA0lpZM9uzJCkr_c40,2287
|
27
|
+
agentops/instrumentation/common/attributes.py,sha256=WelUjg80CQKKNENAipz2t9vuSIUNuQ6Rdz_poxovRck,9337
|
28
|
+
agentops/instrumentation/common/instrumentor.py,sha256=qOaukvOjXRWN0ltw0eupsVZkWfMoESX0oFK-U1IK5JY,4926
|
29
|
+
agentops/instrumentation/common/metrics.py,sha256=sRHuKKTBttU8LE1VTuoU6jLv7d9U2dGvMRC96fr4zQU,3885
|
30
|
+
agentops/instrumentation/common/objects.py,sha256=zpMJTsTNDJ-Qgjzqke47uDDYexlmwpGQC83opdmHnkI,982
|
31
|
+
agentops/instrumentation/common/span_management.py,sha256=WluRQTrFwFNtVsERfT2Q4W6xntwPsupyfhwLEVSFwMk,6090
|
32
|
+
agentops/instrumentation/common/streaming.py,sha256=rSjGhsN8k-so0YjyoqFVtpCeateeApwu5jqOB_De0B0,8085
|
33
|
+
agentops/instrumentation/common/token_counting.py,sha256=ZRrmgcR3YCT568l3MU9GH8eb4wO1qu31d0ohWJAkxy8,6502
|
34
|
+
agentops/instrumentation/common/version.py,sha256=6HIqtkLEKql_OkpQo1rbOitwTFGWEmlgSVYjXaybi0E,2474
|
35
|
+
agentops/instrumentation/common/wrappers.py,sha256=utVwTHxjhS4wCsjPPWtGlFaBy-sBpd4mzy9-I9ftLp0,8242
|
36
|
+
agentops/legacy/__init__.py,sha256=8aiLMhFFuzpm_EvwXHAj4mWvYODkBvWFePOjWcBZffc,9749
|
37
|
+
agentops/legacy/event.py,sha256=mLlDOaI_WWVOF0uHLYWU0PG5UY3VM8qcux2LCCALcv8,5892
|
38
|
+
agentops/logging/__init__.py,sha256=xIz15LVBsdaMzZze-K-vf3z0v467vAz87Khq46Jr7KA,228
|
39
|
+
agentops/logging/config.py,sha256=KnX3W1YplmqpuI3j3gAbmuegr3wUsffl2avC2JeDg24,3168
|
40
|
+
agentops/logging/formatters.py,sha256=dgi78SUc_yQpL5iga99LNone6OqKeDi-Brgf6ZHjdwY,1062
|
41
|
+
agentops/logging/instrument_logging.py,sha256=WurISKObv0eK70FCHw_21V3Dw_OPbQ7smmD_71qPl34,2870
|
42
|
+
agentops/sdk/__init__.py,sha256=W9SBzJ9dLnbqaSbsJJ2vmJXMtsWDHttdx2FHdWsjE3s,657
|
43
|
+
agentops/sdk/attributes.py,sha256=eSZnHaTRdYFOkoCECuuXPS8Wl-tNM4hZaE6dpDrofAc,4521
|
44
|
+
agentops/sdk/core.py,sha256=FdxI0qRfyoppST3WBJYF16kmBsX52PMdTwaq254P7Mk,23993
|
45
|
+
agentops/sdk/exporters.py,sha256=lDsydlo-mU4C8_7M4WZ8v5n71pjkYkGIHaViWJkaoJA,3145
|
46
|
+
agentops/sdk/processors.py,sha256=kAp70nj_tnO32J-7C9thY0BSS2Ku7qje2qCrH_giO0Y,2451
|
47
|
+
agentops/sdk/types.py,sha256=7RMcA65zwiv5zx2-g8z8abtui2UVqpaNujJa7ItY6Yg,889
|
48
|
+
agentops/sdk/decorators/__init__.py,sha256=aq1mcjyG6HqxbJIP3JhgjwE_DU1-vKseroWFpbWDg_c,1936
|
49
|
+
agentops/sdk/decorators/factory.py,sha256=yR8Z5cS2l2W8ehPwvAP2rt3bASHXygW4Th4Cj9GcWDs,26621
|
50
|
+
agentops/sdk/decorators/utility.py,sha256=TxL9hYucmFqiCBOGQ4xaLejBQCjJDo_SaP8qRR3Hkh0,8005
|
51
|
+
agentops/semconv/__init__.py,sha256=DxZe_8vlZMsOjlDGGVxysfScfHlRIXHZLOfwyrJLjiA,1357
|
52
|
+
agentops/semconv/agent.py,sha256=55fv7BTbYBa_NokK80QBfrloZBx_NyVODhNMaMUaNWQ,1086
|
53
|
+
agentops/semconv/core.py,sha256=RI9p6fnSROWjdSI6WolHGrxeoyhNjQy1P5aqmklBxa0,609
|
54
|
+
agentops/semconv/enum.py,sha256=oxlWfUyrowFixJDq3fLzbRi9PQQZqr7MU93Ho3oYAKE,215
|
55
|
+
agentops/semconv/instrumentation.py,sha256=YKMfXoKS5zDmUHYXwrWKSlVomts9x9sTB4XCwHAnJZA,470
|
56
|
+
agentops/semconv/langchain.py,sha256=YIxGgyCWpDMkkNbs5916PBr7-uVFk-dyRICMoPka2Zs,2015
|
57
|
+
agentops/semconv/message.py,sha256=YbFwx2ccCs-lrbaeW6kFAF0UhruieGAACdzSQBBJM_M,3644
|
58
|
+
agentops/semconv/meters.py,sha256=DCEH0oD745E78k-iEvGmTJjQLIAg3Bkxd_gApvQt8zw,1099
|
59
|
+
agentops/semconv/resource.py,sha256=MAj8hHSPrHGGCaMbz1C4Lm0CkJ_JR3BLXto4FKbnmWE,1377
|
60
|
+
agentops/semconv/span_attributes.py,sha256=hyTW7KsLB9sp-HDEvbCUiBlkfGXoC5sKMaSSHbcd6JI,5102
|
61
|
+
agentops/semconv/span_kinds.py,sha256=NjvowyBDKkWiNW6xND4wuWMYGGcUIxB4bb5xWzTkijc,1564
|
62
|
+
agentops/semconv/status.py,sha256=dQ6q-B-kEPWqSPNV7VHF7gojtMgbC-nGvLP_kZe5McY,195
|
63
|
+
agentops/semconv/tool.py,sha256=lW1GQWMuMn449TC-Kz-CQCZy7bC76U7fwUbsihWkhSs,514
|
64
|
+
agentops/semconv/workflow.py,sha256=N7WsN9DgOPd3lZulS9MJeJRv4zeVnUwC8ZRl0fUbD5o,4290
|
65
|
+
mseep_agentops-0.4.18.dist-info/licenses/LICENSE,sha256=zWW9oSZpJVAMBUk-iWOCWBk7c7ITYX2BUU-feXmjKYU,1068
|
66
|
+
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
67
|
+
tests/conftest.py,sha256=JqkAW8DASuGo8kKnc3reM-AUHVu40rbxp5Ko_vUv3bw,156
|
68
|
+
tests/unit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
69
|
+
tests/unit/conftest.py,sha256=xXtm0ej-As6TQdCMg6JWuxIMbGqIcar9s_c4VPL34nY,1205
|
70
|
+
tests/unit/test_config.py,sha256=OWbUvB5-a39bnAJIBYCP5tg0tozYwQA3gCfGCCHYWW8,2811
|
71
|
+
tests/unit/test_context_manager.py,sha256=abmPx2Xi0wyRCyWK2Hiq1ykpS0RCgtFHQWRLV2I6ufg,31724
|
72
|
+
tests/unit/test_events.py,sha256=nr8DQdhZffW52Eq_Q713G8V5T6LzsVMGhi-w0PdKR1U,657
|
73
|
+
tests/unit/test_host_env.py,sha256=991m9TL-AIDs2w-mhWGin043p9Ygp0DrysRG3g1hhWk,1777
|
74
|
+
tests/unit/test_init_py.py,sha256=ZsLjj5TOi25uIJn1cOrVeeE1ZEQeyK7o-se17g31RP4,19813
|
75
|
+
tests/unit/test_serialization.py,sha256=xKJLpP5CwFJHnJ6Ipog_BxjHycSgJuucZ2rlpngrq_g,13817
|
76
|
+
tests/unit/test_session.py,sha256=n9qSNIums64NRPd4cTHbr2OraozFRwexj7PD5tn4_Hk,24303
|
77
|
+
tests/unit/test_user_agent.py,sha256=nV02OvG6DCbLYW1I70ty-gtZMrARNHy6wtY7ehgHFig,1329
|
78
|
+
tests/unit/test_validation.py,sha256=GgBZGiiOo5tKaQOva2WsHh44xboMsqop9o_37ldKlRQ,16248
|
79
|
+
tests/unit/client/__init__.py,sha256=wTTEld19ez6ToxcPNsz6CyTm4edP8SLrav0NUNrFjB4,50
|
80
|
+
tests/unit/client/test_http_adapter.py,sha256=pMSCfT0Zk7X-LsGsFRiDDtdgfxnXQpyT3h6ifE7VxMc,9316
|
81
|
+
tests/unit/client/test_http_client.py,sha256=qFWzntM1-aLV03xBFjeEVB7fQ-ZTkBZ5gYV1y-KsWgA,7699
|
82
|
+
tests/unit/sdk/__init__.py,sha256=pSE-h4UCp-teG9p-a4T0aXHdSCVuVQhw1gyVq-T57JQ,27
|
83
|
+
tests/unit/sdk/instrumentation_tester.py,sha256=_LYJRP-SEmfb9FUcAYrzdgC3JbC-gFF-y2-Z3PT_1Ck,7011
|
84
|
+
tests/unit/sdk/test_attributes.py,sha256=a4ecfgdoaVpj41upEzNR92_oXsuGU0uTxUx6vMW2_Ng,16759
|
85
|
+
tests/unit/sdk/test_concurrent_instrumentation.py,sha256=B047ExN8CJgp_AVCrYWV-rgaKS76NIkFVhRcdjoSovg,20606
|
86
|
+
tests/unit/sdk/test_decorators.py,sha256=CQ1OXOmYfJKfPpfBQuSGfXf578YRX0XXkq6AnecY9IY,31492
|
87
|
+
tests/unit/sdk/test_exporters.py,sha256=7rnw3UIi1uZWni9wVd99jb7Rayk1v3y0Z_eUp3TvZeU,10091
|
88
|
+
tests/unit/sdk/test_factory.py,sha256=ju7CyyV1vyL6TqGGRq4YfqMDpp-jrP918z7GEIgTQuo,47627
|
89
|
+
tests/unit/sdk/test_internal_span_processor.py,sha256=Sbs_4QHtQMYqcNUS6yHtRmI7JUXFSpwpShooVOrH8AY,15917
|
90
|
+
tests/unit/sdk/test_resource_attributes.py,sha256=476tVAr4Q-EyyNtBtbkRgA02EMuAGju3NSj9iFLAl8Q,1415
|
91
|
+
mseep_agentops-0.4.18.dist-info/METADATA,sha256=Zn6ty9CDZJEApqphvjX5c1R4DBrzLZhvSfFyRgYrEMo,1868
|
92
|
+
mseep_agentops-0.4.18.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
93
|
+
mseep_agentops-0.4.18.dist-info/top_level.txt,sha256=UrI_CYrHsaaH2rfrGxmVR9jKHfHV2lv1HVENlV8xEeI,15
|
94
|
+
mseep_agentops-0.4.18.dist-info/RECORD,,
|
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2023 AgentOps-AI
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
tests/__init__.py
ADDED
File without changes
|
tests/conftest.py
ADDED
tests/unit/__init__.py
ADDED
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
"""Unit tests for the agentops.client package."""
|
@@ -0,0 +1,221 @@
|
|
1
|
+
"""Tests for the HTTP adapter classes."""
|
2
|
+
|
3
|
+
from urllib3.util import Retry
|
4
|
+
|
5
|
+
from agentops.client.http.http_adapter import BaseHTTPAdapter
|
6
|
+
|
7
|
+
# from agentops.client.auth_manager import AuthManager
|
8
|
+
|
9
|
+
|
10
|
+
class TestBaseHTTPAdapter:
|
11
|
+
"""Tests for the BaseHTTPAdapter class."""
|
12
|
+
|
13
|
+
def test_init_with_default_params(self):
|
14
|
+
"""Test that the adapter initializes with default parameters."""
|
15
|
+
adapter = BaseHTTPAdapter()
|
16
|
+
|
17
|
+
# Verify the adapter was created with the expected parameters
|
18
|
+
assert adapter.poolmanager is not None
|
19
|
+
|
20
|
+
# Check that max_retries was set
|
21
|
+
assert adapter.max_retries is not None
|
22
|
+
assert isinstance(adapter.max_retries, Retry)
|
23
|
+
assert adapter.max_retries.total == 3
|
24
|
+
assert adapter.max_retries.backoff_factor == 0.1
|
25
|
+
assert adapter.max_retries.status_forcelist == [500, 502, 503, 504]
|
26
|
+
|
27
|
+
def test_init_with_custom_params(self):
|
28
|
+
"""Test that the adapter initializes with custom parameters."""
|
29
|
+
custom_retry = Retry(total=5, backoff_factor=0.5, status_forcelist=[429, 500, 502, 503, 504])
|
30
|
+
|
31
|
+
adapter = BaseHTTPAdapter(pool_connections=20, pool_maxsize=300, max_retries=custom_retry)
|
32
|
+
|
33
|
+
# Verify the adapter was created with the expected parameters
|
34
|
+
assert adapter.poolmanager is not None
|
35
|
+
|
36
|
+
# Check that max_retries was set to our custom value
|
37
|
+
assert adapter.max_retries is custom_retry
|
38
|
+
assert adapter.max_retries.total == 5
|
39
|
+
assert adapter.max_retries.backoff_factor == 0.5
|
40
|
+
assert adapter.max_retries.status_forcelist == [429, 500, 502, 503, 504]
|
41
|
+
|
42
|
+
|
43
|
+
# class TestAuthenticatedHttpAdapter:
|
44
|
+
# """Tests for the AuthenticatedHttpAdapter class."""
|
45
|
+
#
|
46
|
+
# @pytest.fixture
|
47
|
+
# def auth_manager(self):
|
48
|
+
# """Create an AuthManager for testing."""
|
49
|
+
# return AuthManager(token_endpoint="https://api.example.com/auth/token")
|
50
|
+
#
|
51
|
+
# @pytest.fixture
|
52
|
+
# def token_fetcher(self):
|
53
|
+
# """Create a token fetcher function for testing."""
|
54
|
+
# return mock.Mock(return_value={"token": "test-token", "project_id": "test-project"})
|
55
|
+
#
|
56
|
+
# def test_init(self, auth_manager, token_fetcher):
|
57
|
+
# """Test that the adapter initializes correctly."""
|
58
|
+
# adapter = AuthenticatedHttpAdapter(
|
59
|
+
# auth_manager=auth_manager,
|
60
|
+
# api_key="test-api-key",
|
61
|
+
# token_fetcher=token_fetcher
|
62
|
+
# )
|
63
|
+
#
|
64
|
+
# # Verify the adapter was created with the expected parameters
|
65
|
+
# assert adapter.auth_manager is auth_manager
|
66
|
+
# assert adapter.api_key == "test-api-key"
|
67
|
+
# assert adapter.token_fetcher is token_fetcher
|
68
|
+
#
|
69
|
+
# # Verify it's a subclass of BaseHTTPAdapter
|
70
|
+
# assert isinstance(adapter, BaseHTTPAdapter)
|
71
|
+
#
|
72
|
+
# def test_add_headers(self, auth_manager, token_fetcher):
|
73
|
+
# """Test that add_headers adds authentication headers to the request."""
|
74
|
+
# # Setup
|
75
|
+
# adapter = AuthenticatedHttpAdapter(
|
76
|
+
# auth_manager=auth_manager,
|
77
|
+
# api_key="test-api-key",
|
78
|
+
# token_fetcher=token_fetcher
|
79
|
+
# )
|
80
|
+
#
|
81
|
+
# # Mock the auth manager methods
|
82
|
+
# auth_manager.maybe_fetch = mock.Mock(return_value={"token": "test-token", "project_id": "test-project"})
|
83
|
+
# auth_manager.prepare_auth_headers = mock.Mock(return_value={
|
84
|
+
# "Authorization": "Bearer test-token",
|
85
|
+
# "Content-Type": "application/json; charset=UTF-8",
|
86
|
+
# "X-Agentops-Api-Key": "test-api-key"
|
87
|
+
# })
|
88
|
+
#
|
89
|
+
# # Create a request
|
90
|
+
# request = requests.Request('GET', 'https://api.example.com/test').prepare()
|
91
|
+
#
|
92
|
+
# # Call add_headers
|
93
|
+
# modified_request = adapter.add_headers(request)
|
94
|
+
#
|
95
|
+
# # Verify the auth manager methods were called
|
96
|
+
# auth_manager.maybe_fetch.assert_called_once_with("test-api-key", token_fetcher)
|
97
|
+
# auth_manager.prepare_auth_headers.assert_called_once_with("test-api-key")
|
98
|
+
#
|
99
|
+
# # Verify the headers were added to the request
|
100
|
+
# assert modified_request.headers["Authorization"] == "Bearer test-token"
|
101
|
+
# assert modified_request.headers["Content-Type"] == "application/json; charset=UTF-8"
|
102
|
+
# assert modified_request.headers["X-Agentops-Api-Key"] == "test-api-key"
|
103
|
+
#
|
104
|
+
# def test_send_success(self, auth_manager, token_fetcher, mocker: MockerFixture):
|
105
|
+
# """Test that send successfully sends a request."""
|
106
|
+
# # Setup
|
107
|
+
# adapter = AuthenticatedHttpAdapter(
|
108
|
+
# auth_manager=auth_manager,
|
109
|
+
# api_key="test-api-key",
|
110
|
+
# token_fetcher=token_fetcher
|
111
|
+
# )
|
112
|
+
#
|
113
|
+
# # Mock the add_headers method
|
114
|
+
# mocker.patch.object(adapter, 'add_headers', side_effect=lambda r, **kw: r)
|
115
|
+
#
|
116
|
+
# # Mock the parent send method
|
117
|
+
# mock_response = mock.Mock(spec=requests.Response)
|
118
|
+
# mock_response.status_code = 200
|
119
|
+
# mocker.patch.object(BaseHTTPAdapter, 'send', return_value=mock_response)
|
120
|
+
#
|
121
|
+
# # Mock the is_token_expired_response method
|
122
|
+
# auth_manager.is_token_expired_response = mock.Mock(return_value=False)
|
123
|
+
#
|
124
|
+
# # Create a request
|
125
|
+
# request = requests.Request('GET', 'https://api.example.com/test').prepare()
|
126
|
+
#
|
127
|
+
# # Call send
|
128
|
+
# response = adapter.send(request)
|
129
|
+
#
|
130
|
+
# # Verify the response
|
131
|
+
# assert response is mock_response
|
132
|
+
# assert response.status_code == 200
|
133
|
+
#
|
134
|
+
# # Verify the methods were called
|
135
|
+
# adapter.add_headers.assert_called_once()
|
136
|
+
# BaseHTTPAdapter.send.assert_called_once()
|
137
|
+
# auth_manager.is_token_expired_response.assert_called_once_with(mock_response)
|
138
|
+
#
|
139
|
+
# def test_send_with_token_refresh(self, auth_manager, token_fetcher, mocker: MockerFixture):
|
140
|
+
# """Test that send refreshes the token if it's expired."""
|
141
|
+
# # Setup
|
142
|
+
# adapter = AuthenticatedHttpAdapter(
|
143
|
+
# auth_manager=auth_manager,
|
144
|
+
# api_key="test-api-key",
|
145
|
+
# token_fetcher=token_fetcher
|
146
|
+
# )
|
147
|
+
#
|
148
|
+
# # Mock the add_headers method
|
149
|
+
# mocker.patch.object(adapter, 'add_headers', side_effect=lambda r, **kw: r)
|
150
|
+
#
|
151
|
+
# # Mock the parent send method to return a 401 response first, then a 200 response
|
152
|
+
# expired_response = mock.Mock(spec=requests.Response)
|
153
|
+
# expired_response.status_code = 401
|
154
|
+
#
|
155
|
+
# success_response = mock.Mock(spec=requests.Response)
|
156
|
+
# success_response.status_code = 200
|
157
|
+
#
|
158
|
+
# mocker.patch.object(
|
159
|
+
# BaseHTTPAdapter,
|
160
|
+
# 'send',
|
161
|
+
# side_effect=[expired_response, success_response]
|
162
|
+
# )
|
163
|
+
#
|
164
|
+
# # Mock the auth manager methods
|
165
|
+
# auth_manager.is_token_expired_response = mock.Mock(return_value=True)
|
166
|
+
# auth_manager.clear_token = mock.Mock()
|
167
|
+
# auth_manager.maybe_fetch = mock.Mock(return_value={"token": "new-token", "project_id": "test-project"})
|
168
|
+
#
|
169
|
+
# # Create a request
|
170
|
+
# request = requests.Request('GET', 'https://api.example.com/test').prepare()
|
171
|
+
#
|
172
|
+
# # Call send
|
173
|
+
# response = adapter.send(request)
|
174
|
+
#
|
175
|
+
# # Verify the auth manager methods were called
|
176
|
+
# auth_manager.is_token_expired_response.assert_called_once_with(expired_response)
|
177
|
+
# auth_manager.clear_token.assert_called_once()
|
178
|
+
# auth_manager.maybe_fetch.assert_called_once_with("test-api-key", token_fetcher)
|
179
|
+
#
|
180
|
+
# # Verify the response is the success response
|
181
|
+
# assert response is success_response
|
182
|
+
#
|
183
|
+
# def test_send_with_token_refresh_failure(self, auth_manager, token_fetcher, mocker: MockerFixture):
|
184
|
+
# """Test that send handles token refresh failures gracefully."""
|
185
|
+
# # Setup
|
186
|
+
# adapter = AuthenticatedHttpAdapter(
|
187
|
+
# auth_manager=auth_manager,
|
188
|
+
# api_key="test-api-key",
|
189
|
+
# token_fetcher=token_fetcher
|
190
|
+
# )
|
191
|
+
#
|
192
|
+
# # Mock the add_headers method
|
193
|
+
# mocker.patch.object(adapter, 'add_headers', side_effect=lambda r, **kw: r)
|
194
|
+
#
|
195
|
+
# # Mock the parent send method to return a 401 response
|
196
|
+
# expired_response = mock.Mock(spec=requests.Response)
|
197
|
+
# expired_response.status_code = 401
|
198
|
+
#
|
199
|
+
# mocker.patch.object(BaseHTTPAdapter, 'send', return_value=expired_response)
|
200
|
+
#
|
201
|
+
# # Mock the auth manager methods
|
202
|
+
# auth_manager.is_token_expired_response = mock.Mock(return_value=True)
|
203
|
+
# auth_manager.clear_token = mock.Mock()
|
204
|
+
# auth_manager.maybe_fetch = mock.Mock(side_effect=AgentOpsApiJwtExpiredException("Failed to refresh token"))
|
205
|
+
#
|
206
|
+
# # Create a request
|
207
|
+
# request = requests.Request('GET', 'https://api.example.com/test').prepare()
|
208
|
+
#
|
209
|
+
# # Call send
|
210
|
+
# response = adapter.send(request)
|
211
|
+
#
|
212
|
+
# # Verify the response is the original 401 response
|
213
|
+
# assert response is expired_response
|
214
|
+
# assert response.status_code == 401
|
215
|
+
#
|
216
|
+
# # Verify the methods were called
|
217
|
+
# adapter.add_headers.assert_called_once() # Only called for initial request
|
218
|
+
# BaseHTTPAdapter.send.assert_called_once() # Only called for initial request
|
219
|
+
# auth_manager.is_token_expired_response.assert_called_once_with(expired_response)
|
220
|
+
# auth_manager.clear_token.assert_called_once()
|
221
|
+
# auth_manager.maybe_fetch.assert_called_once_with("test-api-key", token_fetcher)
|
@@ -0,0 +1,206 @@
|
|
1
|
+
# """Tests for the HttpClient class."""
|
2
|
+
#
|
3
|
+
# import pytest
|
4
|
+
# import requests
|
5
|
+
# from unittest import mock
|
6
|
+
# from pytest_mock import MockerFixture
|
7
|
+
#
|
8
|
+
# from agentops.client.http.http_client import HttpClient
|
9
|
+
# from agentops.client.http.http_adapter import AuthenticatedHttpAdapter, BaseHTTPAdapter
|
10
|
+
# from agentops.client.auth_manager import AuthManager
|
11
|
+
#
|
12
|
+
#
|
13
|
+
# class TestHttpClient:
|
14
|
+
# """Tests for the HttpClient class."""
|
15
|
+
#
|
16
|
+
# def test_get_session_creates_new_session_if_none_exists(self):
|
17
|
+
# """Test that get_session creates a new session if none exists."""
|
18
|
+
# # Reset the session to ensure we're testing from a clean state
|
19
|
+
# HttpClient._session = None
|
20
|
+
#
|
21
|
+
# # Call get_session
|
22
|
+
# session = HttpClient.get_session()
|
23
|
+
#
|
24
|
+
# # Verify a session was created
|
25
|
+
# assert session is not None
|
26
|
+
# assert isinstance(session, requests.Session)
|
27
|
+
#
|
28
|
+
# # Verify the session has the expected adapters
|
29
|
+
# assert any(isinstance(adapter, BaseHTTPAdapter) for adapter in session.adapters.values())
|
30
|
+
#
|
31
|
+
# # Verify the session has the expected headers
|
32
|
+
# assert "Content-Type" in session.headers
|
33
|
+
# assert "Connection" in session.headers
|
34
|
+
# assert "Keep-Alive" in session.headers
|
35
|
+
#
|
36
|
+
# def test_get_session_returns_existing_session(self):
|
37
|
+
# """Test that get_session returns the existing session if one exists."""
|
38
|
+
# # Create a session
|
39
|
+
# HttpClient._session = None
|
40
|
+
# session1 = HttpClient.get_session()
|
41
|
+
#
|
42
|
+
# # Call get_session again
|
43
|
+
# session2 = HttpClient.get_session()
|
44
|
+
#
|
45
|
+
# # Verify the same session was returned
|
46
|
+
# assert session2 is session1
|
47
|
+
#
|
48
|
+
# def test_get_authenticated_session_creates_new_session(self):
|
49
|
+
# """Test that get_authenticated_session creates a new authenticated session."""
|
50
|
+
# # Call get_authenticated_session
|
51
|
+
# session = HttpClient.get_authenticated_session(
|
52
|
+
# endpoint="https://api.example.com",
|
53
|
+
# api_key="test-api-key"
|
54
|
+
# )
|
55
|
+
#
|
56
|
+
# # Verify a session was created
|
57
|
+
# assert session is not None
|
58
|
+
# assert isinstance(session, requests.Session)
|
59
|
+
#
|
60
|
+
# # Verify the session has the expected adapters
|
61
|
+
# assert any(isinstance(adapter, AuthenticatedHttpAdapter) for adapter in session.adapters.values())
|
62
|
+
#
|
63
|
+
# # Verify the session has the expected headers
|
64
|
+
# assert "Content-Type" in session.headers
|
65
|
+
# assert "Connection" in session.headers
|
66
|
+
# assert "Keep-Alive" in session.headers
|
67
|
+
#
|
68
|
+
# def test_get_authenticated_session_with_custom_token_fetcher(self, mocker: MockerFixture):
|
69
|
+
# """Test that get_authenticated_session accepts a custom token fetcher."""
|
70
|
+
# # Create a mock token fetcher
|
71
|
+
# mock_token_fetcher = mock.Mock(return_value="test-token")
|
72
|
+
#
|
73
|
+
# # Call get_authenticated_session with the custom token fetcher
|
74
|
+
# session = HttpClient.get_authenticated_session(
|
75
|
+
# endpoint="https://api.example.com",
|
76
|
+
# api_key="test-api-key",
|
77
|
+
# token_fetcher=mock_token_fetcher
|
78
|
+
# )
|
79
|
+
#
|
80
|
+
# # Verify a session was created
|
81
|
+
# assert session is not None
|
82
|
+
# assert isinstance(session, requests.Session)
|
83
|
+
#
|
84
|
+
# # Get the adapter
|
85
|
+
# adapter = next(adapter for adapter in session.adapters.values()
|
86
|
+
# if isinstance(adapter, AuthenticatedHttpAdapter))
|
87
|
+
#
|
88
|
+
# # Verify the adapter has the custom token fetcher
|
89
|
+
# assert adapter.token_fetcher is mock_token_fetcher
|
90
|
+
#
|
91
|
+
# def test_request_get(self, mocker: MockerFixture):
|
92
|
+
# """Test that request makes a GET request."""
|
93
|
+
# # Mock the session
|
94
|
+
# mock_session = mock.Mock()
|
95
|
+
# mock_get = mock.Mock()
|
96
|
+
# mock_session.get = mock_get
|
97
|
+
#
|
98
|
+
# # Mock get_session to return our mock session
|
99
|
+
# mocker.patch.object(HttpClient, "get_session", return_value=mock_session)
|
100
|
+
#
|
101
|
+
# # Call request
|
102
|
+
# HttpClient.request(
|
103
|
+
# method="get",
|
104
|
+
# url="https://api.example.com/test",
|
105
|
+
# headers={"X-Test": "test"},
|
106
|
+
# timeout=10
|
107
|
+
# )
|
108
|
+
#
|
109
|
+
# # Verify the session method was called with the expected arguments
|
110
|
+
# mock_get.assert_called_once_with(
|
111
|
+
# "https://api.example.com/test",
|
112
|
+
# headers={"X-Test": "test"},
|
113
|
+
# timeout=10,
|
114
|
+
# allow_redirects=False
|
115
|
+
# )
|
116
|
+
#
|
117
|
+
# def test_request_post(self, mocker: MockerFixture):
|
118
|
+
# """Test that request makes a POST request."""
|
119
|
+
# # Mock the session
|
120
|
+
# mock_session = mock.Mock()
|
121
|
+
# mock_post = mock.Mock()
|
122
|
+
# mock_session.post = mock_post
|
123
|
+
#
|
124
|
+
# # Mock get_session to return our mock session
|
125
|
+
# mocker.patch.object(HttpClient, "get_session", return_value=mock_session)
|
126
|
+
#
|
127
|
+
# # Call request
|
128
|
+
# HttpClient.request(
|
129
|
+
# method="post",
|
130
|
+
# url="https://api.example.com/test",
|
131
|
+
# data={"test": "data"},
|
132
|
+
# headers={"X-Test": "test"},
|
133
|
+
# timeout=10
|
134
|
+
# )
|
135
|
+
#
|
136
|
+
# # Verify the session method was called with the expected arguments
|
137
|
+
# mock_post.assert_called_once_with(
|
138
|
+
# "https://api.example.com/test",
|
139
|
+
# json={"test": "data"},
|
140
|
+
# headers={"X-Test": "test"},
|
141
|
+
# timeout=10,
|
142
|
+
# allow_redirects=False
|
143
|
+
# )
|
144
|
+
#
|
145
|
+
# def test_request_put(self, mocker: MockerFixture):
|
146
|
+
# """Test that request makes a PUT request."""
|
147
|
+
# # Mock the session
|
148
|
+
# mock_session = mock.Mock()
|
149
|
+
# mock_put = mock.Mock()
|
150
|
+
# mock_session.put = mock_put
|
151
|
+
#
|
152
|
+
# # Mock get_session to return our mock session
|
153
|
+
# mocker.patch.object(HttpClient, "get_session", return_value=mock_session)
|
154
|
+
#
|
155
|
+
# # Call request
|
156
|
+
# HttpClient.request(
|
157
|
+
# method="put",
|
158
|
+
# url="https://api.example.com/test",
|
159
|
+
# data={"test": "data"},
|
160
|
+
# headers={"X-Test": "test"},
|
161
|
+
# timeout=10
|
162
|
+
# )
|
163
|
+
#
|
164
|
+
# # Verify the session method was called with the expected arguments
|
165
|
+
# mock_put.assert_called_once_with(
|
166
|
+
# "https://api.example.com/test",
|
167
|
+
# json={"test": "data"},
|
168
|
+
# headers={"X-Test": "test"},
|
169
|
+
# timeout=10,
|
170
|
+
# allow_redirects=False
|
171
|
+
# )
|
172
|
+
#
|
173
|
+
# def test_request_delete(self, mocker: MockerFixture):
|
174
|
+
# """Test that request makes a DELETE request."""
|
175
|
+
# # Mock the session
|
176
|
+
# mock_session = mock.Mock()
|
177
|
+
# mock_delete = mock.Mock()
|
178
|
+
# mock_session.delete = mock_delete
|
179
|
+
#
|
180
|
+
# # Mock get_session to return our mock session
|
181
|
+
# mocker.patch.object(HttpClient, "get_session", return_value=mock_session)
|
182
|
+
#
|
183
|
+
# # Call request
|
184
|
+
# HttpClient.request(
|
185
|
+
# method="delete",
|
186
|
+
# url="https://api.example.com/test",
|
187
|
+
# headers={"X-Test": "test"},
|
188
|
+
# timeout=10
|
189
|
+
# )
|
190
|
+
#
|
191
|
+
# # Verify the session method was called with the expected arguments
|
192
|
+
# mock_delete.assert_called_once_with(
|
193
|
+
# "https://api.example.com/test",
|
194
|
+
# headers={"X-Test": "test"},
|
195
|
+
# timeout=10,
|
196
|
+
# allow_redirects=False
|
197
|
+
# )
|
198
|
+
#
|
199
|
+
# def test_request_unsupported_method(self):
|
200
|
+
# """Test that request raises an error for unsupported methods."""
|
201
|
+
# # Call request with an unsupported method
|
202
|
+
# with pytest.raises(ValueError, match="Unsupported HTTP method: patch"):
|
203
|
+
# HttpClient.request(
|
204
|
+
# method="patch",
|
205
|
+
# url="https://api.example.com/test"
|
206
|
+
# )
|