ccxt 4.2.77__py2.py3-none-any.whl → 4.4.49__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 +3205 -937
  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 +1525 -573
  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 +223 -97
  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 +639 -323
  126. ccxt/async_support/digifinex.py +465 -233
  127. ccxt/async_support/ellipx.py +1887 -0
  128. ccxt/async_support/exmo.py +317 -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 +433 -178
  133. ccxt/async_support/hollaex.py +207 -83
  134. ccxt/async_support/htx.py +1095 -563
  135. ccxt/async_support/huobijp.py +178 -56
  136. ccxt/async_support/hyperliquid.py +1678 -292
  137. ccxt/async_support/idex.py +219 -95
  138. ccxt/async_support/independentreserve.py +300 -31
  139. ccxt/async_support/indodax.py +226 -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 +198 -107
  145. ccxt/async_support/latoken.py +199 -79
  146. ccxt/async_support/lbank.py +360 -113
  147. ccxt/async_support/luno.py +185 -62
  148. ccxt/async_support/lykke.py +168 -55
  149. ccxt/async_support/mercado.py +101 -29
  150. ccxt/async_support/mexc.py +995 -429
  151. ccxt/async_support/myokx.py +53 -0
  152. ccxt/async_support/ndax.py +234 -82
  153. ccxt/async_support/novadax.py +195 -75
  154. ccxt/async_support/oceanex.py +244 -59
  155. ccxt/async_support/okcoin.py +301 -165
  156. ccxt/async_support/okx.py +1776 -454
  157. ccxt/async_support/onetrading.py +198 -414
  158. ccxt/async_support/oxfun.py +2898 -0
  159. ccxt/async_support/p2b.py +142 -52
  160. ccxt/async_support/paradex.py +2085 -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 +3205 -937
  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 +1525 -573
  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 +223 -97
  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 +639 -323
  234. ccxt/digifinex.py +465 -233
  235. ccxt/ellipx.py +1887 -0
  236. ccxt/exmo.py +317 -128
  237. ccxt/gate.py +1472 -463
  238. ccxt/gemini.py +206 -84
  239. ccxt/hashkey.py +4164 -0
  240. ccxt/hitbtc.py +433 -178
  241. ccxt/hollaex.py +207 -83
  242. ccxt/htx.py +1095 -563
  243. ccxt/huobijp.py +178 -56
  244. ccxt/hyperliquid.py +1677 -292
  245. ccxt/idex.py +219 -95
  246. ccxt/independentreserve.py +299 -31
  247. ccxt/indodax.py +226 -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 +198 -107
  253. ccxt/latoken.py +199 -79
  254. ccxt/lbank.py +360 -113
  255. ccxt/luno.py +185 -62
  256. ccxt/lykke.py +168 -55
  257. ccxt/mercado.py +101 -29
  258. ccxt/mexc.py +994 -429
  259. ccxt/myokx.py +53 -0
  260. ccxt/ndax.py +234 -82
  261. ccxt/novadax.py +195 -75
  262. ccxt/oceanex.py +244 -59
  263. ccxt/okcoin.py +301 -165
  264. ccxt/okx.py +1776 -454
  265. ccxt/onetrading.py +198 -414
  266. ccxt/oxfun.py +2897 -0
  267. ccxt/p2b.py +142 -52
  268. ccxt/paradex.py +2085 -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 +143 -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.49.dist-info/LICENSE.txt +21 -0
  496. ccxt-4.4.49.dist-info/METADATA +646 -0
  497. ccxt-4.4.49.dist-info/RECORD +669 -0
  498. {ccxt-4.2.77.dist-info → ccxt-4.4.49.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.49.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,1228 @@
1
+ """The :class:`Schema` class, including its metaclass and options (class Meta)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import copy
6
+ import datetime as dt
7
+ import decimal
8
+ import inspect
9
+ import json
10
+ import typing
11
+ import uuid
12
+ import warnings
13
+ from abc import ABCMeta
14
+ from collections import OrderedDict, defaultdict
15
+ from collections.abc import Mapping
16
+
17
+ from . import base, class_registry, types
18
+ from . import fields as ma_fields
19
+ from .decorators import (
20
+ POST_DUMP,
21
+ POST_LOAD,
22
+ PRE_DUMP,
23
+ PRE_LOAD,
24
+ VALIDATES,
25
+ VALIDATES_SCHEMA,
26
+ )
27
+ from .error_store import ErrorStore
28
+ from .exceptions import StringNotCollectionError, ValidationError
29
+ from .orderedset import OrderedSet
30
+ from .utils import (
31
+ EXCLUDE,
32
+ INCLUDE,
33
+ RAISE,
34
+ get_value,
35
+ is_collection,
36
+ is_instance_or_subclass,
37
+ missing,
38
+ set_value,
39
+ validate_unknown_parameter_value,
40
+ )
41
+ from .warnings import RemovedInMarshmallow4Warning
42
+
43
+ _T = typing.TypeVar("_T")
44
+
45
+
46
+ def _get_fields(attrs):
47
+ """Get fields from a class
48
+
49
+ :param attrs: Mapping of class attributes
50
+ """
51
+ return [
52
+ (field_name, field_value)
53
+ for field_name, field_value in attrs.items()
54
+ if is_instance_or_subclass(field_value, base.FieldABC)
55
+ ]
56
+
57
+
58
+ # This function allows Schemas to inherit from non-Schema classes and ensures
59
+ # inheritance according to the MRO
60
+ def _get_fields_by_mro(klass):
61
+ """Collect fields from a class, following its method resolution order. The
62
+ class itself is excluded from the search; only its parents are checked. Get
63
+ fields from ``_declared_fields`` if available, else use ``__dict__``.
64
+
65
+ :param type klass: Class whose fields to retrieve
66
+ """
67
+ mro = inspect.getmro(klass)
68
+ # Loop over mro in reverse to maintain correct order of fields
69
+ return sum(
70
+ (
71
+ _get_fields(
72
+ getattr(base, "_declared_fields", base.__dict__),
73
+ )
74
+ for base in mro[:0:-1]
75
+ ),
76
+ [],
77
+ )
78
+
79
+
80
+ class SchemaMeta(ABCMeta):
81
+ """Metaclass for the Schema class. Binds the declared fields to
82
+ a ``_declared_fields`` attribute, which is a dictionary mapping attribute
83
+ names to field objects. Also sets the ``opts`` class attribute, which is
84
+ the Schema class's ``class Meta`` options.
85
+ """
86
+
87
+ def __new__(mcs, name, bases, attrs):
88
+ meta = attrs.get("Meta")
89
+ ordered = getattr(meta, "ordered", False)
90
+ if not ordered:
91
+ # Inherit 'ordered' option
92
+ # Warning: We loop through bases instead of MRO because we don't
93
+ # yet have access to the class object
94
+ # (i.e. can't call super before we have fields)
95
+ for base_ in bases:
96
+ if hasattr(base_, "Meta") and hasattr(base_.Meta, "ordered"):
97
+ ordered = base_.Meta.ordered
98
+ break
99
+ else:
100
+ ordered = False
101
+ cls_fields = _get_fields(attrs)
102
+ # Remove fields from list of class attributes to avoid shadowing
103
+ # Schema attributes/methods in case of name conflict
104
+ for field_name, _ in cls_fields:
105
+ del attrs[field_name]
106
+ klass = super().__new__(mcs, name, bases, attrs)
107
+ inherited_fields = _get_fields_by_mro(klass)
108
+
109
+ meta = klass.Meta
110
+ # Set klass.opts in __new__ rather than __init__ so that it is accessible in
111
+ # get_declared_fields
112
+ klass.opts = klass.OPTIONS_CLASS(meta, ordered=ordered)
113
+ # Add fields specified in the `include` class Meta option
114
+ cls_fields += list(klass.opts.include.items())
115
+
116
+ # Assign _declared_fields on class
117
+ klass._declared_fields = mcs.get_declared_fields(
118
+ klass=klass,
119
+ cls_fields=cls_fields,
120
+ inherited_fields=inherited_fields,
121
+ dict_cls=dict,
122
+ )
123
+ return klass
124
+
125
+ @classmethod
126
+ def get_declared_fields(
127
+ mcs,
128
+ klass: type,
129
+ cls_fields: list,
130
+ inherited_fields: list,
131
+ dict_cls: type = dict,
132
+ ):
133
+ """Returns a dictionary of field_name => `Field` pairs declared on the class.
134
+ This is exposed mainly so that plugins can add additional fields, e.g. fields
135
+ computed from class Meta options.
136
+
137
+ :param klass: The class object.
138
+ :param cls_fields: The fields declared on the class, including those added
139
+ by the ``include`` class Meta option.
140
+ :param inherited_fields: Inherited fields.
141
+ :param dict_cls: dict-like class to use for dict output Default to ``dict``.
142
+ """
143
+ return dict_cls(inherited_fields + cls_fields)
144
+
145
+ def __init__(cls, name, bases, attrs):
146
+ super().__init__(name, bases, attrs)
147
+ if name and cls.opts.register:
148
+ class_registry.register(name, cls)
149
+ cls._hooks = cls.resolve_hooks()
150
+
151
+ def resolve_hooks(cls) -> dict[types.Tag, list[str]]:
152
+ """Add in the decorated processors
153
+
154
+ By doing this after constructing the class, we let standard inheritance
155
+ do all the hard work.
156
+ """
157
+ mro = inspect.getmro(cls)
158
+
159
+ hooks = defaultdict(list) # type: typing.Dict[types.Tag, typing.List[str]]
160
+
161
+ for attr_name in dir(cls):
162
+ # Need to look up the actual descriptor, not whatever might be
163
+ # bound to the class. This needs to come from the __dict__ of the
164
+ # declaring class.
165
+ for parent in mro:
166
+ try:
167
+ attr = parent.__dict__[attr_name]
168
+ except KeyError:
169
+ continue
170
+ else:
171
+ break
172
+ else:
173
+ # In case we didn't find the attribute and didn't break above.
174
+ # We should never hit this - it's just here for completeness
175
+ # to exclude the possibility of attr being undefined.
176
+ continue
177
+
178
+ try:
179
+ hook_config = attr.__marshmallow_hook__
180
+ except AttributeError:
181
+ pass
182
+ else:
183
+ for key in hook_config.keys():
184
+ # Use name here so we can get the bound method later, in
185
+ # case the processor was a descriptor or something.
186
+ hooks[key].append(attr_name)
187
+
188
+ return hooks
189
+
190
+
191
+ class SchemaOpts:
192
+ """class Meta options for the :class:`Schema`. Defines defaults."""
193
+
194
+ def __init__(self, meta, ordered: bool = False):
195
+ self.fields = getattr(meta, "fields", ())
196
+ if not isinstance(self.fields, (list, tuple)):
197
+ raise ValueError("`fields` option must be a list or tuple.")
198
+ self.additional = getattr(meta, "additional", ())
199
+ if not isinstance(self.additional, (list, tuple)):
200
+ raise ValueError("`additional` option must be a list or tuple.")
201
+ if self.fields and self.additional:
202
+ raise ValueError(
203
+ "Cannot set both `fields` and `additional` options"
204
+ " for the same Schema."
205
+ )
206
+ self.exclude = getattr(meta, "exclude", ())
207
+ if not isinstance(self.exclude, (list, tuple)):
208
+ raise ValueError("`exclude` must be a list or tuple.")
209
+ self.dateformat = getattr(meta, "dateformat", None)
210
+ self.datetimeformat = getattr(meta, "datetimeformat", None)
211
+ self.timeformat = getattr(meta, "timeformat", None)
212
+ if hasattr(meta, "json_module"):
213
+ warnings.warn(
214
+ "The json_module class Meta option is deprecated. Use render_module instead.",
215
+ RemovedInMarshmallow4Warning,
216
+ stacklevel=2,
217
+ )
218
+ render_module = getattr(meta, "json_module", json)
219
+ else:
220
+ render_module = json
221
+ self.render_module = getattr(meta, "render_module", render_module)
222
+ self.ordered = getattr(meta, "ordered", ordered)
223
+ self.index_errors = getattr(meta, "index_errors", True)
224
+ self.include = getattr(meta, "include", {})
225
+ self.load_only = getattr(meta, "load_only", ())
226
+ self.dump_only = getattr(meta, "dump_only", ())
227
+ self.unknown = validate_unknown_parameter_value(getattr(meta, "unknown", RAISE))
228
+ self.register = getattr(meta, "register", True)
229
+
230
+
231
+ class Schema(base.SchemaABC, metaclass=SchemaMeta):
232
+ """Base schema class with which to define custom schemas.
233
+
234
+ Example usage:
235
+
236
+ .. code-block:: python
237
+
238
+ import datetime as dt
239
+ from dataclasses import dataclass
240
+
241
+ from . import Schema, fields
242
+
243
+
244
+ @dataclass
245
+ class Album:
246
+ title: str
247
+ release_date: dt.date
248
+
249
+
250
+ class AlbumSchema(Schema):
251
+ title = fields.Str()
252
+ release_date = fields.Date()
253
+
254
+
255
+ album = Album("Beggars Banquet", dt.date(1968, 12, 6))
256
+ schema = AlbumSchema()
257
+ data = schema.dump(album)
258
+ data # {'release_date': '1968-12-06', 'title': 'Beggars Banquet'}
259
+
260
+ :param only: Whitelist of the declared fields to select when
261
+ instantiating the Schema. If None, all fields are used. Nested fields
262
+ can be represented with dot delimiters.
263
+ :param exclude: Blacklist of the declared fields to exclude
264
+ when instantiating the Schema. If a field appears in both `only` and
265
+ `exclude`, it is not used. Nested fields can be represented with dot
266
+ delimiters.
267
+ :param many: Should be set to `True` if ``obj`` is a collection
268
+ so that the object will be serialized to a list.
269
+ :param context: Optional context passed to :class:`fields.Method` and
270
+ :class:`fields.Function` fields.
271
+ :param load_only: Fields to skip during serialization (write-only fields)
272
+ :param dump_only: Fields to skip during deserialization (read-only fields)
273
+ :param partial: Whether to ignore missing fields and not require
274
+ any fields declared. Propagates down to ``Nested`` fields as well. If
275
+ its value is an iterable, only missing fields listed in that iterable
276
+ will be ignored. Use dot delimiters to specify nested fields.
277
+ :param unknown: Whether to exclude, include, or raise an error for unknown
278
+ fields in the data. Use `EXCLUDE`, `INCLUDE` or `RAISE`.
279
+
280
+ .. versionchanged:: 3.0.0
281
+ `prefix` parameter removed.
282
+
283
+ .. versionchanged:: 2.0.0
284
+ `__validators__`, `__preprocessors__`, and `__data_handlers__` are removed in favor of
285
+ `marshmallow.decorators.validates_schema`,
286
+ `marshmallow.decorators.pre_load` and `marshmallow.decorators.post_dump`.
287
+ `__accessor__` and `__error_handler__` are deprecated. Implement the
288
+ `handle_error` and `get_attribute` methods instead.
289
+ """
290
+
291
+ TYPE_MAPPING = {
292
+ str: ma_fields.String,
293
+ bytes: ma_fields.String,
294
+ dt.datetime: ma_fields.DateTime,
295
+ float: ma_fields.Float,
296
+ bool: ma_fields.Boolean,
297
+ tuple: ma_fields.Raw,
298
+ list: ma_fields.Raw,
299
+ set: ma_fields.Raw,
300
+ int: ma_fields.Integer,
301
+ uuid.UUID: ma_fields.UUID,
302
+ dt.time: ma_fields.Time,
303
+ dt.date: ma_fields.Date,
304
+ dt.timedelta: ma_fields.TimeDelta,
305
+ decimal.Decimal: ma_fields.Decimal,
306
+ } # type: typing.Dict[type, typing.Type[ma_fields.Field]]
307
+ #: Overrides for default schema-level error messages
308
+ error_messages = {} # type: typing.Dict[str, str]
309
+
310
+ _default_error_messages = {
311
+ "type": "Invalid input type.",
312
+ "unknown": "Unknown field.",
313
+ } # type: typing.Dict[str, str]
314
+
315
+ OPTIONS_CLASS = SchemaOpts # type: type
316
+
317
+ set_class = OrderedSet
318
+
319
+ # These get set by SchemaMeta
320
+ opts = None # type: SchemaOpts
321
+ _declared_fields = {} # type: typing.Dict[str, ma_fields.Field]
322
+ _hooks = {} # type: typing.Dict[types.Tag, typing.List[str]]
323
+
324
+ class Meta:
325
+ """Options object for a Schema.
326
+
327
+ Example usage: ::
328
+
329
+ class Meta:
330
+ fields = ("id", "email", "date_created")
331
+ exclude = ("password", "secret_attribute")
332
+
333
+ Available options:
334
+
335
+ - ``fields``: Tuple or list of fields to include in the serialized result.
336
+ - ``additional``: Tuple or list of fields to include *in addition* to the
337
+ explicitly declared fields. ``additional`` and ``fields`` are
338
+ mutually-exclusive options.
339
+ - ``include``: Dictionary of additional fields to include in the schema. It is
340
+ usually better to define fields as class variables, but you may need to
341
+ use this option, e.g., if your fields are Python keywords. May be an
342
+ `OrderedDict`.
343
+ - ``exclude``: Tuple or list of fields to exclude in the serialized result.
344
+ Nested fields can be represented with dot delimiters.
345
+ - ``dateformat``: Default format for `Date <fields.Date>` fields.
346
+ - ``datetimeformat``: Default format for `DateTime <fields.DateTime>` fields.
347
+ - ``timeformat``: Default format for `Time <fields.Time>` fields.
348
+ - ``render_module``: Module to use for `loads <Schema.loads>` and `dumps <Schema.dumps>`.
349
+ Defaults to `json` from the standard library.
350
+ - ``ordered``: If `True`, output of `Schema.dump` will be a `collections.OrderedDict`.
351
+ - ``index_errors``: If `True`, errors dictionaries will include the index
352
+ of invalid items in a collection.
353
+ - ``load_only``: Tuple or list of fields to exclude from serialized results.
354
+ - ``dump_only``: Tuple or list of fields to exclude from deserialization
355
+ - ``unknown``: Whether to exclude, include, or raise an error for unknown
356
+ fields in the data. Use `EXCLUDE`, `INCLUDE` or `RAISE`.
357
+ - ``register``: Whether to register the `Schema` with marshmallow's internal
358
+ class registry. Must be `True` if you intend to refer to this `Schema`
359
+ by class name in `Nested` fields. Only set this to `False` when memory
360
+ usage is critical. Defaults to `True`.
361
+ """
362
+
363
+ def __init__(
364
+ self,
365
+ *,
366
+ only: types.StrSequenceOrSet | None = None,
367
+ exclude: types.StrSequenceOrSet = (),
368
+ many: bool = False,
369
+ context: dict | None = None,
370
+ load_only: types.StrSequenceOrSet = (),
371
+ dump_only: types.StrSequenceOrSet = (),
372
+ partial: bool | types.StrSequenceOrSet | None = None,
373
+ unknown: str | None = None,
374
+ ):
375
+ # Raise error if only or exclude is passed as string, not list of strings
376
+ if only is not None and not is_collection(only):
377
+ raise StringNotCollectionError('"only" should be a list of strings')
378
+ if not is_collection(exclude):
379
+ raise StringNotCollectionError('"exclude" should be a list of strings')
380
+ # copy declared fields from metaclass
381
+ self.declared_fields = copy.deepcopy(self._declared_fields)
382
+ self.many = many
383
+ self.only = only
384
+ self.exclude: set[typing.Any] | typing.MutableSet[typing.Any] = set(
385
+ self.opts.exclude
386
+ ) | set(exclude)
387
+ self.ordered = self.opts.ordered
388
+ self.load_only = set(load_only) or set(self.opts.load_only)
389
+ self.dump_only = set(dump_only) or set(self.opts.dump_only)
390
+ self.partial = partial
391
+ self.unknown = (
392
+ self.opts.unknown
393
+ if unknown is None
394
+ else validate_unknown_parameter_value(unknown)
395
+ )
396
+ self.context = context or {}
397
+ self._normalize_nested_options()
398
+ #: Dictionary mapping field_names -> :class:`Field` objects
399
+ self.fields = {} # type: typing.Dict[str, ma_fields.Field]
400
+ self.load_fields = {} # type: typing.Dict[str, ma_fields.Field]
401
+ self.dump_fields = {} # type: typing.Dict[str, ma_fields.Field]
402
+ self._init_fields()
403
+ messages = {}
404
+ messages.update(self._default_error_messages)
405
+ for cls in reversed(self.__class__.__mro__):
406
+ messages.update(getattr(cls, "error_messages", {}))
407
+ messages.update(self.error_messages or {})
408
+ self.error_messages = messages
409
+
410
+ def __repr__(self) -> str:
411
+ return f"<{self.__class__.__name__}(many={self.many})>"
412
+
413
+ @property
414
+ def dict_class(self) -> type:
415
+ return OrderedDict if self.ordered else dict
416
+
417
+ @classmethod
418
+ def from_dict(
419
+ cls,
420
+ fields: dict[str, ma_fields.Field | type],
421
+ *,
422
+ name: str = "GeneratedSchema",
423
+ ) -> type:
424
+ """Generate a `Schema` class given a dictionary of fields.
425
+
426
+ .. code-block:: python
427
+
428
+ from . import Schema, fields
429
+
430
+ PersonSchema = Schema.from_dict({"name": fields.Str()})
431
+ print(PersonSchema().load({"name": "David"})) # => {'name': 'David'}
432
+
433
+ Generated schemas are not added to the class registry and therefore cannot
434
+ be referred to by name in `Nested` fields.
435
+
436
+ :param dict fields: Dictionary mapping field names to field instances.
437
+ :param str name: Optional name for the class, which will appear in
438
+ the ``repr`` for the class.
439
+
440
+ .. versionadded:: 3.0.0
441
+ """
442
+ attrs = fields.copy()
443
+ attrs["Meta"] = type(
444
+ "GeneratedMeta", (getattr(cls, "Meta", object),), {"register": False}
445
+ )
446
+ schema_cls = type(name, (cls,), attrs)
447
+ return schema_cls
448
+
449
+ ##### Override-able methods #####
450
+
451
+ def handle_error(
452
+ self, error: ValidationError, data: typing.Any, *, many: bool, **kwargs
453
+ ):
454
+ """Custom error handler function for the schema.
455
+
456
+ :param error: The `ValidationError` raised during (de)serialization.
457
+ :param data: The original input data.
458
+ :param many: Value of ``many`` on dump or load.
459
+ :param partial: Value of ``partial`` on load.
460
+
461
+ .. versionadded:: 2.0.0
462
+
463
+ .. versionchanged:: 3.0.0rc9
464
+ Receives `many` and `partial` (on deserialization) as keyword arguments.
465
+ """
466
+ pass
467
+
468
+ def get_attribute(self, obj: typing.Any, attr: str, default: typing.Any):
469
+ """Defines how to pull values from an object to serialize.
470
+
471
+ .. versionadded:: 2.0.0
472
+
473
+ .. versionchanged:: 3.0.0a1
474
+ Changed position of ``obj`` and ``attr``.
475
+ """
476
+ return get_value(obj, attr, default)
477
+
478
+ ##### Serialization/Deserialization API #####
479
+
480
+ @staticmethod
481
+ def _call_and_store(getter_func, data, *, field_name, error_store, index=None):
482
+ """Call ``getter_func`` with ``data`` as its argument, and store any `ValidationErrors`.
483
+
484
+ :param callable getter_func: Function for getting the serialized/deserialized
485
+ value from ``data``.
486
+ :param data: The data passed to ``getter_func``.
487
+ :param str field_name: Field name.
488
+ :param int index: Index of the item being validated, if validating a collection,
489
+ otherwise `None`.
490
+ """
491
+ try:
492
+ value = getter_func(data)
493
+ except ValidationError as error:
494
+ error_store.store_error(error.messages, field_name, index=index)
495
+ # When a Nested field fails validation, the marshalled data is stored
496
+ # on the ValidationError's valid_data attribute
497
+ return error.valid_data or missing
498
+ return value
499
+
500
+ def _serialize(self, obj: _T | typing.Iterable[_T], *, many: bool = False):
501
+ """Serialize ``obj``.
502
+
503
+ :param obj: The object(s) to serialize.
504
+ :param bool many: `True` if ``data`` should be serialized as a collection.
505
+ :return: A dictionary of the serialized data
506
+
507
+ .. versionchanged:: 1.0.0
508
+ Renamed from ``marshal``.
509
+ """
510
+ if many and obj is not None:
511
+ return [
512
+ self._serialize(d, many=False)
513
+ for d in typing.cast(typing.Iterable[_T], obj)
514
+ ]
515
+ ret = self.dict_class()
516
+ for attr_name, field_obj in self.dump_fields.items():
517
+ value = field_obj.serialize(attr_name, obj, accessor=self.get_attribute)
518
+ if value is missing:
519
+ continue
520
+ key = field_obj.data_key if field_obj.data_key is not None else attr_name
521
+ ret[key] = value
522
+ return ret
523
+
524
+ def dump(self, obj: typing.Any, *, many: bool | None = None):
525
+ """Serialize an object to native Python data types according to this
526
+ Schema's fields.
527
+
528
+ :param obj: The object to serialize.
529
+ :param many: Whether to serialize `obj` as a collection. If `None`, the value
530
+ for `self.many` is used.
531
+ :return: Serialized data
532
+
533
+ .. versionadded:: 1.0.0
534
+ .. versionchanged:: 3.0.0b7
535
+ This method returns the serialized data rather than a ``(data, errors)`` duple.
536
+ A :exc:`ValidationError <marshmallow.exceptions.ValidationError>` is raised
537
+ if ``obj`` is invalid.
538
+ .. versionchanged:: 3.0.0rc9
539
+ Validation no longer occurs upon serialization.
540
+ """
541
+ many = self.many if many is None else bool(many)
542
+ if self._has_processors(PRE_DUMP):
543
+ processed_obj = self._invoke_dump_processors(
544
+ PRE_DUMP, obj, many=many, original_data=obj
545
+ )
546
+ else:
547
+ processed_obj = obj
548
+
549
+ result = self._serialize(processed_obj, many=many)
550
+
551
+ if self._has_processors(POST_DUMP):
552
+ result = self._invoke_dump_processors(
553
+ POST_DUMP, result, many=many, original_data=obj
554
+ )
555
+
556
+ return result
557
+
558
+ def dumps(self, obj: typing.Any, *args, many: bool | None = None, **kwargs):
559
+ """Same as :meth:`dump`, except return a JSON-encoded string.
560
+
561
+ :param obj: The object to serialize.
562
+ :param many: Whether to serialize `obj` as a collection. If `None`, the value
563
+ for `self.many` is used.
564
+ :return: A ``json`` string
565
+
566
+ .. versionadded:: 1.0.0
567
+ .. versionchanged:: 3.0.0b7
568
+ This method returns the serialized data rather than a ``(data, errors)`` duple.
569
+ A :exc:`ValidationError <marshmallow.exceptions.ValidationError>` is raised
570
+ if ``obj`` is invalid.
571
+ """
572
+ serialized = self.dump(obj, many=many)
573
+ return self.opts.render_module.dumps(serialized, *args, **kwargs)
574
+
575
+ def _deserialize(
576
+ self,
577
+ data: (
578
+ typing.Mapping[str, typing.Any]
579
+ | typing.Iterable[typing.Mapping[str, typing.Any]]
580
+ ),
581
+ *,
582
+ error_store: ErrorStore,
583
+ many: bool = False,
584
+ partial=None,
585
+ unknown=RAISE,
586
+ index=None,
587
+ ) -> _T | list[_T]:
588
+ """Deserialize ``data``.
589
+
590
+ :param dict data: The data to deserialize.
591
+ :param ErrorStore error_store: Structure to store errors.
592
+ :param bool many: `True` if ``data`` should be deserialized as a collection.
593
+ :param bool|tuple partial: Whether to ignore missing fields and not require
594
+ any fields declared. Propagates down to ``Nested`` fields as well. If
595
+ its value is an iterable, only missing fields listed in that iterable
596
+ will be ignored. Use dot delimiters to specify nested fields.
597
+ :param unknown: Whether to exclude, include, or raise an error for unknown
598
+ fields in the data. Use `EXCLUDE`, `INCLUDE` or `RAISE`.
599
+ :param int index: Index of the item being serialized (for storing errors) if
600
+ serializing a collection, otherwise `None`.
601
+ :return: A dictionary of the deserialized data.
602
+ """
603
+ index_errors = self.opts.index_errors
604
+ index = index if index_errors else None
605
+ if many:
606
+ if not is_collection(data):
607
+ error_store.store_error([self.error_messages["type"]], index=index)
608
+ ret_l = [] # type: typing.List[_T]
609
+ else:
610
+ ret_l = [
611
+ typing.cast(
612
+ _T,
613
+ self._deserialize(
614
+ typing.cast(typing.Mapping[str, typing.Any], d),
615
+ error_store=error_store,
616
+ many=False,
617
+ partial=partial,
618
+ unknown=unknown,
619
+ index=idx,
620
+ ),
621
+ )
622
+ for idx, d in enumerate(data)
623
+ ]
624
+ return ret_l
625
+ ret_d = self.dict_class()
626
+ # Check data is a dict
627
+ if not isinstance(data, Mapping):
628
+ error_store.store_error([self.error_messages["type"]], index=index)
629
+ else:
630
+ partial_is_collection = is_collection(partial)
631
+ for attr_name, field_obj in self.load_fields.items():
632
+ field_name = (
633
+ field_obj.data_key if field_obj.data_key is not None else attr_name
634
+ )
635
+ raw_value = data.get(field_name, missing)
636
+ if raw_value is missing:
637
+ # Ignore missing field if we're allowed to.
638
+ if partial is True or (
639
+ partial_is_collection and attr_name in partial
640
+ ):
641
+ continue
642
+ d_kwargs = {}
643
+ # Allow partial loading of nested schemas.
644
+ if partial_is_collection:
645
+ prefix = field_name + "."
646
+ len_prefix = len(prefix)
647
+ sub_partial = [
648
+ f[len_prefix:] for f in partial if f.startswith(prefix)
649
+ ]
650
+ d_kwargs["partial"] = sub_partial
651
+ elif partial is not None:
652
+ d_kwargs["partial"] = partial
653
+
654
+ def getter(
655
+ val, field_obj=field_obj, field_name=field_name, d_kwargs=d_kwargs
656
+ ):
657
+ return field_obj.deserialize(
658
+ val,
659
+ field_name,
660
+ data,
661
+ **d_kwargs,
662
+ )
663
+
664
+ value = self._call_and_store(
665
+ getter_func=getter,
666
+ data=raw_value,
667
+ field_name=field_name,
668
+ error_store=error_store,
669
+ index=index,
670
+ )
671
+ if value is not missing:
672
+ key = field_obj.attribute or attr_name
673
+ set_value(ret_d, key, value)
674
+ if unknown != EXCLUDE:
675
+ fields = {
676
+ field_obj.data_key if field_obj.data_key is not None else field_name
677
+ for field_name, field_obj in self.load_fields.items()
678
+ }
679
+ for key in set(data) - fields:
680
+ value = data[key]
681
+ if unknown == INCLUDE:
682
+ ret_d[key] = value
683
+ elif unknown == RAISE:
684
+ error_store.store_error(
685
+ [self.error_messages["unknown"]],
686
+ key,
687
+ (index if index_errors else None),
688
+ )
689
+ return ret_d
690
+
691
+ def load(
692
+ self,
693
+ data: (
694
+ typing.Mapping[str, typing.Any]
695
+ | typing.Iterable[typing.Mapping[str, typing.Any]]
696
+ ),
697
+ *,
698
+ many: bool | None = None,
699
+ partial: bool | types.StrSequenceOrSet | None = None,
700
+ unknown: str | None = None,
701
+ ):
702
+ """Deserialize a data structure to an object defined by this Schema's fields.
703
+
704
+ :param data: The data to deserialize.
705
+ :param many: Whether to deserialize `data` as a collection. If `None`, the
706
+ value for `self.many` is used.
707
+ :param partial: Whether to ignore missing fields and not require
708
+ any fields declared. Propagates down to ``Nested`` fields as well. If
709
+ its value is an iterable, only missing fields listed in that iterable
710
+ will be ignored. Use dot delimiters to specify nested fields.
711
+ :param unknown: Whether to exclude, include, or raise an error for unknown
712
+ fields in the data. Use `EXCLUDE`, `INCLUDE` or `RAISE`.
713
+ If `None`, the value for `self.unknown` is used.
714
+ :return: Deserialized data
715
+
716
+ .. versionadded:: 1.0.0
717
+ .. versionchanged:: 3.0.0b7
718
+ This method returns the deserialized data rather than a ``(data, errors)`` duple.
719
+ A :exc:`ValidationError <marshmallow.exceptions.ValidationError>` is raised
720
+ if invalid data are passed.
721
+ """
722
+ return self._do_load(
723
+ data, many=many, partial=partial, unknown=unknown, postprocess=True
724
+ )
725
+
726
+ def loads(
727
+ self,
728
+ json_data: str,
729
+ *,
730
+ many: bool | None = None,
731
+ partial: bool | types.StrSequenceOrSet | None = None,
732
+ unknown: str | None = None,
733
+ **kwargs,
734
+ ):
735
+ """Same as :meth:`load`, except it takes a JSON string as input.
736
+
737
+ :param json_data: A JSON string of the data to deserialize.
738
+ :param many: Whether to deserialize `obj` as a collection. If `None`, the
739
+ value for `self.many` is used.
740
+ :param partial: Whether to ignore missing fields and not require
741
+ any fields declared. Propagates down to ``Nested`` fields as well. If
742
+ its value is an iterable, only missing fields listed in that iterable
743
+ will be ignored. Use dot delimiters to specify nested fields.
744
+ :param unknown: Whether to exclude, include, or raise an error for unknown
745
+ fields in the data. Use `EXCLUDE`, `INCLUDE` or `RAISE`.
746
+ If `None`, the value for `self.unknown` is used.
747
+ :return: Deserialized data
748
+
749
+ .. versionadded:: 1.0.0
750
+ .. versionchanged:: 3.0.0b7
751
+ This method returns the deserialized data rather than a ``(data, errors)`` duple.
752
+ A :exc:`ValidationError <marshmallow.exceptions.ValidationError>` is raised
753
+ if invalid data are passed.
754
+ """
755
+ data = self.opts.render_module.loads(json_data, **kwargs)
756
+ return self.load(data, many=many, partial=partial, unknown=unknown)
757
+
758
+ def _run_validator(
759
+ self,
760
+ validator_func,
761
+ output,
762
+ *,
763
+ original_data,
764
+ error_store,
765
+ many,
766
+ partial,
767
+ pass_original,
768
+ index=None,
769
+ ):
770
+ try:
771
+ if pass_original: # Pass original, raw data (before unmarshalling)
772
+ validator_func(output, original_data, partial=partial, many=many)
773
+ else:
774
+ validator_func(output, partial=partial, many=many)
775
+ except ValidationError as err:
776
+ error_store.store_error(err.messages, err.field_name, index=index)
777
+
778
+ def validate(
779
+ self,
780
+ data: (
781
+ typing.Mapping[str, typing.Any]
782
+ | typing.Iterable[typing.Mapping[str, typing.Any]]
783
+ ),
784
+ *,
785
+ many: bool | None = None,
786
+ partial: bool | types.StrSequenceOrSet | None = None,
787
+ ) -> dict[str, list[str]]:
788
+ """Validate `data` against the schema, returning a dictionary of
789
+ validation errors.
790
+
791
+ :param data: The data to validate.
792
+ :param many: Whether to validate `data` as a collection. If `None`, the
793
+ value for `self.many` is used.
794
+ :param partial: Whether to ignore missing fields and not require
795
+ any fields declared. Propagates down to ``Nested`` fields as well. If
796
+ its value is an iterable, only missing fields listed in that iterable
797
+ will be ignored. Use dot delimiters to specify nested fields.
798
+ :return: A dictionary of validation errors.
799
+
800
+ .. versionadded:: 1.1.0
801
+ """
802
+ try:
803
+ self._do_load(data, many=many, partial=partial, postprocess=False)
804
+ except ValidationError as exc:
805
+ return typing.cast(typing.Dict[str, typing.List[str]], exc.messages)
806
+ return {}
807
+
808
+ ##### Private Helpers #####
809
+
810
+ def _do_load(
811
+ self,
812
+ data: (
813
+ typing.Mapping[str, typing.Any]
814
+ | typing.Iterable[typing.Mapping[str, typing.Any]]
815
+ ),
816
+ *,
817
+ many: bool | None = None,
818
+ partial: bool | types.StrSequenceOrSet | None = None,
819
+ unknown: str | None = None,
820
+ postprocess: bool = True,
821
+ ):
822
+ """Deserialize `data`, returning the deserialized result.
823
+ This method is private API.
824
+
825
+ :param data: The data to deserialize.
826
+ :param many: Whether to deserialize `data` as a collection. If `None`, the
827
+ value for `self.many` is used.
828
+ :param partial: Whether to validate required fields. If its
829
+ value is an iterable, only fields listed in that iterable will be
830
+ ignored will be allowed missing. If `True`, all fields will be allowed missing.
831
+ If `None`, the value for `self.partial` is used.
832
+ :param unknown: Whether to exclude, include, or raise an error for unknown
833
+ fields in the data. Use `EXCLUDE`, `INCLUDE` or `RAISE`.
834
+ If `None`, the value for `self.unknown` is used.
835
+ :param postprocess: Whether to run post_load methods..
836
+ :return: Deserialized data
837
+ """
838
+ error_store = ErrorStore()
839
+ errors = {} # type: dict[str, list[str]]
840
+ many = self.many if many is None else bool(many)
841
+ unknown = (
842
+ self.unknown
843
+ if unknown is None
844
+ else validate_unknown_parameter_value(unknown)
845
+ )
846
+ if partial is None:
847
+ partial = self.partial
848
+ # Run preprocessors
849
+ if self._has_processors(PRE_LOAD):
850
+ try:
851
+ processed_data = self._invoke_load_processors(
852
+ PRE_LOAD, data, many=many, original_data=data, partial=partial
853
+ )
854
+ except ValidationError as err:
855
+ errors = err.normalized_messages()
856
+ result = None # type: list | dict | None
857
+ else:
858
+ processed_data = data
859
+ if not errors:
860
+ # Deserialize data
861
+ result = self._deserialize(
862
+ processed_data,
863
+ error_store=error_store,
864
+ many=many,
865
+ partial=partial,
866
+ unknown=unknown,
867
+ )
868
+ # Run field-level validation
869
+ self._invoke_field_validators(
870
+ error_store=error_store, data=result, many=many
871
+ )
872
+ # Run schema-level validation
873
+ if self._has_processors(VALIDATES_SCHEMA):
874
+ field_errors = bool(error_store.errors)
875
+ self._invoke_schema_validators(
876
+ error_store=error_store,
877
+ pass_many=True,
878
+ data=result,
879
+ original_data=data,
880
+ many=many,
881
+ partial=partial,
882
+ field_errors=field_errors,
883
+ )
884
+ self._invoke_schema_validators(
885
+ error_store=error_store,
886
+ pass_many=False,
887
+ data=result,
888
+ original_data=data,
889
+ many=many,
890
+ partial=partial,
891
+ field_errors=field_errors,
892
+ )
893
+ errors = error_store.errors
894
+ # Run post processors
895
+ if not errors and postprocess and self._has_processors(POST_LOAD):
896
+ try:
897
+ result = self._invoke_load_processors(
898
+ POST_LOAD,
899
+ result,
900
+ many=many,
901
+ original_data=data,
902
+ partial=partial,
903
+ )
904
+ except ValidationError as err:
905
+ errors = err.normalized_messages()
906
+ if errors:
907
+ exc = ValidationError(errors, data=data, valid_data=result)
908
+ self.handle_error(exc, data, many=many, partial=partial)
909
+ raise exc
910
+
911
+ return result
912
+
913
+ def _normalize_nested_options(self) -> None:
914
+ """Apply then flatten nested schema options.
915
+ This method is private API.
916
+ """
917
+ if self.only is not None:
918
+ # Apply the only option to nested fields.
919
+ self.__apply_nested_option("only", self.only, "intersection")
920
+ # Remove the child field names from the only option.
921
+ self.only = self.set_class([field.split(".", 1)[0] for field in self.only])
922
+ if self.exclude:
923
+ # Apply the exclude option to nested fields.
924
+ self.__apply_nested_option("exclude", self.exclude, "union")
925
+ # Remove the parent field names from the exclude option.
926
+ self.exclude = self.set_class(
927
+ [field for field in self.exclude if "." not in field]
928
+ )
929
+
930
+ def __apply_nested_option(self, option_name, field_names, set_operation) -> None:
931
+ """Apply nested options to nested fields"""
932
+ # Split nested field names on the first dot.
933
+ nested_fields = [name.split(".", 1) for name in field_names if "." in name]
934
+ # Partition the nested field names by parent field.
935
+ nested_options = defaultdict(list) # type: defaultdict
936
+ for parent, nested_names in nested_fields:
937
+ nested_options[parent].append(nested_names)
938
+ # Apply the nested field options.
939
+ for key, options in iter(nested_options.items()):
940
+ new_options = self.set_class(options)
941
+ original_options = getattr(self.declared_fields[key], option_name, ())
942
+ if original_options:
943
+ if set_operation == "union":
944
+ new_options |= self.set_class(original_options)
945
+ if set_operation == "intersection":
946
+ new_options &= self.set_class(original_options)
947
+ setattr(self.declared_fields[key], option_name, new_options)
948
+
949
+ def _init_fields(self) -> None:
950
+ """Update self.fields, self.load_fields, and self.dump_fields based on schema options.
951
+ This method is private API.
952
+ """
953
+ if self.opts.fields:
954
+ available_field_names = self.set_class(self.opts.fields)
955
+ else:
956
+ available_field_names = self.set_class(self.declared_fields.keys())
957
+ if self.opts.additional:
958
+ available_field_names |= self.set_class(self.opts.additional)
959
+
960
+ invalid_fields = self.set_class()
961
+
962
+ if self.only is not None:
963
+ # Return only fields specified in only option
964
+ field_names: typing.AbstractSet[typing.Any] = self.set_class(self.only)
965
+
966
+ invalid_fields |= field_names - available_field_names
967
+ else:
968
+ field_names = available_field_names
969
+
970
+ # If "exclude" option or param is specified, remove those fields.
971
+ if self.exclude:
972
+ # Note that this isn't available_field_names, since we want to
973
+ # apply "only" for the actual calculation.
974
+ field_names = field_names - self.exclude
975
+ invalid_fields |= self.exclude - available_field_names
976
+
977
+ if invalid_fields:
978
+ message = f"Invalid fields for {self}: {invalid_fields}."
979
+ raise ValueError(message)
980
+
981
+ fields_dict = self.dict_class()
982
+ for field_name in field_names:
983
+ field_obj = self.declared_fields.get(field_name, ma_fields.Inferred())
984
+ self._bind_field(field_name, field_obj)
985
+ fields_dict[field_name] = field_obj
986
+
987
+ load_fields, dump_fields = self.dict_class(), self.dict_class()
988
+ for field_name, field_obj in fields_dict.items():
989
+ if not field_obj.dump_only:
990
+ load_fields[field_name] = field_obj
991
+ if not field_obj.load_only:
992
+ dump_fields[field_name] = field_obj
993
+
994
+ dump_data_keys = [
995
+ field_obj.data_key if field_obj.data_key is not None else name
996
+ for name, field_obj in dump_fields.items()
997
+ ]
998
+ if len(dump_data_keys) != len(set(dump_data_keys)):
999
+ data_keys_duplicates = {
1000
+ x for x in dump_data_keys if dump_data_keys.count(x) > 1
1001
+ }
1002
+ raise ValueError(
1003
+ "The data_key argument for one or more fields collides "
1004
+ "with another field's name or data_key argument. "
1005
+ "Check the following field names and "
1006
+ f"data_key arguments: {list(data_keys_duplicates)}"
1007
+ )
1008
+ load_attributes = [obj.attribute or name for name, obj in load_fields.items()]
1009
+ if len(load_attributes) != len(set(load_attributes)):
1010
+ attributes_duplicates = {
1011
+ x for x in load_attributes if load_attributes.count(x) > 1
1012
+ }
1013
+ raise ValueError(
1014
+ "The attribute argument for one or more fields collides "
1015
+ "with another field's name or attribute argument. "
1016
+ "Check the following field names and "
1017
+ f"attribute arguments: {list(attributes_duplicates)}"
1018
+ )
1019
+
1020
+ self.fields = fields_dict
1021
+ self.dump_fields = dump_fields
1022
+ self.load_fields = load_fields
1023
+
1024
+ def on_bind_field(self, field_name: str, field_obj: ma_fields.Field) -> None:
1025
+ """Hook to modify a field when it is bound to the `Schema`.
1026
+
1027
+ No-op by default.
1028
+ """
1029
+ return None
1030
+
1031
+ def _bind_field(self, field_name: str, field_obj: ma_fields.Field) -> None:
1032
+ """Bind field to the schema, setting any necessary attributes on the
1033
+ field (e.g. parent and name).
1034
+
1035
+ Also set field load_only and dump_only values if field_name was
1036
+ specified in ``class Meta``.
1037
+ """
1038
+ if field_name in self.load_only:
1039
+ field_obj.load_only = True
1040
+ if field_name in self.dump_only:
1041
+ field_obj.dump_only = True
1042
+ try:
1043
+ field_obj._bind_to_schema(field_name, self)
1044
+ except TypeError as error:
1045
+ # Field declared as a class, not an instance. Ignore type checking because
1046
+ # we handle unsupported arg types, i.e. this is dead code from
1047
+ # the type checker's perspective.
1048
+ if isinstance(field_obj, type) and issubclass(field_obj, base.FieldABC):
1049
+ msg = (
1050
+ f'Field for "{field_name}" must be declared as a '
1051
+ "Field instance, not a class. "
1052
+ f'Did you mean "fields.{field_obj.__name__}()"?' # type: ignore
1053
+ )
1054
+ raise TypeError(msg) from error
1055
+ raise error
1056
+ self.on_bind_field(field_name, field_obj)
1057
+
1058
+ def _has_processors(self, tag) -> bool:
1059
+ return bool(self._hooks[(tag, True)] or self._hooks[(tag, False)])
1060
+
1061
+ def _invoke_dump_processors(
1062
+ self, tag: str, data, *, many: bool, original_data=None
1063
+ ):
1064
+ # The pass_many post-dump processors may do things like add an envelope, so
1065
+ # invoke those after invoking the non-pass_many processors which will expect
1066
+ # to get a list of items.
1067
+ data = self._invoke_processors(
1068
+ tag, pass_many=False, data=data, many=many, original_data=original_data
1069
+ )
1070
+ data = self._invoke_processors(
1071
+ tag, pass_many=True, data=data, many=many, original_data=original_data
1072
+ )
1073
+ return data
1074
+
1075
+ def _invoke_load_processors(
1076
+ self,
1077
+ tag: str,
1078
+ data,
1079
+ *,
1080
+ many: bool,
1081
+ original_data,
1082
+ partial: bool | types.StrSequenceOrSet | None,
1083
+ ):
1084
+ # This has to invert the order of the dump processors, so run the pass_many
1085
+ # processors first.
1086
+ data = self._invoke_processors(
1087
+ tag,
1088
+ pass_many=True,
1089
+ data=data,
1090
+ many=many,
1091
+ original_data=original_data,
1092
+ partial=partial,
1093
+ )
1094
+ data = self._invoke_processors(
1095
+ tag,
1096
+ pass_many=False,
1097
+ data=data,
1098
+ many=many,
1099
+ original_data=original_data,
1100
+ partial=partial,
1101
+ )
1102
+ return data
1103
+
1104
+ def _invoke_field_validators(self, *, error_store: ErrorStore, data, many: bool):
1105
+ for attr_name in self._hooks[VALIDATES]:
1106
+ validator = getattr(self, attr_name)
1107
+ validator_kwargs = validator.__marshmallow_hook__[VALIDATES]
1108
+ field_name = validator_kwargs["field_name"]
1109
+
1110
+ try:
1111
+ field_obj = self.fields[field_name]
1112
+ except KeyError as error:
1113
+ if field_name in self.declared_fields:
1114
+ continue
1115
+ raise ValueError(f'"{field_name}" field does not exist.') from error
1116
+
1117
+ data_key = (
1118
+ field_obj.data_key if field_obj.data_key is not None else field_name
1119
+ )
1120
+ if many:
1121
+ for idx, item in enumerate(data):
1122
+ try:
1123
+ value = item[field_obj.attribute or field_name]
1124
+ except KeyError:
1125
+ pass
1126
+ else:
1127
+ validated_value = self._call_and_store(
1128
+ getter_func=validator,
1129
+ data=value,
1130
+ field_name=data_key,
1131
+ error_store=error_store,
1132
+ index=(idx if self.opts.index_errors else None),
1133
+ )
1134
+ if validated_value is missing:
1135
+ data[idx].pop(field_name, None)
1136
+ else:
1137
+ try:
1138
+ value = data[field_obj.attribute or field_name]
1139
+ except KeyError:
1140
+ pass
1141
+ else:
1142
+ validated_value = self._call_and_store(
1143
+ getter_func=validator,
1144
+ data=value,
1145
+ field_name=data_key,
1146
+ error_store=error_store,
1147
+ )
1148
+ if validated_value is missing:
1149
+ data.pop(field_name, None)
1150
+
1151
+ def _invoke_schema_validators(
1152
+ self,
1153
+ *,
1154
+ error_store: ErrorStore,
1155
+ pass_many: bool,
1156
+ data,
1157
+ original_data,
1158
+ many: bool,
1159
+ partial: bool | types.StrSequenceOrSet | None,
1160
+ field_errors: bool = False,
1161
+ ):
1162
+ for attr_name in self._hooks[(VALIDATES_SCHEMA, pass_many)]:
1163
+ validator = getattr(self, attr_name)
1164
+ validator_kwargs = validator.__marshmallow_hook__[
1165
+ (VALIDATES_SCHEMA, pass_many)
1166
+ ]
1167
+ if field_errors and validator_kwargs["skip_on_field_errors"]:
1168
+ continue
1169
+ pass_original = validator_kwargs.get("pass_original", False)
1170
+
1171
+ if many and not pass_many:
1172
+ for idx, (item, orig) in enumerate(zip(data, original_data)):
1173
+ self._run_validator(
1174
+ validator,
1175
+ item,
1176
+ original_data=orig,
1177
+ error_store=error_store,
1178
+ many=many,
1179
+ partial=partial,
1180
+ index=idx,
1181
+ pass_original=pass_original,
1182
+ )
1183
+ else:
1184
+ self._run_validator(
1185
+ validator,
1186
+ data,
1187
+ original_data=original_data,
1188
+ error_store=error_store,
1189
+ many=many,
1190
+ pass_original=pass_original,
1191
+ partial=partial,
1192
+ )
1193
+
1194
+ def _invoke_processors(
1195
+ self,
1196
+ tag: str,
1197
+ *,
1198
+ pass_many: bool,
1199
+ data,
1200
+ many: bool,
1201
+ original_data=None,
1202
+ **kwargs,
1203
+ ):
1204
+ key = (tag, pass_many)
1205
+ for attr_name in self._hooks[key]:
1206
+ # This will be a bound method.
1207
+ processor = getattr(self, attr_name)
1208
+
1209
+ processor_kwargs = processor.__marshmallow_hook__[key]
1210
+ pass_original = processor_kwargs.get("pass_original", False)
1211
+
1212
+ if many and not pass_many:
1213
+ if pass_original:
1214
+ data = [
1215
+ processor(item, original, many=many, **kwargs)
1216
+ for item, original in zip(data, original_data)
1217
+ ]
1218
+ else:
1219
+ data = [processor(item, many=many, **kwargs) for item in data]
1220
+ else:
1221
+ if pass_original:
1222
+ data = processor(data, original_data, many=many, **kwargs)
1223
+ else:
1224
+ data = processor(data, many=many, **kwargs)
1225
+ return data
1226
+
1227
+
1228
+ BaseSchema = Schema # for backwards compatibility