xync-client 0.0.25.dev42__tar.gz → 0.0.25.dev43__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. {xync_client-0.0.25.dev42/xync_client.egg-info → xync_client-0.0.25.dev43}/PKG-INFO +1 -1
  2. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/tests/TestEx.py +9 -9
  3. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/Abc/Ex.py +12 -171
  4. xync_client-0.0.25.dev43/xync_client/Abc/types.py +1 -0
  5. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/Gate/ex.py +22 -21
  6. xync_client-0.0.25.dev43/xync_client/pm_unifier.py +161 -0
  7. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43/xync_client.egg-info}/PKG-INFO +1 -1
  8. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client.egg-info/SOURCES.txt +2 -0
  9. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/.env.sample +0 -0
  10. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/.gitignore +0 -0
  11. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/.pre-commit-config.yaml +0 -0
  12. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/README.md +0 -0
  13. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/makefile +0 -0
  14. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/pyproject.toml +0 -0
  15. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/setup.cfg +0 -0
  16. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/tests/TestAgent.py +0 -0
  17. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/tests/TestAsset.py +0 -0
  18. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/tests/TestOrder.py +0 -0
  19. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/tests/_todo_refact/Binance/test_binance.py +0 -0
  20. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/tests/_todo_refact/Bybit/test_bybit.py +0 -0
  21. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/tests/_todo_refact/Bybit/test_bybit_p2p.py +0 -0
  22. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/tests/_todo_refact/Gate/test_gate.py +0 -0
  23. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/tests/_todo_refact/Htx/test_htx_p2p.py +0 -0
  24. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/tests/_todo_refact/Wallet/test_agent.py +0 -0
  25. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/tests/_todo_refact/Wallet/test_ex.py +0 -0
  26. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/tests/_todo_refact/__init__.py +0 -0
  27. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/tests/_todo_refact/_test_ex.py +0 -0
  28. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/Abc/Agent.py +0 -0
  29. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/Abc/Asset.py +0 -0
  30. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/Abc/AuthTrait.py +0 -0
  31. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/Abc/Base.py +0 -0
  32. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/Abc/BaseTest.py +0 -0
  33. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/Abc/InAgent.py +0 -0
  34. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/Abc/Order.py +0 -0
  35. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/Binance/__init__.py +0 -0
  36. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/Binance/binance_async.py +0 -0
  37. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/Binance/earn_api.py +0 -0
  38. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/Binance/ex.py +0 -0
  39. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/Binance/exceptions.py +0 -0
  40. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/Binance/sapi.py +0 -0
  41. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/Binance/web_c2c.py +0 -0
  42. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/BingX/__init__.py +0 -0
  43. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/BingX/agent.py +0 -0
  44. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/BingX/base.py +0 -0
  45. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/BingX/ex.py +0 -0
  46. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/BingX/pyd.py +0 -0
  47. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/BingX/req.mjs +0 -0
  48. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/BingX/sign.js +0 -0
  49. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/BingX/test/main.py +0 -0
  50. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/BitGet/__init__.py +0 -0
  51. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/BitGet/agent.py +0 -0
  52. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/BitGet/ex.py +0 -0
  53. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/BitGet/req.mjs +0 -0
  54. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/Bybit/agent.py +0 -0
  55. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/Bybit/ex.py +0 -0
  56. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/Bybit/web_earn.py +0 -0
  57. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/Bybit/web_p2p.py +0 -0
  58. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/Gate/premarket.py +0 -0
  59. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/Htx/agent.py +0 -0
  60. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/Htx/earn.py +0 -0
  61. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/Htx/etype/__init__.py +0 -0
  62. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/Htx/etype/ad.py +0 -0
  63. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/Htx/etype/cred.py +0 -0
  64. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/Htx/etype/pm.py +0 -0
  65. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/Htx/ex.py +0 -0
  66. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/KuCoin/pub.py +0 -0
  67. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/KuCoin/web.py +0 -0
  68. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/Okx/ex.py +0 -0
  69. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/Okx/pyd.py +0 -0
  70. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/TgWallet/agent.py +0 -0
  71. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/TgWallet/asset.py +0 -0
  72. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/TgWallet/auth.py +0 -0
  73. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/TgWallet/ex.py +0 -0
  74. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/TgWallet/inAgent.py +0 -0
  75. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/TgWallet/order.py +0 -0
  76. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/TgWallet/pyd.py +0 -0
  77. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/TgWallet/pyro.py +0 -0
  78. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/TgWallet/web.py +0 -0
  79. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/__init__.py +0 -0
  80. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/loader.py +0 -0
  81. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client/pyro.py +0 -0
  82. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client.egg-info/dependency_links.txt +0 -0
  83. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client.egg-info/requires.txt +0 -0
  84. {xync_client-0.0.25.dev42 → xync_client-0.0.25.dev43}/xync_client.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: xync-client
3
- Version: 0.0.25.dev42
3
+ Version: 0.0.25.dev43
4
4
  Author-email: Mike Artemiev <mixartemev@gmail.com>
5
5
  Project-URL: Homepage, https://gitlab.com/XyncNet/client
6
6
  Project-URL: Repository, https://gitlab.com/XyncNet/client
@@ -1,7 +1,7 @@
1
1
  import logging
2
2
 
3
3
  import pytest
4
- from xync_schema.types import Pm, BaseAd, CurE, CoinE
4
+ from xync_schema.types import BaseAd, CurEx, CoinEx, PmOut
5
5
 
6
6
  from xync_client.Abc.BaseTest import BaseTest
7
7
  from xync_schema.enums import ExStatus, ExType, ExAction
@@ -13,8 +13,8 @@ from xync_client.Abc.Ex import BaseExClient
13
13
 
14
14
  @pytest.mark.asyncio(loop_scope="session")
15
15
  class TestEx(BaseTest):
16
- coins: dict[int, dict[str, CoinE]] = {}
17
- curs: dict[int, dict[str, CurE]] = {}
16
+ coins: dict[int, dict[str, CoinEx]] = {}
17
+ curs: dict[int, dict[str, CurEx]] = {}
18
18
 
19
19
  @pytest.fixture
20
20
  async def clients(self) -> list[BaseClient]:
@@ -27,8 +27,8 @@ class TestEx(BaseTest):
27
27
  # 19
28
28
  async def test_curs(self, clients: list[BaseExClient]):
29
29
  for client in clients:
30
- curs: dict[str, CurE] = await client.curs()
31
- ok = self.is_dict_of_objects(curs, CurE)
30
+ curs: dict[str, CurEx] = await client.curs()
31
+ ok = self.is_dict_of_objects(curs, CurEx)
32
32
  t, _ = await ExTest.update_or_create({"ok": ok}, ex=client.ex, action=ExAction.curs)
33
33
  assert t.ok, "No curs"
34
34
  self.curs[client.ex.id] = curs
@@ -37,8 +37,8 @@ class TestEx(BaseTest):
37
37
  # 20
38
38
  async def test_pms(self, clients: list[BaseExClient]):
39
39
  for client in clients:
40
- pms: dict[int | str, Pm] = await client.pms()
41
- ok = self.is_dict_of_objects(pms, Pm)
40
+ pms: dict[int | str, PmOut] = await client.pms()
41
+ ok = self.is_dict_of_objects(pms, PmOut)
42
42
  t, _ = await ExTest.update_or_create({"ok": ok}, ex=client.ex, action=ExAction.pms)
43
43
  assert t.ok, "No pms"
44
44
  logging.info(f"{client.ex.name}: {ExAction.pms.name} - ok")
@@ -55,8 +55,8 @@ class TestEx(BaseTest):
55
55
  # 22
56
56
  async def test_coins(self, clients: list[BaseExClient]):
57
57
  for client in clients:
58
- coins: dict[str, CoinE] = await client.coins()
59
- ok = self.is_dict_of_objects(coins, CoinE)
58
+ coins: dict[str, CoinEx] = await client.coins()
59
+ ok = self.is_dict_of_objects(coins, CoinEx)
60
60
  t, _ = await ExTest.update_or_create({"ok": ok}, ex=client.ex, action=ExAction.coins)
61
61
  assert t.ok, "No coins"
62
62
  self.coins[client.ex.id] = coins
@@ -1,173 +1,14 @@
1
1
  import logging
2
- import re
3
2
  from abc import abstractmethod
4
3
 
5
4
  import msgspec
6
5
  from msgspec import Struct
7
6
  from tortoise.exceptions import MultipleObjectsReturned, IntegrityError
8
- from x_model.types import Upd
9
- from xync_schema import types
10
7
  from xync_schema import models
8
+ from xync_schema.types import CurEx, PmOut, CoinEx, BaseAd, BaseAdIn
11
9
 
12
10
  from xync_client.Abc.Base import BaseClient, MapOfIdsList
13
-
14
-
15
- class PmUni(Upd):
16
- _unq: list[str] = ["norm", "country"]
17
-
18
- norm: str
19
- acronym: str = None
20
- country: str = None
21
- alias: str = None
22
- extra: str = None
23
- bank: bool = None
24
-
25
-
26
- class PmUnifier:
27
- pms: dict[str, PmUni] = {} # {origin: normalized}
28
-
29
- pm_map: dict[str, str] = {
30
- "Юmoney": "YooMoney",
31
- # "Local Bank (R-Green)": "Sberbank",
32
- # "Local Bank (S-Green)": "Sberbank",
33
- # "Local Card (Red)": "Alfa-Bank",
34
- # "Local Card (Yellow)": "Tinkoff",
35
- # "Local Card M-redTS": "MTS-bank",
36
- # "Local Card-Green": "Sberbank",
37
- # "Local Card-Yellow": "Tinkoff",
38
- # "GTB Bank (Guarantee Trust Bank)": "GTBank",
39
- }
40
- re_bank = [
41
- r"^bank (?!of )|bank$",
42
- r" banka$",
43
- r" bankas$",
44
- r" bankası$",
45
- r" banca$",
46
- r"^banco(?! de | del )| banco$",
47
- ]
48
- re_extra = [
49
- r"\(card\)$|\bpay$|\bmoney$|\bwallet$|\bcash$",
50
- r"b\.s\.c\.|k\.s\.c|s\.a$| sv$| gt$",
51
- ]
52
- re_glut = [
53
- r"\.io$|\.com$",
54
- r"l'|d’|d'",
55
- ]
56
- i18n_map = {
57
- # " ": " ",
58
- "nationale": "national",
59
- "а": "a",
60
- "á": "a",
61
- "â": "a",
62
- "о": "o",
63
- "ó": "o",
64
- "ō": "o",
65
- "ú": "u",
66
- "ü": "u",
67
- "ų": "u",
68
- "с": "c",
69
- "č": "c",
70
- "ç": "c",
71
- "é": "e",
72
- "è": "e",
73
- "ş": "s",
74
- "š": "s",
75
- "ř": "r",
76
- "í": "i",
77
- }
78
- rms = " -:`'’′"
79
-
80
- def __init__(self, countries: list[str]):
81
- self.cts = countries
82
-
83
- def countries(self, name: str):
84
- for ct in self.cts:
85
- # Если имя кончается на "Название_страны" в скобках
86
- if (
87
- ct
88
- and self.pms[name].norm.endswith((ct + ")", ct))
89
- and not self.pms[name].norm.endswith((" of " + ct, " of the " + ct, " and " + ct, " de " + ct))
90
- ):
91
- self.pms[name].norm = self.pms[name].norm.replace(ct, "")
92
- self.pms[name].country = ct
93
- self.clear(name)
94
- return
95
-
96
- def extra(self, name: str):
97
- for r in self.re_extra:
98
- if match := re.search(r, self.pms[name].norm):
99
- self.pms[name].norm = self.pms[name].norm.replace(match.group(), "")
100
- self.pms[name].extra = match.group()
101
- self.clear(name)
102
- return
103
-
104
- def alias(self, name: str):
105
- if match := re.search(r"\(.+\)$", self.pms[name].norm):
106
- self.pms[name].norm = self.pms[name].norm.replace(match.group(), "")
107
- self.pms[name].alias = match.group()[1:-1]
108
- self.clear(name)
109
- return
110
-
111
- def bank(self, name: str):
112
- for r in self.re_bank:
113
- if match := re.search(r, self.pms[name].norm):
114
- self.pms[name].norm = self.pms[name].norm.replace(match.group(), "")
115
- self.pms[name].bank = True
116
- self.clear(name)
117
- return
118
-
119
- def acro(self, name: str):
120
- acr = "".join(
121
- wrd[0]
122
- for wrd in self.pms[name].norm.split(" ")
123
- if not wrd.isupper()
124
- and not wrd.startswith(("(", "the"))
125
- and len(wrd) > 2
126
- or (len(wrd) > 1 and wrd.istitle())
127
- ).upper()
128
- if len(acr) >= 2 and (
129
- f"({acr})" in self.pms[name].norm
130
- or self.pms[name].norm.startswith((acr + " ", acr + ":"))
131
- or self.pms[name].norm.endswith(" " + acr)
132
- ):
133
- self.pms[name].norm = self.pms[name].norm.replace(acr, "", 1).replace("()", "", 1).strip()
134
- self.pms[name].acronym = acr
135
- self.clear(name)
136
-
137
- def slim(self, name: str):
138
- for rm in self.re_glut:
139
- self.pms[name].norm = re.sub(rm, "", self.pms[name].norm)
140
-
141
- def i18n(self, name: str):
142
- for src, trgt in self.i18n_map.items():
143
- self.pms[name].norm = self.pms[name].norm.replace(src, trgt)
144
-
145
- def clear(self, name: str):
146
- self.pms[name].norm = self.pms[name].norm.replace("()", "").replace(" ", " ").strip(" -:")
147
-
148
- def __call__(self, s: str) -> PmUni:
149
- # если в словаре замен есть текущее назвние - меняем, иначе берем строку до запятой
150
- self.pms[s] = PmUni(norm=self.pm_map.get(s, s.split(",")[0]))
151
- # вырезаем мусорные добавки
152
- self.slim(s)
153
- # заменяем локальные символы на англ:
154
- self.i18n(s)
155
- # находим и вырезаем аббревиатуру, если есть
156
- self.acro(s)
157
- # уменьшаем все буквы
158
- self.pms[s].norm = self.pms[s].norm.lower()
159
- # находим и вырезаем страны, если есть
160
- self.countries(s)
161
- self.bank(s)
162
- self.extra(s)
163
- self.alias(s)
164
- self.bank(s)
165
- self.countries(s)
166
- self.extra(s)
167
- # вырезаем каждый символ rms
168
- [self.pms[s].norm.replace(rm, "") for rm in self.rms]
169
-
170
- return self.pms[s]
11
+ from xync_client.pm_unifier import PmUnifier, PmUni
171
12
 
172
13
 
173
14
  class BaseExClient(BaseClient):
@@ -176,12 +17,12 @@ class BaseExClient(BaseClient):
176
17
 
177
18
  # 19: Список поддерживаемых валют тейкера
178
19
  @abstractmethod
179
- async def curs(self) -> dict[str, types.CurE]: # {cur.ticker: cur}
20
+ async def curs(self) -> dict[str, CurEx]: # {cur.ticker: cur}
180
21
  ...
181
22
 
182
23
  # 20: Список платежных методов
183
24
  @abstractmethod
184
- async def pms(self, cur: models.Cur = None) -> dict[int | str, types.Pm]: # {pm.exid: pm}
25
+ async def pms(self, cur: models.Cur = None) -> dict[int | str, PmOut]: # {pm.exid: pm}
185
26
  ...
186
27
 
187
28
  # 21: Список платежных методов по каждой валюте
@@ -191,7 +32,7 @@ class BaseExClient(BaseClient):
191
32
 
192
33
  # 22: Список торгуемых монет (с ограничениям по валютам, если есть)
193
34
  @abstractmethod
194
- async def coins(self) -> dict[str, types.CoinE]: # {coin.ticker: coin}
35
+ async def coins(self) -> dict[str, CoinEx]: # {coin.ticker: coin}
195
36
  ...
196
37
 
197
38
  # 23: Список пар валюта/монет
@@ -202,16 +43,16 @@ class BaseExClient(BaseClient):
202
43
  @abstractmethod
203
44
  async def ads(
204
45
  self, coin_exid: str, cur_exid: str, is_sell: bool, pm_exids: list[str | int] = None, amount: int = None
205
- ) -> list[types.BaseAd]: # {ad.id: ad}
46
+ ) -> list[BaseAd]: # {ad.id: ad}
206
47
  ...
207
48
 
208
49
  # 42: Чужая объява по id
209
50
  @abstractmethod
210
- async def ad(self, ad_id: int) -> types.BaseAd: ...
51
+ async def ad(self, ad_id: int) -> BaseAd: ...
211
52
 
212
53
  # Преобразрование объекта объявления из формата биржи в формат xync
213
54
  @abstractmethod
214
- async def ad_epyd2pydin(self, ad: types.BaseAd) -> types.BaseAdIn: ... # my_uid: for MyAd
55
+ async def ad_epyd2pydin(self, ad: BaseAd) -> BaseAdIn: ... # my_uid: for MyAd
215
56
 
216
57
  # 99: Страны
217
58
  async def countries(self) -> list[Struct]:
@@ -220,7 +61,7 @@ class BaseExClient(BaseClient):
220
61
  # Импорт Pm-ов (с Pmcur-, Pmex- и Pmcurex-ами) и валют (с Curex-ами) с биржи в бд
221
62
  async def set_pmcurexs(self):
222
63
  # Curs
223
- cur_pyds: dict[str, types.CurE] = await self.curs()
64
+ cur_pyds: dict[str, CurEx] = await self.curs()
224
65
  curs: dict[int | str, models.Cur] = {
225
66
  cur_pyd.exid: (await models.Cur.update_or_create({"rate": cur_pyd.rate}, ticker=tkr))[0]
226
67
  for tkr, cur_pyd in cur_pyds.items()
@@ -274,7 +115,7 @@ class BaseExClient(BaseClient):
274
115
  # todo: curexcountry
275
116
 
276
117
  # Pms
277
- pms_epyds: dict[int | str, types.Pm] = {
118
+ pms_epyds: dict[int | str, PmOut] = {
278
119
  k: v for k, v in sorted((await self.pms()).items(), key=lambda x: x[1].name)
279
120
  } # sort by name
280
121
  pms: dict[int | str, models.Pm] = dict({})
@@ -343,7 +184,7 @@ class BaseExClient(BaseClient):
343
184
 
344
185
  # Импорт монет (с Coinex-ами) с биржи в бд
345
186
  async def set_coinexs(self):
346
- coins: dict[str, types.CoinE] = await self.coins()
187
+ coins: dict[str, CoinEx] = await self.coins()
347
188
  coins_db: dict[int, models.Coin] = {
348
189
  c.exid: (await models.Coin.update_or_create(ticker=c.ticker))[0] for c in coins.values()
349
190
  }
@@ -353,7 +194,7 @@ class BaseExClient(BaseClient):
353
194
  await models.Coinex.bulk_create(coinexs, update_fields=["minimum"], on_conflict=["coin_id", "ex_id"])
354
195
 
355
196
  # Сохранение чужого объявления (с Pm-ами) в бд
356
- async def ad_pydin2db(self, ad_pydin: types.BaseAdIn) -> models.Ad:
197
+ async def ad_pydin2db(self, ad_pydin: BaseAdIn) -> models.Ad:
357
198
  df, unq = ad_pydin.args()
358
199
  ad_db, _ = await models.Ad.update_or_create(df, **unq)
359
200
  if getattr(ad_pydin, "pms_", None): # if it ListItem, not Full One # todo: remove?
@@ -1,7 +1,9 @@
1
1
  import re
2
+ import subprocess
2
3
  from asyncio import run, sleep
3
- from json import JSONDecoder
4
+ from json import loads
4
5
 
6
+ import requests
5
7
  from bs4 import BeautifulSoup, Script
6
8
  from x_model import init_db
7
9
  from xync_schema import models
@@ -13,31 +15,30 @@ from xync_client.loader import PG_DSN
13
15
 
14
16
 
15
17
  class ExClient(BaseExClient):
16
- # 20: Список всех платежных методов на бирже
17
- async def pms(self, cur: Cur = None) -> DictOfDicts:
18
+ # Данные для р2р из html Gate.io
19
+ async def c2c_data(self) -> dict:
18
20
  await sleep(1)
19
- doc = await self._get("/p2p")
21
+ # doc = await self._get("/p2p") # todo: почему не работает? хз
22
+ doc = requests.get("https://www.gate.io/p2p").text
20
23
  await sleep(1)
21
24
  soup = BeautifulSoup(doc, "html.parser")
22
- script: Script = soup.body.find_all("script")[17] # 17-th not stable
23
- strng = (
24
- script.get_text(strip=True)
25
- .replace("\n", "")
26
- .replace(" ", "")
27
- .replace(
28
- ',\'bank\': {image: "/images/payment/bank.png",index: "2",pay_name: lang_string("银行卡"),pay_type: "bank",rgb: "#FF860D",}',
29
- "",
30
- )
31
- )
32
- # pattern = r'var c2cData = (\{.*?\})\s+var transLang'
33
- # pattern = r'payment_settings:\s{1}(\{.*?\}),\s?// 用户放开的支付方式'
34
- pattern = r"payment_settings:\s{1}(\{.*?\}),paymentIdMap:"
25
+ script: Script = soup.body.find_all("script")[19] # 17-th not stable
26
+ strng = script.get_text().replace(" ", "")
27
+ pattern = r"var c2cData = (\{.*?\})\s+var transLang"
35
28
  match = re.search(pattern, strng.replace(",}", "}").replace(",]", "]"), re.DOTALL)
36
29
  res = match.group(1)
37
- pms = JSONDecoder(strict=False).decode(res)
30
+ p = subprocess.Popen(
31
+ ["node", "-e", f"const lang_string = a => a;console.log(JSON.stringify({res}))"], stdout=subprocess.PIPE
32
+ )
33
+ out = p.stdout.read().decode()
34
+ return loads(out)
35
+
36
+ # 20: Список всех платежных методов на бирже
37
+ async def pms(self, cur: Cur = None) -> DictOfDicts:
38
+ data = await self.c2c_data()
38
39
  return {
39
- pm["index"]: {"name": pm["pay_name"], "logo": pm["image"], "identifier": idf, "type_": pm["base_type"]}
40
- for idf, pm in pms.items()
40
+ pm["index"]: {"name": pm["pay_name"], "logo": pm["image"], "identifier": idf, "type_": pm.get("base_type")}
41
+ for idf, pm in data["payment_settings"].items()
41
42
  }
42
43
 
43
44
  # 21: Список поддерживаемых валют
@@ -62,7 +63,7 @@ async def main():
62
63
  _ = await init_db(PG_DSN, models, True)
63
64
  bg = await Ex.get(name="Gate")
64
65
  cl = ExClient(bg)
65
- await cl.curs()
66
+ # curs = await cl.curs()
66
67
  # await cl.coins()
67
68
  pms = await cl.pms()
68
69
  print(pms)
@@ -0,0 +1,161 @@
1
+ import re
2
+
3
+ from x_model.types import Upd
4
+
5
+
6
+ class PmUni(Upd):
7
+ _unq: list[str] = ["norm", "country"]
8
+
9
+ norm: str
10
+ acronym: str = None
11
+ country: str = None
12
+ alias: str = None
13
+ extra: str = None
14
+ bank: bool = None
15
+
16
+
17
+ class PmUnifier:
18
+ pms: dict[str, PmUni] = {} # {origin: normalized}
19
+
20
+ pm_map: dict[str, str] = {
21
+ "Юmoney": "YooMoney",
22
+ # "Local Bank (R-Green)": "Sberbank",
23
+ # "Local Bank (S-Green)": "Sberbank",
24
+ # "Local Card (Red)": "Alfa-Bank",
25
+ # "Local Card (Yellow)": "Tinkoff",
26
+ # "Local Card M-redTS": "MTS-bank",
27
+ # "Local Card-Green": "Sberbank",
28
+ # "Local Card-Yellow": "Tinkoff",
29
+ # "GTB Bank (Guarantee Trust Bank)": "GTBank",
30
+ }
31
+ re_bank = [
32
+ r"^bank (?!of )|bank$",
33
+ r" banka$",
34
+ r" bankas$",
35
+ r" bankası$",
36
+ r" banca$",
37
+ r"^banco(?! de | del )| banco$",
38
+ ]
39
+ re_extra = [
40
+ r"\(card\)$|\bpay$|\bmoney$|\bwallet$|\bcash$",
41
+ r"b\.s\.c\.|k\.s\.c|s\.a$| sv$| gt$",
42
+ ]
43
+ re_glut = [
44
+ r"\.io$|\.com$",
45
+ r"l'|d’|d'",
46
+ ]
47
+ i18n_map = {
48
+ # " ": " ",
49
+ "nationale": "national",
50
+ "а": "a",
51
+ "á": "a",
52
+ "â": "a",
53
+ "о": "o",
54
+ "ó": "o",
55
+ "ō": "o",
56
+ "ú": "u",
57
+ "ü": "u",
58
+ "ų": "u",
59
+ "с": "c",
60
+ "č": "c",
61
+ "ç": "c",
62
+ "é": "e",
63
+ "è": "e",
64
+ "ş": "s",
65
+ "š": "s",
66
+ "ř": "r",
67
+ "í": "i",
68
+ }
69
+ rms = " -:`'’′"
70
+
71
+ def __init__(self, countries: list[str]):
72
+ self.cts = countries
73
+
74
+ def countries(self, name: str):
75
+ for ct in self.cts:
76
+ # Если имя кончается на "Название_страны" в скобках
77
+ if (
78
+ ct
79
+ and self.pms[name].norm.endswith((ct + ")", ct))
80
+ and not self.pms[name].norm.endswith((" of " + ct, " of the " + ct, " and " + ct, " de " + ct))
81
+ ):
82
+ self.pms[name].norm = self.pms[name].norm.replace(ct, "")
83
+ self.pms[name].country = ct
84
+ self.clear(name)
85
+ return
86
+
87
+ def extra(self, name: str):
88
+ for r in self.re_extra:
89
+ if match := re.search(r, self.pms[name].norm):
90
+ self.pms[name].norm = self.pms[name].norm.replace(match.group(), "")
91
+ self.pms[name].extra = match.group()
92
+ self.clear(name)
93
+ return
94
+
95
+ def alias(self, name: str):
96
+ if match := re.search(r"\(.+\)$", self.pms[name].norm):
97
+ self.pms[name].norm = self.pms[name].norm.replace(match.group(), "")
98
+ self.pms[name].alias = match.group()[1:-1]
99
+ self.clear(name)
100
+ return
101
+
102
+ def bank(self, name: str):
103
+ for r in self.re_bank:
104
+ if match := re.search(r, self.pms[name].norm):
105
+ self.pms[name].norm = self.pms[name].norm.replace(match.group(), "")
106
+ self.pms[name].bank = True
107
+ self.clear(name)
108
+ return
109
+
110
+ def acro(self, name: str):
111
+ acr = "".join(
112
+ wrd[0]
113
+ for wrd in self.pms[name].norm.split(" ")
114
+ if not wrd.isupper()
115
+ and not wrd.startswith(("(", "the"))
116
+ and len(wrd) > 2
117
+ or (len(wrd) > 1 and wrd.istitle())
118
+ ).upper()
119
+ if len(acr) >= 2 and (
120
+ f"({acr})" in self.pms[name].norm
121
+ or self.pms[name].norm.startswith((acr + " ", acr + ":"))
122
+ or self.pms[name].norm.endswith(" " + acr)
123
+ ):
124
+ self.pms[name].norm = self.pms[name].norm.replace(acr, "", 1).replace("()", "", 1).strip()
125
+ self.pms[name].acronym = acr
126
+ self.clear(name)
127
+
128
+ def slim(self, name: str):
129
+ for rm in self.re_glut:
130
+ self.pms[name].norm = re.sub(rm, "", self.pms[name].norm)
131
+
132
+ def i18n(self, name: str):
133
+ for src, trgt in self.i18n_map.items():
134
+ self.pms[name].norm = self.pms[name].norm.replace(src, trgt)
135
+
136
+ def clear(self, name: str):
137
+ self.pms[name].norm = self.pms[name].norm.replace("()", "").replace(" ", " ").strip(" -:")
138
+
139
+ def __call__(self, s: str) -> PmUni:
140
+ # если в словаре замен есть текущее назвние - меняем, иначе берем строку до запятой
141
+ self.pms[s] = PmUni(norm=self.pm_map.get(s, s.split(",")[0]))
142
+ # вырезаем мусорные добавки
143
+ self.slim(s)
144
+ # заменяем локальные символы на англ:
145
+ self.i18n(s)
146
+ # находим и вырезаем аббревиатуру, если есть
147
+ self.acro(s)
148
+ # уменьшаем все буквы
149
+ self.pms[s].norm = self.pms[s].norm.lower()
150
+ # находим и вырезаем страны, если есть
151
+ self.countries(s)
152
+ self.bank(s)
153
+ self.extra(s)
154
+ self.alias(s)
155
+ self.bank(s)
156
+ self.countries(s)
157
+ self.extra(s)
158
+ # вырезаем каждый символ rms
159
+ [self.pms[s].norm.replace(rm, "") for rm in self.rms]
160
+
161
+ return self.pms[s]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: xync-client
3
- Version: 0.0.25.dev42
3
+ Version: 0.0.25.dev43
4
4
  Author-email: Mike Artemiev <mixartemev@gmail.com>
5
5
  Project-URL: Homepage, https://gitlab.com/XyncNet/client
6
6
  Project-URL: Repository, https://gitlab.com/XyncNet/client
@@ -19,6 +19,7 @@ tests/_todo_refact/Wallet/test_agent.py
19
19
  tests/_todo_refact/Wallet/test_ex.py
20
20
  xync_client/__init__.py
21
21
  xync_client/loader.py
22
+ xync_client/pm_unifier.py
22
23
  xync_client/pyro.py
23
24
  xync_client.egg-info/PKG-INFO
24
25
  xync_client.egg-info/SOURCES.txt
@@ -33,6 +34,7 @@ xync_client/Abc/BaseTest.py
33
34
  xync_client/Abc/Ex.py
34
35
  xync_client/Abc/InAgent.py
35
36
  xync_client/Abc/Order.py
37
+ xync_client/Abc/types.py
36
38
  xync_client/Binance/__init__.py
37
39
  xync_client/Binance/binance_async.py
38
40
  xync_client/Binance/earn_api.py