schemathesis 4.1.3__py3-none-any.whl → 4.2.0__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.
- schemathesis/cli/commands/run/executor.py +1 -1
- schemathesis/cli/commands/run/handlers/base.py +28 -1
- schemathesis/cli/commands/run/handlers/cassettes.py +10 -12
- schemathesis/cli/commands/run/handlers/junitxml.py +5 -6
- schemathesis/cli/commands/run/handlers/output.py +7 -1
- schemathesis/cli/ext/fs.py +1 -1
- schemathesis/config/_diff_base.py +3 -1
- schemathesis/config/_operations.py +2 -0
- schemathesis/config/_phases.py +21 -4
- schemathesis/config/_projects.py +10 -2
- schemathesis/core/adapter.py +34 -0
- schemathesis/core/errors.py +29 -5
- schemathesis/core/jsonschema/__init__.py +13 -0
- schemathesis/core/jsonschema/bundler.py +163 -0
- schemathesis/{specs/openapi/constants.py → core/jsonschema/keywords.py} +0 -8
- schemathesis/core/jsonschema/references.py +122 -0
- schemathesis/core/jsonschema/types.py +41 -0
- schemathesis/core/media_types.py +6 -4
- schemathesis/core/parameters.py +37 -0
- schemathesis/core/transforms.py +25 -2
- schemathesis/core/validation.py +19 -0
- schemathesis/engine/context.py +1 -1
- schemathesis/engine/errors.py +11 -18
- schemathesis/engine/phases/stateful/_executor.py +1 -1
- schemathesis/engine/phases/unit/_executor.py +30 -13
- schemathesis/errors.py +4 -0
- schemathesis/filters.py +2 -2
- schemathesis/generation/coverage.py +89 -13
- schemathesis/generation/hypothesis/__init__.py +4 -1
- schemathesis/generation/hypothesis/builder.py +108 -70
- schemathesis/generation/meta.py +5 -14
- schemathesis/generation/overrides.py +17 -17
- schemathesis/pytest/lazy.py +1 -1
- schemathesis/pytest/plugin.py +1 -6
- schemathesis/schemas.py +22 -72
- schemathesis/specs/graphql/schemas.py +27 -16
- schemathesis/specs/openapi/_hypothesis.py +83 -68
- schemathesis/specs/openapi/adapter/__init__.py +10 -0
- schemathesis/specs/openapi/adapter/parameters.py +504 -0
- schemathesis/specs/openapi/adapter/protocol.py +57 -0
- schemathesis/specs/openapi/adapter/references.py +19 -0
- schemathesis/specs/openapi/adapter/responses.py +329 -0
- schemathesis/specs/openapi/adapter/security.py +141 -0
- schemathesis/specs/openapi/adapter/v2.py +28 -0
- schemathesis/specs/openapi/adapter/v3_0.py +28 -0
- schemathesis/specs/openapi/adapter/v3_1.py +28 -0
- schemathesis/specs/openapi/checks.py +99 -90
- schemathesis/specs/openapi/converter.py +114 -27
- schemathesis/specs/openapi/examples.py +210 -168
- schemathesis/specs/openapi/negative/__init__.py +12 -7
- schemathesis/specs/openapi/negative/mutations.py +68 -40
- schemathesis/specs/openapi/references.py +2 -175
- schemathesis/specs/openapi/schemas.py +142 -490
- schemathesis/specs/openapi/serialization.py +15 -7
- schemathesis/specs/openapi/stateful/__init__.py +17 -12
- schemathesis/specs/openapi/stateful/inference.py +13 -11
- schemathesis/specs/openapi/stateful/links.py +5 -20
- schemathesis/specs/openapi/types/__init__.py +3 -0
- schemathesis/specs/openapi/types/v3.py +68 -0
- schemathesis/specs/openapi/utils.py +1 -13
- schemathesis/transport/requests.py +3 -11
- schemathesis/transport/serialization.py +63 -27
- schemathesis/transport/wsgi.py +1 -8
- {schemathesis-4.1.3.dist-info → schemathesis-4.2.0.dist-info}/METADATA +2 -2
- {schemathesis-4.1.3.dist-info → schemathesis-4.2.0.dist-info}/RECORD +68 -53
- schemathesis/specs/openapi/parameters.py +0 -405
- schemathesis/specs/openapi/security.py +0 -162
- {schemathesis-4.1.3.dist-info → schemathesis-4.2.0.dist-info}/WHEEL +0 -0
- {schemathesis-4.1.3.dist-info → schemathesis-4.2.0.dist-info}/entry_points.txt +0 -0
- {schemathesis-4.1.3.dist-info → schemathesis-4.2.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,11 +1,11 @@
|
|
1
1
|
schemathesis/__init__.py,sha256=QqVUCBQr-RDEstgCZLsxzIa9HJslVSeijrm9gES4b_0,1423
|
2
2
|
schemathesis/auths.py,sha256=JdEwPRS9WKmPcxzGXYYz9pjlIUMQYCfif7ZJU0Kde-I,16400
|
3
3
|
schemathesis/checks.py,sha256=GTdejjXDooAOuq66nvCK3i-AMPBuU-_-aNeSeL9JIlc,6561
|
4
|
-
schemathesis/errors.py,sha256=
|
5
|
-
schemathesis/filters.py,sha256=
|
4
|
+
schemathesis/errors.py,sha256=K3irHIZkrBH2-9LIjlgXlm8RNC41Nffd39ncfwagUvw,1053
|
5
|
+
schemathesis/filters.py,sha256=IevPA5A04GfRLLjmkFLZ0CLhjNO3RmpZq_yw6MqjLIA,13515
|
6
6
|
schemathesis/hooks.py,sha256=q2wqYNgpMCO8ImSBkbrWDSwN0BSELelqJMgAAgGvv2M,14836
|
7
7
|
schemathesis/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
8
|
-
schemathesis/schemas.py,sha256=
|
8
|
+
schemathesis/schemas.py,sha256=jq2KSphzfLn63FNROrc3GwukTDt4ih4-RmF0Z4WSpu8,27582
|
9
9
|
schemathesis/cli/__init__.py,sha256=U9gjzWWpiFhaqevPjZbwyTNjABdpvXETI4HgwdGKnvs,877
|
10
10
|
schemathesis/cli/__main__.py,sha256=MWaenjaUTZIfNPFzKmnkTiawUri7DVldtg3mirLwzU8,92
|
11
11
|
schemathesis/cli/constants.py,sha256=CVcQNHEiX-joAQmyuEVKWPOSxDHsOw_EXXZsEclzLuY,341
|
@@ -15,84 +15,91 @@ schemathesis/cli/commands/data.py,sha256=_ALywjIeCZjuaoDQFy-Kj8RZkEGqXd-Y95O47h8
|
|
15
15
|
schemathesis/cli/commands/run/__init__.py,sha256=_ApiSVh9q-TsJQ_-IiVBNnLCtTCDMTnOLwuJhOvbCp4,18925
|
16
16
|
schemathesis/cli/commands/run/context.py,sha256=taegOHWc_B-HDwiU1R9Oi4q57mdfLXc-B954QUj8t7A,7984
|
17
17
|
schemathesis/cli/commands/run/events.py,sha256=ew0TQOc9T2YBZynYWv95k9yfAk8-hGuZDLMxjT8EhvY,1595
|
18
|
-
schemathesis/cli/commands/run/executor.py,sha256=
|
18
|
+
schemathesis/cli/commands/run/executor.py,sha256=_koznTX0DoELPN_1mxr9K_Qg7-9MPXWdld1MFn3YG_Y,5329
|
19
19
|
schemathesis/cli/commands/run/filters.py,sha256=pzkNRcf5vLPSsMfnvt711GNzRSBK5iZIFjPA0fiH1N4,1701
|
20
20
|
schemathesis/cli/commands/run/loaders.py,sha256=6j0ez7wduAUYbUT28ELKxMf-dYEWr_67m_KIuTSyNGk,4358
|
21
21
|
schemathesis/cli/commands/run/validation.py,sha256=DQaMiBLN2tYT9hONvv8xnyPvNXZH768UlOdUxTd5kZs,9193
|
22
22
|
schemathesis/cli/commands/run/handlers/__init__.py,sha256=TPZ3KdGi8m0fjlN0GjA31MAXXn1qI7uU4FtiDwroXZI,1915
|
23
|
-
schemathesis/cli/commands/run/handlers/base.py,sha256=
|
24
|
-
schemathesis/cli/commands/run/handlers/cassettes.py,sha256=
|
25
|
-
schemathesis/cli/commands/run/handlers/junitxml.py,sha256=
|
26
|
-
schemathesis/cli/commands/run/handlers/output.py,sha256=
|
23
|
+
schemathesis/cli/commands/run/handlers/base.py,sha256=qUtDvtr3F6were_BznfnaPpMibGJMnQ5CA9aEzcIUBc,1306
|
24
|
+
schemathesis/cli/commands/run/handlers/cassettes.py,sha256=Px1-xBw5t6tg8rzYNM-VBTpe6qvbUu_RsrYBG_RWGt8,19501
|
25
|
+
schemathesis/cli/commands/run/handlers/junitxml.py,sha256=qiFvM4-SlM67sep003SkLqPslzaEb4nOm3bkzw-DO-Q,2602
|
26
|
+
schemathesis/cli/commands/run/handlers/output.py,sha256=TwK82zNpIZ7Q76ggTp8gcW2clzrw0WBmHFJMcvYL1nE,63927
|
27
27
|
schemathesis/cli/ext/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
28
|
-
schemathesis/cli/ext/fs.py,sha256=
|
28
|
+
schemathesis/cli/ext/fs.py,sha256=dHQYBjQozQmuSSfXVp-2KWFK0ESOb_w-lV2SptfMfco,461
|
29
29
|
schemathesis/cli/ext/groups.py,sha256=kQ37t6qeArcKaY2y5VxyK3_KwAkBKCVm58IYV8gewds,2720
|
30
30
|
schemathesis/cli/ext/options.py,sha256=6yYwZNJL__FCEEL7kI3r5MbVmbp3ZeQjm7DrZ6J_h7s,3347
|
31
31
|
schemathesis/config/__init__.py,sha256=Ff-mcdwCatFIS_WpJNpSe-gl7ez0-m_s4F2_4Teg2eM,6240
|
32
32
|
schemathesis/config/_auth.py,sha256=83RLVPm97W2thbn-yi01Rt94YwOxLG_a5VoxhEfjUjs,1528
|
33
33
|
schemathesis/config/_checks.py,sha256=F0r16eSSiICvoiTUkNNOE2PH73EGd8bikoeZdME_3Yw,10763
|
34
|
-
schemathesis/config/_diff_base.py,sha256
|
34
|
+
schemathesis/config/_diff_base.py,sha256=U7wuE4480EjP3K16mfC528TP5q7Q5IwAZwZLqRIrS1E,4300
|
35
35
|
schemathesis/config/_env.py,sha256=8XfIyrnGNQuCDnfG0lwmKRFbasRUjgeQGBAMupsmtOU,613
|
36
36
|
schemathesis/config/_error.py,sha256=jfv9chQ4NGoDYypszNGymr0zxXVo65yP0AWK1WVEPIM,5781
|
37
37
|
schemathesis/config/_generation.py,sha256=giWs4z17z9nRe_9Z3mAZ3LEoyh4hkcJnlAA6LSy6iEo,5210
|
38
38
|
schemathesis/config/_health_check.py,sha256=zC9inla5ibMBlEy5WyM4_TME7ju_KH3Bwfo21RI3Gks,561
|
39
|
-
schemathesis/config/_operations.py,sha256=
|
39
|
+
schemathesis/config/_operations.py,sha256=JvfMkieYBkbEmZRb4cTvQLfvHQLhmsxa3GXzgjOtmFc,12383
|
40
40
|
schemathesis/config/_output.py,sha256=3G9SOi-4oNcQPHeNRG3HggFCwvcKOW1kF28a9m0H-pU,4434
|
41
41
|
schemathesis/config/_parameters.py,sha256=i76Hwaf834fBAMmtKfKTl1SFCicJ-Y-5tZt5QNGW2fA,618
|
42
|
-
schemathesis/config/_phases.py,sha256=
|
43
|
-
schemathesis/config/_projects.py,sha256=
|
42
|
+
schemathesis/config/_phases.py,sha256=JgDyh579iR301OpD93L3WBeEpYUrNxD7R59WZE1X2MA,8390
|
43
|
+
schemathesis/config/_projects.py,sha256=MpXFBIkNAWAzE_NWQISI9R8dlbCVId2eXGdIqZBgK98,20468
|
44
44
|
schemathesis/config/_rate_limit.py,sha256=ekEW-jP_Ichk_O6hYpj-h2TTTKfp7Fm0nyFUbvlWcbA,456
|
45
45
|
schemathesis/config/_report.py,sha256=ZECDpaCY4WWHD5UbjvgZoSjLz-rlTvfd5Ivzdgzqf2I,3891
|
46
46
|
schemathesis/config/_validator.py,sha256=IcE8geFZ0ZwR18rkIRs25i7pTl7Z84XbjYGUB-mqReU,258
|
47
47
|
schemathesis/config/_warnings.py,sha256=sI0VZcTj3dOnphhBwYwU_KTagxr89HGWTtQ99HcY84k,772
|
48
48
|
schemathesis/config/schema.json,sha256=3CRSBfUK2vLVl1h5PfeK_YDdEoBZSojYl8Q1kT-ITLE,19846
|
49
49
|
schemathesis/core/__init__.py,sha256=h4gmDePIPvPiVuYxnjrpPKytSZPi6fZeVdTG6c822E4,1973
|
50
|
+
schemathesis/core/adapter.py,sha256=zwJ0vNhalrF9sYXN8_0pMSkJ71GPDnUBKqBCVsnuVIY,951
|
50
51
|
schemathesis/core/compat.py,sha256=9BWCrFoqN2sJIaiht_anxe8kLjYMR7t0iiOkXqLRUZ8,1058
|
51
52
|
schemathesis/core/control.py,sha256=IzwIc8HIAEMtZWW0Q0iXI7T1niBpjvcLlbuwOSmy5O8,130
|
52
53
|
schemathesis/core/curl.py,sha256=jrPL9KpNHteyJ6A1oxJRSkL5bfuBeuPs3xh9Z_ml2cE,1892
|
53
54
|
schemathesis/core/deserialization.py,sha256=qjXUPaz_mc1OSgXzTUSkC8tuVR8wgVQtb9g3CcAF6D0,2951
|
54
|
-
schemathesis/core/errors.py,sha256=
|
55
|
+
schemathesis/core/errors.py,sha256=CeZtzZOwBELzf-T_lLkwLU9Wtla50HuF_17CNJzgNPU,17087
|
55
56
|
schemathesis/core/failures.py,sha256=yFpAxWdEnm0Ri8z8RqRI9H7vcLH5ztOeSIi4m4SGx5g,8996
|
56
57
|
schemathesis/core/fs.py,sha256=ItQT0_cVwjDdJX9IiI7EnU75NI2H3_DCEyyUjzg_BgI,472
|
57
58
|
schemathesis/core/hooks.py,sha256=qhbkkRSf8URJ4LKv2wmKRINKpquUOgxQzWBHKWRWo3Q,475
|
58
59
|
schemathesis/core/lazy_import.py,sha256=aMhWYgbU2JOltyWBb32vnWBb6kykOghucEzI_F70yVE,470
|
59
60
|
schemathesis/core/loaders.py,sha256=04WRkiWfWPH4xjgi0nMO1NyjGw8zvraIq6PqMqCq1c4,3590
|
60
61
|
schemathesis/core/marks.py,sha256=SH7jsVuNRJjx2gZN9Ze5MY01u7FJiHeO0iruzKi5rm4,2135
|
61
|
-
schemathesis/core/media_types.py,sha256=
|
62
|
+
schemathesis/core/media_types.py,sha256=VN1QhgfwBHpTw0CQquzAfhJstxXIXBzSSy0NZmAUcAo,2185
|
63
|
+
schemathesis/core/parameters.py,sha256=20pd4DLW1uXs61YuESKG1Fx9QJJQN3JY7CKnOJMgDb4,790
|
62
64
|
schemathesis/core/rate_limit.py,sha256=7tg9Znk11erTfw8-ANutjEmu7hbfUHZx_iEdkoaP174,1757
|
63
65
|
schemathesis/core/registries.py,sha256=T4jZB4y3zBHdeSgQc0pRbgSeMblvO-6z4I3zmzIfTi0,811
|
64
66
|
schemathesis/core/result.py,sha256=d449YvyONjqjDs-A5DAPgtAI96iT753K8sU6_1HLo2Q,461
|
65
|
-
schemathesis/core/transforms.py,sha256=
|
67
|
+
schemathesis/core/transforms.py,sha256=rgr22JdVjFj0di9Oeo94Leo1JmdLJdCjnA-eGpfszV8,4095
|
66
68
|
schemathesis/core/transport.py,sha256=LQcamAkFqJ0HuXQzepevAq2MCJW-uq5Nm-HE9yc7HMI,7503
|
67
|
-
schemathesis/core/validation.py,sha256=
|
69
|
+
schemathesis/core/validation.py,sha256=b0USkKzkWvdz3jOW1JXYc_TfYshfKZeP7xAUnMqcNoc,2303
|
68
70
|
schemathesis/core/version.py,sha256=dOBUWrY3-uA2NQXJp9z7EtZgkR6jYeLg8sMhQCL1mcI,205
|
71
|
+
schemathesis/core/jsonschema/__init__.py,sha256=gBZGsXIpK2EFfcp8x0b69dqzWAm2OeZHepKImkkLvoE,320
|
72
|
+
schemathesis/core/jsonschema/bundler.py,sha256=ECNAHrXl5nh52crm5Qu1QvRWVV2Vv9gU8H722oKA7k0,7711
|
73
|
+
schemathesis/core/jsonschema/keywords.py,sha256=pjseXTfH9OItNs_Qq6ubkhNWQOrxTnwHmrP_jxrHeJU,631
|
74
|
+
schemathesis/core/jsonschema/references.py,sha256=uB7-DGYhLFqbIAvuO-IDc9xSatoGw54FOYn4xE4qE6A,4667
|
75
|
+
schemathesis/core/jsonschema/types.py,sha256=_B1Q6pFzLqjuLU6mR1JiHsRbuz_pnSmN5HNnbeZJtT0,1223
|
69
76
|
schemathesis/core/output/__init__.py,sha256=SiHqONFskXl73AtP5dV29L14nZoKo7B-IeG52KZB32M,1446
|
70
77
|
schemathesis/core/output/sanitization.py,sha256=Ev3tae8dVwsYd7yVb2_1VBFYs92WFsQ4Eu1fGaymItE,2013
|
71
78
|
schemathesis/engine/__init__.py,sha256=QaFE-FinaTAaarteADo2RRMJ-Sz6hZB9TzD5KjMinIA,706
|
72
|
-
schemathesis/engine/context.py,sha256=
|
79
|
+
schemathesis/engine/context.py,sha256=40L4rEu34Y6a4jrag5O7N7sYh3qG5asE2ErF8w9-ktA,5362
|
73
80
|
schemathesis/engine/control.py,sha256=FXzP8dxL47j1Giqpy2-Bsr_MdMw9YiATSK_UfpFwDtk,1348
|
74
81
|
schemathesis/engine/core.py,sha256=qlPHnZVq2RrUe93fOciXd1hC3E1gVyF2BIWMPMeLIj8,6655
|
75
|
-
schemathesis/engine/errors.py,sha256=
|
82
|
+
schemathesis/engine/errors.py,sha256=FlpEk44WRLzRkdK9m37z93EQuY3kbeMIQRGwU5e3Qm4,19005
|
76
83
|
schemathesis/engine/events.py,sha256=jpCtMkWWfNe2jUeZh_Ly_wfZEF44EOodL-I_W4C9rgg,6594
|
77
84
|
schemathesis/engine/observations.py,sha256=T-5R8GeVIqvxpCMxc6vZ04UUxUTx3w7689r3Dc6bIcE,1416
|
78
85
|
schemathesis/engine/recorder.py,sha256=K3HfMARrT5mPWXPnYebjjcq5CcsBRhMrtZwEL9_Lvtg,8432
|
79
86
|
schemathesis/engine/phases/__init__.py,sha256=7Yp7dQbd6-K9pavIJeURg6jiNeMpW8UU-Iiikr668ts,3278
|
80
87
|
schemathesis/engine/phases/probes.py,sha256=YogjJcZJcTMS8sMdGnG4oXKmMUj_4r_J7MY-BBJtCRU,5690
|
81
88
|
schemathesis/engine/phases/stateful/__init__.py,sha256=Lz1rgNqCfUSIz173XqCGsiMuUI5bh4L-RIFexU1-c_Q,2461
|
82
|
-
schemathesis/engine/phases/stateful/_executor.py,sha256=
|
89
|
+
schemathesis/engine/phases/stateful/_executor.py,sha256=yRpUJqKLTKMVRy7hEXPwmI23CtgGIprz341lCJwvTrU,15613
|
83
90
|
schemathesis/engine/phases/stateful/context.py,sha256=A7X1SLDOWFpCvFN9IiIeNVZM0emjqatmJL_k9UsO7vM,2946
|
84
91
|
schemathesis/engine/phases/unit/__init__.py,sha256=9dDcxyj887pktnE9YDIPNaR-vc7iqKQWIrFr77SbUTQ,8786
|
85
|
-
schemathesis/engine/phases/unit/_executor.py,sha256=
|
92
|
+
schemathesis/engine/phases/unit/_executor.py,sha256=UkOcmR23rl5PSIuNMjthZxadbAOHYSmTWft7Wa91yLs,17206
|
86
93
|
schemathesis/engine/phases/unit/_pool.py,sha256=iU0hdHDmohPnEv7_S1emcabuzbTf-Cznqwn0pGQ5wNQ,2480
|
87
94
|
schemathesis/generation/__init__.py,sha256=tvNO2FLiY8z3fZ_kL_QJhSgzXfnT4UqwSXMHCwfLI0g,645
|
88
95
|
schemathesis/generation/case.py,sha256=Qc2_5JrWuUkCzAFTTgnVqNUJ2sioslmINTXiY7nHHgA,12326
|
89
|
-
schemathesis/generation/coverage.py,sha256=
|
90
|
-
schemathesis/generation/meta.py,sha256=
|
96
|
+
schemathesis/generation/coverage.py,sha256=dZYX0gkHDHDenrubVQ58P3ww2xf91fEqk9s54AIokw4,59699
|
97
|
+
schemathesis/generation/meta.py,sha256=tXhUZBEdpQMn68uMx1SW8Vv59Uf6Wl6yzs-VB9lu_8o,2589
|
91
98
|
schemathesis/generation/metrics.py,sha256=cZU5HdeAMcLFEDnTbNE56NuNq4P0N4ew-g1NEz5-kt4,2836
|
92
99
|
schemathesis/generation/modes.py,sha256=Q1fhjWr3zxabU5qdtLvKfpMFZJAwlW9pnxgenjeXTyU,481
|
93
|
-
schemathesis/generation/overrides.py,sha256=
|
94
|
-
schemathesis/generation/hypothesis/__init__.py,sha256=
|
95
|
-
schemathesis/generation/hypothesis/builder.py,sha256=
|
100
|
+
schemathesis/generation/overrides.py,sha256=xI2djHsa42fzP32xpxgxO52INixKagf5DjDAWJYswM8,3890
|
101
|
+
schemathesis/generation/hypothesis/__init__.py,sha256=j_lKp7loYRe63TCzIx5yozyt0Ub1ilSsXEP-2zfJ0Ok,2144
|
102
|
+
schemathesis/generation/hypothesis/builder.py,sha256=ZdY68aDGeZLLtIld288KF_O6ardFKZdFMBogwltTx2o,38362
|
96
103
|
schemathesis/generation/hypothesis/examples.py,sha256=6eGaKUEC3elmKsaqfKj1sLvM8EHc-PWT4NRBq4NI0Rs,1409
|
97
104
|
schemathesis/generation/hypothesis/given.py,sha256=sTZR1of6XaHAPWtHx2_WLlZ50M8D5Rjux0GmWkWjDq4,2337
|
98
105
|
schemathesis/generation/hypothesis/reporting.py,sha256=uDVow6Ya8YFkqQuOqRsjbzsbyP4KKfr3jA7ZaY4FuKY,279
|
@@ -109,9 +116,9 @@ schemathesis/openapi/generation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm
|
|
109
116
|
schemathesis/openapi/generation/filters.py,sha256=pY9cUZdL_kQK80Z2aylTOqqa12zmaYUlYC5BfYgeQMk,2395
|
110
117
|
schemathesis/pytest/__init__.py,sha256=7W0q-Thcw03IAQfXE_Mo8JPZpUdHJzfu85fjK1ZdfQM,88
|
111
118
|
schemathesis/pytest/control_flow.py,sha256=F8rAPsPeNv_sJiJgbZYtTpwKWjauZmqFUaKroY2GmQI,217
|
112
|
-
schemathesis/pytest/lazy.py,sha256=
|
119
|
+
schemathesis/pytest/lazy.py,sha256=wP0sqcVFcD-OjDIFUpYdJdFQ-BY18CVyL0iB6eHiWRw,11088
|
113
120
|
schemathesis/pytest/loaders.py,sha256=Sbv8e5F77_x4amLP50iwubfm6kpOhx7LhLFGsVXW5Ys,925
|
114
|
-
schemathesis/pytest/plugin.py,sha256
|
121
|
+
schemathesis/pytest/plugin.py,sha256=8VaaYoO4RtgtZLOAHiheFNjd0xceyKe0U1n6AV5s9kY,14253
|
115
122
|
schemathesis/python/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
116
123
|
schemathesis/python/asgi.py,sha256=5PyvuTBaivvyPUEi3pwJni91K1kX5Zc0u9c6c1D8a1Q,287
|
117
124
|
schemathesis/python/wsgi.py,sha256=uShAgo_NChbfYaV1117e6UHp0MTg7jaR0Sy_to3Jmf8,219
|
@@ -119,46 +126,54 @@ schemathesis/specs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuF
|
|
119
126
|
schemathesis/specs/graphql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
120
127
|
schemathesis/specs/graphql/nodes.py,sha256=bE3G1kNmqJ8OV4igBvIK-UORrkQA6Nofduf87O3TD9I,541
|
121
128
|
schemathesis/specs/graphql/scalars.py,sha256=6lew8mnwhrtg23leiEbG43mLGPLlRln8mClCY94XpDA,2680
|
122
|
-
schemathesis/specs/graphql/schemas.py,sha256=
|
129
|
+
schemathesis/specs/graphql/schemas.py,sha256=GKJcnTAT1wUzzUr3r6wiTfiAdFLcgFQjYRRz7x4VQl0,14457
|
123
130
|
schemathesis/specs/graphql/validation.py,sha256=-W1Noc1MQmTb4RX-gNXMeU2qkgso4mzVfHxtdLkCPKM,1422
|
124
131
|
schemathesis/specs/openapi/__init__.py,sha256=C5HOsfuDJGq_3mv8CRBvRvb0Diy1p0BFdqyEXMS-loE,238
|
125
|
-
schemathesis/specs/openapi/_hypothesis.py,sha256=
|
126
|
-
schemathesis/specs/openapi/checks.py,sha256=
|
127
|
-
schemathesis/specs/openapi/
|
128
|
-
schemathesis/specs/openapi/converter.py,sha256=LkpCCAxZzET4Qa_3YStSNuhGlsm5G6TVwpxYu6lPO4g,4169
|
132
|
+
schemathesis/specs/openapi/_hypothesis.py,sha256=g5476s_ArzheWKHHlOfKwx46tqoiehP3KaQM7L_AoEI,22359
|
133
|
+
schemathesis/specs/openapi/checks.py,sha256=YYV6j6idyw2ubY4sLp-avs2OVEkAWeIihjT0xiV1RRA,30669
|
134
|
+
schemathesis/specs/openapi/converter.py,sha256=4a6-8STT5snF7B-t6IsOIGdK5rV16oNqsdvWL7VFf2M,6472
|
129
135
|
schemathesis/specs/openapi/definitions.py,sha256=8htclglV3fW6JPBqs59lgM4LnA25Mm9IptXBPb_qUT0,93949
|
130
|
-
schemathesis/specs/openapi/examples.py,sha256=
|
136
|
+
schemathesis/specs/openapi/examples.py,sha256=UquzOwy5QhmpHjFXv_QnZGpWZTU-N4CkQ1PQOxACIb8,22981
|
131
137
|
schemathesis/specs/openapi/formats.py,sha256=4tYRdckauHxkJCmOhmdwDq_eOpHPaKloi89lzMPbPzw,3975
|
132
138
|
schemathesis/specs/openapi/media_types.py,sha256=F5M6TKl0s6Z5X8mZpPsWDEdPBvxclKRcUOc41eEwKbo,2472
|
133
|
-
schemathesis/specs/openapi/parameters.py,sha256=XpuZ2sex2aYUzKDK17GXVNWFBmvamuyVtloQ1oGQhLk,14468
|
134
139
|
schemathesis/specs/openapi/patterns.py,sha256=GqPZEXMRdWENQxanWjBOalIZ2MQUjuxk21kmdiI703E,18027
|
135
|
-
schemathesis/specs/openapi/references.py,sha256=
|
136
|
-
schemathesis/specs/openapi/schemas.py,sha256=
|
137
|
-
schemathesis/specs/openapi/
|
138
|
-
schemathesis/specs/openapi/
|
139
|
-
schemathesis/specs/openapi/
|
140
|
+
schemathesis/specs/openapi/references.py,sha256=AW1laU23BkiRf0EEFM538vyVFLXycGUiucGVV461le0,1927
|
141
|
+
schemathesis/specs/openapi/schemas.py,sha256=vwBgw7kznPlQJIufgJ48oRxCzDFkUWKfb4uK7rMZUT4,33704
|
142
|
+
schemathesis/specs/openapi/serialization.py,sha256=RPNdadne5wdhsGmjSvgKLRF58wpzpRx3wura8PsHM3o,12152
|
143
|
+
schemathesis/specs/openapi/utils.py,sha256=XkOJT8qD-6uhq-Tmwxk_xYku1Gy5F9pKL3ldNg_DRZw,522
|
144
|
+
schemathesis/specs/openapi/adapter/__init__.py,sha256=YEovBgLjnXd3WGPMJXq0KbSGHezkRlEv4dNRO7_evfk,249
|
145
|
+
schemathesis/specs/openapi/adapter/parameters.py,sha256=jX6tQuJ8k0Ml9w4jAquncGv2ZbJzsG2fUwLu6Grmlq8,18614
|
146
|
+
schemathesis/specs/openapi/adapter/protocol.py,sha256=6Ioe563EL_ZAyRe8Kj8AE6l6grpFbIVn4C3GDuqizTA,2567
|
147
|
+
schemathesis/specs/openapi/adapter/references.py,sha256=6M59pJy_U_sLh3Xzgu6-izWXtz3bjXnqJYSD65wRHtk,549
|
148
|
+
schemathesis/specs/openapi/adapter/responses.py,sha256=bti5FhqZaq_8g95kdpYx5lD2_1cUZEq56yIjlASji8I,12455
|
149
|
+
schemathesis/specs/openapi/adapter/security.py,sha256=W3cqlbs80NxF9SAavOi7BhtNGzdxHO476lYxiWN0D08,4945
|
150
|
+
schemathesis/specs/openapi/adapter/v2.py,sha256=tWbq3EuJnSomWylPw_BT6TfEw8sIJQEFnVKpxCiq5XE,1153
|
151
|
+
schemathesis/specs/openapi/adapter/v3_0.py,sha256=Q6b1Rfajx2tiO5W6uEwLosxQcdFqVgT5TS4r2jYFwg4,1145
|
152
|
+
schemathesis/specs/openapi/adapter/v3_1.py,sha256=lvLvoxMC_AEwm8c_d3RGHk0BptaOFCdDcV8RrH-uOGw,1155
|
140
153
|
schemathesis/specs/openapi/expressions/__init__.py,sha256=hfuRtXD75tQFhzSo6QgDZ3zByyWeZRKevB8edszAVj4,2272
|
141
154
|
schemathesis/specs/openapi/expressions/errors.py,sha256=YLVhps-sYcslgVaahfcUYxUSHlIfWL-rQMeT5PZSMZ8,219
|
142
155
|
schemathesis/specs/openapi/expressions/extractors.py,sha256=IvOrgq_1IWNnirOSV_wLi0UcWOTiL-mLvBLFzLwRpVA,498
|
143
156
|
schemathesis/specs/openapi/expressions/lexer.py,sha256=ZbYPbVX-2c2Dan-6fi4NrDlFT6N55Wrz-4921TKHlZs,4030
|
144
157
|
schemathesis/specs/openapi/expressions/nodes.py,sha256=qaFpAM3seIzmlYLr9So2kRCSNrteZTa7djcRiOD_ji4,4811
|
145
158
|
schemathesis/specs/openapi/expressions/parser.py,sha256=e-ZxshrGE_5CVbgcZLYgdGSjdifgyzgKkLQp0dI0cJY,4503
|
146
|
-
schemathesis/specs/openapi/negative/__init__.py,sha256=
|
147
|
-
schemathesis/specs/openapi/negative/mutations.py,sha256=
|
159
|
+
schemathesis/specs/openapi/negative/__init__.py,sha256=B78vps314fJOMZwlPdv7vUHo78-jEoaGUhhnrTtNaqw,4173
|
160
|
+
schemathesis/specs/openapi/negative/mutations.py,sha256=9U352xJsdZBR-Zfy1V7_X3a5i91LIUS9Zqotrzp3BLA,21000
|
148
161
|
schemathesis/specs/openapi/negative/types.py,sha256=a7buCcVxNBG6ILBM3A7oNTAX0lyDseEtZndBuej8MbI,174
|
149
162
|
schemathesis/specs/openapi/negative/utils.py,sha256=ozcOIuASufLqZSgnKUACjX-EOZrrkuNdXX0SDnLoGYA,168
|
150
|
-
schemathesis/specs/openapi/stateful/__init__.py,sha256=
|
163
|
+
schemathesis/specs/openapi/stateful/__init__.py,sha256=nD5f9pP2Rx2DKIeXtbc_KqUukC4Nf2834cHeOp52byM,16247
|
151
164
|
schemathesis/specs/openapi/stateful/control.py,sha256=QaXLSbwQWtai5lxvvVtQV3BLJ8n5ePqSKB00XFxp-MA,3695
|
152
|
-
schemathesis/specs/openapi/stateful/inference.py,sha256=
|
153
|
-
schemathesis/specs/openapi/stateful/links.py,sha256=
|
165
|
+
schemathesis/specs/openapi/stateful/inference.py,sha256=TCgEnDdTg2syk8KM8YCM96eE6-hMRNMW4OvVCxuyZkc,9603
|
166
|
+
schemathesis/specs/openapi/stateful/links.py,sha256=G6vqW6JFOdhF044ZjG6PsSwAHU1yP4E3FolcNFE55NM,7918
|
167
|
+
schemathesis/specs/openapi/types/__init__.py,sha256=VPsWtLJle__Kodw_QqtQ3OuvBzBcCIKsTOrXy3eA7OU,66
|
168
|
+
schemathesis/specs/openapi/types/v3.py,sha256=Vondr9Amk6JKCIM6i6RGcmTUjFfPgOOqzBXqerccLpo,1468
|
154
169
|
schemathesis/transport/__init__.py,sha256=6yg_RfV_9L0cpA6qpbH-SL9_3ggtHQji9CZrpIkbA6s,5321
|
155
170
|
schemathesis/transport/asgi.py,sha256=qTClt6oT_xUEWnRHokACN_uqCNNUZrRPT6YG0PjbElY,926
|
156
171
|
schemathesis/transport/prepare.py,sha256=erYXRaxpQokIDzaIuvt_csHcw72iHfCyNq8VNEzXd0o,4743
|
157
|
-
schemathesis/transport/requests.py,sha256=
|
158
|
-
schemathesis/transport/serialization.py,sha256=
|
159
|
-
schemathesis/transport/wsgi.py,sha256=
|
160
|
-
schemathesis-4.
|
161
|
-
schemathesis-4.
|
162
|
-
schemathesis-4.
|
163
|
-
schemathesis-4.
|
164
|
-
schemathesis-4.
|
172
|
+
schemathesis/transport/requests.py,sha256=wriRI9fprTplE_qEZLEz1TerX6GwkE3pwr6ZnU2o6vQ,10648
|
173
|
+
schemathesis/transport/serialization.py,sha256=GwO6OAVTmL1JyKw7HiZ256tjV4CbrRbhQN0ep1uaZwI,11157
|
174
|
+
schemathesis/transport/wsgi.py,sha256=kQtasFre6pjdJWRKwLA_Qb-RyQHCFNpaey9ubzlFWKI,5907
|
175
|
+
schemathesis-4.2.0.dist-info/METADATA,sha256=kkIlvuG4NKfAwk6kzHRslKYeYaaFhfSYciy9777c4L0,8540
|
176
|
+
schemathesis-4.2.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
177
|
+
schemathesis-4.2.0.dist-info/entry_points.txt,sha256=hiK3un-xfgPdwj9uj16YVDtTNpO128bmk0U82SMv8ZQ,152
|
178
|
+
schemathesis-4.2.0.dist-info/licenses/LICENSE,sha256=2Ve4J8v5jMQAWrT7r1nf3bI8Vflk3rZVQefiF2zpxwg,1121
|
179
|
+
schemathesis-4.2.0.dist-info/RECORD,,
|
@@ -1,405 +0,0 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
|
3
|
-
from dataclasses import dataclass
|
4
|
-
from typing import TYPE_CHECKING, Any, ClassVar, Iterable
|
5
|
-
|
6
|
-
from schemathesis.core.errors import InvalidSchema
|
7
|
-
from schemathesis.schemas import Parameter
|
8
|
-
|
9
|
-
from .converter import to_json_schema_recursive
|
10
|
-
|
11
|
-
if TYPE_CHECKING:
|
12
|
-
from ...schemas import APIOperation
|
13
|
-
|
14
|
-
|
15
|
-
@dataclass(eq=False)
|
16
|
-
class OpenAPIParameter(Parameter):
|
17
|
-
"""A single Open API operation parameter."""
|
18
|
-
|
19
|
-
example_field: ClassVar[str]
|
20
|
-
examples_field: ClassVar[str]
|
21
|
-
nullable_field: ClassVar[str]
|
22
|
-
supported_jsonschema_keywords: ClassVar[tuple[str, ...]]
|
23
|
-
|
24
|
-
def _repr_pretty_(self, *args: Any, **kwargs: Any) -> None: ...
|
25
|
-
|
26
|
-
@property
|
27
|
-
def description(self) -> str | None:
|
28
|
-
"""A brief parameter description."""
|
29
|
-
return self.definition.get("description")
|
30
|
-
|
31
|
-
@property
|
32
|
-
def location(self) -> str:
|
33
|
-
"""Where this parameter is located.
|
34
|
-
|
35
|
-
E.g. "query".
|
36
|
-
"""
|
37
|
-
return {"formData": "body"}.get(self.raw_location, self.raw_location)
|
38
|
-
|
39
|
-
@property
|
40
|
-
def raw_location(self) -> str:
|
41
|
-
"""Open API specific location name."""
|
42
|
-
return self.definition["in"]
|
43
|
-
|
44
|
-
@property
|
45
|
-
def name(self) -> str:
|
46
|
-
"""Parameter name."""
|
47
|
-
return self.definition["name"]
|
48
|
-
|
49
|
-
@property
|
50
|
-
def is_required(self) -> bool:
|
51
|
-
return self.definition.get("required", False)
|
52
|
-
|
53
|
-
@property
|
54
|
-
def is_header(self) -> bool:
|
55
|
-
return self.location in ("header", "cookie")
|
56
|
-
|
57
|
-
def as_json_schema(self, operation: APIOperation, *, update_quantifiers: bool = True) -> dict[str, Any]:
|
58
|
-
"""Convert parameter's definition to JSON Schema."""
|
59
|
-
# JSON Schema allows `examples` as an array
|
60
|
-
examples = []
|
61
|
-
if self.examples_field in self.definition:
|
62
|
-
container = self.definition[self.examples_field]
|
63
|
-
if isinstance(container, dict):
|
64
|
-
examples.extend([example["value"] for example in container.values() if "value" in example])
|
65
|
-
elif isinstance(container, list):
|
66
|
-
examples.extend(container)
|
67
|
-
if self.example_field in self.definition:
|
68
|
-
examples.append(self.definition[self.example_field])
|
69
|
-
schema = self.from_open_api_to_json_schema(operation, self.definition)
|
70
|
-
if examples:
|
71
|
-
schema["examples"] = examples
|
72
|
-
return self.transform_keywords(schema, update_quantifiers=update_quantifiers)
|
73
|
-
|
74
|
-
def transform_keywords(self, schema: dict[str, Any], *, update_quantifiers: bool = True) -> dict[str, Any]:
|
75
|
-
"""Transform Open API specific keywords into JSON Schema compatible form."""
|
76
|
-
definition = to_json_schema_recursive(schema, self.nullable_field, update_quantifiers=update_quantifiers)
|
77
|
-
# Headers are strings, but it is not always explicitly defined in the schema. By preparing them properly, we
|
78
|
-
# can achieve significant performance improvements for such cases.
|
79
|
-
# For reference (my machine) - running a single test with 100 examples with the resulting strategy:
|
80
|
-
# - without: 4.37 s
|
81
|
-
# - with: 294 ms
|
82
|
-
#
|
83
|
-
# It also reduces the number of cases when the "filter_too_much" health check fails during testing.
|
84
|
-
if self.is_header:
|
85
|
-
definition.setdefault("type", "string")
|
86
|
-
return definition
|
87
|
-
|
88
|
-
def from_open_api_to_json_schema(self, operation: APIOperation, open_api_schema: dict[str, Any]) -> dict[str, Any]:
|
89
|
-
"""Convert Open API's `Schema` to JSON Schema."""
|
90
|
-
return {
|
91
|
-
key: value
|
92
|
-
for key, value in open_api_schema.items()
|
93
|
-
# Allow only supported keywords or vendor extensions
|
94
|
-
if key in self.supported_jsonschema_keywords or key.startswith("x-") or key == self.nullable_field
|
95
|
-
}
|
96
|
-
|
97
|
-
|
98
|
-
@dataclass(eq=False)
|
99
|
-
class OpenAPI20Parameter(OpenAPIParameter):
|
100
|
-
"""Open API 2.0 parameter.
|
101
|
-
|
102
|
-
https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#parameterObject
|
103
|
-
"""
|
104
|
-
|
105
|
-
example_field = "x-example"
|
106
|
-
examples_field = "x-examples"
|
107
|
-
nullable_field = "x-nullable"
|
108
|
-
# https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#parameterObject
|
109
|
-
# Excluding informative keywords - `title`, `description`, `default`.
|
110
|
-
# `required` is not included because it has a different meaning here. It determines whether or not this parameter
|
111
|
-
# is required, which is not relevant because these parameters are later constructed
|
112
|
-
# into an "object" schema, and the value of this keyword is used there.
|
113
|
-
# The following keywords are relevant only for non-body parameters.
|
114
|
-
supported_jsonschema_keywords: ClassVar[tuple[str, ...]] = (
|
115
|
-
"$ref",
|
116
|
-
"type", # only as a string
|
117
|
-
"format",
|
118
|
-
"items",
|
119
|
-
"maximum",
|
120
|
-
"exclusiveMaximum",
|
121
|
-
"minimum",
|
122
|
-
"exclusiveMinimum",
|
123
|
-
"maxLength",
|
124
|
-
"minLength",
|
125
|
-
"pattern",
|
126
|
-
"maxItems",
|
127
|
-
"minItems",
|
128
|
-
"uniqueItems",
|
129
|
-
"enum",
|
130
|
-
"multipleOf",
|
131
|
-
"example",
|
132
|
-
"examples",
|
133
|
-
"default",
|
134
|
-
)
|
135
|
-
|
136
|
-
|
137
|
-
@dataclass(eq=False)
|
138
|
-
class OpenAPI30Parameter(OpenAPIParameter):
|
139
|
-
"""Open API 3.0 parameter.
|
140
|
-
|
141
|
-
https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.3.md#parameter-object
|
142
|
-
"""
|
143
|
-
|
144
|
-
example_field = "example"
|
145
|
-
examples_field = "examples"
|
146
|
-
nullable_field = "nullable"
|
147
|
-
# https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.3.md#schema-object
|
148
|
-
# Excluding informative keywords - `title`, `description`, `default`.
|
149
|
-
# In contrast with Open API 2.0 non-body parameters, in Open API 3.0, all parameters have the `schema` keyword.
|
150
|
-
supported_jsonschema_keywords = (
|
151
|
-
"$ref",
|
152
|
-
"multipleOf",
|
153
|
-
"maximum",
|
154
|
-
"exclusiveMaximum",
|
155
|
-
"minimum",
|
156
|
-
"exclusiveMinimum",
|
157
|
-
"maxLength",
|
158
|
-
"minLength",
|
159
|
-
"pattern",
|
160
|
-
"maxItems",
|
161
|
-
"minItems",
|
162
|
-
"uniqueItems",
|
163
|
-
"maxProperties",
|
164
|
-
"minProperties",
|
165
|
-
"required",
|
166
|
-
"enum",
|
167
|
-
"const",
|
168
|
-
"type",
|
169
|
-
"allOf",
|
170
|
-
"oneOf",
|
171
|
-
"anyOf",
|
172
|
-
"not",
|
173
|
-
"items",
|
174
|
-
"properties",
|
175
|
-
"additionalProperties",
|
176
|
-
"additionalItems",
|
177
|
-
"dependencies",
|
178
|
-
"if",
|
179
|
-
"then",
|
180
|
-
"else",
|
181
|
-
"patternProperties",
|
182
|
-
"propertyNames",
|
183
|
-
"contains",
|
184
|
-
"format",
|
185
|
-
"example",
|
186
|
-
"examples",
|
187
|
-
"default",
|
188
|
-
)
|
189
|
-
|
190
|
-
def from_open_api_to_json_schema(self, operation: APIOperation, open_api_schema: dict[str, Any]) -> dict[str, Any]:
|
191
|
-
open_api_schema = get_parameter_schema(operation, open_api_schema)
|
192
|
-
return super().from_open_api_to_json_schema(operation, open_api_schema)
|
193
|
-
|
194
|
-
|
195
|
-
@dataclass(eq=False)
|
196
|
-
class OpenAPIBody(OpenAPIParameter):
|
197
|
-
media_type: str
|
198
|
-
|
199
|
-
@property
|
200
|
-
def location(self) -> str:
|
201
|
-
return "body"
|
202
|
-
|
203
|
-
@property
|
204
|
-
def name(self) -> str:
|
205
|
-
# The name doesn't matter but is here for the interface completeness.
|
206
|
-
return "body"
|
207
|
-
|
208
|
-
|
209
|
-
@dataclass(eq=False)
|
210
|
-
class OpenAPI20Body(OpenAPIBody, OpenAPI20Parameter):
|
211
|
-
"""Open API 2.0 body variant."""
|
212
|
-
|
213
|
-
# https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#schemaObject
|
214
|
-
# The `body` parameter contains the `schema` keyword that represents the `Schema Object`.
|
215
|
-
# It has slightly different keywords than other parameters. Informational keywords are excluded as well.
|
216
|
-
supported_jsonschema_keywords = (
|
217
|
-
"$ref",
|
218
|
-
"format",
|
219
|
-
"multipleOf",
|
220
|
-
"maximum",
|
221
|
-
"exclusiveMaximum",
|
222
|
-
"minimum",
|
223
|
-
"exclusiveMinimum",
|
224
|
-
"maxLength",
|
225
|
-
"minLength",
|
226
|
-
"pattern",
|
227
|
-
"maxItems",
|
228
|
-
"minItems",
|
229
|
-
"uniqueItems",
|
230
|
-
"maxProperties",
|
231
|
-
"minProperties",
|
232
|
-
"enum",
|
233
|
-
"type",
|
234
|
-
"items",
|
235
|
-
"allOf",
|
236
|
-
"properties",
|
237
|
-
"additionalProperties",
|
238
|
-
"example",
|
239
|
-
"examples",
|
240
|
-
"default",
|
241
|
-
)
|
242
|
-
# NOTE. For Open API 2.0 bodies, we still give `x-example` precedence over the schema-level `example` field to keep
|
243
|
-
# the precedence rules consistent.
|
244
|
-
|
245
|
-
def as_json_schema(self, operation: APIOperation, *, update_quantifiers: bool = True) -> dict[str, Any]:
|
246
|
-
"""Convert body definition to JSON Schema."""
|
247
|
-
# `schema` is required in Open API 2.0 when the `in` keyword is `body`
|
248
|
-
schema = self.definition["schema"]
|
249
|
-
return self.transform_keywords(schema, update_quantifiers=update_quantifiers)
|
250
|
-
|
251
|
-
|
252
|
-
FORM_MEDIA_TYPES = ("multipart/form-data", "application/x-www-form-urlencoded")
|
253
|
-
|
254
|
-
|
255
|
-
@dataclass(eq=False)
|
256
|
-
class OpenAPI30Body(OpenAPIBody, OpenAPI30Parameter):
|
257
|
-
"""Open API 3.0 body variant.
|
258
|
-
|
259
|
-
We consider each media type defined in the schema as a separate variant that can be chosen for data generation.
|
260
|
-
The value of the `definition` field is essentially the Open API 3.0 `MediaType`.
|
261
|
-
"""
|
262
|
-
|
263
|
-
# The `required` keyword is located above the schema for concrete media-type;
|
264
|
-
# Therefore, it is passed here explicitly
|
265
|
-
required: bool = False
|
266
|
-
description: str | None = None
|
267
|
-
|
268
|
-
def as_json_schema(self, operation: APIOperation, *, update_quantifiers: bool = True) -> dict[str, Any]:
|
269
|
-
"""Convert body definition to JSON Schema."""
|
270
|
-
schema = get_media_type_schema(self.definition)
|
271
|
-
return self.transform_keywords(schema, update_quantifiers=update_quantifiers)
|
272
|
-
|
273
|
-
def transform_keywords(self, schema: dict[str, Any], *, update_quantifiers: bool = True) -> dict[str, Any]:
|
274
|
-
definition = super().transform_keywords(schema, update_quantifiers=update_quantifiers)
|
275
|
-
if self.is_form:
|
276
|
-
# It significantly reduces the "filtering" part of data generation.
|
277
|
-
definition.setdefault("type", "object")
|
278
|
-
return definition
|
279
|
-
|
280
|
-
@property
|
281
|
-
def is_form(self) -> bool:
|
282
|
-
"""Whether this payload represent a form."""
|
283
|
-
return self.media_type in FORM_MEDIA_TYPES
|
284
|
-
|
285
|
-
@property
|
286
|
-
def is_required(self) -> bool:
|
287
|
-
return self.required
|
288
|
-
|
289
|
-
|
290
|
-
@dataclass(eq=False)
|
291
|
-
class OpenAPI20CompositeBody(OpenAPIBody, OpenAPI20Parameter):
|
292
|
-
"""A special container to abstract over multiple `formData` parameters."""
|
293
|
-
|
294
|
-
definition: list[OpenAPI20Parameter]
|
295
|
-
|
296
|
-
@classmethod
|
297
|
-
def from_parameters(cls, *parameters: dict[str, Any], media_type: str) -> OpenAPI20CompositeBody:
|
298
|
-
return cls(
|
299
|
-
definition=[OpenAPI20Parameter(parameter) for parameter in parameters],
|
300
|
-
media_type=media_type,
|
301
|
-
)
|
302
|
-
|
303
|
-
@property
|
304
|
-
def description(self) -> str | None:
|
305
|
-
return None
|
306
|
-
|
307
|
-
@property
|
308
|
-
def is_required(self) -> bool:
|
309
|
-
# We generate an object for formData - it is always required.
|
310
|
-
return bool(self.definition)
|
311
|
-
|
312
|
-
def as_json_schema(self, operation: APIOperation, *, update_quantifiers: bool = True) -> dict[str, Any]:
|
313
|
-
"""The composite body is transformed into an "object" JSON Schema."""
|
314
|
-
return parameters_to_json_schema(operation, self.definition, update_quantifiers=update_quantifiers)
|
315
|
-
|
316
|
-
|
317
|
-
def parameters_to_json_schema(
|
318
|
-
operation: APIOperation, parameters: Iterable[OpenAPIParameter], *, update_quantifiers: bool = True
|
319
|
-
) -> dict[str, Any]:
|
320
|
-
"""Create an "object" JSON schema from a list of Open API parameters.
|
321
|
-
|
322
|
-
For each input parameter, there will be a property in the output schema.
|
323
|
-
|
324
|
-
This:
|
325
|
-
|
326
|
-
[
|
327
|
-
{
|
328
|
-
"in": "query",
|
329
|
-
"name": "id",
|
330
|
-
"type": "string",
|
331
|
-
"required": True
|
332
|
-
}
|
333
|
-
]
|
334
|
-
|
335
|
-
Will become:
|
336
|
-
|
337
|
-
{
|
338
|
-
"properties": {
|
339
|
-
"id": {"type": "string"}
|
340
|
-
},
|
341
|
-
"additionalProperties": False,
|
342
|
-
"type": "object",
|
343
|
-
"required": ["id"]
|
344
|
-
}
|
345
|
-
|
346
|
-
We need this transformation for locations that imply multiple components with a unique name within
|
347
|
-
the same location.
|
348
|
-
|
349
|
-
For example, "query" - first, we generate an object that contains all defined parameters and then serialize it
|
350
|
-
to the proper format.
|
351
|
-
"""
|
352
|
-
properties = {}
|
353
|
-
required = []
|
354
|
-
for parameter in parameters:
|
355
|
-
name = parameter.name
|
356
|
-
properties[name] = parameter.as_json_schema(operation, update_quantifiers=update_quantifiers)
|
357
|
-
# If parameter names are duplicated, we need to avoid duplicate entries in `required` anyway
|
358
|
-
if parameter.is_required and name not in required:
|
359
|
-
required.append(name)
|
360
|
-
return {"properties": properties, "additionalProperties": False, "type": "object", "required": required}
|
361
|
-
|
362
|
-
|
363
|
-
MISSING_SCHEMA_OR_CONTENT_MESSAGE = (
|
364
|
-
'Can not generate data for {location} parameter "{name}"! '
|
365
|
-
"It should have either `schema` or `content` keywords defined"
|
366
|
-
)
|
367
|
-
|
368
|
-
INVALID_SCHEMA_MESSAGE = (
|
369
|
-
'Can not generate data for {location} parameter "{name}"! Its schema should be an object, got {schema}'
|
370
|
-
)
|
371
|
-
|
372
|
-
|
373
|
-
def get_parameter_schema(operation: APIOperation, data: dict[str, Any]) -> dict[str, Any]:
|
374
|
-
"""Extract `schema` from Open API 3.0 `Parameter`."""
|
375
|
-
# In Open API 3.0, there could be "schema" or "content" field. They are mutually exclusive.
|
376
|
-
if "schema" in data:
|
377
|
-
if not isinstance(data["schema"], dict):
|
378
|
-
raise InvalidSchema(
|
379
|
-
INVALID_SCHEMA_MESSAGE.format(
|
380
|
-
location=data.get("in", ""), name=data.get("name", "<UNKNOWN>"), schema=data["schema"]
|
381
|
-
),
|
382
|
-
path=operation.path,
|
383
|
-
method=operation.method,
|
384
|
-
)
|
385
|
-
return data["schema"]
|
386
|
-
# https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.3.md#fixed-fields-10
|
387
|
-
# > The map MUST only contain one entry.
|
388
|
-
try:
|
389
|
-
content = data["content"]
|
390
|
-
except KeyError as exc:
|
391
|
-
raise InvalidSchema(
|
392
|
-
MISSING_SCHEMA_OR_CONTENT_MESSAGE.format(location=data.get("in", ""), name=data.get("name", "<UNKNOWN>")),
|
393
|
-
path=operation.path,
|
394
|
-
method=operation.method,
|
395
|
-
) from exc
|
396
|
-
options = iter(content.values())
|
397
|
-
media_type_object = next(options)
|
398
|
-
return get_media_type_schema(media_type_object)
|
399
|
-
|
400
|
-
|
401
|
-
def get_media_type_schema(definition: dict[str, Any]) -> dict[str, Any]:
|
402
|
-
"""Extract `schema` from Open API 3.0 `MediaType`."""
|
403
|
-
# The `schema` keyword is optional, and we treat it as the payload could be any value of the specified media type
|
404
|
-
# Note, the main reason to have this function is to have an explicit name for the action we're doing.
|
405
|
-
return definition.get("schema", {})
|