ccxt 4.3.69__py2.py3-none-any.whl → 4.3.71__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 +3 -1
- ccxt/abstract/coinbaseinternational.py +1 -1
- ccxt/abstract/paradex.py +40 -0
- ccxt/async_support/__init__.py +3 -1
- ccxt/async_support/base/exchange.py +1 -1
- ccxt/async_support/blofin.py +63 -6
- ccxt/async_support/bybit.py +1 -1
- ccxt/async_support/coinbaseinternational.py +155 -2
- ccxt/async_support/cryptocom.py +12 -1
- ccxt/async_support/paradex.py +1966 -0
- ccxt/async_support/poloniex.py +1 -0
- ccxt/async_support/woo.py +4 -2
- ccxt/base/exchange.py +63 -1
- ccxt/blofin.py +63 -6
- ccxt/bybit.py +1 -1
- ccxt/coinbaseinternational.py +155 -2
- ccxt/cryptocom.py +12 -1
- ccxt/paradex.py +1966 -0
- ccxt/poloniex.py +1 -0
- ccxt/pro/__init__.py +5 -1
- ccxt/pro/bequant.py +4 -0
- ccxt/pro/blofin.py +608 -0
- ccxt/pro/coinbaseinternational.py +142 -11
- ccxt/pro/cryptocom.py +4 -1
- ccxt/pro/hitbtc.py +20 -8
- ccxt/pro/okx.py +6 -0
- ccxt/pro/paradex.py +340 -0
- ccxt/pro/poloniex.py +32 -10
- ccxt/pro/woo.py +5 -4
- 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/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/sympy/__init__.py +0 -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_extensions/__init__.py +0 -0
- ccxt/static_dependencies/typing_extensions/typing_extensions.py +3839 -0
- ccxt/static_dependencies/typing_inspect/__init__.py +0 -0
- ccxt/static_dependencies/typing_inspect/typing_inspect.py +851 -0
- ccxt/test/tests_async.py +43 -1
- ccxt/test/tests_sync.py +43 -1
- ccxt/woo.py +4 -2
- {ccxt-4.3.69.dist-info → ccxt-4.3.71.dist-info}/METADATA +8 -7
- {ccxt-4.3.69.dist-info → ccxt-4.3.71.dist-info}/RECORD +159 -33
- {ccxt-4.3.69.dist-info → ccxt-4.3.71.dist-info}/LICENSE.txt +0 -0
- {ccxt-4.3.69.dist-info → ccxt-4.3.71.dist-info}/WHEEL +0 -0
- {ccxt-4.3.69.dist-info → ccxt-4.3.71.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,182 @@
|
|
1
|
+
from dataclasses import dataclass
|
2
|
+
from typing import Dict, List, Union, cast
|
3
|
+
|
4
|
+
from ...marshmallow import Schema, fields, post_load
|
5
|
+
|
6
|
+
from ..cairo.felt import encode_shortstring
|
7
|
+
from ..hash.selector import get_selector_from_name
|
8
|
+
from ..hash.utils import compute_hash_on_elements
|
9
|
+
from ..models.typed_data import StarkNetDomainDict, TypedDataDict
|
10
|
+
|
11
|
+
|
12
|
+
@dataclass(frozen=True)
|
13
|
+
class Parameter:
|
14
|
+
"""
|
15
|
+
Dataclass representing a Parameter object
|
16
|
+
"""
|
17
|
+
|
18
|
+
name: str
|
19
|
+
type: str
|
20
|
+
|
21
|
+
|
22
|
+
@dataclass(frozen=True)
|
23
|
+
class TypedData:
|
24
|
+
"""
|
25
|
+
Dataclass representing a TypedData object
|
26
|
+
"""
|
27
|
+
|
28
|
+
types: Dict[str, List[Parameter]]
|
29
|
+
primary_type: str
|
30
|
+
domain: StarkNetDomainDict
|
31
|
+
message: dict
|
32
|
+
|
33
|
+
@staticmethod
|
34
|
+
def from_dict(data: TypedDataDict) -> "TypedData":
|
35
|
+
"""
|
36
|
+
Create TypedData dataclass from dictionary.
|
37
|
+
|
38
|
+
:param data: TypedData dictionary.
|
39
|
+
:return: TypedData dataclass instance.
|
40
|
+
"""
|
41
|
+
return cast(TypedData, TypedDataSchema().load(data))
|
42
|
+
|
43
|
+
def _is_struct(self, type_name: str) -> bool:
|
44
|
+
return type_name in self.types
|
45
|
+
|
46
|
+
def _encode_value(self, type_name: str, value: Union[int, str, dict, list]) -> int:
|
47
|
+
if is_pointer(type_name) and isinstance(value, list):
|
48
|
+
type_name = strip_pointer(type_name)
|
49
|
+
|
50
|
+
if self._is_struct(type_name):
|
51
|
+
return compute_hash_on_elements(
|
52
|
+
[self.struct_hash(type_name, data) for data in value]
|
53
|
+
)
|
54
|
+
return compute_hash_on_elements([int(get_hex(val), 16) for val in value])
|
55
|
+
|
56
|
+
if self._is_struct(type_name) and isinstance(value, dict):
|
57
|
+
return self.struct_hash(type_name, value)
|
58
|
+
|
59
|
+
value = cast(Union[int, str], value)
|
60
|
+
return int(get_hex(value), 16)
|
61
|
+
|
62
|
+
def _encode_data(self, type_name: str, data: dict) -> List[int]:
|
63
|
+
values = []
|
64
|
+
for param in self.types[type_name]:
|
65
|
+
encoded_value = self._encode_value(param.type, data[param.name])
|
66
|
+
values.append(encoded_value)
|
67
|
+
|
68
|
+
return values
|
69
|
+
|
70
|
+
def _get_dependencies(self, type_name: str) -> List[str]:
|
71
|
+
if type_name not in self.types:
|
72
|
+
# type_name is a primitive type, has no dependencies
|
73
|
+
return []
|
74
|
+
|
75
|
+
dependencies = set()
|
76
|
+
|
77
|
+
def collect_deps(type_name: str) -> None:
|
78
|
+
for param in self.types[type_name]:
|
79
|
+
fixed_type = strip_pointer(param.type)
|
80
|
+
if fixed_type in self.types and fixed_type not in dependencies:
|
81
|
+
dependencies.add(fixed_type)
|
82
|
+
# recursive call
|
83
|
+
collect_deps(fixed_type)
|
84
|
+
|
85
|
+
# collect dependencies into a set
|
86
|
+
collect_deps(type_name)
|
87
|
+
return [type_name, *list(dependencies)]
|
88
|
+
|
89
|
+
def _encode_type(self, type_name: str) -> str:
|
90
|
+
primary, *dependencies = self._get_dependencies(type_name)
|
91
|
+
types = [primary, *sorted(dependencies)]
|
92
|
+
|
93
|
+
def make_dependency_str(dependency):
|
94
|
+
lst = [f"{t.name}:{t.type}" for t in self.types[dependency]]
|
95
|
+
return f"{dependency}({','.join(lst)})"
|
96
|
+
|
97
|
+
return "".join([make_dependency_str(x) for x in types])
|
98
|
+
|
99
|
+
def type_hash(self, type_name: str) -> int:
|
100
|
+
"""
|
101
|
+
Calculate the hash of a type name.
|
102
|
+
|
103
|
+
:param type_name: Name of the type.
|
104
|
+
:return: Hash of the type name.
|
105
|
+
"""
|
106
|
+
return get_selector_from_name(self._encode_type(type_name))
|
107
|
+
|
108
|
+
def struct_hash(self, type_name: str, data: dict) -> int:
|
109
|
+
"""
|
110
|
+
Calculate the hash of a struct.
|
111
|
+
|
112
|
+
:param type_name: Name of the type.
|
113
|
+
:param data: Data defining the struct.
|
114
|
+
:return: Hash of the struct.
|
115
|
+
"""
|
116
|
+
return compute_hash_on_elements(
|
117
|
+
[self.type_hash(type_name), *self._encode_data(type_name, data)]
|
118
|
+
)
|
119
|
+
|
120
|
+
def message_hash(self, account_address: int) -> int:
|
121
|
+
"""
|
122
|
+
Calculate the hash of the message.
|
123
|
+
|
124
|
+
:param account_address: Address of an account.
|
125
|
+
:return: Hash of the message.
|
126
|
+
"""
|
127
|
+
message = [
|
128
|
+
encode_shortstring("StarkNet Message"),
|
129
|
+
self.struct_hash("StarkNetDomain", cast(dict, self.domain)),
|
130
|
+
account_address,
|
131
|
+
self.struct_hash(self.primary_type, self.message),
|
132
|
+
]
|
133
|
+
|
134
|
+
return compute_hash_on_elements(message)
|
135
|
+
|
136
|
+
|
137
|
+
def get_hex(value: Union[int, str]) -> str:
|
138
|
+
if isinstance(value, int):
|
139
|
+
return hex(value)
|
140
|
+
if value[:2] == "0x":
|
141
|
+
return value
|
142
|
+
if value.isnumeric():
|
143
|
+
return hex(int(value))
|
144
|
+
return hex(encode_shortstring(value))
|
145
|
+
|
146
|
+
|
147
|
+
def is_pointer(value: str) -> bool:
|
148
|
+
return len(value) > 0 and value[-1] == "*"
|
149
|
+
|
150
|
+
|
151
|
+
def strip_pointer(value: str) -> str:
|
152
|
+
if is_pointer(value):
|
153
|
+
return value[:-1]
|
154
|
+
return value
|
155
|
+
|
156
|
+
|
157
|
+
# pylint: disable=unused-argument
|
158
|
+
# pylint: disable=no-self-use
|
159
|
+
|
160
|
+
|
161
|
+
class ParameterSchema(Schema):
|
162
|
+
name = fields.String(data_key="name", required=True)
|
163
|
+
type = fields.String(data_key="type", required=True)
|
164
|
+
|
165
|
+
@post_load
|
166
|
+
def make_dataclass(self, data, **kwargs) -> Parameter:
|
167
|
+
return Parameter(**data)
|
168
|
+
|
169
|
+
|
170
|
+
class TypedDataSchema(Schema):
|
171
|
+
types = fields.Dict(
|
172
|
+
data_key="types",
|
173
|
+
keys=fields.Str(),
|
174
|
+
values=fields.List(fields.Nested(ParameterSchema())),
|
175
|
+
)
|
176
|
+
primary_type = fields.String(data_key="primaryType", required=True)
|
177
|
+
domain = fields.Dict(data_key="domain", required=True)
|
178
|
+
message = fields.Dict(data_key="message", required=True)
|
179
|
+
|
180
|
+
@post_load
|
181
|
+
def make_dataclass(self, data, **kwargs) -> TypedData:
|
182
|
+
return TypedData(**data)
|
File without changes
|
File without changes
|
@@ -0,0 +1,345 @@
|
|
1
|
+
import os
|
2
|
+
from ctypes import c_long, sizeof
|
3
|
+
from functools import reduce
|
4
|
+
from typing import Tuple as tTuple, Type
|
5
|
+
from warnings import warn
|
6
|
+
|
7
|
+
from .importtools import import_module
|
8
|
+
|
9
|
+
from .pythonmpq import PythonMPQ
|
10
|
+
|
11
|
+
from .ntheory import (
|
12
|
+
# bit_scan1 as python_bit_scan1,
|
13
|
+
# bit_scan0 as python_bit_scan0,
|
14
|
+
# remove as python_remove,
|
15
|
+
# factorial as python_factorial,
|
16
|
+
# sqrt as python_sqrt,
|
17
|
+
# sqrtrem as python_sqrtrem,
|
18
|
+
# gcd as python_gcd,
|
19
|
+
# lcm as python_lcm,
|
20
|
+
gcdext as python_gcdext,
|
21
|
+
# is_square as python_is_square,
|
22
|
+
# invert as python_invert,
|
23
|
+
# legendre as python_legendre,
|
24
|
+
# jacobi as python_jacobi,
|
25
|
+
# kronecker as python_kronecker,
|
26
|
+
# iroot as python_iroot,
|
27
|
+
# is_fermat_prp as python_is_fermat_prp,
|
28
|
+
# is_euler_prp as python_is_euler_prp,
|
29
|
+
# is_strong_prp as python_is_strong_prp,
|
30
|
+
# is_fibonacci_prp as python_is_fibonacci_prp,
|
31
|
+
# is_lucas_prp as python_is_lucas_prp,
|
32
|
+
# is_selfridge_prp as python_is_selfridge_prp,
|
33
|
+
# is_strong_lucas_prp as python_is_strong_lucas_prp,
|
34
|
+
# is_strong_selfridge_prp as python_is_strong_selfridge_prp,
|
35
|
+
# is_bpsw_prp as python_is_bpsw_prp,
|
36
|
+
# is_strong_bpsw_prp as python_is_strong_bpsw_prp,
|
37
|
+
)
|
38
|
+
|
39
|
+
|
40
|
+
__all__ = [
|
41
|
+
# GROUND_TYPES is either 'gmpy' or 'python' depending on which is used. If
|
42
|
+
# gmpy is installed then it will be used unless the environment variable
|
43
|
+
# SYMPY_GROUND_TYPES is set to something other than 'auto', 'gmpy', or
|
44
|
+
# 'gmpy2'.
|
45
|
+
'GROUND_TYPES',
|
46
|
+
|
47
|
+
# If HAS_GMPY is 0, no supported version of gmpy is available. Otherwise,
|
48
|
+
# HAS_GMPY will be 2 for gmpy2 if GROUND_TYPES is 'gmpy'. It used to be
|
49
|
+
# possible for HAS_GMPY to be 1 for gmpy but gmpy is no longer supported.
|
50
|
+
'HAS_GMPY',
|
51
|
+
|
52
|
+
# SYMPY_INTS is a tuple containing the base types for valid integer types.
|
53
|
+
# This is either (int,) or (int, type(mpz(0))) depending on GROUND_TYPES.
|
54
|
+
'SYMPY_INTS',
|
55
|
+
|
56
|
+
# MPQ is either gmpy.mpq or the Python equivalent from
|
57
|
+
# sympy.external.pythonmpq
|
58
|
+
'MPQ',
|
59
|
+
|
60
|
+
# MPZ is either gmpy.mpz or int.
|
61
|
+
'MPZ',
|
62
|
+
|
63
|
+
# 'bit_scan1',
|
64
|
+
# 'bit_scan0',
|
65
|
+
# 'remove',
|
66
|
+
# 'factorial',
|
67
|
+
# 'sqrt',
|
68
|
+
# 'is_square',
|
69
|
+
# 'sqrtrem',
|
70
|
+
# 'gcd',
|
71
|
+
# 'lcm',
|
72
|
+
'gcdext',
|
73
|
+
# 'invert',
|
74
|
+
# 'legendre',
|
75
|
+
# 'jacobi',
|
76
|
+
# 'kronecker',
|
77
|
+
# 'iroot',
|
78
|
+
# 'is_fermat_prp',
|
79
|
+
# 'is_euler_prp',
|
80
|
+
# 'is_strong_prp',
|
81
|
+
# 'is_fibonacci_prp',
|
82
|
+
# 'is_lucas_prp',
|
83
|
+
# 'is_selfridge_prp',
|
84
|
+
# 'is_strong_lucas_prp',
|
85
|
+
# 'is_strong_selfridge_prp',
|
86
|
+
# 'is_bpsw_prp',
|
87
|
+
# 'is_strong_bpsw_prp',
|
88
|
+
]
|
89
|
+
|
90
|
+
|
91
|
+
#
|
92
|
+
# Tested python-flint version. Future versions might work but we will only use
|
93
|
+
# them if explicitly requested by SYMPY_GROUND_TYPES=flint.
|
94
|
+
#
|
95
|
+
_PYTHON_FLINT_VERSION_NEEDED = "0.6.*"
|
96
|
+
|
97
|
+
|
98
|
+
def _flint_version_okay(flint_version):
|
99
|
+
flint_ver = flint_version.split('.')[:2]
|
100
|
+
needed_ver = _PYTHON_FLINT_VERSION_NEEDED.split('.')[:2]
|
101
|
+
return flint_ver == needed_ver
|
102
|
+
|
103
|
+
#
|
104
|
+
# We will only use gmpy2 >= 2.0.0
|
105
|
+
#
|
106
|
+
_GMPY2_MIN_VERSION = '2.0.0'
|
107
|
+
|
108
|
+
|
109
|
+
def _get_flint(sympy_ground_types):
|
110
|
+
if sympy_ground_types not in ('auto', 'flint'):
|
111
|
+
return None
|
112
|
+
|
113
|
+
try:
|
114
|
+
import flint
|
115
|
+
# Earlier versions of python-flint may not have __version__.
|
116
|
+
from flint import __version__ as _flint_version
|
117
|
+
except ImportError:
|
118
|
+
if sympy_ground_types == 'flint':
|
119
|
+
warn("SYMPY_GROUND_TYPES was set to flint but python-flint is not "
|
120
|
+
"installed. Falling back to other ground types.")
|
121
|
+
return None
|
122
|
+
|
123
|
+
if _flint_version_okay(_flint_version):
|
124
|
+
return flint
|
125
|
+
elif sympy_ground_types == 'auto':
|
126
|
+
warn(f"python-flint {_flint_version} is installed but only version "
|
127
|
+
f"{_PYTHON_FLINT_VERSION_NEEDED} will be used by default. "
|
128
|
+
f"Falling back to other ground types. Use "
|
129
|
+
f"SYMPY_GROUND_TYPES=flint to force the use of python-flint.")
|
130
|
+
return None
|
131
|
+
else:
|
132
|
+
warn(f"Using python-flint {_flint_version} because SYMPY_GROUND_TYPES "
|
133
|
+
f"is set to flint but this version of SymPy has only been tested "
|
134
|
+
f"with python-flint {_PYTHON_FLINT_VERSION_NEEDED}.")
|
135
|
+
return flint
|
136
|
+
|
137
|
+
|
138
|
+
def _get_gmpy2(sympy_ground_types):
|
139
|
+
if sympy_ground_types not in ('auto', 'gmpy', 'gmpy2'):
|
140
|
+
return None
|
141
|
+
|
142
|
+
gmpy = import_module('gmpy2', min_module_version=_GMPY2_MIN_VERSION,
|
143
|
+
module_version_attr='version', module_version_attr_call_args=())
|
144
|
+
|
145
|
+
if sympy_ground_types != 'auto' and gmpy is None:
|
146
|
+
warn("gmpy2 library is not installed, switching to 'python' ground types")
|
147
|
+
|
148
|
+
return gmpy
|
149
|
+
|
150
|
+
|
151
|
+
#
|
152
|
+
# SYMPY_GROUND_TYPES can be flint, gmpy, gmpy2, python or auto (default)
|
153
|
+
#
|
154
|
+
_SYMPY_GROUND_TYPES = os.environ.get('SYMPY_GROUND_TYPES', 'auto').lower()
|
155
|
+
_flint = None
|
156
|
+
_gmpy = None
|
157
|
+
|
158
|
+
#
|
159
|
+
# First handle auto-detection of flint/gmpy2. We will prefer flint if available
|
160
|
+
# or otherwise gmpy2 if available and then lastly the python types.
|
161
|
+
#
|
162
|
+
if _SYMPY_GROUND_TYPES in ('auto', 'flint'):
|
163
|
+
_flint = _get_flint(_SYMPY_GROUND_TYPES)
|
164
|
+
if _flint is not None:
|
165
|
+
_SYMPY_GROUND_TYPES = 'flint'
|
166
|
+
else:
|
167
|
+
_SYMPY_GROUND_TYPES = 'auto'
|
168
|
+
|
169
|
+
if _SYMPY_GROUND_TYPES in ('auto', 'gmpy', 'gmpy2'):
|
170
|
+
_gmpy = _get_gmpy2(_SYMPY_GROUND_TYPES)
|
171
|
+
if _gmpy is not None:
|
172
|
+
_SYMPY_GROUND_TYPES = 'gmpy'
|
173
|
+
else:
|
174
|
+
_SYMPY_GROUND_TYPES = 'python'
|
175
|
+
|
176
|
+
if _SYMPY_GROUND_TYPES not in ('flint', 'gmpy', 'python'):
|
177
|
+
warn("SYMPY_GROUND_TYPES environment variable unrecognised. "
|
178
|
+
"Should be 'auto', 'flint', 'gmpy', 'gmpy2' or 'python'.")
|
179
|
+
_SYMPY_GROUND_TYPES = 'python'
|
180
|
+
|
181
|
+
#
|
182
|
+
# At this point _SYMPY_GROUND_TYPES is either flint, gmpy or python. The blocks
|
183
|
+
# below define the values exported by this module in each case.
|
184
|
+
#
|
185
|
+
|
186
|
+
#
|
187
|
+
# In gmpy2 and flint, there are functions that take a long (or unsigned long)
|
188
|
+
# argument. That is, it is not possible to input a value larger than that.
|
189
|
+
#
|
190
|
+
LONG_MAX = (1 << (8*sizeof(c_long) - 1)) - 1
|
191
|
+
|
192
|
+
#
|
193
|
+
# Type checkers are confused by what SYMPY_INTS is. There may be a better type
|
194
|
+
# hint for this like Type[Integral] or something.
|
195
|
+
#
|
196
|
+
SYMPY_INTS: tTuple[Type, ...]
|
197
|
+
|
198
|
+
if _SYMPY_GROUND_TYPES == 'gmpy':
|
199
|
+
|
200
|
+
assert _gmpy is not None
|
201
|
+
|
202
|
+
flint = None
|
203
|
+
gmpy = _gmpy
|
204
|
+
|
205
|
+
HAS_GMPY = 2
|
206
|
+
GROUND_TYPES = 'gmpy'
|
207
|
+
SYMPY_INTS = (int, type(gmpy.mpz(0)))
|
208
|
+
MPZ = gmpy.mpz
|
209
|
+
MPQ = gmpy.mpq
|
210
|
+
|
211
|
+
# bit_scan1 = gmpy.bit_scan1
|
212
|
+
# bit_scan0 = gmpy.bit_scan0
|
213
|
+
# remove = gmpy.remove
|
214
|
+
# factorial = gmpy.fac
|
215
|
+
# sqrt = gmpy.isqrt
|
216
|
+
# is_square = gmpy.is_square
|
217
|
+
# sqrtrem = gmpy.isqrt_rem
|
218
|
+
# gcd = gmpy.gcd
|
219
|
+
# lcm = gmpy.lcm
|
220
|
+
gcdext = gmpy.gcdext
|
221
|
+
# invert = gmpy.invert
|
222
|
+
# legendre = gmpy.legendre
|
223
|
+
# jacobi = gmpy.jacobi
|
224
|
+
# kronecker = gmpy.kronecker
|
225
|
+
|
226
|
+
# def iroot(x, n):
|
227
|
+
# # In the latest gmpy2, the threshold for n is ULONG_MAX,
|
228
|
+
# # but adjust to the older one.
|
229
|
+
# if n <= LONG_MAX:
|
230
|
+
# return gmpy.iroot(x, n)
|
231
|
+
# return python_iroot(x, n)
|
232
|
+
|
233
|
+
# is_fermat_prp = gmpy.is_fermat_prp
|
234
|
+
# is_euler_prp = gmpy.is_euler_prp
|
235
|
+
# is_strong_prp = gmpy.is_strong_prp
|
236
|
+
# is_fibonacci_prp = gmpy.is_fibonacci_prp
|
237
|
+
# is_lucas_prp = gmpy.is_lucas_prp
|
238
|
+
# is_selfridge_prp = gmpy.is_selfridge_prp
|
239
|
+
# is_strong_lucas_prp = gmpy.is_strong_lucas_prp
|
240
|
+
# is_strong_selfridge_prp = gmpy.is_strong_selfridge_prp
|
241
|
+
# is_bpsw_prp = gmpy.is_bpsw_prp
|
242
|
+
# is_strong_bpsw_prp = gmpy.is_strong_bpsw_prp
|
243
|
+
|
244
|
+
elif _SYMPY_GROUND_TYPES == 'flint':
|
245
|
+
|
246
|
+
assert _flint is not None
|
247
|
+
|
248
|
+
flint = _flint
|
249
|
+
gmpy = None
|
250
|
+
|
251
|
+
HAS_GMPY = 0
|
252
|
+
GROUND_TYPES = 'flint'
|
253
|
+
SYMPY_INTS = (int, flint.fmpz) # type: ignore
|
254
|
+
MPZ = flint.fmpz # type: ignore
|
255
|
+
MPQ = flint.fmpq # type: ignore
|
256
|
+
|
257
|
+
# bit_scan1 = python_bit_scan1
|
258
|
+
# bit_scan0 = python_bit_scan0
|
259
|
+
# remove = python_remove
|
260
|
+
# factorial = python_factorial
|
261
|
+
|
262
|
+
# def sqrt(x):
|
263
|
+
# return flint.fmpz(x).isqrt()
|
264
|
+
|
265
|
+
# def is_square(x):
|
266
|
+
# if x < 0:
|
267
|
+
# return False
|
268
|
+
# return flint.fmpz(x).sqrtrem()[1] == 0
|
269
|
+
|
270
|
+
# def sqrtrem(x):
|
271
|
+
# return flint.fmpz(x).sqrtrem()
|
272
|
+
|
273
|
+
# def gcd(*args):
|
274
|
+
# return reduce(flint.fmpz.gcd, args, flint.fmpz(0))
|
275
|
+
|
276
|
+
# def lcm(*args):
|
277
|
+
# return reduce(flint.fmpz.lcm, args, flint.fmpz(1))
|
278
|
+
|
279
|
+
gcdext = python_gcdext
|
280
|
+
# invert = python_invert
|
281
|
+
# legendre = python_legendre
|
282
|
+
|
283
|
+
# def jacobi(x, y):
|
284
|
+
# if y <= 0 or not y % 2:
|
285
|
+
# raise ValueError("y should be an odd positive integer")
|
286
|
+
# return flint.fmpz(x).jacobi(y)
|
287
|
+
|
288
|
+
# kronecker = python_kronecker
|
289
|
+
|
290
|
+
# def iroot(x, n):
|
291
|
+
# if n <= LONG_MAX:
|
292
|
+
# y = flint.fmpz(x).root(n)
|
293
|
+
# return y, y**n == x
|
294
|
+
# return python_iroot(x, n)
|
295
|
+
|
296
|
+
# is_fermat_prp = python_is_fermat_prp
|
297
|
+
# is_euler_prp = python_is_euler_prp
|
298
|
+
# is_strong_prp = python_is_strong_prp
|
299
|
+
# is_fibonacci_prp = python_is_fibonacci_prp
|
300
|
+
# is_lucas_prp = python_is_lucas_prp
|
301
|
+
# is_selfridge_prp = python_is_selfridge_prp
|
302
|
+
# is_strong_lucas_prp = python_is_strong_lucas_prp
|
303
|
+
# is_strong_selfridge_prp = python_is_strong_selfridge_prp
|
304
|
+
# is_bpsw_prp = python_is_bpsw_prp
|
305
|
+
# is_strong_bpsw_prp = python_is_strong_bpsw_prp
|
306
|
+
|
307
|
+
elif _SYMPY_GROUND_TYPES == 'python':
|
308
|
+
|
309
|
+
flint = None
|
310
|
+
gmpy = None
|
311
|
+
|
312
|
+
HAS_GMPY = 0
|
313
|
+
GROUND_TYPES = 'python'
|
314
|
+
SYMPY_INTS = (int,)
|
315
|
+
MPZ = int
|
316
|
+
MPQ = PythonMPQ
|
317
|
+
|
318
|
+
# bit_scan1 = python_bit_scan1
|
319
|
+
# bit_scan0 = python_bit_scan0
|
320
|
+
# remove = python_remove
|
321
|
+
# factorial = python_factorial
|
322
|
+
# sqrt = python_sqrt
|
323
|
+
# is_square = python_is_square
|
324
|
+
# sqrtrem = python_sqrtrem
|
325
|
+
# gcd = python_gcd
|
326
|
+
# lcm = python_lcm
|
327
|
+
gcdext = python_gcdext
|
328
|
+
# invert = python_invert
|
329
|
+
# legendre = python_legendre
|
330
|
+
# jacobi = python_jacobi
|
331
|
+
# kronecker = python_kronecker
|
332
|
+
# iroot = python_iroot
|
333
|
+
# is_fermat_prp = python_is_fermat_prp
|
334
|
+
# is_euler_prp = python_is_euler_prp
|
335
|
+
# is_strong_prp = python_is_strong_prp
|
336
|
+
# is_fibonacci_prp = python_is_fibonacci_prp
|
337
|
+
# is_lucas_prp = python_is_lucas_prp
|
338
|
+
# is_selfridge_prp = python_is_selfridge_prp
|
339
|
+
# is_strong_lucas_prp = python_is_strong_lucas_prp
|
340
|
+
# is_strong_selfridge_prp = python_is_strong_selfridge_prp
|
341
|
+
# is_bpsw_prp = python_is_bpsw_prp
|
342
|
+
# is_strong_bpsw_prp = python_is_strong_bpsw_prp
|
343
|
+
|
344
|
+
else:
|
345
|
+
assert False
|