fpx-engine 0.3.2__tar.gz → 0.4.0__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 (36) hide show
  1. {fpx_engine-0.3.2/fpx_engine.egg-info → fpx_engine-0.4.0}/PKG-INFO +2 -1
  2. {fpx_engine-0.3.2 → fpx_engine-0.4.0}/README.md +1 -0
  3. {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/classes/runner/runner.py +1 -1
  4. {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/classes/runner/subclasses/category.py +22 -10
  5. {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/classes/runner/subclasses/order.py +44 -9
  6. {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/classes/runner/subclasses/review.py +17 -12
  7. {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/classes/runner/subclasses/router.py +32 -22
  8. {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/main.py +6 -2
  9. {fpx_engine-0.3.2 → fpx_engine-0.4.0/fpx_engine.egg-info}/PKG-INFO +2 -1
  10. {fpx_engine-0.3.2 → fpx_engine-0.4.0}/pyproject.toml +1 -1
  11. {fpx_engine-0.3.2 → fpx_engine-0.4.0}/LICENSE +0 -0
  12. {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/__init__.py +0 -0
  13. {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/api/client.py +0 -0
  14. {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/api/parsers.py +0 -0
  15. {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/classes/account/account.py +0 -0
  16. {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/classes/account/subclasses/addons.py +0 -0
  17. {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/classes/account/subclasses/category.py +0 -0
  18. {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/classes/account/subclasses/chat.py +0 -0
  19. {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/classes/account/subclasses/editor.py +0 -0
  20. {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/classes/account/subclasses/lot.py +0 -0
  21. {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/classes/account/subclasses/order.py +0 -0
  22. {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/classes/account/subclasses/profile.py +0 -0
  23. {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/classes/account/subclasses/review.py +0 -0
  24. {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/classes/runner/subclasses/chat.py +0 -0
  25. {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/classes/runner/subclasses/handler.py +0 -0
  26. {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/fsm.py +0 -0
  27. {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/middlewares/request_engine.py +0 -0
  28. {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/models/account.py +0 -0
  29. {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/models/chat.py +0 -0
  30. {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/models/lots.py +0 -0
  31. {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx/utils/errors.py +0 -0
  32. {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx_engine.egg-info/SOURCES.txt +0 -0
  33. {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx_engine.egg-info/dependency_links.txt +0 -0
  34. {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx_engine.egg-info/requires.txt +0 -0
  35. {fpx_engine-0.3.2 → fpx_engine-0.4.0}/fpx_engine.egg-info/top_level.txt +0 -0
  36. {fpx_engine-0.3.2 → fpx_engine-0.4.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fpx-engine
3
- Version: 0.3.2
3
+ Version: 0.4.0
4
4
  Summary: Автоматизация работы с FunPay
5
5
  Author-email: Be My Code <gettofarmila@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/bymyforge/fpx
@@ -77,6 +77,7 @@ async def main():
77
77
  await message.answer('Привет')
78
78
  #запускаем приём событий
79
79
  await fp.runner.start_polling(3, is_background=True)
80
+ await fp.runner.idle()
80
81
 
81
82
  if __name__ == '__main__':
82
83
  asyncio.run(main())
@@ -61,6 +61,7 @@ async def main():
61
61
  await message.answer('Привет')
62
62
  #запускаем приём событий
63
63
  await fp.runner.start_polling(3, is_background=True)
64
+ await fp.runner.idle()
64
65
 
65
66
  if __name__ == '__main__':
66
67
  asyncio.run(main())
@@ -48,7 +48,7 @@ class Runner:
48
48
  await asyncio.sleep(timer)
49
49
  except fpx_err.FpxRequestError:
50
50
  await asyncio.sleep(60)
51
- except (httpx.ConnectTimeout, httpx.RemoteProtocolError, httpx.ReadTimeout, httpx.ConnectError):
51
+ except (httpx.HTTPError, httpx.NetworkError):
52
52
  await asyncio.sleep(timer)
53
53
  except Exception as e:
54
54
  raise fpx_err.FpxCriticalRunnerError(message=str(e))
@@ -1,4 +1,4 @@
1
-
1
+ import asyncio
2
2
 
3
3
 
4
4
  class CategoryRunner:
@@ -6,23 +6,35 @@ class CategoryRunner:
6
6
  self.runner = runner
7
7
 
8
8
  async def _update_lot_category_cache(self, lot_category_ids):
9
+ tasks = [
10
+ self.runner._account.category.get_lot_category_last_lot(cat_id)
11
+ for cat_id in lot_category_ids
12
+ ]
13
+ results = await asyncio.gather(*tasks, return_exceptions=True)
9
14
  new_cache = []
10
- for category_id in lot_category_ids:
11
- lots = await self.runner._account.category.get_lot_category_last_lot(category_id)
15
+ for category_id, lots in zip(lot_category_ids, results):
16
+ if isinstance(lots, Exception):
17
+ continue
12
18
  for lot in lots:
13
- lot.category_id = category_id
19
+ lot.category_id = category_id
14
20
  new_cache.append(lot)
15
- self.runner._cache['old_lot_categories'] = self.runner._cache['lot_categories']
21
+ self.runner._cache['old_lot_categories'] = self.runner._cache.get('lot_categories')
16
22
  self.runner._cache['lot_categories'] = new_cache
17
23
 
18
24
  async def _update_chip_category_cache(self, chip_category_ids):
25
+ tasks = [
26
+ self.runner._account.category.get_chip_category_last_lot(cat_id)
27
+ for cat_id in chip_category_ids
28
+ ]
29
+ results = await asyncio.gather(*tasks, return_exceptions=True)
19
30
  new_cache = []
20
- for category_id in chip_category_ids:
21
- lots = await self.runner._account.category.get_chip_category_last_lot(category_id)
31
+ for category_id, lots in zip(chip_category_ids, results):
32
+ if isinstance(lots, Exception):
33
+ continue
22
34
  for lot in lots:
23
35
  lot.category_id = category_id
24
36
  new_cache.append(lot)
25
- self.runner._cache['old_chip_categories'] = self.runner._cache['chip_categories']
37
+ self.runner._cache['old_chip_categories'] = self.runner._cache.get('chip_categories', [])
26
38
  self.runner._cache['chip_categories'] = new_cache
27
39
 
28
40
  async def _compare_lot_category_cache(self):
@@ -65,7 +77,7 @@ class CategoryRunner:
65
77
  if lot.owner_username == self.runner._account.username:
66
78
  continue
67
79
  for handler in self.runner.handler._handlers['lot_category']:
68
- await handler(lot)
80
+ asyncio.create_task(handler(lot))
69
81
 
70
82
  async def _check_chip_categories(self, chip_category_ids):
71
83
  await self._update_chip_category_cache(chip_category_ids)
@@ -75,4 +87,4 @@ class CategoryRunner:
75
87
  if lot.owner_username == self.runner._account.username:
76
88
  continue
77
89
  for handler in self.runner.handler._handlers['chip_category']:
78
- await handler(lot)
90
+ asyncio.create_task(handler(lot))
@@ -1,4 +1,5 @@
1
1
  import inspect
2
+ import asyncio
2
3
 
3
4
  from fpx.models.account import Order
4
5
  from fpx.fsm import FSMContext
@@ -48,8 +49,8 @@ class OrderRunner:
48
49
  order.finded_mapping = trigger
49
50
  matched = True
50
51
  break
51
- if not matched:
52
- return False
52
+ if not matched:
53
+ return False
53
54
  sig = inspect.signature(h_func)
54
55
  has_state = False
55
56
  for param in sig.parameters.values():
@@ -61,6 +62,33 @@ class OrderRunner:
61
62
  else:
62
63
  await h_func(order)
63
64
 
65
+ async def _check_trigger_for_command(self, order: Order, state_ctx: FSMContext):
66
+ if order.description is None:
67
+ return False
68
+ for cmd_handler in self.runner.handler._handlers['order_command']:
69
+ target_command = cmd_handler['trigger_command']
70
+ target_command_lower = {k.lower(): v for k, v in target_command.items()}
71
+ target_function = None
72
+ for command_name in target_command_lower:
73
+ if command_name in order.description.lower():
74
+ target_function = target_command_lower[command_name]
75
+ order.finded_mapping = command_name
76
+ break
77
+ if target_function is None:
78
+ continue
79
+ sig = inspect.signature(target_function)
80
+ has_state = False
81
+ for param in sig.parameters.values():
82
+ if param.annotation == FSMContext:
83
+ has_state = True
84
+ break
85
+ if has_state:
86
+ await target_function(order, state_ctx)
87
+ else:
88
+ await target_function(order)
89
+ return True
90
+ return False
91
+
64
92
  async def _trigger_order_handlers(self, order: Order):
65
93
  state_ctx = FSMContext(self.runner.storage, order.chat_id)
66
94
  status = order.status.lower()
@@ -69,20 +97,27 @@ class OrderRunner:
69
97
  if status in ('закрыт', 'closed', 'закрито'):
70
98
  for handler in self.runner.handler._handlers['confirmed_order']:
71
99
  await self._check_handler(handler, order, state_ctx)
72
- elif status in('оплачен', 'оплачено', 'paid', 'opened', 'відкрито'):
100
+ elif status in ('оплачен', 'оплачено', 'paid', 'відкрито'):
73
101
  for handler in self.runner.handler._handlers['new_order']:
74
102
  await self._check_handler(handler, order, state_ctx)
103
+ await self._check_trigger_for_command(order, state_ctx)
75
104
  elif status in ('возврат', 'повернення', 'refund'):
76
105
  for handler in self.runner.handler._handlers['refund']:
77
106
  await self._check_handler(handler, order, state_ctx)
78
107
 
108
+ async def _process_single_order(self, order: Order):
109
+ try:
110
+ order_info = await self.runner._account.order.get_order_details(order.order_id)
111
+ order.description = order_info.description
112
+ order.chat_id = order_info.chat_id
113
+ order._client = self.runner
114
+ await self._trigger_order_handlers(order)
115
+ except Exception:
116
+ pass
117
+
79
118
  async def _check_orders(self):
80
119
  await self.runner._order._update_order_cache()
81
120
  orders = await self.runner._order._compare_order_cache()
82
121
  if orders:
83
- for order in orders:
84
- order_info = await self.runner._account.order.get_order_details(order.order_id)
85
- order.description = order_info.description
86
- order.chat_id = order_info.chat_id
87
- order._client = self.runner
88
- await self._trigger_order_handlers(order)
122
+ tasks = [self._process_single_order(order) for order in orders]
123
+ await asyncio.gather(*tasks)
@@ -1,3 +1,5 @@
1
+ import asyncio
2
+
1
3
 
2
4
  from fpx.models.account import CurReview, Order
3
5
 
@@ -10,7 +12,7 @@ class ReviewRunner:
10
12
  async def _update_review_cache(self):
11
13
  '''Обновляет кеш отзывов'''
12
14
  profile = await self.runner._account.profile.profile()
13
- self.runner._cache['old_reviews'] = self.runner._cache['reviews'].copy()
15
+ self.runner._cache['old_reviews'] = self.runner._cache.get('reviews', [])
14
16
  self.runner._cache['reviews'] = profile.reviews
15
17
 
16
18
  async def _compare_review_cache(self):
@@ -23,19 +25,22 @@ class ReviewRunner:
23
25
  return result
24
26
 
25
27
  async def _target_review_processing(self, review: CurReview):
26
- order = await self.runner._account.order.get_order_details(review.order_id)
27
- review._client = self.runner
28
- review.order = order
29
- for handler in self.runner.handler._handlers['review']:
30
- if handler['stars'] is None:
31
- await handler['function'](review)
32
- else:
33
- if review.stars == handler['stars']:
34
- await handler['function'](review)
28
+ try:
29
+ order = await self.runner._account.order.get_order_details(review.order_id)
30
+ review._client = self.runner
31
+ review.order = order
32
+ for handler in self.runner.handler._handlers['review']:
33
+ if handler['stars'] is None:
34
+ asyncio.create_task(handler['function'](review))
35
+ else:
36
+ if review.stars == handler['stars']:
37
+ await handler['function'](review)
38
+ except Exception:
39
+ pass
35
40
 
36
41
  async def _check_reviews(self):
37
42
  await self.runner._review._update_review_cache()
38
43
  reviews = await self.runner._review._compare_review_cache()
39
44
  if reviews:
40
- for review in reviews:
41
- await self._target_review_processing(review)
45
+ tasks = [self._target_review_processing(review) for review in reviews]
46
+ await asyncio.gather(*tasks)
@@ -14,12 +14,35 @@ class Router:
14
14
  'chip_category': [],
15
15
  'commands': [],
16
16
  'error': [],
17
+ 'order_command': [],
17
18
 
18
19
  # системные
19
20
  'startup': [],
20
21
  'flood': []
21
22
  }
22
23
 
24
+ def registrate_order_targets(self, target_dict: dict):
25
+ '''
26
+ Метод для регистрации команд автоматизации новых заказов.
27
+
28
+ Args:
29
+ target_dict (dict): Словарь вида {'target': answer_new_def, 'моя пометка в описании': another_func}
30
+ '''
31
+ self._handlers['order_command'].append({
32
+ 'trigger_command': target_dict
33
+ })
34
+
35
+ def registrate_message_command(self, command_dict: dict):
36
+ '''
37
+ Метод для регистрации команд автоматизации сообщений.
38
+
39
+ Args:
40
+ target_dict (dict): Словарь вида {'command': answer_new_def, '!start': another_func}
41
+ '''
42
+ self._handlers['commands'].append({
43
+ 'command': command_dict
44
+ })
45
+
23
46
  def on_error(self):
24
47
  '''Декоратор для отлова ошибок'''
25
48
  def decorator(func):
@@ -31,8 +54,7 @@ class Router:
31
54
  self,
32
55
  text: str | None = None,
33
56
  mapping: dict[str, str] | None = None,
34
- state: str | None = None,
35
- command: dict | None = None
57
+ state: str | None = None
36
58
  ):
37
59
  '''Декоратор отслеживает новые сообщения.
38
60
 
@@ -48,24 +70,13 @@ class Router:
48
70
  - is_system (bool): Системное ли сообщение
49
71
  - anwer (method): При указании текста в аргументах, отвечает на сообщение
50
72
  '''
51
- if command and (text is not None or mapping is not None):
52
- raise fpx_err.FpxAttributeError('В декоратор on_message неправильно переданы аттрибуты, если вы передаёте command, остальные аргументы нельзя передавать.')
53
73
  def decorator(func):
54
- if command:
55
- self._handlers['commands'].append({
56
- 'function': func,
57
- 'filter_text': text,
58
- 'mapping': mapping,
59
- 'command': command,
60
- 'state': state
61
- })
62
- else:
63
- self._handlers['message'].append({
64
- 'function': func,
65
- 'filter_text': text,
66
- 'mapping': mapping,
67
- 'state': state
68
- })
74
+ self._handlers['message'].append({
75
+ 'function': func,
76
+ 'filter_text': text,
77
+ 'mapping': mapping,
78
+ 'state': state
79
+ })
69
80
  return func
70
81
  return decorator
71
82
 
@@ -117,9 +128,8 @@ class Router:
117
128
 
118
129
  def on_new_order(
119
130
  self,
120
- mapping: list | None = None,
121
- trigger_with_command: dict | None = None
122
- ):
131
+ mapping: list | None = None
132
+ ):
123
133
  '''
124
134
  Декоратор, который отслеживает только новые заказы.
125
135
 
@@ -6,7 +6,10 @@ from fpx.fsm import MemoryStorage, BaseStorage
6
6
 
7
7
  class FunPayTools:
8
8
  def __init__(self, gkey, storage: BaseStorage | None = None):
9
- self.cookies = {'golden_key': gkey}
9
+ self.cookies = {
10
+ 'golden_key': gkey,
11
+ 'locale': 'ru'
12
+ }
10
13
  self.headers = {
11
14
  "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:120.0) Gecko/20100101 Firefox/120.0",
12
15
  "Accept-Language": "ru-RU,ru;q=0.9"
@@ -15,7 +18,8 @@ class FunPayTools:
15
18
  http2=True,
16
19
  cookies=self.cookies,
17
20
  headers=self.headers,
18
- base_url='https://funpay.com'
21
+ base_url='https://funpay.com',
22
+ follow_redirects=True
19
23
  )
20
24
  self.account = Account(self.client)
21
25
  self.runner = Runner(self.account)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fpx-engine
3
- Version: 0.3.2
3
+ Version: 0.4.0
4
4
  Summary: Автоматизация работы с FunPay
5
5
  Author-email: Be My Code <gettofarmila@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/bymyforge/fpx
@@ -77,6 +77,7 @@ async def main():
77
77
  await message.answer('Привет')
78
78
  #запускаем приём событий
79
79
  await fp.runner.start_polling(3, is_background=True)
80
+ await fp.runner.idle()
80
81
 
81
82
  if __name__ == '__main__':
82
83
  asyncio.run(main())
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "fpx-engine"
7
- version = "0.3.2"
7
+ version = "0.4.0"
8
8
  authors = [
9
9
  { name="Be My Code", email="gettofarmila@gmail.com" },
10
10
  ]
File without changes
File without changes
File without changes
File without changes
File without changes