ccxt 4.2.76__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 +25 -0
- ccxt/abstract/kucoinfutures.py +35 -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 +3513 -1511
- 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 +3105 -881
- 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 +239 -50
- ccxt/async_support/bitget.py +1513 -563
- ccxt/async_support/bithumb.py +201 -67
- 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 +403 -150
- 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 +2326 -1255
- ccxt/async_support/cex.py +1409 -1329
- ccxt/async_support/coinbase.py +1455 -288
- 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 +467 -158
- ccxt/async_support/deribit.py +558 -324
- 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 +1473 -464
- 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 +1634 -269
- 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 +1050 -355
- 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 +1777 -455
- 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 +1155 -295
- 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 +1729 -482
- 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 +3513 -1511
- ccxt/binancecoinm.py +2 -1
- ccxt/binanceus.py +12 -1
- ccxt/binanceusdm.py +3 -1
- ccxt/bingx.py +3105 -881
- 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 +239 -50
- ccxt/bitget.py +1513 -563
- ccxt/bithumb.py +200 -67
- 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 +403 -150
- ccxt/btcalpha.py +161 -55
- ccxt/btcbox.py +250 -34
- ccxt/btcmarkets.py +232 -85
- ccxt/btcturk.py +159 -60
- ccxt/bybit.py +2326 -1255
- ccxt/cex.py +1408 -1329
- ccxt/coinbase.py +1455 -288
- 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 +467 -158
- ccxt/deribit.py +558 -324
- ccxt/digifinex.py +340 -223
- ccxt/ellipx.py +1826 -0
- ccxt/exmo.py +259 -128
- ccxt/gate.py +1473 -464
- 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 +1633 -269
- 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 +1050 -355
- 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 +1777 -455
- 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 +63 -15
- 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 +204 -82
- 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 +967 -661
- 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 +168 -32
- ccxt/pro/exmo.py +253 -21
- 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 +93 -34
- ccxt/pro/poloniex.py +129 -50
- ccxt/pro/poloniexfutures.py +53 -32
- ccxt/pro/probit.py +93 -86
- 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 +486 -70
- 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} +465 -407
- ccxt/test/tests_helpers.py +285 -0
- ccxt/test/tests_init.py +39 -0
- ccxt/test/{test_sync.py → tests_sync.py} +465 -409
- 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 +1155 -295
- 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.76.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.76.dist-info/METADATA +0 -626
- ccxt-4.2.76.dist-info/RECORD +0 -534
- {ccxt-4.2.76.dist-info → ccxt-4.4.48.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,340 @@
|
|
1
|
+
"""This module implements a CYK parser."""
|
2
|
+
|
3
|
+
# Author: https://github.com/ehudt (2018)
|
4
|
+
#
|
5
|
+
# Adapted by Erez
|
6
|
+
|
7
|
+
|
8
|
+
from collections import defaultdict
|
9
|
+
import itertools
|
10
|
+
|
11
|
+
from ..exceptions import ParseError
|
12
|
+
from ..lexer import Token
|
13
|
+
from ..tree import Tree
|
14
|
+
from ..grammar import Terminal as T, NonTerminal as NT, Symbol
|
15
|
+
|
16
|
+
def match(t, s):
|
17
|
+
assert isinstance(t, T)
|
18
|
+
return t.name == s.type
|
19
|
+
|
20
|
+
|
21
|
+
class Rule:
|
22
|
+
"""Context-free grammar rule."""
|
23
|
+
|
24
|
+
def __init__(self, lhs, rhs, weight, alias):
|
25
|
+
super(Rule, self).__init__()
|
26
|
+
assert isinstance(lhs, NT), lhs
|
27
|
+
assert all(isinstance(x, NT) or isinstance(x, T) for x in rhs), rhs
|
28
|
+
self.lhs = lhs
|
29
|
+
self.rhs = rhs
|
30
|
+
self.weight = weight
|
31
|
+
self.alias = alias
|
32
|
+
|
33
|
+
def __str__(self):
|
34
|
+
return '%s -> %s' % (str(self.lhs), ' '.join(str(x) for x in self.rhs))
|
35
|
+
|
36
|
+
def __repr__(self):
|
37
|
+
return str(self)
|
38
|
+
|
39
|
+
def __hash__(self):
|
40
|
+
return hash((self.lhs, tuple(self.rhs)))
|
41
|
+
|
42
|
+
def __eq__(self, other):
|
43
|
+
return self.lhs == other.lhs and self.rhs == other.rhs
|
44
|
+
|
45
|
+
def __ne__(self, other):
|
46
|
+
return not (self == other)
|
47
|
+
|
48
|
+
|
49
|
+
class Grammar:
|
50
|
+
"""Context-free grammar."""
|
51
|
+
|
52
|
+
def __init__(self, rules):
|
53
|
+
self.rules = frozenset(rules)
|
54
|
+
|
55
|
+
def __eq__(self, other):
|
56
|
+
return self.rules == other.rules
|
57
|
+
|
58
|
+
def __str__(self):
|
59
|
+
return '\n' + '\n'.join(sorted(repr(x) for x in self.rules)) + '\n'
|
60
|
+
|
61
|
+
def __repr__(self):
|
62
|
+
return str(self)
|
63
|
+
|
64
|
+
|
65
|
+
# Parse tree data structures
|
66
|
+
class RuleNode:
|
67
|
+
"""A node in the parse tree, which also contains the full rhs rule."""
|
68
|
+
|
69
|
+
def __init__(self, rule, children, weight=0):
|
70
|
+
self.rule = rule
|
71
|
+
self.children = children
|
72
|
+
self.weight = weight
|
73
|
+
|
74
|
+
def __repr__(self):
|
75
|
+
return 'RuleNode(%s, [%s])' % (repr(self.rule.lhs), ', '.join(str(x) for x in self.children))
|
76
|
+
|
77
|
+
|
78
|
+
|
79
|
+
class Parser:
|
80
|
+
"""Parser wrapper."""
|
81
|
+
|
82
|
+
def __init__(self, rules):
|
83
|
+
super(Parser, self).__init__()
|
84
|
+
self.orig_rules = {rule: rule for rule in rules}
|
85
|
+
rules = [self._to_rule(rule) for rule in rules]
|
86
|
+
self.grammar = to_cnf(Grammar(rules))
|
87
|
+
|
88
|
+
def _to_rule(self, lark_rule):
|
89
|
+
"""Converts a lark rule, (lhs, rhs, callback, options), to a Rule."""
|
90
|
+
assert isinstance(lark_rule.origin, NT)
|
91
|
+
assert all(isinstance(x, Symbol) for x in lark_rule.expansion)
|
92
|
+
return Rule(
|
93
|
+
lark_rule.origin, lark_rule.expansion,
|
94
|
+
weight=lark_rule.options.priority if lark_rule.options.priority else 0,
|
95
|
+
alias=lark_rule)
|
96
|
+
|
97
|
+
def parse(self, tokenized, start): # pylint: disable=invalid-name
|
98
|
+
"""Parses input, which is a list of tokens."""
|
99
|
+
assert start
|
100
|
+
start = NT(start)
|
101
|
+
|
102
|
+
table, trees = _parse(tokenized, self.grammar)
|
103
|
+
# Check if the parse succeeded.
|
104
|
+
if all(r.lhs != start for r in table[(0, len(tokenized) - 1)]):
|
105
|
+
raise ParseError('Parsing failed.')
|
106
|
+
parse = trees[(0, len(tokenized) - 1)][start]
|
107
|
+
return self._to_tree(revert_cnf(parse))
|
108
|
+
|
109
|
+
def _to_tree(self, rule_node):
|
110
|
+
"""Converts a RuleNode parse tree to a lark Tree."""
|
111
|
+
orig_rule = self.orig_rules[rule_node.rule.alias]
|
112
|
+
children = []
|
113
|
+
for child in rule_node.children:
|
114
|
+
if isinstance(child, RuleNode):
|
115
|
+
children.append(self._to_tree(child))
|
116
|
+
else:
|
117
|
+
assert isinstance(child.name, Token)
|
118
|
+
children.append(child.name)
|
119
|
+
t = Tree(orig_rule.origin, children)
|
120
|
+
t.rule=orig_rule
|
121
|
+
return t
|
122
|
+
|
123
|
+
|
124
|
+
def print_parse(node, indent=0):
|
125
|
+
if isinstance(node, RuleNode):
|
126
|
+
print(' ' * (indent * 2) + str(node.rule.lhs))
|
127
|
+
for child in node.children:
|
128
|
+
print_parse(child, indent + 1)
|
129
|
+
else:
|
130
|
+
print(' ' * (indent * 2) + str(node.s))
|
131
|
+
|
132
|
+
|
133
|
+
def _parse(s, g):
|
134
|
+
"""Parses sentence 's' using CNF grammar 'g'."""
|
135
|
+
# The CYK table. Indexed with a 2-tuple: (start pos, end pos)
|
136
|
+
table = defaultdict(set)
|
137
|
+
# Top-level structure is similar to the CYK table. Each cell is a dict from
|
138
|
+
# rule name to the best (lightest) tree for that rule.
|
139
|
+
trees = defaultdict(dict)
|
140
|
+
# Populate base case with existing terminal production rules
|
141
|
+
for i, w in enumerate(s):
|
142
|
+
for terminal, rules in g.terminal_rules.items():
|
143
|
+
if match(terminal, w):
|
144
|
+
for rule in rules:
|
145
|
+
table[(i, i)].add(rule)
|
146
|
+
if (rule.lhs not in trees[(i, i)] or
|
147
|
+
rule.weight < trees[(i, i)][rule.lhs].weight):
|
148
|
+
trees[(i, i)][rule.lhs] = RuleNode(rule, [T(w)], weight=rule.weight)
|
149
|
+
|
150
|
+
# Iterate over lengths of sub-sentences
|
151
|
+
for l in range(2, len(s) + 1):
|
152
|
+
# Iterate over sub-sentences with the given length
|
153
|
+
for i in range(len(s) - l + 1):
|
154
|
+
# Choose partition of the sub-sentence in [1, l)
|
155
|
+
for p in range(i + 1, i + l):
|
156
|
+
span1 = (i, p - 1)
|
157
|
+
span2 = (p, i + l - 1)
|
158
|
+
for r1, r2 in itertools.product(table[span1], table[span2]):
|
159
|
+
for rule in g.nonterminal_rules.get((r1.lhs, r2.lhs), []):
|
160
|
+
table[(i, i + l - 1)].add(rule)
|
161
|
+
r1_tree = trees[span1][r1.lhs]
|
162
|
+
r2_tree = trees[span2][r2.lhs]
|
163
|
+
rule_total_weight = rule.weight + r1_tree.weight + r2_tree.weight
|
164
|
+
if (rule.lhs not in trees[(i, i + l - 1)]
|
165
|
+
or rule_total_weight < trees[(i, i + l - 1)][rule.lhs].weight):
|
166
|
+
trees[(i, i + l - 1)][rule.lhs] = RuleNode(rule, [r1_tree, r2_tree], weight=rule_total_weight)
|
167
|
+
return table, trees
|
168
|
+
|
169
|
+
|
170
|
+
# This section implements context-free grammar converter to Chomsky normal form.
|
171
|
+
# It also implements a conversion of parse trees from its CNF to the original
|
172
|
+
# grammar.
|
173
|
+
# Overview:
|
174
|
+
# Applies the following operations in this order:
|
175
|
+
# * TERM: Eliminates non-solitary terminals from all rules
|
176
|
+
# * BIN: Eliminates rules with more than 2 symbols on their right-hand-side.
|
177
|
+
# * UNIT: Eliminates non-terminal unit rules
|
178
|
+
#
|
179
|
+
# The following grammar characteristics aren't featured:
|
180
|
+
# * Start symbol appears on RHS
|
181
|
+
# * Empty rules (epsilon rules)
|
182
|
+
|
183
|
+
|
184
|
+
class CnfWrapper:
|
185
|
+
"""CNF wrapper for grammar.
|
186
|
+
|
187
|
+
Validates that the input grammar is CNF and provides helper data structures.
|
188
|
+
"""
|
189
|
+
|
190
|
+
def __init__(self, grammar):
|
191
|
+
super(CnfWrapper, self).__init__()
|
192
|
+
self.grammar = grammar
|
193
|
+
self.rules = grammar.rules
|
194
|
+
self.terminal_rules = defaultdict(list)
|
195
|
+
self.nonterminal_rules = defaultdict(list)
|
196
|
+
for r in self.rules:
|
197
|
+
# Validate that the grammar is CNF and populate auxiliary data structures.
|
198
|
+
assert isinstance(r.lhs, NT), r
|
199
|
+
if len(r.rhs) not in [1, 2]:
|
200
|
+
raise ParseError("CYK doesn't support empty rules")
|
201
|
+
if len(r.rhs) == 1 and isinstance(r.rhs[0], T):
|
202
|
+
self.terminal_rules[r.rhs[0]].append(r)
|
203
|
+
elif len(r.rhs) == 2 and all(isinstance(x, NT) for x in r.rhs):
|
204
|
+
self.nonterminal_rules[tuple(r.rhs)].append(r)
|
205
|
+
else:
|
206
|
+
assert False, r
|
207
|
+
|
208
|
+
def __eq__(self, other):
|
209
|
+
return self.grammar == other.grammar
|
210
|
+
|
211
|
+
def __repr__(self):
|
212
|
+
return repr(self.grammar)
|
213
|
+
|
214
|
+
|
215
|
+
class UnitSkipRule(Rule):
|
216
|
+
"""A rule that records NTs that were skipped during transformation."""
|
217
|
+
|
218
|
+
def __init__(self, lhs, rhs, skipped_rules, weight, alias):
|
219
|
+
super(UnitSkipRule, self).__init__(lhs, rhs, weight, alias)
|
220
|
+
self.skipped_rules = skipped_rules
|
221
|
+
|
222
|
+
def __eq__(self, other):
|
223
|
+
return isinstance(other, type(self)) and self.skipped_rules == other.skipped_rules
|
224
|
+
|
225
|
+
__hash__ = Rule.__hash__
|
226
|
+
|
227
|
+
|
228
|
+
def build_unit_skiprule(unit_rule, target_rule):
|
229
|
+
skipped_rules = []
|
230
|
+
if isinstance(unit_rule, UnitSkipRule):
|
231
|
+
skipped_rules += unit_rule.skipped_rules
|
232
|
+
skipped_rules.append(target_rule)
|
233
|
+
if isinstance(target_rule, UnitSkipRule):
|
234
|
+
skipped_rules += target_rule.skipped_rules
|
235
|
+
return UnitSkipRule(unit_rule.lhs, target_rule.rhs, skipped_rules,
|
236
|
+
weight=unit_rule.weight + target_rule.weight, alias=unit_rule.alias)
|
237
|
+
|
238
|
+
|
239
|
+
def get_any_nt_unit_rule(g):
|
240
|
+
"""Returns a non-terminal unit rule from 'g', or None if there is none."""
|
241
|
+
for rule in g.rules:
|
242
|
+
if len(rule.rhs) == 1 and isinstance(rule.rhs[0], NT):
|
243
|
+
return rule
|
244
|
+
return None
|
245
|
+
|
246
|
+
|
247
|
+
def _remove_unit_rule(g, rule):
|
248
|
+
"""Removes 'rule' from 'g' without changing the language produced by 'g'."""
|
249
|
+
new_rules = [x for x in g.rules if x != rule]
|
250
|
+
refs = [x for x in g.rules if x.lhs == rule.rhs[0]]
|
251
|
+
new_rules += [build_unit_skiprule(rule, ref) for ref in refs]
|
252
|
+
return Grammar(new_rules)
|
253
|
+
|
254
|
+
|
255
|
+
def _split(rule):
|
256
|
+
"""Splits a rule whose len(rhs) > 2 into shorter rules."""
|
257
|
+
rule_str = str(rule.lhs) + '__' + '_'.join(str(x) for x in rule.rhs)
|
258
|
+
rule_name = '__SP_%s' % (rule_str) + '_%d'
|
259
|
+
yield Rule(rule.lhs, [rule.rhs[0], NT(rule_name % 1)], weight=rule.weight, alias=rule.alias)
|
260
|
+
for i in range(1, len(rule.rhs) - 2):
|
261
|
+
yield Rule(NT(rule_name % i), [rule.rhs[i], NT(rule_name % (i + 1))], weight=0, alias='Split')
|
262
|
+
yield Rule(NT(rule_name % (len(rule.rhs) - 2)), rule.rhs[-2:], weight=0, alias='Split')
|
263
|
+
|
264
|
+
|
265
|
+
def _term(g):
|
266
|
+
"""Applies the TERM rule on 'g' (see top comment)."""
|
267
|
+
all_t = {x for rule in g.rules for x in rule.rhs if isinstance(x, T)}
|
268
|
+
t_rules = {t: Rule(NT('__T_%s' % str(t)), [t], weight=0, alias='Term') for t in all_t}
|
269
|
+
new_rules = []
|
270
|
+
for rule in g.rules:
|
271
|
+
if len(rule.rhs) > 1 and any(isinstance(x, T) for x in rule.rhs):
|
272
|
+
new_rhs = [t_rules[x].lhs if isinstance(x, T) else x for x in rule.rhs]
|
273
|
+
new_rules.append(Rule(rule.lhs, new_rhs, weight=rule.weight, alias=rule.alias))
|
274
|
+
new_rules.extend(v for k, v in t_rules.items() if k in rule.rhs)
|
275
|
+
else:
|
276
|
+
new_rules.append(rule)
|
277
|
+
return Grammar(new_rules)
|
278
|
+
|
279
|
+
|
280
|
+
def _bin(g):
|
281
|
+
"""Applies the BIN rule to 'g' (see top comment)."""
|
282
|
+
new_rules = []
|
283
|
+
for rule in g.rules:
|
284
|
+
if len(rule.rhs) > 2:
|
285
|
+
new_rules += _split(rule)
|
286
|
+
else:
|
287
|
+
new_rules.append(rule)
|
288
|
+
return Grammar(new_rules)
|
289
|
+
|
290
|
+
|
291
|
+
def _unit(g):
|
292
|
+
"""Applies the UNIT rule to 'g' (see top comment)."""
|
293
|
+
nt_unit_rule = get_any_nt_unit_rule(g)
|
294
|
+
while nt_unit_rule:
|
295
|
+
g = _remove_unit_rule(g, nt_unit_rule)
|
296
|
+
nt_unit_rule = get_any_nt_unit_rule(g)
|
297
|
+
return g
|
298
|
+
|
299
|
+
|
300
|
+
def to_cnf(g):
|
301
|
+
"""Creates a CNF grammar from a general context-free grammar 'g'."""
|
302
|
+
g = _unit(_bin(_term(g)))
|
303
|
+
return CnfWrapper(g)
|
304
|
+
|
305
|
+
|
306
|
+
def unroll_unit_skiprule(lhs, orig_rhs, skipped_rules, children, weight, alias):
|
307
|
+
if not skipped_rules:
|
308
|
+
return RuleNode(Rule(lhs, orig_rhs, weight=weight, alias=alias), children, weight=weight)
|
309
|
+
else:
|
310
|
+
weight = weight - skipped_rules[0].weight
|
311
|
+
return RuleNode(
|
312
|
+
Rule(lhs, [skipped_rules[0].lhs], weight=weight, alias=alias), [
|
313
|
+
unroll_unit_skiprule(skipped_rules[0].lhs, orig_rhs,
|
314
|
+
skipped_rules[1:], children,
|
315
|
+
skipped_rules[0].weight, skipped_rules[0].alias)
|
316
|
+
], weight=weight)
|
317
|
+
|
318
|
+
|
319
|
+
def revert_cnf(node):
|
320
|
+
"""Reverts a parse tree (RuleNode) to its original non-CNF form (Node)."""
|
321
|
+
if isinstance(node, T):
|
322
|
+
return node
|
323
|
+
# Reverts TERM rule.
|
324
|
+
if node.rule.lhs.name.startswith('__T_'):
|
325
|
+
return node.children[0]
|
326
|
+
else:
|
327
|
+
children = []
|
328
|
+
for child in map(revert_cnf, node.children):
|
329
|
+
# Reverts BIN rule.
|
330
|
+
if isinstance(child, RuleNode) and child.rule.lhs.name.startswith('__SP_'):
|
331
|
+
children += child.children
|
332
|
+
else:
|
333
|
+
children.append(child)
|
334
|
+
# Reverts UNIT rule.
|
335
|
+
if isinstance(node.rule, UnitSkipRule):
|
336
|
+
return unroll_unit_skiprule(node.rule.lhs, node.rule.rhs,
|
337
|
+
node.rule.skipped_rules, children,
|
338
|
+
node.rule.weight, node.rule.alias)
|
339
|
+
else:
|
340
|
+
return RuleNode(node.rule, children)
|
@@ -0,0 +1,314 @@
|
|
1
|
+
"""This module implements an Earley parser.
|
2
|
+
|
3
|
+
The core Earley algorithm used here is based on Elizabeth Scott's implementation, here:
|
4
|
+
https://www.sciencedirect.com/science/article/pii/S1571066108001497
|
5
|
+
|
6
|
+
That is probably the best reference for understanding the algorithm here.
|
7
|
+
|
8
|
+
The Earley parser outputs an SPPF-tree as per that document. The SPPF tree format
|
9
|
+
is explained here: https://lark-parser.readthedocs.io/en/latest/_static/sppf/sppf.html
|
10
|
+
"""
|
11
|
+
|
12
|
+
from typing import TYPE_CHECKING, Callable, Optional, List, Any
|
13
|
+
from collections import deque
|
14
|
+
|
15
|
+
from ..lexer import Token
|
16
|
+
from ..tree import Tree
|
17
|
+
from ..exceptions import UnexpectedEOF, UnexpectedToken
|
18
|
+
from ..utils import logger, OrderedSet, dedup_list
|
19
|
+
from .grammar_analysis import GrammarAnalyzer
|
20
|
+
from ..grammar import NonTerminal
|
21
|
+
from .earley_common import Item
|
22
|
+
from .earley_forest import ForestSumVisitor, SymbolNode, StableSymbolNode, TokenNode, ForestToParseTree
|
23
|
+
|
24
|
+
if TYPE_CHECKING:
|
25
|
+
from ..common import LexerConf, ParserConf
|
26
|
+
|
27
|
+
class Parser:
|
28
|
+
lexer_conf: 'LexerConf'
|
29
|
+
parser_conf: 'ParserConf'
|
30
|
+
debug: bool
|
31
|
+
|
32
|
+
def __init__(self, lexer_conf: 'LexerConf', parser_conf: 'ParserConf', term_matcher: Callable,
|
33
|
+
resolve_ambiguity: bool=True, debug: bool=False,
|
34
|
+
tree_class: Optional[Callable[[str, List], Any]]=Tree, ordered_sets: bool=True):
|
35
|
+
analysis = GrammarAnalyzer(parser_conf)
|
36
|
+
self.lexer_conf = lexer_conf
|
37
|
+
self.parser_conf = parser_conf
|
38
|
+
self.resolve_ambiguity = resolve_ambiguity
|
39
|
+
self.debug = debug
|
40
|
+
self.Tree = tree_class
|
41
|
+
self.Set = OrderedSet if ordered_sets else set
|
42
|
+
self.SymbolNode = StableSymbolNode if ordered_sets else SymbolNode
|
43
|
+
|
44
|
+
self.FIRST = analysis.FIRST
|
45
|
+
self.NULLABLE = analysis.NULLABLE
|
46
|
+
self.callbacks = parser_conf.callbacks
|
47
|
+
# TODO add typing info
|
48
|
+
self.predictions = {} # type: ignore[var-annotated]
|
49
|
+
|
50
|
+
## These could be moved to the grammar analyzer. Pre-computing these is *much* faster than
|
51
|
+
# the slow 'isupper' in is_terminal.
|
52
|
+
self.TERMINALS = { sym for r in parser_conf.rules for sym in r.expansion if sym.is_term }
|
53
|
+
self.NON_TERMINALS = { sym for r in parser_conf.rules for sym in r.expansion if not sym.is_term }
|
54
|
+
|
55
|
+
self.forest_sum_visitor = None
|
56
|
+
for rule in parser_conf.rules:
|
57
|
+
if rule.origin not in self.predictions:
|
58
|
+
self.predictions[rule.origin] = [x.rule for x in analysis.expand_rule(rule.origin)]
|
59
|
+
|
60
|
+
## Detect if any rules/terminals have priorities set. If the user specified priority = None, then
|
61
|
+
# the priorities will be stripped from all rules/terminals before they reach us, allowing us to
|
62
|
+
# skip the extra tree walk. We'll also skip this if the user just didn't specify priorities
|
63
|
+
# on any rules/terminals.
|
64
|
+
if self.forest_sum_visitor is None and rule.options.priority is not None:
|
65
|
+
self.forest_sum_visitor = ForestSumVisitor
|
66
|
+
|
67
|
+
# Check terminals for priorities
|
68
|
+
# Ignore terminal priorities if the basic lexer is used
|
69
|
+
if self.lexer_conf.lexer_type != 'basic' and self.forest_sum_visitor is None:
|
70
|
+
for term in self.lexer_conf.terminals:
|
71
|
+
if term.priority:
|
72
|
+
self.forest_sum_visitor = ForestSumVisitor
|
73
|
+
break
|
74
|
+
|
75
|
+
self.term_matcher = term_matcher
|
76
|
+
|
77
|
+
|
78
|
+
def predict_and_complete(self, i, to_scan, columns, transitives):
|
79
|
+
"""The core Earley Predictor and Completer.
|
80
|
+
|
81
|
+
At each stage of the input, we handling any completed items (things
|
82
|
+
that matched on the last cycle) and use those to predict what should
|
83
|
+
come next in the input stream. The completions and any predicted
|
84
|
+
non-terminals are recursively processed until we reach a set of,
|
85
|
+
which can be added to the scan list for the next scanner cycle."""
|
86
|
+
# Held Completions (H in E.Scotts paper).
|
87
|
+
node_cache = {}
|
88
|
+
held_completions = {}
|
89
|
+
|
90
|
+
column = columns[i]
|
91
|
+
# R (items) = Ei (column.items)
|
92
|
+
items = deque(column)
|
93
|
+
while items:
|
94
|
+
item = items.pop() # remove an element, A say, from R
|
95
|
+
|
96
|
+
### The Earley completer
|
97
|
+
if item.is_complete: ### (item.s == string)
|
98
|
+
if item.node is None:
|
99
|
+
label = (item.s, item.start, i)
|
100
|
+
item.node = node_cache[label] if label in node_cache else node_cache.setdefault(label, self.SymbolNode(*label))
|
101
|
+
item.node.add_family(item.s, item.rule, item.start, None, None)
|
102
|
+
|
103
|
+
# create_leo_transitives(item.rule.origin, item.start)
|
104
|
+
|
105
|
+
###R Joop Leo right recursion Completer
|
106
|
+
if item.rule.origin in transitives[item.start]:
|
107
|
+
transitive = transitives[item.start][item.s]
|
108
|
+
if transitive.previous in transitives[transitive.column]:
|
109
|
+
root_transitive = transitives[transitive.column][transitive.previous]
|
110
|
+
else:
|
111
|
+
root_transitive = transitive
|
112
|
+
|
113
|
+
new_item = Item(transitive.rule, transitive.ptr, transitive.start)
|
114
|
+
label = (root_transitive.s, root_transitive.start, i)
|
115
|
+
new_item.node = node_cache[label] if label in node_cache else node_cache.setdefault(label, self.SymbolNode(*label))
|
116
|
+
new_item.node.add_path(root_transitive, item.node)
|
117
|
+
if new_item.expect in self.TERMINALS:
|
118
|
+
# Add (B :: aC.B, h, y) to Q
|
119
|
+
to_scan.add(new_item)
|
120
|
+
elif new_item not in column:
|
121
|
+
# Add (B :: aC.B, h, y) to Ei and R
|
122
|
+
column.add(new_item)
|
123
|
+
items.append(new_item)
|
124
|
+
###R Regular Earley completer
|
125
|
+
else:
|
126
|
+
# Empty has 0 length. If we complete an empty symbol in a particular
|
127
|
+
# parse step, we need to be able to use that same empty symbol to complete
|
128
|
+
# any predictions that result, that themselves require empty. Avoids
|
129
|
+
# infinite recursion on empty symbols.
|
130
|
+
# held_completions is 'H' in E.Scott's paper.
|
131
|
+
is_empty_item = item.start == i
|
132
|
+
if is_empty_item:
|
133
|
+
held_completions[item.rule.origin] = item.node
|
134
|
+
|
135
|
+
originators = [originator for originator in columns[item.start] if originator.expect is not None and originator.expect == item.s]
|
136
|
+
for originator in originators:
|
137
|
+
new_item = originator.advance()
|
138
|
+
label = (new_item.s, originator.start, i)
|
139
|
+
new_item.node = node_cache[label] if label in node_cache else node_cache.setdefault(label, self.SymbolNode(*label))
|
140
|
+
new_item.node.add_family(new_item.s, new_item.rule, i, originator.node, item.node)
|
141
|
+
if new_item.expect in self.TERMINALS:
|
142
|
+
# Add (B :: aC.B, h, y) to Q
|
143
|
+
to_scan.add(new_item)
|
144
|
+
elif new_item not in column:
|
145
|
+
# Add (B :: aC.B, h, y) to Ei and R
|
146
|
+
column.add(new_item)
|
147
|
+
items.append(new_item)
|
148
|
+
|
149
|
+
### The Earley predictor
|
150
|
+
elif item.expect in self.NON_TERMINALS: ### (item.s == lr0)
|
151
|
+
new_items = []
|
152
|
+
for rule in self.predictions[item.expect]:
|
153
|
+
new_item = Item(rule, 0, i)
|
154
|
+
new_items.append(new_item)
|
155
|
+
|
156
|
+
# Process any held completions (H).
|
157
|
+
if item.expect in held_completions:
|
158
|
+
new_item = item.advance()
|
159
|
+
label = (new_item.s, item.start, i)
|
160
|
+
new_item.node = node_cache[label] if label in node_cache else node_cache.setdefault(label, self.SymbolNode(*label))
|
161
|
+
new_item.node.add_family(new_item.s, new_item.rule, new_item.start, item.node, held_completions[item.expect])
|
162
|
+
new_items.append(new_item)
|
163
|
+
|
164
|
+
for new_item in new_items:
|
165
|
+
if new_item.expect in self.TERMINALS:
|
166
|
+
to_scan.add(new_item)
|
167
|
+
elif new_item not in column:
|
168
|
+
column.add(new_item)
|
169
|
+
items.append(new_item)
|
170
|
+
|
171
|
+
def _parse(self, lexer, columns, to_scan, start_symbol=None):
|
172
|
+
|
173
|
+
def is_quasi_complete(item):
|
174
|
+
if item.is_complete:
|
175
|
+
return True
|
176
|
+
|
177
|
+
quasi = item.advance()
|
178
|
+
while not quasi.is_complete:
|
179
|
+
if quasi.expect not in self.NULLABLE:
|
180
|
+
return False
|
181
|
+
if quasi.rule.origin == start_symbol and quasi.expect == start_symbol:
|
182
|
+
return False
|
183
|
+
quasi = quasi.advance()
|
184
|
+
return True
|
185
|
+
|
186
|
+
# def create_leo_transitives(origin, start):
|
187
|
+
# ... # removed at commit 4c1cfb2faf24e8f8bff7112627a00b94d261b420
|
188
|
+
|
189
|
+
def scan(i, token, to_scan):
|
190
|
+
"""The core Earley Scanner.
|
191
|
+
|
192
|
+
This is a custom implementation of the scanner that uses the
|
193
|
+
Lark lexer to match tokens. The scan list is built by the
|
194
|
+
Earley predictor, based on the previously completed tokens.
|
195
|
+
This ensures that at each phase of the parse we have a custom
|
196
|
+
lexer context, allowing for more complex ambiguities."""
|
197
|
+
next_to_scan = self.Set()
|
198
|
+
next_set = self.Set()
|
199
|
+
columns.append(next_set)
|
200
|
+
transitives.append({})
|
201
|
+
node_cache = {}
|
202
|
+
|
203
|
+
for item in self.Set(to_scan):
|
204
|
+
if match(item.expect, token):
|
205
|
+
new_item = item.advance()
|
206
|
+
label = (new_item.s, new_item.start, i)
|
207
|
+
# 'terminals' may not contain token.type when using %declare
|
208
|
+
# Additionally, token is not always a Token
|
209
|
+
# For example, it can be a Tree when using TreeMatcher
|
210
|
+
term = terminals.get(token.type) if isinstance(token, Token) else None
|
211
|
+
# Set the priority of the token node to 0 so that the
|
212
|
+
# terminal priorities do not affect the Tree chosen by
|
213
|
+
# ForestSumVisitor after the basic lexer has already
|
214
|
+
# "used up" the terminal priorities
|
215
|
+
token_node = TokenNode(token, term, priority=0)
|
216
|
+
new_item.node = node_cache[label] if label in node_cache else node_cache.setdefault(label, self.SymbolNode(*label))
|
217
|
+
new_item.node.add_family(new_item.s, item.rule, new_item.start, item.node, token_node)
|
218
|
+
|
219
|
+
if new_item.expect in self.TERMINALS:
|
220
|
+
# add (B ::= Aai+1.B, h, y) to Q'
|
221
|
+
next_to_scan.add(new_item)
|
222
|
+
else:
|
223
|
+
# add (B ::= Aa+1.B, h, y) to Ei+1
|
224
|
+
next_set.add(new_item)
|
225
|
+
|
226
|
+
if not next_set and not next_to_scan:
|
227
|
+
expect = {i.expect.name for i in to_scan}
|
228
|
+
raise UnexpectedToken(token, expect, considered_rules=set(to_scan), state=frozenset(i.s for i in to_scan))
|
229
|
+
|
230
|
+
return next_to_scan
|
231
|
+
|
232
|
+
|
233
|
+
# Define parser functions
|
234
|
+
match = self.term_matcher
|
235
|
+
|
236
|
+
terminals = self.lexer_conf.terminals_by_name
|
237
|
+
|
238
|
+
# Cache for nodes & tokens created in a particular parse step.
|
239
|
+
transitives = [{}]
|
240
|
+
|
241
|
+
## The main Earley loop.
|
242
|
+
# Run the Prediction/Completion cycle for any Items in the current Earley set.
|
243
|
+
# Completions will be added to the SPPF tree, and predictions will be recursively
|
244
|
+
# processed down to terminals/empty nodes to be added to the scanner for the next
|
245
|
+
# step.
|
246
|
+
expects = {i.expect for i in to_scan}
|
247
|
+
i = 0
|
248
|
+
for token in lexer.lex(expects):
|
249
|
+
self.predict_and_complete(i, to_scan, columns, transitives)
|
250
|
+
|
251
|
+
to_scan = scan(i, token, to_scan)
|
252
|
+
i += 1
|
253
|
+
|
254
|
+
expects.clear()
|
255
|
+
expects |= {i.expect for i in to_scan}
|
256
|
+
|
257
|
+
self.predict_and_complete(i, to_scan, columns, transitives)
|
258
|
+
|
259
|
+
## Column is now the final column in the parse.
|
260
|
+
assert i == len(columns)-1
|
261
|
+
return to_scan
|
262
|
+
|
263
|
+
def parse(self, lexer, start):
|
264
|
+
assert start, start
|
265
|
+
start_symbol = NonTerminal(start)
|
266
|
+
|
267
|
+
columns = [self.Set()]
|
268
|
+
to_scan = self.Set() # The scan buffer. 'Q' in E.Scott's paper.
|
269
|
+
|
270
|
+
## Predict for the start_symbol.
|
271
|
+
# Add predicted items to the first Earley set (for the predictor) if they
|
272
|
+
# result in a non-terminal, or the scanner if they result in a terminal.
|
273
|
+
for rule in self.predictions[start_symbol]:
|
274
|
+
item = Item(rule, 0, 0)
|
275
|
+
if item.expect in self.TERMINALS:
|
276
|
+
to_scan.add(item)
|
277
|
+
else:
|
278
|
+
columns[0].add(item)
|
279
|
+
|
280
|
+
to_scan = self._parse(lexer, columns, to_scan, start_symbol)
|
281
|
+
|
282
|
+
# If the parse was successful, the start
|
283
|
+
# symbol should have been completed in the last step of the Earley cycle, and will be in
|
284
|
+
# this column. Find the item for the start_symbol, which is the root of the SPPF tree.
|
285
|
+
solutions = dedup_list(n.node for n in columns[-1] if n.is_complete and n.node is not None and n.s == start_symbol and n.start == 0)
|
286
|
+
if not solutions:
|
287
|
+
expected_terminals = [t.expect.name for t in to_scan]
|
288
|
+
raise UnexpectedEOF(expected_terminals, state=frozenset(i.s for i in to_scan))
|
289
|
+
|
290
|
+
if self.debug:
|
291
|
+
from .earley_forest import ForestToPyDotVisitor
|
292
|
+
try:
|
293
|
+
debug_walker = ForestToPyDotVisitor()
|
294
|
+
except ImportError:
|
295
|
+
logger.warning("Cannot find dependency 'pydot', will not generate sppf debug image")
|
296
|
+
else:
|
297
|
+
for i, s in enumerate(solutions):
|
298
|
+
debug_walker.visit(s, f"sppf{i}.png")
|
299
|
+
|
300
|
+
|
301
|
+
if self.Tree is not None:
|
302
|
+
# Perform our SPPF -> AST conversion
|
303
|
+
transformer = ForestToParseTree(self.Tree, self.callbacks, self.forest_sum_visitor and self.forest_sum_visitor(), self.resolve_ambiguity)
|
304
|
+
solutions = [transformer.transform(s) for s in solutions]
|
305
|
+
|
306
|
+
if len(solutions) > 1:
|
307
|
+
t: Tree = self.Tree('_ambig', solutions)
|
308
|
+
t.expand_kids_by_data('_ambig') # solutions may themselves be _ambig nodes
|
309
|
+
return t
|
310
|
+
return solutions[0]
|
311
|
+
|
312
|
+
# return the root of the SPPF
|
313
|
+
# TODO return a list of solutions, or join them together somehow
|
314
|
+
return solutions[0]
|
@@ -0,0 +1,42 @@
|
|
1
|
+
"""This module implements useful building blocks for the Earley parser
|
2
|
+
"""
|
3
|
+
|
4
|
+
|
5
|
+
class Item:
|
6
|
+
"An Earley Item, the atom of the algorithm."
|
7
|
+
|
8
|
+
__slots__ = ('s', 'rule', 'ptr', 'start', 'is_complete', 'expect', 'previous', 'node', '_hash')
|
9
|
+
def __init__(self, rule, ptr, start):
|
10
|
+
self.is_complete = len(rule.expansion) == ptr
|
11
|
+
self.rule = rule # rule
|
12
|
+
self.ptr = ptr # ptr
|
13
|
+
self.start = start # j
|
14
|
+
self.node = None # w
|
15
|
+
if self.is_complete:
|
16
|
+
self.s = rule.origin
|
17
|
+
self.expect = None
|
18
|
+
self.previous = rule.expansion[ptr - 1] if ptr > 0 and len(rule.expansion) else None
|
19
|
+
else:
|
20
|
+
self.s = (rule, ptr)
|
21
|
+
self.expect = rule.expansion[ptr]
|
22
|
+
self.previous = rule.expansion[ptr - 1] if ptr > 0 and len(rule.expansion) else None
|
23
|
+
self._hash = hash((self.s, self.start, self.rule))
|
24
|
+
|
25
|
+
def advance(self):
|
26
|
+
return Item(self.rule, self.ptr + 1, self.start)
|
27
|
+
|
28
|
+
def __eq__(self, other):
|
29
|
+
return self is other or (self.s == other.s and self.start == other.start and self.rule == other.rule)
|
30
|
+
|
31
|
+
def __hash__(self):
|
32
|
+
return self._hash
|
33
|
+
|
34
|
+
def __repr__(self):
|
35
|
+
before = ( expansion.name for expansion in self.rule.expansion[:self.ptr] )
|
36
|
+
after = ( expansion.name for expansion in self.rule.expansion[self.ptr:] )
|
37
|
+
symbol = "{} ::= {}* {}".format(self.rule.origin.name, ' '.join(before), ' '.join(after))
|
38
|
+
return '%s (%d)' % (symbol, self.start)
|
39
|
+
|
40
|
+
|
41
|
+
# class TransitiveItem(Item):
|
42
|
+
# ... # removed at commit 4c1cfb2faf24e8f8bff7112627a00b94d261b420
|