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.
- ccxt/__init__.py +36 -14
- ccxt/abstract/alpaca.py +4 -0
- ccxt/abstract/bigone.py +1 -1
- ccxt/abstract/binance.py +112 -48
- ccxt/abstract/binancecoinm.py +112 -48
- ccxt/abstract/binanceus.py +147 -83
- ccxt/abstract/binanceusdm.py +112 -48
- ccxt/abstract/bingx.py +133 -78
- ccxt/abstract/bitbank.py +5 -0
- ccxt/abstract/bitfinex.py +136 -65
- ccxt/abstract/bitfinex1.py +69 -0
- ccxt/abstract/bitflyer.py +1 -0
- ccxt/abstract/bitget.py +8 -1
- ccxt/abstract/bitmart.py +13 -1
- ccxt/abstract/bitopro.py +1 -0
- ccxt/abstract/bitpanda.py +0 -12
- ccxt/abstract/bitrue.py +3 -3
- ccxt/abstract/bitstamp.py +26 -3
- ccxt/abstract/blofin.py +24 -0
- ccxt/abstract/btcbox.py +1 -0
- ccxt/abstract/bybit.py +29 -14
- ccxt/abstract/cex.py +28 -29
- ccxt/abstract/coinbase.py +6 -0
- ccxt/abstract/coinbaseadvanced.py +94 -0
- ccxt/abstract/{coinbasepro.py → coinbaseexchange.py} +1 -0
- ccxt/abstract/coinbaseinternational.py +1 -1
- ccxt/abstract/coincatch.py +94 -0
- ccxt/abstract/coinex.py +233 -123
- ccxt/abstract/coinmetro.py +1 -0
- ccxt/abstract/cryptocom.py +14 -0
- ccxt/abstract/defx.py +69 -0
- ccxt/abstract/deribit.py +1 -0
- ccxt/abstract/digifinex.py +1 -0
- ccxt/abstract/ellipx.py +25 -0
- ccxt/abstract/gate.py +20 -0
- ccxt/abstract/gateio.py +20 -0
- ccxt/abstract/gemini.py +1 -0
- ccxt/abstract/hashkey.py +67 -0
- ccxt/abstract/hyperliquid.py +1 -1
- ccxt/abstract/independentreserve.py +6 -0
- ccxt/abstract/kraken.py +4 -3
- ccxt/abstract/krakenfutures.py +4 -0
- ccxt/abstract/kucoin.py +24 -0
- ccxt/abstract/kucoinfutures.py +34 -0
- ccxt/abstract/luno.py +2 -0
- ccxt/abstract/mexc.py +4 -0
- ccxt/abstract/myokx.py +340 -0
- ccxt/abstract/oceanex.py +5 -0
- ccxt/abstract/okx.py +30 -0
- ccxt/abstract/onetrading.py +0 -12
- ccxt/abstract/oxfun.py +34 -0
- ccxt/abstract/paradex.py +40 -0
- ccxt/abstract/phemex.py +1 -0
- ccxt/abstract/upbit.py +4 -0
- ccxt/abstract/vertex.py +19 -0
- ccxt/abstract/whitebit.py +31 -1
- ccxt/abstract/woo.py +6 -2
- ccxt/abstract/woofipro.py +119 -0
- ccxt/abstract/xt.py +153 -0
- ccxt/abstract/zonda.py +6 -0
- ccxt/ace.py +164 -60
- ccxt/alpaca.py +727 -63
- ccxt/ascendex.py +395 -249
- ccxt/async_support/__init__.py +36 -14
- ccxt/async_support/ace.py +164 -60
- ccxt/async_support/alpaca.py +727 -63
- ccxt/async_support/ascendex.py +396 -249
- ccxt/async_support/base/exchange.py +531 -155
- ccxt/async_support/base/ws/aiohttp_client.py +28 -5
- ccxt/async_support/base/ws/cache.py +3 -2
- ccxt/async_support/base/ws/client.py +26 -5
- ccxt/async_support/base/ws/fast_client.py +4 -3
- ccxt/async_support/base/ws/functions.py +1 -1
- ccxt/async_support/base/ws/future.py +40 -31
- ccxt/async_support/base/ws/order_book_side.py +3 -0
- ccxt/async_support/bequant.py +1 -1
- ccxt/async_support/bigone.py +329 -202
- ccxt/async_support/binance.py +3030 -1087
- ccxt/async_support/binancecoinm.py +2 -1
- ccxt/async_support/binanceus.py +12 -1
- ccxt/async_support/binanceusdm.py +3 -1
- ccxt/async_support/bingx.py +3104 -880
- ccxt/async_support/bit2c.py +119 -38
- ccxt/async_support/bitbank.py +215 -76
- ccxt/async_support/bitbns.py +124 -53
- ccxt/async_support/bitfinex.py +3236 -1078
- ccxt/async_support/bitfinex1.py +1711 -0
- ccxt/async_support/bitflyer.py +238 -49
- ccxt/async_support/bitget.py +1513 -563
- ccxt/async_support/bithumb.py +199 -65
- ccxt/async_support/bitmart.py +1320 -435
- ccxt/async_support/bitmex.py +308 -111
- ccxt/async_support/bitopro.py +256 -96
- ccxt/async_support/bitrue.py +365 -233
- ccxt/async_support/bitso.py +201 -89
- ccxt/async_support/bitstamp.py +438 -269
- ccxt/async_support/bitteam.py +179 -73
- ccxt/async_support/bitvavo.py +180 -70
- ccxt/async_support/bl3p.py +92 -25
- ccxt/async_support/blockchaincom.py +193 -79
- ccxt/async_support/blofin.py +392 -148
- ccxt/async_support/btcalpha.py +161 -55
- ccxt/async_support/btcbox.py +250 -34
- ccxt/async_support/btcmarkets.py +232 -85
- ccxt/async_support/btcturk.py +159 -60
- ccxt/async_support/bybit.py +2231 -1193
- ccxt/async_support/cex.py +1409 -1329
- ccxt/async_support/coinbase.py +1454 -287
- ccxt/async_support/coinbaseadvanced.py +17 -0
- ccxt/async_support/{coinbasepro.py → coinbaseexchange.py} +233 -99
- ccxt/async_support/coinbaseinternational.py +428 -88
- ccxt/async_support/coincatch.py +5152 -0
- ccxt/async_support/coincheck.py +121 -38
- ccxt/async_support/coinex.py +4020 -3339
- ccxt/async_support/coinlist.py +273 -116
- ccxt/async_support/coinmate.py +204 -97
- ccxt/async_support/coinmetro.py +203 -110
- ccxt/async_support/coinone.py +142 -68
- ccxt/async_support/coinsph.py +206 -89
- ccxt/async_support/coinspot.py +137 -62
- ccxt/async_support/cryptocom.py +515 -185
- ccxt/async_support/currencycom.py +203 -85
- ccxt/async_support/defx.py +2066 -0
- ccxt/async_support/delta.py +404 -109
- ccxt/async_support/deribit.py +557 -323
- ccxt/async_support/digifinex.py +340 -223
- ccxt/async_support/ellipx.py +1826 -0
- ccxt/async_support/exmo.py +259 -128
- ccxt/async_support/gate.py +1472 -463
- ccxt/async_support/gemini.py +206 -84
- ccxt/async_support/hashkey.py +4164 -0
- ccxt/async_support/hitbtc.py +334 -178
- ccxt/async_support/hollaex.py +134 -83
- ccxt/async_support/htx.py +1095 -563
- ccxt/async_support/huobijp.py +105 -56
- ccxt/async_support/hyperliquid.py +1633 -268
- ccxt/async_support/idex.py +148 -95
- ccxt/async_support/independentreserve.py +236 -31
- ccxt/async_support/indodax.py +165 -62
- ccxt/async_support/kraken.py +871 -354
- ccxt/async_support/krakenfutures.py +324 -100
- ccxt/async_support/kucoin.py +917 -357
- ccxt/async_support/kucoinfutures.py +1004 -149
- ccxt/async_support/kuna.py +138 -106
- ccxt/async_support/latoken.py +135 -79
- ccxt/async_support/lbank.py +290 -113
- ccxt/async_support/luno.py +112 -62
- ccxt/async_support/lykke.py +104 -55
- ccxt/async_support/mercado.py +36 -29
- ccxt/async_support/mexc.py +995 -429
- ccxt/async_support/myokx.py +43 -0
- ccxt/async_support/ndax.py +163 -82
- ccxt/async_support/novadax.py +121 -75
- ccxt/async_support/oceanex.py +175 -59
- ccxt/async_support/okcoin.py +222 -163
- ccxt/async_support/okx.py +1776 -454
- ccxt/async_support/onetrading.py +132 -414
- ccxt/async_support/oxfun.py +2832 -0
- ccxt/async_support/p2b.py +79 -51
- ccxt/async_support/paradex.py +2017 -0
- ccxt/async_support/paymium.py +56 -32
- ccxt/async_support/phemex.py +572 -196
- ccxt/async_support/poloniex.py +218 -95
- ccxt/async_support/poloniexfutures.py +260 -92
- ccxt/async_support/probit.py +143 -110
- ccxt/async_support/timex.py +123 -70
- ccxt/async_support/tokocrypto.py +129 -93
- ccxt/async_support/tradeogre.py +39 -25
- ccxt/async_support/upbit.py +322 -113
- ccxt/async_support/vertex.py +2983 -0
- ccxt/async_support/wavesexchange.py +227 -173
- ccxt/async_support/wazirx.py +145 -65
- ccxt/async_support/whitebit.py +533 -138
- ccxt/async_support/woo.py +1137 -296
- ccxt/async_support/woofipro.py +2716 -0
- ccxt/async_support/xt.py +4628 -0
- ccxt/async_support/yobit.py +160 -92
- ccxt/async_support/zaif.py +80 -33
- ccxt/async_support/zonda.py +140 -69
- ccxt/base/errors.py +51 -20
- ccxt/base/exchange.py +1722 -480
- ccxt/base/precise.py +10 -0
- ccxt/base/types.py +223 -4
- ccxt/bequant.py +1 -1
- ccxt/bigone.py +329 -202
- ccxt/binance.py +3030 -1087
- ccxt/binancecoinm.py +2 -1
- ccxt/binanceus.py +12 -1
- ccxt/binanceusdm.py +3 -1
- ccxt/bingx.py +3104 -880
- ccxt/bit2c.py +119 -38
- ccxt/bitbank.py +215 -76
- ccxt/bitbns.py +124 -53
- ccxt/bitfinex.py +3235 -1078
- ccxt/bitfinex1.py +1710 -0
- ccxt/bitflyer.py +238 -49
- ccxt/bitget.py +1513 -563
- ccxt/bithumb.py +198 -65
- ccxt/bitmart.py +1320 -435
- ccxt/bitmex.py +308 -111
- ccxt/bitopro.py +256 -96
- ccxt/bitrue.py +365 -233
- ccxt/bitso.py +201 -89
- ccxt/bitstamp.py +438 -269
- ccxt/bitteam.py +179 -73
- ccxt/bitvavo.py +180 -70
- ccxt/bl3p.py +92 -25
- ccxt/blockchaincom.py +193 -79
- ccxt/blofin.py +392 -148
- ccxt/btcalpha.py +161 -55
- ccxt/btcbox.py +250 -34
- ccxt/btcmarkets.py +232 -85
- ccxt/btcturk.py +159 -60
- ccxt/bybit.py +2231 -1193
- ccxt/cex.py +1408 -1329
- ccxt/coinbase.py +1454 -287
- ccxt/coinbaseadvanced.py +17 -0
- ccxt/{coinbasepro.py → coinbaseexchange.py} +233 -99
- ccxt/coinbaseinternational.py +428 -88
- ccxt/coincatch.py +5152 -0
- ccxt/coincheck.py +121 -38
- ccxt/coinex.py +4020 -3339
- ccxt/coinlist.py +273 -116
- ccxt/coinmate.py +204 -97
- ccxt/coinmetro.py +203 -110
- ccxt/coinone.py +142 -68
- ccxt/coinsph.py +206 -89
- ccxt/coinspot.py +137 -62
- ccxt/cryptocom.py +515 -185
- ccxt/currencycom.py +203 -85
- ccxt/defx.py +2065 -0
- ccxt/delta.py +404 -109
- ccxt/deribit.py +557 -323
- ccxt/digifinex.py +340 -223
- ccxt/ellipx.py +1826 -0
- ccxt/exmo.py +259 -128
- ccxt/gate.py +1472 -463
- ccxt/gemini.py +206 -84
- ccxt/hashkey.py +4164 -0
- ccxt/hitbtc.py +334 -178
- ccxt/hollaex.py +134 -83
- ccxt/htx.py +1095 -563
- ccxt/huobijp.py +105 -56
- ccxt/hyperliquid.py +1632 -268
- ccxt/idex.py +148 -95
- ccxt/independentreserve.py +235 -31
- ccxt/indodax.py +165 -62
- ccxt/kraken.py +871 -354
- ccxt/krakenfutures.py +324 -100
- ccxt/kucoin.py +917 -357
- ccxt/kucoinfutures.py +1004 -149
- ccxt/kuna.py +138 -106
- ccxt/latoken.py +135 -79
- ccxt/lbank.py +290 -113
- ccxt/luno.py +112 -62
- ccxt/lykke.py +104 -55
- ccxt/mercado.py +36 -29
- ccxt/mexc.py +994 -429
- ccxt/myokx.py +43 -0
- ccxt/ndax.py +163 -82
- ccxt/novadax.py +121 -75
- ccxt/oceanex.py +175 -59
- ccxt/okcoin.py +222 -163
- ccxt/okx.py +1776 -454
- ccxt/onetrading.py +132 -414
- ccxt/oxfun.py +2831 -0
- ccxt/p2b.py +79 -51
- ccxt/paradex.py +2017 -0
- ccxt/paymium.py +56 -32
- ccxt/phemex.py +572 -196
- ccxt/poloniex.py +218 -95
- ccxt/poloniexfutures.py +260 -92
- ccxt/pro/__init__.py +29 -5
- ccxt/pro/alpaca.py +32 -17
- ccxt/pro/ascendex.py +62 -14
- ccxt/pro/bequant.py +4 -0
- ccxt/pro/binance.py +1596 -329
- ccxt/pro/binancecoinm.py +1 -0
- ccxt/pro/binanceus.py +2 -9
- ccxt/pro/binanceusdm.py +2 -0
- ccxt/pro/bingx.py +527 -134
- ccxt/pro/bitcoincom.py +4 -1
- ccxt/pro/bitfinex.py +731 -266
- ccxt/pro/bitfinex1.py +635 -0
- ccxt/pro/bitget.py +726 -357
- ccxt/pro/bithumb.py +380 -0
- ccxt/pro/bitmart.py +138 -39
- ccxt/pro/bitmex.py +199 -40
- ccxt/pro/bitopro.py +25 -13
- ccxt/pro/bitrue.py +31 -32
- ccxt/pro/bitstamp.py +7 -6
- ccxt/pro/bitvavo.py +203 -81
- ccxt/pro/blockchaincom.py +30 -17
- ccxt/pro/blofin.py +692 -0
- ccxt/pro/bybit.py +791 -82
- ccxt/pro/cex.py +99 -51
- ccxt/pro/coinbase.py +220 -30
- ccxt/{async_support/hitbtc3.py → pro/coinbaseadvanced.py} +5 -5
- ccxt/pro/{coinbasepro.py → coinbaseexchange.py} +19 -19
- ccxt/pro/coinbaseinternational.py +193 -30
- ccxt/pro/coincatch.py +1464 -0
- ccxt/pro/coincheck.py +11 -6
- ccxt/pro/coinex.py +965 -665
- ccxt/pro/coinone.py +17 -10
- ccxt/pro/cryptocom.py +446 -66
- ccxt/pro/currencycom.py +11 -10
- ccxt/pro/defx.py +832 -0
- ccxt/pro/deribit.py +167 -31
- ccxt/pro/exmo.py +252 -20
- ccxt/pro/gate.py +729 -64
- ccxt/pro/gemini.py +44 -26
- ccxt/pro/hashkey.py +802 -0
- ccxt/pro/hitbtc.py +208 -103
- ccxt/pro/hollaex.py +25 -9
- ccxt/pro/htx.py +83 -39
- ccxt/pro/huobijp.py +17 -16
- ccxt/pro/hyperliquid.py +502 -31
- ccxt/pro/idex.py +28 -13
- ccxt/pro/independentreserve.py +21 -16
- ccxt/pro/kraken.py +298 -51
- ccxt/pro/krakenfutures.py +166 -75
- ccxt/pro/kucoin.py +395 -77
- ccxt/pro/kucoinfutures.py +400 -99
- ccxt/pro/lbank.py +52 -31
- ccxt/pro/luno.py +12 -10
- ccxt/pro/mexc.py +400 -50
- ccxt/pro/myokx.py +28 -0
- ccxt/pro/ndax.py +25 -12
- ccxt/pro/okcoin.py +28 -9
- ccxt/pro/okx.py +935 -124
- ccxt/pro/onetrading.py +41 -24
- ccxt/pro/oxfun.py +1054 -0
- ccxt/pro/p2b.py +100 -24
- ccxt/pro/paradex.py +352 -0
- ccxt/pro/phemex.py +92 -33
- ccxt/pro/poloniex.py +128 -49
- ccxt/pro/poloniexfutures.py +53 -32
- ccxt/pro/probit.py +92 -85
- ccxt/pro/upbit.py +401 -8
- ccxt/pro/vertex.py +943 -0
- ccxt/pro/wazirx.py +46 -28
- ccxt/pro/whitebit.py +65 -12
- ccxt/pro/woo.py +437 -65
- ccxt/pro/woofipro.py +1271 -0
- ccxt/pro/xt.py +1067 -0
- ccxt/probit.py +143 -110
- ccxt/static_dependencies/__init__.py +1 -1
- ccxt/static_dependencies/lark/__init__.py +38 -0
- ccxt/static_dependencies/lark/__pyinstaller/__init__.py +6 -0
- ccxt/static_dependencies/lark/__pyinstaller/hook-lark.py +14 -0
- ccxt/static_dependencies/lark/ast_utils.py +59 -0
- ccxt/static_dependencies/lark/common.py +86 -0
- ccxt/static_dependencies/lark/exceptions.py +292 -0
- ccxt/static_dependencies/lark/grammar.py +130 -0
- ccxt/static_dependencies/lark/grammars/__init__.py +0 -0
- ccxt/static_dependencies/lark/indenter.py +143 -0
- ccxt/static_dependencies/lark/lark.py +658 -0
- ccxt/static_dependencies/lark/lexer.py +678 -0
- ccxt/static_dependencies/lark/load_grammar.py +1428 -0
- ccxt/static_dependencies/lark/parse_tree_builder.py +391 -0
- ccxt/static_dependencies/lark/parser_frontends.py +257 -0
- ccxt/static_dependencies/lark/parsers/__init__.py +0 -0
- ccxt/static_dependencies/lark/parsers/cyk.py +340 -0
- ccxt/static_dependencies/lark/parsers/earley.py +314 -0
- ccxt/static_dependencies/lark/parsers/earley_common.py +42 -0
- ccxt/static_dependencies/lark/parsers/earley_forest.py +801 -0
- ccxt/static_dependencies/lark/parsers/grammar_analysis.py +203 -0
- ccxt/static_dependencies/lark/parsers/lalr_analysis.py +332 -0
- ccxt/static_dependencies/lark/parsers/lalr_interactive_parser.py +158 -0
- ccxt/static_dependencies/lark/parsers/lalr_parser.py +122 -0
- ccxt/static_dependencies/lark/parsers/lalr_parser_state.py +110 -0
- ccxt/static_dependencies/lark/parsers/xearley.py +165 -0
- ccxt/static_dependencies/lark/py.typed +0 -0
- ccxt/static_dependencies/lark/reconstruct.py +107 -0
- ccxt/static_dependencies/lark/tools/__init__.py +70 -0
- ccxt/static_dependencies/lark/tools/nearley.py +202 -0
- ccxt/static_dependencies/lark/tools/serialize.py +32 -0
- ccxt/static_dependencies/lark/tools/standalone.py +196 -0
- ccxt/static_dependencies/lark/tree.py +267 -0
- ccxt/static_dependencies/lark/tree_matcher.py +186 -0
- ccxt/static_dependencies/lark/tree_templates.py +180 -0
- ccxt/static_dependencies/lark/utils.py +343 -0
- ccxt/static_dependencies/lark/visitors.py +596 -0
- ccxt/static_dependencies/marshmallow/__init__.py +81 -0
- ccxt/static_dependencies/marshmallow/base.py +65 -0
- ccxt/static_dependencies/marshmallow/class_registry.py +94 -0
- ccxt/static_dependencies/marshmallow/decorators.py +231 -0
- ccxt/static_dependencies/marshmallow/error_store.py +60 -0
- ccxt/static_dependencies/marshmallow/exceptions.py +71 -0
- ccxt/static_dependencies/marshmallow/fields.py +2114 -0
- ccxt/static_dependencies/marshmallow/orderedset.py +89 -0
- ccxt/static_dependencies/marshmallow/py.typed +0 -0
- ccxt/static_dependencies/marshmallow/schema.py +1228 -0
- ccxt/static_dependencies/marshmallow/types.py +12 -0
- ccxt/static_dependencies/marshmallow/utils.py +378 -0
- ccxt/static_dependencies/marshmallow/validate.py +678 -0
- ccxt/static_dependencies/marshmallow/warnings.py +2 -0
- ccxt/static_dependencies/marshmallow_dataclass/__init__.py +1047 -0
- ccxt/static_dependencies/marshmallow_dataclass/collection_field.py +51 -0
- ccxt/static_dependencies/marshmallow_dataclass/lazy_class_attribute.py +45 -0
- ccxt/static_dependencies/marshmallow_dataclass/mypy.py +71 -0
- ccxt/static_dependencies/marshmallow_dataclass/py.typed +0 -0
- ccxt/static_dependencies/marshmallow_dataclass/typing.py +14 -0
- ccxt/static_dependencies/marshmallow_dataclass/union_field.py +82 -0
- ccxt/static_dependencies/marshmallow_oneofschema/__init__.py +1 -0
- ccxt/static_dependencies/marshmallow_oneofschema/one_of_schema.py +193 -0
- ccxt/static_dependencies/marshmallow_oneofschema/py.typed +0 -0
- ccxt/static_dependencies/starknet/__init__.py +0 -0
- ccxt/static_dependencies/starknet/cairo/__init__.py +0 -0
- ccxt/static_dependencies/starknet/cairo/data_types.py +123 -0
- ccxt/static_dependencies/starknet/cairo/deprecated_parse/__init__.py +0 -0
- ccxt/static_dependencies/starknet/cairo/deprecated_parse/cairo_types.py +77 -0
- ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser.py +46 -0
- ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser_transformer.py +138 -0
- ccxt/static_dependencies/starknet/cairo/felt.py +64 -0
- ccxt/static_dependencies/starknet/cairo/type_parser.py +121 -0
- ccxt/static_dependencies/starknet/cairo/v1/__init__.py +0 -0
- ccxt/static_dependencies/starknet/cairo/v1/type_parser.py +59 -0
- ccxt/static_dependencies/starknet/cairo/v2/__init__.py +0 -0
- ccxt/static_dependencies/starknet/cairo/v2/type_parser.py +77 -0
- ccxt/static_dependencies/starknet/ccxt_utils.py +7 -0
- ccxt/static_dependencies/starknet/common.py +15 -0
- ccxt/static_dependencies/starknet/constants.py +39 -0
- ccxt/static_dependencies/starknet/hash/__init__.py +0 -0
- ccxt/static_dependencies/starknet/hash/address.py +79 -0
- ccxt/static_dependencies/starknet/hash/compiled_class_hash_objects.py +111 -0
- ccxt/static_dependencies/starknet/hash/selector.py +16 -0
- ccxt/static_dependencies/starknet/hash/storage.py +12 -0
- ccxt/static_dependencies/starknet/hash/utils.py +78 -0
- ccxt/static_dependencies/starknet/models/__init__.py +0 -0
- ccxt/static_dependencies/starknet/models/typed_data.py +45 -0
- ccxt/static_dependencies/starknet/serialization/__init__.py +24 -0
- ccxt/static_dependencies/starknet/serialization/_calldata_reader.py +40 -0
- ccxt/static_dependencies/starknet/serialization/_context.py +142 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/__init__.py +10 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/_common.py +82 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/array_serializer.py +43 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/bool_serializer.py +37 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/byte_array_serializer.py +66 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/cairo_data_serializer.py +71 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/enum_serializer.py +71 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/felt_serializer.py +50 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/named_tuple_serializer.py +58 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/option_serializer.py +43 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/output_serializer.py +40 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/payload_serializer.py +72 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/struct_serializer.py +36 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/tuple_serializer.py +36 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/uint256_serializer.py +76 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/uint_serializer.py +100 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/unit_serializer.py +32 -0
- ccxt/static_dependencies/starknet/serialization/errors.py +10 -0
- ccxt/static_dependencies/starknet/serialization/factory.py +229 -0
- ccxt/static_dependencies/starknet/serialization/function_serialization_adapter.py +110 -0
- ccxt/static_dependencies/starknet/serialization/tuple_dataclass.py +59 -0
- ccxt/static_dependencies/starknet/utils/__init__.py +0 -0
- ccxt/static_dependencies/starknet/utils/constructor_args_translator.py +86 -0
- ccxt/static_dependencies/starknet/utils/iterable.py +13 -0
- ccxt/static_dependencies/starknet/utils/schema.py +13 -0
- ccxt/static_dependencies/starknet/utils/typed_data.py +182 -0
- ccxt/static_dependencies/starkware/__init__.py +0 -0
- ccxt/static_dependencies/starkware/crypto/__init__.py +0 -0
- ccxt/static_dependencies/starkware/crypto/fast_pedersen_hash.py +50 -0
- ccxt/static_dependencies/starkware/crypto/math_utils.py +78 -0
- ccxt/static_dependencies/starkware/crypto/signature.py +2344 -0
- ccxt/static_dependencies/starkware/crypto/utils.py +63 -0
- ccxt/static_dependencies/sympy/__init__.py +0 -0
- ccxt/static_dependencies/sympy/core/__init__.py +0 -0
- ccxt/static_dependencies/sympy/core/intfunc.py +35 -0
- ccxt/static_dependencies/sympy/external/__init__.py +0 -0
- ccxt/static_dependencies/sympy/external/gmpy.py +345 -0
- ccxt/static_dependencies/sympy/external/importtools.py +187 -0
- ccxt/static_dependencies/sympy/external/ntheory.py +637 -0
- ccxt/static_dependencies/sympy/external/pythonmpq.py +341 -0
- ccxt/static_dependencies/typing_inspect/__init__.py +0 -0
- ccxt/static_dependencies/typing_inspect/typing_inspect.py +851 -0
- ccxt/test/{test_async.py → tests_async.py} +456 -391
- ccxt/test/tests_helpers.py +285 -0
- ccxt/test/tests_init.py +39 -0
- ccxt/test/{test_sync.py → tests_sync.py} +456 -393
- ccxt/timex.py +123 -70
- ccxt/tokocrypto.py +129 -93
- ccxt/tradeogre.py +39 -25
- ccxt/upbit.py +322 -113
- ccxt/vertex.py +2983 -0
- ccxt/wavesexchange.py +227 -173
- ccxt/wazirx.py +145 -65
- ccxt/whitebit.py +533 -138
- ccxt/woo.py +1137 -296
- ccxt/woofipro.py +2716 -0
- ccxt/xt.py +4627 -0
- ccxt/yobit.py +159 -92
- ccxt/zaif.py +80 -33
- ccxt/zonda.py +140 -69
- ccxt-4.4.48.dist-info/LICENSE.txt +21 -0
- ccxt-4.4.48.dist-info/METADATA +646 -0
- ccxt-4.4.48.dist-info/RECORD +669 -0
- {ccxt-4.2.77.dist-info → ccxt-4.4.48.dist-info}/WHEEL +1 -1
- ccxt/abstract/bitbay.py +0 -47
- ccxt/abstract/bitfinex2.py +0 -139
- ccxt/abstract/hitbtc3.py +0 -115
- ccxt/async_support/bitbay.py +0 -17
- ccxt/async_support/bitfinex2.py +0 -3496
- ccxt/async_support/flowbtc.py +0 -34
- ccxt/bitbay.py +0 -17
- ccxt/bitfinex2.py +0 -3496
- ccxt/flowbtc.py +0 -34
- ccxt/hitbtc3.py +0 -16
- ccxt/pro/bitfinex2.py +0 -1081
- ccxt/test/base/__init__.py +0 -28
- ccxt/test/base/test_account.py +0 -26
- ccxt/test/base/test_balance.py +0 -56
- ccxt/test/base/test_borrow_interest.py +0 -35
- ccxt/test/base/test_borrow_rate.py +0 -32
- ccxt/test/base/test_calculate_fee.py +0 -51
- ccxt/test/base/test_crypto.py +0 -127
- ccxt/test/base/test_currency.py +0 -76
- ccxt/test/base/test_datetime.py +0 -103
- ccxt/test/base/test_decimal_to_precision.py +0 -392
- ccxt/test/base/test_deep_extend.py +0 -68
- ccxt/test/base/test_deposit_withdrawal.py +0 -50
- ccxt/test/base/test_exchange_datetime_functions.py +0 -76
- ccxt/test/base/test_funding_rate_history.py +0 -29
- ccxt/test/base/test_last_price.py +0 -32
- ccxt/test/base/test_ledger_entry.py +0 -45
- ccxt/test/base/test_ledger_item.py +0 -48
- ccxt/test/base/test_leverage_tier.py +0 -33
- ccxt/test/base/test_margin_mode.py +0 -24
- ccxt/test/base/test_margin_modification.py +0 -35
- ccxt/test/base/test_market.py +0 -190
- ccxt/test/base/test_number.py +0 -411
- ccxt/test/base/test_ohlcv.py +0 -32
- ccxt/test/base/test_open_interest.py +0 -32
- ccxt/test/base/test_order.py +0 -64
- ccxt/test/base/test_order_book.py +0 -63
- ccxt/test/base/test_position.py +0 -60
- ccxt/test/base/test_shared_methods.py +0 -345
- ccxt/test/base/test_status.py +0 -24
- ccxt/test/base/test_throttle.py +0 -126
- ccxt/test/base/test_ticker.py +0 -86
- ccxt/test/base/test_trade.py +0 -47
- ccxt/test/base/test_trading_fee.py +0 -26
- ccxt/test/base/test_transaction.py +0 -39
- ccxt-4.2.77.dist-info/METADATA +0 -626
- ccxt-4.2.77.dist-info/RECORD +0 -534
- {ccxt-4.2.77.dist-info → ccxt-4.4.48.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,186 @@
|
|
1
|
+
"""Tree matcher based on Lark grammar"""
|
2
|
+
|
3
|
+
import re
|
4
|
+
from collections import defaultdict
|
5
|
+
|
6
|
+
from . import Tree, Token
|
7
|
+
from .common import ParserConf
|
8
|
+
from .parsers import earley
|
9
|
+
from .grammar import Rule, Terminal, NonTerminal
|
10
|
+
|
11
|
+
|
12
|
+
def is_discarded_terminal(t):
|
13
|
+
return t.is_term and t.filter_out
|
14
|
+
|
15
|
+
|
16
|
+
class _MakeTreeMatch:
|
17
|
+
def __init__(self, name, expansion):
|
18
|
+
self.name = name
|
19
|
+
self.expansion = expansion
|
20
|
+
|
21
|
+
def __call__(self, args):
|
22
|
+
t = Tree(self.name, args)
|
23
|
+
t.meta.match_tree = True
|
24
|
+
t.meta.orig_expansion = self.expansion
|
25
|
+
return t
|
26
|
+
|
27
|
+
|
28
|
+
def _best_from_group(seq, group_key, cmp_key):
|
29
|
+
d = {}
|
30
|
+
for item in seq:
|
31
|
+
key = group_key(item)
|
32
|
+
if key in d:
|
33
|
+
v1 = cmp_key(item)
|
34
|
+
v2 = cmp_key(d[key])
|
35
|
+
if v2 > v1:
|
36
|
+
d[key] = item
|
37
|
+
else:
|
38
|
+
d[key] = item
|
39
|
+
return list(d.values())
|
40
|
+
|
41
|
+
|
42
|
+
def _best_rules_from_group(rules):
|
43
|
+
rules = _best_from_group(rules, lambda r: r, lambda r: -len(r.expansion))
|
44
|
+
rules.sort(key=lambda r: len(r.expansion))
|
45
|
+
return rules
|
46
|
+
|
47
|
+
|
48
|
+
def _match(term, token):
|
49
|
+
if isinstance(token, Tree):
|
50
|
+
name, _args = parse_rulename(term.name)
|
51
|
+
return token.data == name
|
52
|
+
elif isinstance(token, Token):
|
53
|
+
return term == Terminal(token.type)
|
54
|
+
assert False, (term, token)
|
55
|
+
|
56
|
+
|
57
|
+
def make_recons_rule(origin, expansion, old_expansion):
|
58
|
+
return Rule(origin, expansion, alias=_MakeTreeMatch(origin.name, old_expansion))
|
59
|
+
|
60
|
+
|
61
|
+
def make_recons_rule_to_term(origin, term):
|
62
|
+
return make_recons_rule(origin, [Terminal(term.name)], [term])
|
63
|
+
|
64
|
+
|
65
|
+
def parse_rulename(s):
|
66
|
+
"Parse rule names that may contain a template syntax (like rule{a, b, ...})"
|
67
|
+
name, args_str = re.match(r'(\w+)(?:{(.+)})?', s).groups()
|
68
|
+
args = args_str and [a.strip() for a in args_str.split(',')]
|
69
|
+
return name, args
|
70
|
+
|
71
|
+
|
72
|
+
|
73
|
+
class ChildrenLexer:
|
74
|
+
def __init__(self, children):
|
75
|
+
self.children = children
|
76
|
+
|
77
|
+
def lex(self, parser_state):
|
78
|
+
return self.children
|
79
|
+
|
80
|
+
class TreeMatcher:
|
81
|
+
"""Match the elements of a tree node, based on an ontology
|
82
|
+
provided by a Lark grammar.
|
83
|
+
|
84
|
+
Supports templates and inlined rules (`rule{a, b,..}` and `_rule`)
|
85
|
+
|
86
|
+
Initialize with an instance of Lark.
|
87
|
+
"""
|
88
|
+
|
89
|
+
def __init__(self, parser):
|
90
|
+
# XXX TODO calling compile twice returns different results!
|
91
|
+
assert not parser.options.maybe_placeholders
|
92
|
+
# XXX TODO: we just ignore the potential existence of a postlexer
|
93
|
+
self.tokens, rules, _extra = parser.grammar.compile(parser.options.start, set())
|
94
|
+
|
95
|
+
self.rules_for_root = defaultdict(list)
|
96
|
+
|
97
|
+
self.rules = list(self._build_recons_rules(rules))
|
98
|
+
self.rules.reverse()
|
99
|
+
|
100
|
+
# Choose the best rule from each group of {rule => [rule.alias]}, since we only really need one derivation.
|
101
|
+
self.rules = _best_rules_from_group(self.rules)
|
102
|
+
|
103
|
+
self.parser = parser
|
104
|
+
self._parser_cache = {}
|
105
|
+
|
106
|
+
def _build_recons_rules(self, rules):
|
107
|
+
"Convert tree-parsing/construction rules to tree-matching rules"
|
108
|
+
expand1s = {r.origin for r in rules if r.options.expand1}
|
109
|
+
|
110
|
+
aliases = defaultdict(list)
|
111
|
+
for r in rules:
|
112
|
+
if r.alias:
|
113
|
+
aliases[r.origin].append(r.alias)
|
114
|
+
|
115
|
+
rule_names = {r.origin for r in rules}
|
116
|
+
nonterminals = {sym for sym in rule_names
|
117
|
+
if sym.name.startswith('_') or sym in expand1s or sym in aliases}
|
118
|
+
|
119
|
+
seen = set()
|
120
|
+
for r in rules:
|
121
|
+
recons_exp = [sym if sym in nonterminals else Terminal(sym.name)
|
122
|
+
for sym in r.expansion if not is_discarded_terminal(sym)]
|
123
|
+
|
124
|
+
# Skip self-recursive constructs
|
125
|
+
if recons_exp == [r.origin] and r.alias is None:
|
126
|
+
continue
|
127
|
+
|
128
|
+
sym = NonTerminal(r.alias) if r.alias else r.origin
|
129
|
+
rule = make_recons_rule(sym, recons_exp, r.expansion)
|
130
|
+
|
131
|
+
if sym in expand1s and len(recons_exp) != 1:
|
132
|
+
self.rules_for_root[sym.name].append(rule)
|
133
|
+
|
134
|
+
if sym.name not in seen:
|
135
|
+
yield make_recons_rule_to_term(sym, sym)
|
136
|
+
seen.add(sym.name)
|
137
|
+
else:
|
138
|
+
if sym.name.startswith('_') or sym in expand1s:
|
139
|
+
yield rule
|
140
|
+
else:
|
141
|
+
self.rules_for_root[sym.name].append(rule)
|
142
|
+
|
143
|
+
for origin, rule_aliases in aliases.items():
|
144
|
+
for alias in rule_aliases:
|
145
|
+
yield make_recons_rule_to_term(origin, NonTerminal(alias))
|
146
|
+
yield make_recons_rule_to_term(origin, origin)
|
147
|
+
|
148
|
+
def match_tree(self, tree, rulename):
|
149
|
+
"""Match the elements of `tree` to the symbols of rule `rulename`.
|
150
|
+
|
151
|
+
Parameters:
|
152
|
+
tree (Tree): the tree node to match
|
153
|
+
rulename (str): The expected full rule name (including template args)
|
154
|
+
|
155
|
+
Returns:
|
156
|
+
Tree: an unreduced tree that matches `rulename`
|
157
|
+
|
158
|
+
Raises:
|
159
|
+
UnexpectedToken: If no match was found.
|
160
|
+
|
161
|
+
Note:
|
162
|
+
It's the callers' responsibility match the tree recursively.
|
163
|
+
"""
|
164
|
+
if rulename:
|
165
|
+
# validate
|
166
|
+
name, _args = parse_rulename(rulename)
|
167
|
+
assert tree.data == name
|
168
|
+
else:
|
169
|
+
rulename = tree.data
|
170
|
+
|
171
|
+
# TODO: ambiguity?
|
172
|
+
try:
|
173
|
+
parser = self._parser_cache[rulename]
|
174
|
+
except KeyError:
|
175
|
+
rules = self.rules + _best_rules_from_group(self.rules_for_root[rulename])
|
176
|
+
|
177
|
+
# TODO pass callbacks through dict, instead of alias?
|
178
|
+
callbacks = {rule: rule.alias for rule in rules}
|
179
|
+
conf = ParserConf(rules, callbacks, [rulename])
|
180
|
+
parser = earley.Parser(self.parser.lexer_conf, conf, _match, resolve_ambiguity=True)
|
181
|
+
self._parser_cache[rulename] = parser
|
182
|
+
|
183
|
+
# find a full derivation
|
184
|
+
unreduced_tree = parser.parse(ChildrenLexer(tree.children), rulename)
|
185
|
+
assert unreduced_tree.data == rulename
|
186
|
+
return unreduced_tree
|
@@ -0,0 +1,180 @@
|
|
1
|
+
"""This module defines utilities for matching and translation tree templates.
|
2
|
+
|
3
|
+
A tree templates is a tree that contains nodes that are template variables.
|
4
|
+
|
5
|
+
"""
|
6
|
+
|
7
|
+
from typing import Union, Optional, Mapping, Dict, Tuple, Iterator
|
8
|
+
|
9
|
+
from lark import Tree, Transformer
|
10
|
+
from lark.exceptions import MissingVariableError
|
11
|
+
|
12
|
+
Branch = Union[Tree[str], str]
|
13
|
+
TreeOrCode = Union[Tree[str], str]
|
14
|
+
MatchResult = Dict[str, Tree]
|
15
|
+
_TEMPLATE_MARKER = '$'
|
16
|
+
|
17
|
+
|
18
|
+
class TemplateConf:
|
19
|
+
"""Template Configuration
|
20
|
+
|
21
|
+
Allows customization for different uses of Template
|
22
|
+
|
23
|
+
parse() must return a Tree instance.
|
24
|
+
"""
|
25
|
+
|
26
|
+
def __init__(self, parse=None):
|
27
|
+
self._parse = parse
|
28
|
+
|
29
|
+
def test_var(self, var: Union[Tree[str], str]) -> Optional[str]:
|
30
|
+
"""Given a tree node, if it is a template variable return its name. Otherwise, return None.
|
31
|
+
|
32
|
+
This method may be overridden for customization
|
33
|
+
|
34
|
+
Parameters:
|
35
|
+
var: Tree | str - The tree node to test
|
36
|
+
|
37
|
+
"""
|
38
|
+
if isinstance(var, str):
|
39
|
+
return _get_template_name(var)
|
40
|
+
|
41
|
+
if (
|
42
|
+
isinstance(var, Tree)
|
43
|
+
and var.data == "var"
|
44
|
+
and len(var.children) > 0
|
45
|
+
and isinstance(var.children[0], str)
|
46
|
+
):
|
47
|
+
return _get_template_name(var.children[0])
|
48
|
+
|
49
|
+
return None
|
50
|
+
|
51
|
+
def _get_tree(self, template: TreeOrCode) -> Tree[str]:
|
52
|
+
if isinstance(template, str):
|
53
|
+
assert self._parse
|
54
|
+
template = self._parse(template)
|
55
|
+
|
56
|
+
if not isinstance(template, Tree):
|
57
|
+
raise TypeError("template parser must return a Tree instance")
|
58
|
+
|
59
|
+
return template
|
60
|
+
|
61
|
+
def __call__(self, template: Tree[str]) -> 'Template':
|
62
|
+
return Template(template, conf=self)
|
63
|
+
|
64
|
+
def _match_tree_template(self, template: TreeOrCode, tree: Branch) -> Optional[MatchResult]:
|
65
|
+
"""Returns dict of {var: match} if found a match, else None
|
66
|
+
"""
|
67
|
+
template_var = self.test_var(template)
|
68
|
+
if template_var:
|
69
|
+
if not isinstance(tree, Tree):
|
70
|
+
raise TypeError(f"Template variables can only match Tree instances. Not {tree!r}")
|
71
|
+
return {template_var: tree}
|
72
|
+
|
73
|
+
if isinstance(template, str):
|
74
|
+
if template == tree:
|
75
|
+
return {}
|
76
|
+
return None
|
77
|
+
|
78
|
+
assert isinstance(template, Tree) and isinstance(tree, Tree), f"template={template} tree={tree}"
|
79
|
+
|
80
|
+
if template.data == tree.data and len(template.children) == len(tree.children):
|
81
|
+
res = {}
|
82
|
+
for t1, t2 in zip(template.children, tree.children):
|
83
|
+
matches = self._match_tree_template(t1, t2)
|
84
|
+
if matches is None:
|
85
|
+
return None
|
86
|
+
|
87
|
+
res.update(matches)
|
88
|
+
|
89
|
+
return res
|
90
|
+
|
91
|
+
return None
|
92
|
+
|
93
|
+
|
94
|
+
class _ReplaceVars(Transformer[str, Tree[str]]):
|
95
|
+
def __init__(self, conf: TemplateConf, vars: Mapping[str, Tree[str]]) -> None:
|
96
|
+
super().__init__()
|
97
|
+
self._conf = conf
|
98
|
+
self._vars = vars
|
99
|
+
|
100
|
+
def __default__(self, data, children, meta) -> Tree[str]:
|
101
|
+
tree = super().__default__(data, children, meta)
|
102
|
+
|
103
|
+
var = self._conf.test_var(tree)
|
104
|
+
if var:
|
105
|
+
try:
|
106
|
+
return self._vars[var]
|
107
|
+
except KeyError:
|
108
|
+
raise MissingVariableError(f"No mapping for template variable ({var})")
|
109
|
+
return tree
|
110
|
+
|
111
|
+
|
112
|
+
class Template:
|
113
|
+
"""Represents a tree template, tied to a specific configuration
|
114
|
+
|
115
|
+
A tree template is a tree that contains nodes that are template variables.
|
116
|
+
Those variables will match any tree.
|
117
|
+
(future versions may support annotations on the variables, to allow more complex templates)
|
118
|
+
"""
|
119
|
+
|
120
|
+
def __init__(self, tree: Tree[str], conf: TemplateConf = TemplateConf()):
|
121
|
+
self.conf = conf
|
122
|
+
self.tree = conf._get_tree(tree)
|
123
|
+
|
124
|
+
def match(self, tree: TreeOrCode) -> Optional[MatchResult]:
|
125
|
+
"""Match a tree template to a tree.
|
126
|
+
|
127
|
+
A tree template without variables will only match ``tree`` if it is equal to the template.
|
128
|
+
|
129
|
+
Parameters:
|
130
|
+
tree (Tree): The tree to match to the template
|
131
|
+
|
132
|
+
Returns:
|
133
|
+
Optional[Dict[str, Tree]]: If match is found, returns a dictionary mapping
|
134
|
+
template variable names to their matching tree nodes.
|
135
|
+
If no match was found, returns None.
|
136
|
+
"""
|
137
|
+
tree = self.conf._get_tree(tree)
|
138
|
+
return self.conf._match_tree_template(self.tree, tree)
|
139
|
+
|
140
|
+
def search(self, tree: TreeOrCode) -> Iterator[Tuple[Tree[str], MatchResult]]:
|
141
|
+
"""Search for all occurrences of the tree template inside ``tree``.
|
142
|
+
"""
|
143
|
+
tree = self.conf._get_tree(tree)
|
144
|
+
for subtree in tree.iter_subtrees():
|
145
|
+
res = self.match(subtree)
|
146
|
+
if res:
|
147
|
+
yield subtree, res
|
148
|
+
|
149
|
+
def apply_vars(self, vars: Mapping[str, Tree[str]]) -> Tree[str]:
|
150
|
+
"""Apply vars to the template tree
|
151
|
+
"""
|
152
|
+
return _ReplaceVars(self.conf, vars).transform(self.tree)
|
153
|
+
|
154
|
+
|
155
|
+
def translate(t1: Template, t2: Template, tree: TreeOrCode):
|
156
|
+
"""Search tree and translate each occurrence of t1 into t2.
|
157
|
+
"""
|
158
|
+
tree = t1.conf._get_tree(tree) # ensure it's a tree, parse if necessary and possible
|
159
|
+
for subtree, vars in t1.search(tree):
|
160
|
+
res = t2.apply_vars(vars)
|
161
|
+
subtree.set(res.data, res.children)
|
162
|
+
return tree
|
163
|
+
|
164
|
+
|
165
|
+
class TemplateTranslator:
|
166
|
+
"""Utility class for translating a collection of patterns
|
167
|
+
"""
|
168
|
+
|
169
|
+
def __init__(self, translations: Mapping[Template, Template]):
|
170
|
+
assert all(isinstance(k, Template) and isinstance(v, Template) for k, v in translations.items())
|
171
|
+
self.translations = translations
|
172
|
+
|
173
|
+
def translate(self, tree: Tree[str]):
|
174
|
+
for k, v in self.translations.items():
|
175
|
+
tree = translate(k, v, tree)
|
176
|
+
return tree
|
177
|
+
|
178
|
+
|
179
|
+
def _get_template_name(value: str) -> Optional[str]:
|
180
|
+
return value.lstrip(_TEMPLATE_MARKER) if value.startswith(_TEMPLATE_MARKER) else None
|
@@ -0,0 +1,343 @@
|
|
1
|
+
import unicodedata
|
2
|
+
import os
|
3
|
+
from itertools import product
|
4
|
+
from collections import deque
|
5
|
+
from typing import Callable, Iterator, List, Optional, Tuple, Type, TypeVar, Union, Dict, Any, Sequence, Iterable, AbstractSet
|
6
|
+
|
7
|
+
###{standalone
|
8
|
+
import sys, re
|
9
|
+
import logging
|
10
|
+
|
11
|
+
logger: logging.Logger = logging.getLogger("lark")
|
12
|
+
logger.addHandler(logging.StreamHandler())
|
13
|
+
# Set to highest level, since we have some warnings amongst the code
|
14
|
+
# By default, we should not output any log messages
|
15
|
+
logger.setLevel(logging.CRITICAL)
|
16
|
+
|
17
|
+
|
18
|
+
NO_VALUE = object()
|
19
|
+
|
20
|
+
T = TypeVar("T")
|
21
|
+
|
22
|
+
|
23
|
+
def classify(seq: Iterable, key: Optional[Callable] = None, value: Optional[Callable] = None) -> Dict:
|
24
|
+
d: Dict[Any, Any] = {}
|
25
|
+
for item in seq:
|
26
|
+
k = key(item) if (key is not None) else item
|
27
|
+
v = value(item) if (value is not None) else item
|
28
|
+
try:
|
29
|
+
d[k].append(v)
|
30
|
+
except KeyError:
|
31
|
+
d[k] = [v]
|
32
|
+
return d
|
33
|
+
|
34
|
+
|
35
|
+
def _deserialize(data: Any, namespace: Dict[str, Any], memo: Dict) -> Any:
|
36
|
+
if isinstance(data, dict):
|
37
|
+
if '__type__' in data: # Object
|
38
|
+
class_ = namespace[data['__type__']]
|
39
|
+
return class_.deserialize(data, memo)
|
40
|
+
elif '@' in data:
|
41
|
+
return memo[data['@']]
|
42
|
+
return {key:_deserialize(value, namespace, memo) for key, value in data.items()}
|
43
|
+
elif isinstance(data, list):
|
44
|
+
return [_deserialize(value, namespace, memo) for value in data]
|
45
|
+
return data
|
46
|
+
|
47
|
+
|
48
|
+
_T = TypeVar("_T", bound="Serialize")
|
49
|
+
|
50
|
+
class Serialize:
|
51
|
+
"""Safe-ish serialization interface that doesn't rely on Pickle
|
52
|
+
|
53
|
+
Attributes:
|
54
|
+
__serialize_fields__ (List[str]): Fields (aka attributes) to serialize.
|
55
|
+
__serialize_namespace__ (list): List of classes that deserialization is allowed to instantiate.
|
56
|
+
Should include all field types that aren't builtin types.
|
57
|
+
"""
|
58
|
+
|
59
|
+
def memo_serialize(self, types_to_memoize: List) -> Any:
|
60
|
+
memo = SerializeMemoizer(types_to_memoize)
|
61
|
+
return self.serialize(memo), memo.serialize()
|
62
|
+
|
63
|
+
def serialize(self, memo = None) -> Dict[str, Any]:
|
64
|
+
if memo and memo.in_types(self):
|
65
|
+
return {'@': memo.memoized.get(self)}
|
66
|
+
|
67
|
+
fields = getattr(self, '__serialize_fields__')
|
68
|
+
res = {f: _serialize(getattr(self, f), memo) for f in fields}
|
69
|
+
res['__type__'] = type(self).__name__
|
70
|
+
if hasattr(self, '_serialize'):
|
71
|
+
self._serialize(res, memo)
|
72
|
+
return res
|
73
|
+
|
74
|
+
@classmethod
|
75
|
+
def deserialize(cls: Type[_T], data: Dict[str, Any], memo: Dict[int, Any]) -> _T:
|
76
|
+
namespace = getattr(cls, '__serialize_namespace__', [])
|
77
|
+
namespace = {c.__name__:c for c in namespace}
|
78
|
+
|
79
|
+
fields = getattr(cls, '__serialize_fields__')
|
80
|
+
|
81
|
+
if '@' in data:
|
82
|
+
return memo[data['@']]
|
83
|
+
|
84
|
+
inst = cls.__new__(cls)
|
85
|
+
for f in fields:
|
86
|
+
try:
|
87
|
+
setattr(inst, f, _deserialize(data[f], namespace, memo))
|
88
|
+
except KeyError as e:
|
89
|
+
raise KeyError("Cannot find key for class", cls, e)
|
90
|
+
|
91
|
+
if hasattr(inst, '_deserialize'):
|
92
|
+
inst._deserialize()
|
93
|
+
|
94
|
+
return inst
|
95
|
+
|
96
|
+
|
97
|
+
class SerializeMemoizer(Serialize):
|
98
|
+
"A version of serialize that memoizes objects to reduce space"
|
99
|
+
|
100
|
+
__serialize_fields__ = 'memoized',
|
101
|
+
|
102
|
+
def __init__(self, types_to_memoize: List) -> None:
|
103
|
+
self.types_to_memoize = tuple(types_to_memoize)
|
104
|
+
self.memoized = Enumerator()
|
105
|
+
|
106
|
+
def in_types(self, value: Serialize) -> bool:
|
107
|
+
return isinstance(value, self.types_to_memoize)
|
108
|
+
|
109
|
+
def serialize(self) -> Dict[int, Any]: # type: ignore[override]
|
110
|
+
return _serialize(self.memoized.reversed(), None)
|
111
|
+
|
112
|
+
@classmethod
|
113
|
+
def deserialize(cls, data: Dict[int, Any], namespace: Dict[str, Any], memo: Dict[Any, Any]) -> Dict[int, Any]: # type: ignore[override]
|
114
|
+
return _deserialize(data, namespace, memo)
|
115
|
+
|
116
|
+
|
117
|
+
try:
|
118
|
+
import regex
|
119
|
+
_has_regex = True
|
120
|
+
except ImportError:
|
121
|
+
_has_regex = False
|
122
|
+
|
123
|
+
if sys.version_info >= (3, 11):
|
124
|
+
import re._parser as sre_parse
|
125
|
+
import re._constants as sre_constants
|
126
|
+
else:
|
127
|
+
import sre_parse
|
128
|
+
import sre_constants
|
129
|
+
|
130
|
+
categ_pattern = re.compile(r'\\p{[A-Za-z_]+}')
|
131
|
+
|
132
|
+
def get_regexp_width(expr: str) -> Union[Tuple[int, int], List[int]]:
|
133
|
+
if _has_regex:
|
134
|
+
# Since `sre_parse` cannot deal with Unicode categories of the form `\p{Mn}`, we replace these with
|
135
|
+
# a simple letter, which makes no difference as we are only trying to get the possible lengths of the regex
|
136
|
+
# match here below.
|
137
|
+
regexp_final = re.sub(categ_pattern, 'A', expr)
|
138
|
+
else:
|
139
|
+
if re.search(categ_pattern, expr):
|
140
|
+
raise ImportError('`regex` module must be installed in order to use Unicode categories.', expr)
|
141
|
+
regexp_final = expr
|
142
|
+
try:
|
143
|
+
# Fixed in next version (past 0.960) of typeshed
|
144
|
+
return [int(x) for x in sre_parse.parse(regexp_final).getwidth()]
|
145
|
+
except sre_constants.error:
|
146
|
+
if not _has_regex:
|
147
|
+
raise ValueError(expr)
|
148
|
+
else:
|
149
|
+
# sre_parse does not support the new features in regex. To not completely fail in that case,
|
150
|
+
# we manually test for the most important info (whether the empty string is matched)
|
151
|
+
c = regex.compile(regexp_final)
|
152
|
+
# Python 3.11.7 introducded sre_parse.MAXWIDTH that is used instead of MAXREPEAT
|
153
|
+
# See lark-parser/lark#1376 and python/cpython#109859
|
154
|
+
MAXWIDTH = getattr(sre_parse, "MAXWIDTH", sre_constants.MAXREPEAT)
|
155
|
+
if c.match('') is None:
|
156
|
+
# MAXREPEAT is a none pickable subclass of int, therefore needs to be converted to enable caching
|
157
|
+
return 1, int(MAXWIDTH)
|
158
|
+
else:
|
159
|
+
return 0, int(MAXWIDTH)
|
160
|
+
|
161
|
+
###}
|
162
|
+
|
163
|
+
|
164
|
+
_ID_START = 'Lu', 'Ll', 'Lt', 'Lm', 'Lo', 'Mn', 'Mc', 'Pc'
|
165
|
+
_ID_CONTINUE = _ID_START + ('Nd', 'Nl',)
|
166
|
+
|
167
|
+
def _test_unicode_category(s: str, categories: Sequence[str]) -> bool:
|
168
|
+
if len(s) != 1:
|
169
|
+
return all(_test_unicode_category(char, categories) for char in s)
|
170
|
+
return s == '_' or unicodedata.category(s) in categories
|
171
|
+
|
172
|
+
def is_id_continue(s: str) -> bool:
|
173
|
+
"""
|
174
|
+
Checks if all characters in `s` are alphanumeric characters (Unicode standard, so diacritics, indian vowels, non-latin
|
175
|
+
numbers, etc. all pass). Synonymous with a Python `ID_CONTINUE` identifier. See PEP 3131 for details.
|
176
|
+
"""
|
177
|
+
return _test_unicode_category(s, _ID_CONTINUE)
|
178
|
+
|
179
|
+
def is_id_start(s: str) -> bool:
|
180
|
+
"""
|
181
|
+
Checks if all characters in `s` are alphabetic characters (Unicode standard, so diacritics, indian vowels, non-latin
|
182
|
+
numbers, etc. all pass). Synonymous with a Python `ID_START` identifier. See PEP 3131 for details.
|
183
|
+
"""
|
184
|
+
return _test_unicode_category(s, _ID_START)
|
185
|
+
|
186
|
+
|
187
|
+
def dedup_list(l: Sequence[T]) -> List[T]:
|
188
|
+
"""Given a list (l) will removing duplicates from the list,
|
189
|
+
preserving the original order of the list. Assumes that
|
190
|
+
the list entries are hashable."""
|
191
|
+
return list(dict.fromkeys(l))
|
192
|
+
|
193
|
+
|
194
|
+
class Enumerator(Serialize):
|
195
|
+
def __init__(self) -> None:
|
196
|
+
self.enums: Dict[Any, int] = {}
|
197
|
+
|
198
|
+
def get(self, item) -> int:
|
199
|
+
if item not in self.enums:
|
200
|
+
self.enums[item] = len(self.enums)
|
201
|
+
return self.enums[item]
|
202
|
+
|
203
|
+
def __len__(self):
|
204
|
+
return len(self.enums)
|
205
|
+
|
206
|
+
def reversed(self) -> Dict[int, Any]:
|
207
|
+
r = {v: k for k, v in self.enums.items()}
|
208
|
+
assert len(r) == len(self.enums)
|
209
|
+
return r
|
210
|
+
|
211
|
+
|
212
|
+
|
213
|
+
def combine_alternatives(lists):
|
214
|
+
"""
|
215
|
+
Accepts a list of alternatives, and enumerates all their possible concatenations.
|
216
|
+
|
217
|
+
Examples:
|
218
|
+
>>> combine_alternatives([range(2), [4,5]])
|
219
|
+
[[0, 4], [0, 5], [1, 4], [1, 5]]
|
220
|
+
|
221
|
+
>>> combine_alternatives(["abc", "xy", '$'])
|
222
|
+
[['a', 'x', '$'], ['a', 'y', '$'], ['b', 'x', '$'], ['b', 'y', '$'], ['c', 'x', '$'], ['c', 'y', '$']]
|
223
|
+
|
224
|
+
>>> combine_alternatives([])
|
225
|
+
[[]]
|
226
|
+
"""
|
227
|
+
if not lists:
|
228
|
+
return [[]]
|
229
|
+
assert all(l for l in lists), lists
|
230
|
+
return list(product(*lists))
|
231
|
+
|
232
|
+
try:
|
233
|
+
import atomicwrites
|
234
|
+
_has_atomicwrites = True
|
235
|
+
except ImportError:
|
236
|
+
_has_atomicwrites = False
|
237
|
+
|
238
|
+
class FS:
|
239
|
+
exists = staticmethod(os.path.exists)
|
240
|
+
|
241
|
+
@staticmethod
|
242
|
+
def open(name, mode="r", **kwargs):
|
243
|
+
if _has_atomicwrites and "w" in mode:
|
244
|
+
return atomicwrites.atomic_write(name, mode=mode, overwrite=True, **kwargs)
|
245
|
+
else:
|
246
|
+
return open(name, mode, **kwargs)
|
247
|
+
|
248
|
+
|
249
|
+
class fzset(frozenset):
|
250
|
+
def __repr__(self):
|
251
|
+
return '{%s}' % ', '.join(map(repr, self))
|
252
|
+
|
253
|
+
|
254
|
+
def classify_bool(seq: Iterable, pred: Callable) -> Any:
|
255
|
+
false_elems = []
|
256
|
+
true_elems = [elem for elem in seq if pred(elem) or false_elems.append(elem)] # type: ignore[func-returns-value]
|
257
|
+
return true_elems, false_elems
|
258
|
+
|
259
|
+
|
260
|
+
def bfs(initial: Iterable, expand: Callable) -> Iterator:
|
261
|
+
open_q = deque(list(initial))
|
262
|
+
visited = set(open_q)
|
263
|
+
while open_q:
|
264
|
+
node = open_q.popleft()
|
265
|
+
yield node
|
266
|
+
for next_node in expand(node):
|
267
|
+
if next_node not in visited:
|
268
|
+
visited.add(next_node)
|
269
|
+
open_q.append(next_node)
|
270
|
+
|
271
|
+
def bfs_all_unique(initial, expand):
|
272
|
+
"bfs, but doesn't keep track of visited (aka seen), because there can be no repetitions"
|
273
|
+
open_q = deque(list(initial))
|
274
|
+
while open_q:
|
275
|
+
node = open_q.popleft()
|
276
|
+
yield node
|
277
|
+
open_q += expand(node)
|
278
|
+
|
279
|
+
|
280
|
+
def _serialize(value: Any, memo: Optional[SerializeMemoizer]) -> Any:
|
281
|
+
if isinstance(value, Serialize):
|
282
|
+
return value.serialize(memo)
|
283
|
+
elif isinstance(value, list):
|
284
|
+
return [_serialize(elem, memo) for elem in value]
|
285
|
+
elif isinstance(value, frozenset):
|
286
|
+
return list(value) # TODO reversible?
|
287
|
+
elif isinstance(value, dict):
|
288
|
+
return {key:_serialize(elem, memo) for key, elem in value.items()}
|
289
|
+
# assert value is None or isinstance(value, (int, float, str, tuple)), value
|
290
|
+
return value
|
291
|
+
|
292
|
+
|
293
|
+
|
294
|
+
|
295
|
+
def small_factors(n: int, max_factor: int) -> List[Tuple[int, int]]:
|
296
|
+
"""
|
297
|
+
Splits n up into smaller factors and summands <= max_factor.
|
298
|
+
Returns a list of [(a, b), ...]
|
299
|
+
so that the following code returns n:
|
300
|
+
|
301
|
+
n = 1
|
302
|
+
for a, b in values:
|
303
|
+
n = n * a + b
|
304
|
+
|
305
|
+
Currently, we also keep a + b <= max_factor, but that might change
|
306
|
+
"""
|
307
|
+
assert n >= 0
|
308
|
+
assert max_factor > 2
|
309
|
+
if n <= max_factor:
|
310
|
+
return [(n, 0)]
|
311
|
+
|
312
|
+
for a in range(max_factor, 1, -1):
|
313
|
+
r, b = divmod(n, a)
|
314
|
+
if a + b <= max_factor:
|
315
|
+
return small_factors(r, max_factor) + [(a, b)]
|
316
|
+
assert False, "Failed to factorize %s" % n
|
317
|
+
|
318
|
+
|
319
|
+
class OrderedSet(AbstractSet[T]):
|
320
|
+
"""A minimal OrderedSet implementation, using a dictionary.
|
321
|
+
|
322
|
+
(relies on the dictionary being ordered)
|
323
|
+
"""
|
324
|
+
def __init__(self, items: Iterable[T] =()):
|
325
|
+
self.d = dict.fromkeys(items)
|
326
|
+
|
327
|
+
def __contains__(self, item: Any) -> bool:
|
328
|
+
return item in self.d
|
329
|
+
|
330
|
+
def add(self, item: T):
|
331
|
+
self.d[item] = None
|
332
|
+
|
333
|
+
def __iter__(self) -> Iterator[T]:
|
334
|
+
return iter(self.d)
|
335
|
+
|
336
|
+
def remove(self, item: T):
|
337
|
+
del self.d[item]
|
338
|
+
|
339
|
+
def __bool__(self):
|
340
|
+
return bool(self.d)
|
341
|
+
|
342
|
+
def __len__(self) -> int:
|
343
|
+
return len(self.d)
|