ccxt 4.2.77__py2.py3-none-any.whl → 4.4.48__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (546) hide show
  1. ccxt/__init__.py +36 -14
  2. ccxt/abstract/alpaca.py +4 -0
  3. ccxt/abstract/bigone.py +1 -1
  4. ccxt/abstract/binance.py +112 -48
  5. ccxt/abstract/binancecoinm.py +112 -48
  6. ccxt/abstract/binanceus.py +147 -83
  7. ccxt/abstract/binanceusdm.py +112 -48
  8. ccxt/abstract/bingx.py +133 -78
  9. ccxt/abstract/bitbank.py +5 -0
  10. ccxt/abstract/bitfinex.py +136 -65
  11. ccxt/abstract/bitfinex1.py +69 -0
  12. ccxt/abstract/bitflyer.py +1 -0
  13. ccxt/abstract/bitget.py +8 -1
  14. ccxt/abstract/bitmart.py +13 -1
  15. ccxt/abstract/bitopro.py +1 -0
  16. ccxt/abstract/bitpanda.py +0 -12
  17. ccxt/abstract/bitrue.py +3 -3
  18. ccxt/abstract/bitstamp.py +26 -3
  19. ccxt/abstract/blofin.py +24 -0
  20. ccxt/abstract/btcbox.py +1 -0
  21. ccxt/abstract/bybit.py +29 -14
  22. ccxt/abstract/cex.py +28 -29
  23. ccxt/abstract/coinbase.py +6 -0
  24. ccxt/abstract/coinbaseadvanced.py +94 -0
  25. ccxt/abstract/{coinbasepro.py → coinbaseexchange.py} +1 -0
  26. ccxt/abstract/coinbaseinternational.py +1 -1
  27. ccxt/abstract/coincatch.py +94 -0
  28. ccxt/abstract/coinex.py +233 -123
  29. ccxt/abstract/coinmetro.py +1 -0
  30. ccxt/abstract/cryptocom.py +14 -0
  31. ccxt/abstract/defx.py +69 -0
  32. ccxt/abstract/deribit.py +1 -0
  33. ccxt/abstract/digifinex.py +1 -0
  34. ccxt/abstract/ellipx.py +25 -0
  35. ccxt/abstract/gate.py +20 -0
  36. ccxt/abstract/gateio.py +20 -0
  37. ccxt/abstract/gemini.py +1 -0
  38. ccxt/abstract/hashkey.py +67 -0
  39. ccxt/abstract/hyperliquid.py +1 -1
  40. ccxt/abstract/independentreserve.py +6 -0
  41. ccxt/abstract/kraken.py +4 -3
  42. ccxt/abstract/krakenfutures.py +4 -0
  43. ccxt/abstract/kucoin.py +24 -0
  44. ccxt/abstract/kucoinfutures.py +34 -0
  45. ccxt/abstract/luno.py +2 -0
  46. ccxt/abstract/mexc.py +4 -0
  47. ccxt/abstract/myokx.py +340 -0
  48. ccxt/abstract/oceanex.py +5 -0
  49. ccxt/abstract/okx.py +30 -0
  50. ccxt/abstract/onetrading.py +0 -12
  51. ccxt/abstract/oxfun.py +34 -0
  52. ccxt/abstract/paradex.py +40 -0
  53. ccxt/abstract/phemex.py +1 -0
  54. ccxt/abstract/upbit.py +4 -0
  55. ccxt/abstract/vertex.py +19 -0
  56. ccxt/abstract/whitebit.py +31 -1
  57. ccxt/abstract/woo.py +6 -2
  58. ccxt/abstract/woofipro.py +119 -0
  59. ccxt/abstract/xt.py +153 -0
  60. ccxt/abstract/zonda.py +6 -0
  61. ccxt/ace.py +164 -60
  62. ccxt/alpaca.py +727 -63
  63. ccxt/ascendex.py +395 -249
  64. ccxt/async_support/__init__.py +36 -14
  65. ccxt/async_support/ace.py +164 -60
  66. ccxt/async_support/alpaca.py +727 -63
  67. ccxt/async_support/ascendex.py +396 -249
  68. ccxt/async_support/base/exchange.py +531 -155
  69. ccxt/async_support/base/ws/aiohttp_client.py +28 -5
  70. ccxt/async_support/base/ws/cache.py +3 -2
  71. ccxt/async_support/base/ws/client.py +26 -5
  72. ccxt/async_support/base/ws/fast_client.py +4 -3
  73. ccxt/async_support/base/ws/functions.py +1 -1
  74. ccxt/async_support/base/ws/future.py +40 -31
  75. ccxt/async_support/base/ws/order_book_side.py +3 -0
  76. ccxt/async_support/bequant.py +1 -1
  77. ccxt/async_support/bigone.py +329 -202
  78. ccxt/async_support/binance.py +3030 -1087
  79. ccxt/async_support/binancecoinm.py +2 -1
  80. ccxt/async_support/binanceus.py +12 -1
  81. ccxt/async_support/binanceusdm.py +3 -1
  82. ccxt/async_support/bingx.py +3104 -880
  83. ccxt/async_support/bit2c.py +119 -38
  84. ccxt/async_support/bitbank.py +215 -76
  85. ccxt/async_support/bitbns.py +124 -53
  86. ccxt/async_support/bitfinex.py +3236 -1078
  87. ccxt/async_support/bitfinex1.py +1711 -0
  88. ccxt/async_support/bitflyer.py +238 -49
  89. ccxt/async_support/bitget.py +1513 -563
  90. ccxt/async_support/bithumb.py +199 -65
  91. ccxt/async_support/bitmart.py +1320 -435
  92. ccxt/async_support/bitmex.py +308 -111
  93. ccxt/async_support/bitopro.py +256 -96
  94. ccxt/async_support/bitrue.py +365 -233
  95. ccxt/async_support/bitso.py +201 -89
  96. ccxt/async_support/bitstamp.py +438 -269
  97. ccxt/async_support/bitteam.py +179 -73
  98. ccxt/async_support/bitvavo.py +180 -70
  99. ccxt/async_support/bl3p.py +92 -25
  100. ccxt/async_support/blockchaincom.py +193 -79
  101. ccxt/async_support/blofin.py +392 -148
  102. ccxt/async_support/btcalpha.py +161 -55
  103. ccxt/async_support/btcbox.py +250 -34
  104. ccxt/async_support/btcmarkets.py +232 -85
  105. ccxt/async_support/btcturk.py +159 -60
  106. ccxt/async_support/bybit.py +2231 -1193
  107. ccxt/async_support/cex.py +1409 -1329
  108. ccxt/async_support/coinbase.py +1454 -287
  109. ccxt/async_support/coinbaseadvanced.py +17 -0
  110. ccxt/async_support/{coinbasepro.py → coinbaseexchange.py} +233 -99
  111. ccxt/async_support/coinbaseinternational.py +428 -88
  112. ccxt/async_support/coincatch.py +5152 -0
  113. ccxt/async_support/coincheck.py +121 -38
  114. ccxt/async_support/coinex.py +4020 -3339
  115. ccxt/async_support/coinlist.py +273 -116
  116. ccxt/async_support/coinmate.py +204 -97
  117. ccxt/async_support/coinmetro.py +203 -110
  118. ccxt/async_support/coinone.py +142 -68
  119. ccxt/async_support/coinsph.py +206 -89
  120. ccxt/async_support/coinspot.py +137 -62
  121. ccxt/async_support/cryptocom.py +515 -185
  122. ccxt/async_support/currencycom.py +203 -85
  123. ccxt/async_support/defx.py +2066 -0
  124. ccxt/async_support/delta.py +404 -109
  125. ccxt/async_support/deribit.py +557 -323
  126. ccxt/async_support/digifinex.py +340 -223
  127. ccxt/async_support/ellipx.py +1826 -0
  128. ccxt/async_support/exmo.py +259 -128
  129. ccxt/async_support/gate.py +1472 -463
  130. ccxt/async_support/gemini.py +206 -84
  131. ccxt/async_support/hashkey.py +4164 -0
  132. ccxt/async_support/hitbtc.py +334 -178
  133. ccxt/async_support/hollaex.py +134 -83
  134. ccxt/async_support/htx.py +1095 -563
  135. ccxt/async_support/huobijp.py +105 -56
  136. ccxt/async_support/hyperliquid.py +1633 -268
  137. ccxt/async_support/idex.py +148 -95
  138. ccxt/async_support/independentreserve.py +236 -31
  139. ccxt/async_support/indodax.py +165 -62
  140. ccxt/async_support/kraken.py +871 -354
  141. ccxt/async_support/krakenfutures.py +324 -100
  142. ccxt/async_support/kucoin.py +917 -357
  143. ccxt/async_support/kucoinfutures.py +1004 -149
  144. ccxt/async_support/kuna.py +138 -106
  145. ccxt/async_support/latoken.py +135 -79
  146. ccxt/async_support/lbank.py +290 -113
  147. ccxt/async_support/luno.py +112 -62
  148. ccxt/async_support/lykke.py +104 -55
  149. ccxt/async_support/mercado.py +36 -29
  150. ccxt/async_support/mexc.py +995 -429
  151. ccxt/async_support/myokx.py +43 -0
  152. ccxt/async_support/ndax.py +163 -82
  153. ccxt/async_support/novadax.py +121 -75
  154. ccxt/async_support/oceanex.py +175 -59
  155. ccxt/async_support/okcoin.py +222 -163
  156. ccxt/async_support/okx.py +1776 -454
  157. ccxt/async_support/onetrading.py +132 -414
  158. ccxt/async_support/oxfun.py +2832 -0
  159. ccxt/async_support/p2b.py +79 -51
  160. ccxt/async_support/paradex.py +2017 -0
  161. ccxt/async_support/paymium.py +56 -32
  162. ccxt/async_support/phemex.py +572 -196
  163. ccxt/async_support/poloniex.py +218 -95
  164. ccxt/async_support/poloniexfutures.py +260 -92
  165. ccxt/async_support/probit.py +143 -110
  166. ccxt/async_support/timex.py +123 -70
  167. ccxt/async_support/tokocrypto.py +129 -93
  168. ccxt/async_support/tradeogre.py +39 -25
  169. ccxt/async_support/upbit.py +322 -113
  170. ccxt/async_support/vertex.py +2983 -0
  171. ccxt/async_support/wavesexchange.py +227 -173
  172. ccxt/async_support/wazirx.py +145 -65
  173. ccxt/async_support/whitebit.py +533 -138
  174. ccxt/async_support/woo.py +1137 -296
  175. ccxt/async_support/woofipro.py +2716 -0
  176. ccxt/async_support/xt.py +4628 -0
  177. ccxt/async_support/yobit.py +160 -92
  178. ccxt/async_support/zaif.py +80 -33
  179. ccxt/async_support/zonda.py +140 -69
  180. ccxt/base/errors.py +51 -20
  181. ccxt/base/exchange.py +1722 -480
  182. ccxt/base/precise.py +10 -0
  183. ccxt/base/types.py +223 -4
  184. ccxt/bequant.py +1 -1
  185. ccxt/bigone.py +329 -202
  186. ccxt/binance.py +3030 -1087
  187. ccxt/binancecoinm.py +2 -1
  188. ccxt/binanceus.py +12 -1
  189. ccxt/binanceusdm.py +3 -1
  190. ccxt/bingx.py +3104 -880
  191. ccxt/bit2c.py +119 -38
  192. ccxt/bitbank.py +215 -76
  193. ccxt/bitbns.py +124 -53
  194. ccxt/bitfinex.py +3235 -1078
  195. ccxt/bitfinex1.py +1710 -0
  196. ccxt/bitflyer.py +238 -49
  197. ccxt/bitget.py +1513 -563
  198. ccxt/bithumb.py +198 -65
  199. ccxt/bitmart.py +1320 -435
  200. ccxt/bitmex.py +308 -111
  201. ccxt/bitopro.py +256 -96
  202. ccxt/bitrue.py +365 -233
  203. ccxt/bitso.py +201 -89
  204. ccxt/bitstamp.py +438 -269
  205. ccxt/bitteam.py +179 -73
  206. ccxt/bitvavo.py +180 -70
  207. ccxt/bl3p.py +92 -25
  208. ccxt/blockchaincom.py +193 -79
  209. ccxt/blofin.py +392 -148
  210. ccxt/btcalpha.py +161 -55
  211. ccxt/btcbox.py +250 -34
  212. ccxt/btcmarkets.py +232 -85
  213. ccxt/btcturk.py +159 -60
  214. ccxt/bybit.py +2231 -1193
  215. ccxt/cex.py +1408 -1329
  216. ccxt/coinbase.py +1454 -287
  217. ccxt/coinbaseadvanced.py +17 -0
  218. ccxt/{coinbasepro.py → coinbaseexchange.py} +233 -99
  219. ccxt/coinbaseinternational.py +428 -88
  220. ccxt/coincatch.py +5152 -0
  221. ccxt/coincheck.py +121 -38
  222. ccxt/coinex.py +4020 -3339
  223. ccxt/coinlist.py +273 -116
  224. ccxt/coinmate.py +204 -97
  225. ccxt/coinmetro.py +203 -110
  226. ccxt/coinone.py +142 -68
  227. ccxt/coinsph.py +206 -89
  228. ccxt/coinspot.py +137 -62
  229. ccxt/cryptocom.py +515 -185
  230. ccxt/currencycom.py +203 -85
  231. ccxt/defx.py +2065 -0
  232. ccxt/delta.py +404 -109
  233. ccxt/deribit.py +557 -323
  234. ccxt/digifinex.py +340 -223
  235. ccxt/ellipx.py +1826 -0
  236. ccxt/exmo.py +259 -128
  237. ccxt/gate.py +1472 -463
  238. ccxt/gemini.py +206 -84
  239. ccxt/hashkey.py +4164 -0
  240. ccxt/hitbtc.py +334 -178
  241. ccxt/hollaex.py +134 -83
  242. ccxt/htx.py +1095 -563
  243. ccxt/huobijp.py +105 -56
  244. ccxt/hyperliquid.py +1632 -268
  245. ccxt/idex.py +148 -95
  246. ccxt/independentreserve.py +235 -31
  247. ccxt/indodax.py +165 -62
  248. ccxt/kraken.py +871 -354
  249. ccxt/krakenfutures.py +324 -100
  250. ccxt/kucoin.py +917 -357
  251. ccxt/kucoinfutures.py +1004 -149
  252. ccxt/kuna.py +138 -106
  253. ccxt/latoken.py +135 -79
  254. ccxt/lbank.py +290 -113
  255. ccxt/luno.py +112 -62
  256. ccxt/lykke.py +104 -55
  257. ccxt/mercado.py +36 -29
  258. ccxt/mexc.py +994 -429
  259. ccxt/myokx.py +43 -0
  260. ccxt/ndax.py +163 -82
  261. ccxt/novadax.py +121 -75
  262. ccxt/oceanex.py +175 -59
  263. ccxt/okcoin.py +222 -163
  264. ccxt/okx.py +1776 -454
  265. ccxt/onetrading.py +132 -414
  266. ccxt/oxfun.py +2831 -0
  267. ccxt/p2b.py +79 -51
  268. ccxt/paradex.py +2017 -0
  269. ccxt/paymium.py +56 -32
  270. ccxt/phemex.py +572 -196
  271. ccxt/poloniex.py +218 -95
  272. ccxt/poloniexfutures.py +260 -92
  273. ccxt/pro/__init__.py +29 -5
  274. ccxt/pro/alpaca.py +32 -17
  275. ccxt/pro/ascendex.py +62 -14
  276. ccxt/pro/bequant.py +4 -0
  277. ccxt/pro/binance.py +1596 -329
  278. ccxt/pro/binancecoinm.py +1 -0
  279. ccxt/pro/binanceus.py +2 -9
  280. ccxt/pro/binanceusdm.py +2 -0
  281. ccxt/pro/bingx.py +527 -134
  282. ccxt/pro/bitcoincom.py +4 -1
  283. ccxt/pro/bitfinex.py +731 -266
  284. ccxt/pro/bitfinex1.py +635 -0
  285. ccxt/pro/bitget.py +726 -357
  286. ccxt/pro/bithumb.py +380 -0
  287. ccxt/pro/bitmart.py +138 -39
  288. ccxt/pro/bitmex.py +199 -40
  289. ccxt/pro/bitopro.py +25 -13
  290. ccxt/pro/bitrue.py +31 -32
  291. ccxt/pro/bitstamp.py +7 -6
  292. ccxt/pro/bitvavo.py +203 -81
  293. ccxt/pro/blockchaincom.py +30 -17
  294. ccxt/pro/blofin.py +692 -0
  295. ccxt/pro/bybit.py +791 -82
  296. ccxt/pro/cex.py +99 -51
  297. ccxt/pro/coinbase.py +220 -30
  298. ccxt/{async_support/hitbtc3.py → pro/coinbaseadvanced.py} +5 -5
  299. ccxt/pro/{coinbasepro.py → coinbaseexchange.py} +19 -19
  300. ccxt/pro/coinbaseinternational.py +193 -30
  301. ccxt/pro/coincatch.py +1464 -0
  302. ccxt/pro/coincheck.py +11 -6
  303. ccxt/pro/coinex.py +965 -665
  304. ccxt/pro/coinone.py +17 -10
  305. ccxt/pro/cryptocom.py +446 -66
  306. ccxt/pro/currencycom.py +11 -10
  307. ccxt/pro/defx.py +832 -0
  308. ccxt/pro/deribit.py +167 -31
  309. ccxt/pro/exmo.py +252 -20
  310. ccxt/pro/gate.py +729 -64
  311. ccxt/pro/gemini.py +44 -26
  312. ccxt/pro/hashkey.py +802 -0
  313. ccxt/pro/hitbtc.py +208 -103
  314. ccxt/pro/hollaex.py +25 -9
  315. ccxt/pro/htx.py +83 -39
  316. ccxt/pro/huobijp.py +17 -16
  317. ccxt/pro/hyperliquid.py +502 -31
  318. ccxt/pro/idex.py +28 -13
  319. ccxt/pro/independentreserve.py +21 -16
  320. ccxt/pro/kraken.py +298 -51
  321. ccxt/pro/krakenfutures.py +166 -75
  322. ccxt/pro/kucoin.py +395 -77
  323. ccxt/pro/kucoinfutures.py +400 -99
  324. ccxt/pro/lbank.py +52 -31
  325. ccxt/pro/luno.py +12 -10
  326. ccxt/pro/mexc.py +400 -50
  327. ccxt/pro/myokx.py +28 -0
  328. ccxt/pro/ndax.py +25 -12
  329. ccxt/pro/okcoin.py +28 -9
  330. ccxt/pro/okx.py +935 -124
  331. ccxt/pro/onetrading.py +41 -24
  332. ccxt/pro/oxfun.py +1054 -0
  333. ccxt/pro/p2b.py +100 -24
  334. ccxt/pro/paradex.py +352 -0
  335. ccxt/pro/phemex.py +92 -33
  336. ccxt/pro/poloniex.py +128 -49
  337. ccxt/pro/poloniexfutures.py +53 -32
  338. ccxt/pro/probit.py +92 -85
  339. ccxt/pro/upbit.py +401 -8
  340. ccxt/pro/vertex.py +943 -0
  341. ccxt/pro/wazirx.py +46 -28
  342. ccxt/pro/whitebit.py +65 -12
  343. ccxt/pro/woo.py +437 -65
  344. ccxt/pro/woofipro.py +1271 -0
  345. ccxt/pro/xt.py +1067 -0
  346. ccxt/probit.py +143 -110
  347. ccxt/static_dependencies/__init__.py +1 -1
  348. ccxt/static_dependencies/lark/__init__.py +38 -0
  349. ccxt/static_dependencies/lark/__pyinstaller/__init__.py +6 -0
  350. ccxt/static_dependencies/lark/__pyinstaller/hook-lark.py +14 -0
  351. ccxt/static_dependencies/lark/ast_utils.py +59 -0
  352. ccxt/static_dependencies/lark/common.py +86 -0
  353. ccxt/static_dependencies/lark/exceptions.py +292 -0
  354. ccxt/static_dependencies/lark/grammar.py +130 -0
  355. ccxt/static_dependencies/lark/grammars/__init__.py +0 -0
  356. ccxt/static_dependencies/lark/indenter.py +143 -0
  357. ccxt/static_dependencies/lark/lark.py +658 -0
  358. ccxt/static_dependencies/lark/lexer.py +678 -0
  359. ccxt/static_dependencies/lark/load_grammar.py +1428 -0
  360. ccxt/static_dependencies/lark/parse_tree_builder.py +391 -0
  361. ccxt/static_dependencies/lark/parser_frontends.py +257 -0
  362. ccxt/static_dependencies/lark/parsers/__init__.py +0 -0
  363. ccxt/static_dependencies/lark/parsers/cyk.py +340 -0
  364. ccxt/static_dependencies/lark/parsers/earley.py +314 -0
  365. ccxt/static_dependencies/lark/parsers/earley_common.py +42 -0
  366. ccxt/static_dependencies/lark/parsers/earley_forest.py +801 -0
  367. ccxt/static_dependencies/lark/parsers/grammar_analysis.py +203 -0
  368. ccxt/static_dependencies/lark/parsers/lalr_analysis.py +332 -0
  369. ccxt/static_dependencies/lark/parsers/lalr_interactive_parser.py +158 -0
  370. ccxt/static_dependencies/lark/parsers/lalr_parser.py +122 -0
  371. ccxt/static_dependencies/lark/parsers/lalr_parser_state.py +110 -0
  372. ccxt/static_dependencies/lark/parsers/xearley.py +165 -0
  373. ccxt/static_dependencies/lark/py.typed +0 -0
  374. ccxt/static_dependencies/lark/reconstruct.py +107 -0
  375. ccxt/static_dependencies/lark/tools/__init__.py +70 -0
  376. ccxt/static_dependencies/lark/tools/nearley.py +202 -0
  377. ccxt/static_dependencies/lark/tools/serialize.py +32 -0
  378. ccxt/static_dependencies/lark/tools/standalone.py +196 -0
  379. ccxt/static_dependencies/lark/tree.py +267 -0
  380. ccxt/static_dependencies/lark/tree_matcher.py +186 -0
  381. ccxt/static_dependencies/lark/tree_templates.py +180 -0
  382. ccxt/static_dependencies/lark/utils.py +343 -0
  383. ccxt/static_dependencies/lark/visitors.py +596 -0
  384. ccxt/static_dependencies/marshmallow/__init__.py +81 -0
  385. ccxt/static_dependencies/marshmallow/base.py +65 -0
  386. ccxt/static_dependencies/marshmallow/class_registry.py +94 -0
  387. ccxt/static_dependencies/marshmallow/decorators.py +231 -0
  388. ccxt/static_dependencies/marshmallow/error_store.py +60 -0
  389. ccxt/static_dependencies/marshmallow/exceptions.py +71 -0
  390. ccxt/static_dependencies/marshmallow/fields.py +2114 -0
  391. ccxt/static_dependencies/marshmallow/orderedset.py +89 -0
  392. ccxt/static_dependencies/marshmallow/py.typed +0 -0
  393. ccxt/static_dependencies/marshmallow/schema.py +1228 -0
  394. ccxt/static_dependencies/marshmallow/types.py +12 -0
  395. ccxt/static_dependencies/marshmallow/utils.py +378 -0
  396. ccxt/static_dependencies/marshmallow/validate.py +678 -0
  397. ccxt/static_dependencies/marshmallow/warnings.py +2 -0
  398. ccxt/static_dependencies/marshmallow_dataclass/__init__.py +1047 -0
  399. ccxt/static_dependencies/marshmallow_dataclass/collection_field.py +51 -0
  400. ccxt/static_dependencies/marshmallow_dataclass/lazy_class_attribute.py +45 -0
  401. ccxt/static_dependencies/marshmallow_dataclass/mypy.py +71 -0
  402. ccxt/static_dependencies/marshmallow_dataclass/py.typed +0 -0
  403. ccxt/static_dependencies/marshmallow_dataclass/typing.py +14 -0
  404. ccxt/static_dependencies/marshmallow_dataclass/union_field.py +82 -0
  405. ccxt/static_dependencies/marshmallow_oneofschema/__init__.py +1 -0
  406. ccxt/static_dependencies/marshmallow_oneofschema/one_of_schema.py +193 -0
  407. ccxt/static_dependencies/marshmallow_oneofschema/py.typed +0 -0
  408. ccxt/static_dependencies/starknet/__init__.py +0 -0
  409. ccxt/static_dependencies/starknet/cairo/__init__.py +0 -0
  410. ccxt/static_dependencies/starknet/cairo/data_types.py +123 -0
  411. ccxt/static_dependencies/starknet/cairo/deprecated_parse/__init__.py +0 -0
  412. ccxt/static_dependencies/starknet/cairo/deprecated_parse/cairo_types.py +77 -0
  413. ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser.py +46 -0
  414. ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser_transformer.py +138 -0
  415. ccxt/static_dependencies/starknet/cairo/felt.py +64 -0
  416. ccxt/static_dependencies/starknet/cairo/type_parser.py +121 -0
  417. ccxt/static_dependencies/starknet/cairo/v1/__init__.py +0 -0
  418. ccxt/static_dependencies/starknet/cairo/v1/type_parser.py +59 -0
  419. ccxt/static_dependencies/starknet/cairo/v2/__init__.py +0 -0
  420. ccxt/static_dependencies/starknet/cairo/v2/type_parser.py +77 -0
  421. ccxt/static_dependencies/starknet/ccxt_utils.py +7 -0
  422. ccxt/static_dependencies/starknet/common.py +15 -0
  423. ccxt/static_dependencies/starknet/constants.py +39 -0
  424. ccxt/static_dependencies/starknet/hash/__init__.py +0 -0
  425. ccxt/static_dependencies/starknet/hash/address.py +79 -0
  426. ccxt/static_dependencies/starknet/hash/compiled_class_hash_objects.py +111 -0
  427. ccxt/static_dependencies/starknet/hash/selector.py +16 -0
  428. ccxt/static_dependencies/starknet/hash/storage.py +12 -0
  429. ccxt/static_dependencies/starknet/hash/utils.py +78 -0
  430. ccxt/static_dependencies/starknet/models/__init__.py +0 -0
  431. ccxt/static_dependencies/starknet/models/typed_data.py +45 -0
  432. ccxt/static_dependencies/starknet/serialization/__init__.py +24 -0
  433. ccxt/static_dependencies/starknet/serialization/_calldata_reader.py +40 -0
  434. ccxt/static_dependencies/starknet/serialization/_context.py +142 -0
  435. ccxt/static_dependencies/starknet/serialization/data_serializers/__init__.py +10 -0
  436. ccxt/static_dependencies/starknet/serialization/data_serializers/_common.py +82 -0
  437. ccxt/static_dependencies/starknet/serialization/data_serializers/array_serializer.py +43 -0
  438. ccxt/static_dependencies/starknet/serialization/data_serializers/bool_serializer.py +37 -0
  439. ccxt/static_dependencies/starknet/serialization/data_serializers/byte_array_serializer.py +66 -0
  440. ccxt/static_dependencies/starknet/serialization/data_serializers/cairo_data_serializer.py +71 -0
  441. ccxt/static_dependencies/starknet/serialization/data_serializers/enum_serializer.py +71 -0
  442. ccxt/static_dependencies/starknet/serialization/data_serializers/felt_serializer.py +50 -0
  443. ccxt/static_dependencies/starknet/serialization/data_serializers/named_tuple_serializer.py +58 -0
  444. ccxt/static_dependencies/starknet/serialization/data_serializers/option_serializer.py +43 -0
  445. ccxt/static_dependencies/starknet/serialization/data_serializers/output_serializer.py +40 -0
  446. ccxt/static_dependencies/starknet/serialization/data_serializers/payload_serializer.py +72 -0
  447. ccxt/static_dependencies/starknet/serialization/data_serializers/struct_serializer.py +36 -0
  448. ccxt/static_dependencies/starknet/serialization/data_serializers/tuple_serializer.py +36 -0
  449. ccxt/static_dependencies/starknet/serialization/data_serializers/uint256_serializer.py +76 -0
  450. ccxt/static_dependencies/starknet/serialization/data_serializers/uint_serializer.py +100 -0
  451. ccxt/static_dependencies/starknet/serialization/data_serializers/unit_serializer.py +32 -0
  452. ccxt/static_dependencies/starknet/serialization/errors.py +10 -0
  453. ccxt/static_dependencies/starknet/serialization/factory.py +229 -0
  454. ccxt/static_dependencies/starknet/serialization/function_serialization_adapter.py +110 -0
  455. ccxt/static_dependencies/starknet/serialization/tuple_dataclass.py +59 -0
  456. ccxt/static_dependencies/starknet/utils/__init__.py +0 -0
  457. ccxt/static_dependencies/starknet/utils/constructor_args_translator.py +86 -0
  458. ccxt/static_dependencies/starknet/utils/iterable.py +13 -0
  459. ccxt/static_dependencies/starknet/utils/schema.py +13 -0
  460. ccxt/static_dependencies/starknet/utils/typed_data.py +182 -0
  461. ccxt/static_dependencies/starkware/__init__.py +0 -0
  462. ccxt/static_dependencies/starkware/crypto/__init__.py +0 -0
  463. ccxt/static_dependencies/starkware/crypto/fast_pedersen_hash.py +50 -0
  464. ccxt/static_dependencies/starkware/crypto/math_utils.py +78 -0
  465. ccxt/static_dependencies/starkware/crypto/signature.py +2344 -0
  466. ccxt/static_dependencies/starkware/crypto/utils.py +63 -0
  467. ccxt/static_dependencies/sympy/__init__.py +0 -0
  468. ccxt/static_dependencies/sympy/core/__init__.py +0 -0
  469. ccxt/static_dependencies/sympy/core/intfunc.py +35 -0
  470. ccxt/static_dependencies/sympy/external/__init__.py +0 -0
  471. ccxt/static_dependencies/sympy/external/gmpy.py +345 -0
  472. ccxt/static_dependencies/sympy/external/importtools.py +187 -0
  473. ccxt/static_dependencies/sympy/external/ntheory.py +637 -0
  474. ccxt/static_dependencies/sympy/external/pythonmpq.py +341 -0
  475. ccxt/static_dependencies/typing_inspect/__init__.py +0 -0
  476. ccxt/static_dependencies/typing_inspect/typing_inspect.py +851 -0
  477. ccxt/test/{test_async.py → tests_async.py} +456 -391
  478. ccxt/test/tests_helpers.py +285 -0
  479. ccxt/test/tests_init.py +39 -0
  480. ccxt/test/{test_sync.py → tests_sync.py} +456 -393
  481. ccxt/timex.py +123 -70
  482. ccxt/tokocrypto.py +129 -93
  483. ccxt/tradeogre.py +39 -25
  484. ccxt/upbit.py +322 -113
  485. ccxt/vertex.py +2983 -0
  486. ccxt/wavesexchange.py +227 -173
  487. ccxt/wazirx.py +145 -65
  488. ccxt/whitebit.py +533 -138
  489. ccxt/woo.py +1137 -296
  490. ccxt/woofipro.py +2716 -0
  491. ccxt/xt.py +4627 -0
  492. ccxt/yobit.py +159 -92
  493. ccxt/zaif.py +80 -33
  494. ccxt/zonda.py +140 -69
  495. ccxt-4.4.48.dist-info/LICENSE.txt +21 -0
  496. ccxt-4.4.48.dist-info/METADATA +646 -0
  497. ccxt-4.4.48.dist-info/RECORD +669 -0
  498. {ccxt-4.2.77.dist-info → ccxt-4.4.48.dist-info}/WHEEL +1 -1
  499. ccxt/abstract/bitbay.py +0 -47
  500. ccxt/abstract/bitfinex2.py +0 -139
  501. ccxt/abstract/hitbtc3.py +0 -115
  502. ccxt/async_support/bitbay.py +0 -17
  503. ccxt/async_support/bitfinex2.py +0 -3496
  504. ccxt/async_support/flowbtc.py +0 -34
  505. ccxt/bitbay.py +0 -17
  506. ccxt/bitfinex2.py +0 -3496
  507. ccxt/flowbtc.py +0 -34
  508. ccxt/hitbtc3.py +0 -16
  509. ccxt/pro/bitfinex2.py +0 -1081
  510. ccxt/test/base/__init__.py +0 -28
  511. ccxt/test/base/test_account.py +0 -26
  512. ccxt/test/base/test_balance.py +0 -56
  513. ccxt/test/base/test_borrow_interest.py +0 -35
  514. ccxt/test/base/test_borrow_rate.py +0 -32
  515. ccxt/test/base/test_calculate_fee.py +0 -51
  516. ccxt/test/base/test_crypto.py +0 -127
  517. ccxt/test/base/test_currency.py +0 -76
  518. ccxt/test/base/test_datetime.py +0 -103
  519. ccxt/test/base/test_decimal_to_precision.py +0 -392
  520. ccxt/test/base/test_deep_extend.py +0 -68
  521. ccxt/test/base/test_deposit_withdrawal.py +0 -50
  522. ccxt/test/base/test_exchange_datetime_functions.py +0 -76
  523. ccxt/test/base/test_funding_rate_history.py +0 -29
  524. ccxt/test/base/test_last_price.py +0 -32
  525. ccxt/test/base/test_ledger_entry.py +0 -45
  526. ccxt/test/base/test_ledger_item.py +0 -48
  527. ccxt/test/base/test_leverage_tier.py +0 -33
  528. ccxt/test/base/test_margin_mode.py +0 -24
  529. ccxt/test/base/test_margin_modification.py +0 -35
  530. ccxt/test/base/test_market.py +0 -190
  531. ccxt/test/base/test_number.py +0 -411
  532. ccxt/test/base/test_ohlcv.py +0 -32
  533. ccxt/test/base/test_open_interest.py +0 -32
  534. ccxt/test/base/test_order.py +0 -64
  535. ccxt/test/base/test_order_book.py +0 -63
  536. ccxt/test/base/test_position.py +0 -60
  537. ccxt/test/base/test_shared_methods.py +0 -345
  538. ccxt/test/base/test_status.py +0 -24
  539. ccxt/test/base/test_throttle.py +0 -126
  540. ccxt/test/base/test_ticker.py +0 -86
  541. ccxt/test/base/test_trade.py +0 -47
  542. ccxt/test/base/test_trading_fee.py +0 -26
  543. ccxt/test/base/test_transaction.py +0 -39
  544. ccxt-4.2.77.dist-info/METADATA +0 -626
  545. ccxt-4.2.77.dist-info/RECORD +0 -534
  546. {ccxt-4.2.77.dist-info → ccxt-4.4.48.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,678 @@
1
+ """Validation classes for various types of data."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import re
6
+ import typing
7
+ from abc import ABC, abstractmethod
8
+ from itertools import zip_longest
9
+ from operator import attrgetter
10
+
11
+ from . import types
12
+ from .exceptions import ValidationError
13
+
14
+ _T = typing.TypeVar("_T")
15
+
16
+
17
+ class Validator(ABC):
18
+ """Abstract base class for validators.
19
+
20
+ .. note::
21
+ This class does not provide any validation behavior. It is only used to
22
+ add a useful `__repr__` implementation for validators.
23
+ """
24
+
25
+ error = None # type: str | None
26
+
27
+ def __repr__(self) -> str:
28
+ args = self._repr_args()
29
+ args = f"{args}, " if args else ""
30
+
31
+ return f"<{self.__class__.__name__}({args}error={self.error!r})>"
32
+
33
+ def _repr_args(self) -> str:
34
+ """A string representation of the args passed to this validator. Used by
35
+ `__repr__`.
36
+ """
37
+ return ""
38
+
39
+ @abstractmethod
40
+ def __call__(self, value: typing.Any) -> typing.Any: ...
41
+
42
+
43
+ class And(Validator):
44
+ """Compose multiple validators and combine their error messages.
45
+
46
+ Example: ::
47
+
48
+ from . import validate, ValidationError
49
+
50
+
51
+ def is_even(value):
52
+ if value % 2 != 0:
53
+ raise ValidationError("Not an even value.")
54
+
55
+
56
+ validator = validate.And(validate.Range(min=0), is_even)
57
+ validator(-1)
58
+ # ValidationError: ['Must be greater than or equal to 0.', 'Not an even value.']
59
+
60
+ :param validators: Validators to combine.
61
+ :param error: Error message to use when a validator returns ``False``.
62
+ """
63
+
64
+ default_error_message = "Invalid value."
65
+
66
+ def __init__(self, *validators: types.Validator, error: str | None = None):
67
+ self.validators = tuple(validators)
68
+ self.error = error or self.default_error_message # type: str
69
+
70
+ def _repr_args(self) -> str:
71
+ return f"validators={self.validators!r}"
72
+
73
+ def __call__(self, value: typing.Any) -> typing.Any:
74
+ errors = []
75
+ kwargs = {}
76
+ for validator in self.validators:
77
+ try:
78
+ r = validator(value)
79
+ if not isinstance(validator, Validator) and r is False:
80
+ raise ValidationError(self.error)
81
+ except ValidationError as err:
82
+ kwargs.update(err.kwargs)
83
+ if isinstance(err.messages, dict):
84
+ errors.append(err.messages)
85
+ else:
86
+ # FIXME : Get rid of cast
87
+ errors.extend(typing.cast(list, err.messages))
88
+ if errors:
89
+ raise ValidationError(errors, **kwargs)
90
+ return value
91
+
92
+
93
+ class URL(Validator):
94
+ """Validate a URL.
95
+
96
+ :param relative: Whether to allow relative URLs.
97
+ :param absolute: Whether to allow absolute URLs.
98
+ :param error: Error message to raise in case of a validation error.
99
+ Can be interpolated with `{input}`.
100
+ :param schemes: Valid schemes. By default, ``http``, ``https``,
101
+ ``ftp``, and ``ftps`` are allowed.
102
+ :param require_tld: Whether to reject non-FQDN hostnames.
103
+ """
104
+
105
+ class RegexMemoizer:
106
+ def __init__(self):
107
+ self._memoized = {}
108
+
109
+ def _regex_generator(
110
+ self, relative: bool, absolute: bool, require_tld: bool
111
+ ) -> typing.Pattern:
112
+ hostname_variants = [
113
+ # a normal domain name, expressed in [A-Z0-9] chars with hyphens allowed only in the middle
114
+ # note that the regex will be compiled with IGNORECASE, so these are upper and lowercase chars
115
+ (
116
+ r"(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+"
117
+ r"(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)"
118
+ ),
119
+ # or the special string 'localhost'
120
+ r"localhost",
121
+ # or IPv4
122
+ r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}",
123
+ # or IPv6
124
+ r"\[[A-F0-9]*:[A-F0-9:]+\]",
125
+ ]
126
+ if not require_tld:
127
+ # allow dotless hostnames
128
+ hostname_variants.append(r"(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.?)")
129
+
130
+ absolute_part = "".join(
131
+ (
132
+ # scheme (e.g. 'https://', 'ftp://', etc)
133
+ # this is validated separately against allowed schemes, so in the regex
134
+ # we simply want to capture its existence
135
+ r"(?:[a-z0-9\.\-\+]*)://",
136
+ # userinfo, for URLs encoding authentication
137
+ # e.g. 'ftp://foo:bar@ftp.example.org/'
138
+ r"(?:(?:[a-z0-9\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?",
139
+ # netloc, the hostname/domain part of the URL plus the optional port
140
+ r"(?:",
141
+ "|".join(hostname_variants),
142
+ r")",
143
+ r"(?::\d+)?",
144
+ )
145
+ )
146
+ relative_part = r"(?:/?|[/?]\S+)\Z"
147
+
148
+ if relative:
149
+ if absolute:
150
+ parts: tuple[str, ...] = (
151
+ r"^(",
152
+ absolute_part,
153
+ r")?",
154
+ relative_part,
155
+ )
156
+ else:
157
+ parts = (r"^", relative_part)
158
+ else:
159
+ parts = (r"^", absolute_part, relative_part)
160
+
161
+ return re.compile("".join(parts), re.IGNORECASE)
162
+
163
+ def __call__(
164
+ self, relative: bool, absolute: bool, require_tld: bool
165
+ ) -> typing.Pattern:
166
+ key = (relative, absolute, require_tld)
167
+ if key not in self._memoized:
168
+ self._memoized[key] = self._regex_generator(
169
+ relative, absolute, require_tld
170
+ )
171
+
172
+ return self._memoized[key]
173
+
174
+ _regex = RegexMemoizer()
175
+
176
+ default_message = "Not a valid URL."
177
+ default_schemes = {"http", "https", "ftp", "ftps"}
178
+
179
+ def __init__(
180
+ self,
181
+ *,
182
+ relative: bool = False,
183
+ absolute: bool = True,
184
+ schemes: types.StrSequenceOrSet | None = None,
185
+ require_tld: bool = True,
186
+ error: str | None = None,
187
+ ):
188
+ if not relative and not absolute:
189
+ raise ValueError(
190
+ "URL validation cannot set both relative and absolute to False."
191
+ )
192
+ self.relative = relative
193
+ self.absolute = absolute
194
+ self.error = error or self.default_message # type: str
195
+ self.schemes = schemes or self.default_schemes
196
+ self.require_tld = require_tld
197
+
198
+ def _repr_args(self) -> str:
199
+ return f"relative={self.relative!r}, absolute={self.absolute!r}"
200
+
201
+ def _format_error(self, value) -> str:
202
+ return self.error.format(input=value)
203
+
204
+ def __call__(self, value: str) -> str:
205
+ message = self._format_error(value)
206
+ if not value:
207
+ raise ValidationError(message)
208
+
209
+ # Check first if the scheme is valid
210
+ if "://" in value:
211
+ scheme = value.split("://")[0].lower()
212
+ if scheme not in self.schemes:
213
+ raise ValidationError(message)
214
+
215
+ regex = self._regex(self.relative, self.absolute, self.require_tld)
216
+
217
+ if not regex.search(value):
218
+ raise ValidationError(message)
219
+
220
+ return value
221
+
222
+
223
+ class Email(Validator):
224
+ """Validate an email address.
225
+
226
+ :param error: Error message to raise in case of a validation error. Can be
227
+ interpolated with `{input}`.
228
+ """
229
+
230
+ USER_REGEX = re.compile(
231
+ r"(^[-!#$%&'*+/=?^`{}|~\w]+(\.[-!#$%&'*+/=?^`{}|~\w]+)*\Z" # dot-atom
232
+ # quoted-string
233
+ r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]'
234
+ r'|\\[\001-\011\013\014\016-\177])*"\Z)',
235
+ re.IGNORECASE | re.UNICODE,
236
+ )
237
+
238
+ DOMAIN_REGEX = re.compile(
239
+ # domain
240
+ r"(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+"
241
+ r"(?:[A-Z]{2,6}|[A-Z0-9-]{2,})\Z"
242
+ # literal form, ipv4 address (SMTP 4.1.3)
243
+ r"|^\[(25[0-5]|2[0-4]\d|[0-1]?\d?\d)"
244
+ r"(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\]\Z",
245
+ re.IGNORECASE | re.UNICODE,
246
+ )
247
+
248
+ DOMAIN_WHITELIST = ("localhost",)
249
+
250
+ default_message = "Not a valid email address."
251
+
252
+ def __init__(self, *, error: str | None = None):
253
+ self.error = error or self.default_message # type: str
254
+
255
+ def _format_error(self, value: str) -> str:
256
+ return self.error.format(input=value)
257
+
258
+ def __call__(self, value: str) -> str:
259
+ message = self._format_error(value)
260
+
261
+ if not value or "@" not in value:
262
+ raise ValidationError(message)
263
+
264
+ user_part, domain_part = value.rsplit("@", 1)
265
+
266
+ if not self.USER_REGEX.match(user_part):
267
+ raise ValidationError(message)
268
+
269
+ if domain_part not in self.DOMAIN_WHITELIST:
270
+ if not self.DOMAIN_REGEX.match(domain_part):
271
+ try:
272
+ domain_part = domain_part.encode("idna").decode("ascii")
273
+ except UnicodeError:
274
+ pass
275
+ else:
276
+ if self.DOMAIN_REGEX.match(domain_part):
277
+ return value
278
+ raise ValidationError(message)
279
+
280
+ return value
281
+
282
+
283
+ class Range(Validator):
284
+ """Validator which succeeds if the value passed to it is within the specified
285
+ range. If ``min`` is not specified, or is specified as `None`,
286
+ no lower bound exists. If ``max`` is not specified, or is specified as `None`,
287
+ no upper bound exists. The inclusivity of the bounds (if they exist) is configurable.
288
+ If ``min_inclusive`` is not specified, or is specified as `True`, then
289
+ the ``min`` bound is included in the range. If ``max_inclusive`` is not specified,
290
+ or is specified as `True`, then the ``max`` bound is included in the range.
291
+
292
+ :param min: The minimum value (lower bound). If not provided, minimum
293
+ value will not be checked.
294
+ :param max: The maximum value (upper bound). If not provided, maximum
295
+ value will not be checked.
296
+ :param min_inclusive: Whether the `min` bound is included in the range.
297
+ :param max_inclusive: Whether the `max` bound is included in the range.
298
+ :param error: Error message to raise in case of a validation error.
299
+ Can be interpolated with `{input}`, `{min}` and `{max}`.
300
+ """
301
+
302
+ message_min = "Must be {min_op} {{min}}."
303
+ message_max = "Must be {max_op} {{max}}."
304
+ message_all = "Must be {min_op} {{min}} and {max_op} {{max}}."
305
+
306
+ message_gte = "greater than or equal to"
307
+ message_gt = "greater than"
308
+ message_lte = "less than or equal to"
309
+ message_lt = "less than"
310
+
311
+ def __init__(
312
+ self,
313
+ min=None,
314
+ max=None,
315
+ *,
316
+ min_inclusive: bool = True,
317
+ max_inclusive: bool = True,
318
+ error: str | None = None,
319
+ ):
320
+ self.min = min
321
+ self.max = max
322
+ self.error = error
323
+ self.min_inclusive = min_inclusive
324
+ self.max_inclusive = max_inclusive
325
+
326
+ # interpolate messages based on bound inclusivity
327
+ self.message_min = self.message_min.format(
328
+ min_op=self.message_gte if self.min_inclusive else self.message_gt
329
+ )
330
+ self.message_max = self.message_max.format(
331
+ max_op=self.message_lte if self.max_inclusive else self.message_lt
332
+ )
333
+ self.message_all = self.message_all.format(
334
+ min_op=self.message_gte if self.min_inclusive else self.message_gt,
335
+ max_op=self.message_lte if self.max_inclusive else self.message_lt,
336
+ )
337
+
338
+ def _repr_args(self) -> str:
339
+ return f"min={self.min!r}, max={self.max!r}, min_inclusive={self.min_inclusive!r}, max_inclusive={self.max_inclusive!r}"
340
+
341
+ def _format_error(self, value: _T, message: str) -> str:
342
+ return (self.error or message).format(input=value, min=self.min, max=self.max)
343
+
344
+ def __call__(self, value: _T) -> _T:
345
+ if self.min is not None and (
346
+ value < self.min if self.min_inclusive else value <= self.min
347
+ ):
348
+ message = self.message_min if self.max is None else self.message_all
349
+ raise ValidationError(self._format_error(value, message))
350
+
351
+ if self.max is not None and (
352
+ value > self.max if self.max_inclusive else value >= self.max
353
+ ):
354
+ message = self.message_max if self.min is None else self.message_all
355
+ raise ValidationError(self._format_error(value, message))
356
+
357
+ return value
358
+
359
+
360
+ class Length(Validator):
361
+ """Validator which succeeds if the value passed to it has a
362
+ length between a minimum and maximum. Uses len(), so it
363
+ can work for strings, lists, or anything with length.
364
+
365
+ :param min: The minimum length. If not provided, minimum length
366
+ will not be checked.
367
+ :param max: The maximum length. If not provided, maximum length
368
+ will not be checked.
369
+ :param equal: The exact length. If provided, maximum and minimum
370
+ length will not be checked.
371
+ :param error: Error message to raise in case of a validation error.
372
+ Can be interpolated with `{input}`, `{min}` and `{max}`.
373
+ """
374
+
375
+ message_min = "Shorter than minimum length {min}."
376
+ message_max = "Longer than maximum length {max}."
377
+ message_all = "Length must be between {min} and {max}."
378
+ message_equal = "Length must be {equal}."
379
+
380
+ def __init__(
381
+ self,
382
+ min: int | None = None,
383
+ max: int | None = None,
384
+ *,
385
+ equal: int | None = None,
386
+ error: str | None = None,
387
+ ):
388
+ if equal is not None and any([min, max]):
389
+ raise ValueError(
390
+ "The `equal` parameter was provided, maximum or "
391
+ "minimum parameter must not be provided."
392
+ )
393
+
394
+ self.min = min
395
+ self.max = max
396
+ self.error = error
397
+ self.equal = equal
398
+
399
+ def _repr_args(self) -> str:
400
+ return f"min={self.min!r}, max={self.max!r}, equal={self.equal!r}"
401
+
402
+ def _format_error(self, value: typing.Sized, message: str) -> str:
403
+ return (self.error or message).format(
404
+ input=value, min=self.min, max=self.max, equal=self.equal
405
+ )
406
+
407
+ def __call__(self, value: typing.Sized) -> typing.Sized:
408
+ length = len(value)
409
+
410
+ if self.equal is not None:
411
+ if length != self.equal:
412
+ raise ValidationError(self._format_error(value, self.message_equal))
413
+ return value
414
+
415
+ if self.min is not None and length < self.min:
416
+ message = self.message_min if self.max is None else self.message_all
417
+ raise ValidationError(self._format_error(value, message))
418
+
419
+ if self.max is not None and length > self.max:
420
+ message = self.message_max if self.min is None else self.message_all
421
+ raise ValidationError(self._format_error(value, message))
422
+
423
+ return value
424
+
425
+
426
+ class Equal(Validator):
427
+ """Validator which succeeds if the ``value`` passed to it is
428
+ equal to ``comparable``.
429
+
430
+ :param comparable: The object to compare to.
431
+ :param error: Error message to raise in case of a validation error.
432
+ Can be interpolated with `{input}` and `{other}`.
433
+ """
434
+
435
+ default_message = "Must be equal to {other}."
436
+
437
+ def __init__(self, comparable, *, error: str | None = None):
438
+ self.comparable = comparable
439
+ self.error = error or self.default_message # type: str
440
+
441
+ def _repr_args(self) -> str:
442
+ return f"comparable={self.comparable!r}"
443
+
444
+ def _format_error(self, value: _T) -> str:
445
+ return self.error.format(input=value, other=self.comparable)
446
+
447
+ def __call__(self, value: _T) -> _T:
448
+ if value != self.comparable:
449
+ raise ValidationError(self._format_error(value))
450
+ return value
451
+
452
+
453
+ class Regexp(Validator):
454
+ """Validator which succeeds if the ``value`` matches ``regex``.
455
+
456
+ .. note::
457
+
458
+ Uses `re.match`, which searches for a match at the beginning of a string.
459
+
460
+ :param regex: The regular expression string to use. Can also be a compiled
461
+ regular expression pattern.
462
+ :param flags: The regexp flags to use, for example re.IGNORECASE. Ignored
463
+ if ``regex`` is not a string.
464
+ :param error: Error message to raise in case of a validation error.
465
+ Can be interpolated with `{input}` and `{regex}`.
466
+ """
467
+
468
+ default_message = "String does not match expected pattern."
469
+
470
+ def __init__(
471
+ self,
472
+ regex: str | bytes | typing.Pattern,
473
+ flags: int = 0,
474
+ *,
475
+ error: str | None = None,
476
+ ):
477
+ self.regex = (
478
+ re.compile(regex, flags) if isinstance(regex, (str, bytes)) else regex
479
+ )
480
+ self.error = error or self.default_message # type: str
481
+
482
+ def _repr_args(self) -> str:
483
+ return f"regex={self.regex!r}"
484
+
485
+ def _format_error(self, value: str | bytes) -> str:
486
+ return self.error.format(input=value, regex=self.regex.pattern)
487
+
488
+ @typing.overload
489
+ def __call__(self, value: str) -> str: ...
490
+
491
+ @typing.overload
492
+ def __call__(self, value: bytes) -> bytes: ...
493
+
494
+ def __call__(self, value):
495
+ if self.regex.match(value) is None:
496
+ raise ValidationError(self._format_error(value))
497
+
498
+ return value
499
+
500
+
501
+ class Predicate(Validator):
502
+ """Call the specified ``method`` of the ``value`` object. The
503
+ validator succeeds if the invoked method returns an object that
504
+ evaluates to True in a Boolean context. Any additional keyword
505
+ argument will be passed to the method.
506
+
507
+ :param method: The name of the method to invoke.
508
+ :param error: Error message to raise in case of a validation error.
509
+ Can be interpolated with `{input}` and `{method}`.
510
+ :param kwargs: Additional keyword arguments to pass to the method.
511
+ """
512
+
513
+ default_message = "Invalid input."
514
+
515
+ def __init__(self, method: str, *, error: str | None = None, **kwargs):
516
+ self.method = method
517
+ self.error = error or self.default_message # type: str
518
+ self.kwargs = kwargs
519
+
520
+ def _repr_args(self) -> str:
521
+ return f"method={self.method!r}, kwargs={self.kwargs!r}"
522
+
523
+ def _format_error(self, value: typing.Any) -> str:
524
+ return self.error.format(input=value, method=self.method)
525
+
526
+ def __call__(self, value: typing.Any) -> typing.Any:
527
+ method = getattr(value, self.method)
528
+
529
+ if not method(**self.kwargs):
530
+ raise ValidationError(self._format_error(value))
531
+
532
+ return value
533
+
534
+
535
+ class NoneOf(Validator):
536
+ """Validator which fails if ``value`` is a member of ``iterable``.
537
+
538
+ :param iterable: A sequence of invalid values.
539
+ :param error: Error message to raise in case of a validation error. Can be
540
+ interpolated using `{input}` and `{values}`.
541
+ """
542
+
543
+ default_message = "Invalid input."
544
+
545
+ def __init__(self, iterable: typing.Iterable, *, error: str | None = None):
546
+ self.iterable = iterable
547
+ self.values_text = ", ".join(str(each) for each in self.iterable)
548
+ self.error = error or self.default_message # type: str
549
+
550
+ def _repr_args(self) -> str:
551
+ return f"iterable={self.iterable!r}"
552
+
553
+ def _format_error(self, value) -> str:
554
+ return self.error.format(input=value, values=self.values_text)
555
+
556
+ def __call__(self, value: typing.Any) -> typing.Any:
557
+ try:
558
+ if value in self.iterable:
559
+ raise ValidationError(self._format_error(value))
560
+ except TypeError:
561
+ pass
562
+
563
+ return value
564
+
565
+
566
+ class OneOf(Validator):
567
+ """Validator which succeeds if ``value`` is a member of ``choices``.
568
+
569
+ :param choices: A sequence of valid values.
570
+ :param labels: Optional sequence of labels to pair with the choices.
571
+ :param error: Error message to raise in case of a validation error. Can be
572
+ interpolated with `{input}`, `{choices}` and `{labels}`.
573
+ """
574
+
575
+ default_message = "Must be one of: {choices}."
576
+
577
+ def __init__(
578
+ self,
579
+ choices: typing.Iterable,
580
+ labels: typing.Iterable[str] | None = None,
581
+ *,
582
+ error: str | None = None,
583
+ ):
584
+ self.choices = choices
585
+ self.choices_text = ", ".join(str(choice) for choice in self.choices)
586
+ self.labels = labels if labels is not None else []
587
+ self.labels_text = ", ".join(str(label) for label in self.labels)
588
+ self.error = error or self.default_message # type: str
589
+
590
+ def _repr_args(self) -> str:
591
+ return f"choices={self.choices!r}, labels={self.labels!r}"
592
+
593
+ def _format_error(self, value) -> str:
594
+ return self.error.format(
595
+ input=value, choices=self.choices_text, labels=self.labels_text
596
+ )
597
+
598
+ def __call__(self, value: typing.Any) -> typing.Any:
599
+ try:
600
+ if value not in self.choices:
601
+ raise ValidationError(self._format_error(value))
602
+ except TypeError as error:
603
+ raise ValidationError(self._format_error(value)) from error
604
+
605
+ return value
606
+
607
+ def options(
608
+ self,
609
+ valuegetter: str | typing.Callable[[typing.Any], typing.Any] = str,
610
+ ) -> typing.Iterable[tuple[typing.Any, str]]:
611
+ """Return a generator over the (value, label) pairs, where value
612
+ is a string associated with each choice. This convenience method
613
+ is useful to populate, for instance, a form select field.
614
+
615
+ :param valuegetter: Can be a callable or a string. In the former case, it must
616
+ be a one-argument callable which returns the value of a
617
+ choice. In the latter case, the string specifies the name
618
+ of an attribute of the choice objects. Defaults to `str()`
619
+ or `str()`.
620
+ """
621
+ valuegetter = valuegetter if callable(valuegetter) else attrgetter(valuegetter)
622
+ pairs = zip_longest(self.choices, self.labels, fillvalue="")
623
+
624
+ return ((valuegetter(choice), label) for choice, label in pairs)
625
+
626
+
627
+ class ContainsOnly(OneOf):
628
+ """Validator which succeeds if ``value`` is a sequence and each element
629
+ in the sequence is also in the sequence passed as ``choices``. Empty input
630
+ is considered valid.
631
+
632
+ :param iterable choices: Same as :class:`OneOf`.
633
+ :param iterable labels: Same as :class:`OneOf`.
634
+ :param str error: Same as :class:`OneOf`.
635
+
636
+ .. versionchanged:: 3.0.0b2
637
+ Duplicate values are considered valid.
638
+ .. versionchanged:: 3.0.0b2
639
+ Empty input is considered valid. Use `validate.Length(min=1) <marshmallow.validate.Length>`
640
+ to validate against empty inputs.
641
+ """
642
+
643
+ default_message = "One or more of the choices you made was not in: {choices}."
644
+
645
+ def _format_error(self, value) -> str:
646
+ value_text = ", ".join(str(val) for val in value)
647
+ return super()._format_error(value_text)
648
+
649
+ def __call__(self, value: typing.Sequence[_T]) -> typing.Sequence[_T]:
650
+ # We can't use set.issubset because does not handle unhashable types
651
+ for val in value:
652
+ if val not in self.choices:
653
+ raise ValidationError(self._format_error(value))
654
+ return value
655
+
656
+
657
+ class ContainsNoneOf(NoneOf):
658
+ """Validator which fails if ``value`` is a sequence and any element
659
+ in the sequence is a member of the sequence passed as ``iterable``. Empty input
660
+ is considered valid.
661
+
662
+ :param iterable iterable: Same as :class:`NoneOf`.
663
+ :param str error: Same as :class:`NoneOf`.
664
+
665
+ .. versionadded:: 3.6.0
666
+ """
667
+
668
+ default_message = "One or more of the choices you made was in: {values}."
669
+
670
+ def _format_error(self, value) -> str:
671
+ value_text = ", ".join(str(val) for val in value)
672
+ return super()._format_error(value_text)
673
+
674
+ def __call__(self, value: typing.Sequence[_T]) -> typing.Sequence[_T]:
675
+ for val in value:
676
+ if val in self.iterable:
677
+ raise ValidationError(self._format_error(value))
678
+ return value
@@ -0,0 +1,2 @@
1
+ class RemovedInMarshmallow4Warning(DeprecationWarning):
2
+ pass