itd-sdk 2.4.2__tar.gz → 2.4.3__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 (43) hide show
  1. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/PKG-INFO +1 -1
  2. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/itd/base.py +11 -9
  3. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/itd/client.py +2 -2
  4. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/itd/comment.py +2 -2
  5. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/itd/notification.py +1 -1
  6. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/itd/post.py +7 -6
  7. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/itd/user.py +3 -14
  8. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/pyproject.toml +58 -58
  9. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/README.md +0 -0
  10. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/itd/__init__.py +0 -0
  11. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/itd/_default.py +0 -0
  12. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/itd/api/__init__.py +0 -0
  13. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/itd/api/auth.py +0 -0
  14. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/itd/api/comments.py +0 -0
  15. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/itd/api/dwell.py +0 -0
  16. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/itd/api/etc.py +0 -0
  17. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/itd/api/files.py +0 -0
  18. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/itd/api/hashtags.py +0 -0
  19. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/itd/api/notifications.py +0 -0
  20. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/itd/api/pins.py +0 -0
  21. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/itd/api/platform.py +0 -0
  22. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/itd/api/polls.py +0 -0
  23. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/itd/api/posts.py +0 -0
  24. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/itd/api/reports.py +0 -0
  25. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/itd/api/search.py +0 -0
  26. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/itd/api/sessions.py +0 -0
  27. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/itd/api/subscription.py +0 -0
  28. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/itd/api/users.py +0 -0
  29. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/itd/api/verification.py +0 -0
  30. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/itd/clan.py +0 -0
  31. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/itd/enums.py +0 -0
  32. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/itd/exceptions.py +0 -0
  33. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/itd/file.py +0 -0
  34. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/itd/hashtag.py +0 -0
  35. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/itd/logger.py +0 -0
  36. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/itd/pin.py +0 -0
  37. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/itd/poll.py +0 -0
  38. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/itd/report.py +0 -0
  39. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/itd/request.py +0 -0
  40. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/itd/session.py +0 -0
  41. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/itd/span.py +0 -0
  42. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/itd/utils.py +0 -0
  43. {itd_sdk-2.4.2 → itd_sdk-2.4.3}/itd/version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: itd-sdk
3
- Version: 2.4.2
3
+ Version: 2.4.3
4
4
  Summary: ITD client for python
5
5
  Keywords: itd,itdsocial
6
6
  Author: firedotguy
@@ -1,5 +1,5 @@
1
1
  from __future__ import annotations
2
- from typing import Any, Callable, TYPE_CHECKING, Iterator, TypeVar, overload, Literal
2
+ from typing import Any, Callable, TYPE_CHECKING, Iterator, TypeVar, overload
3
3
  from functools import wraps
4
4
  from time import sleep
5
5
  from datetime import datetime, timedelta
@@ -53,11 +53,12 @@ class ITDBaseModel:
53
53
 
54
54
  def __init__(self, client: Client | None = None) -> None:
55
55
  self._client = client or get_default_client()
56
- self._fields_from_data: set[str] = set()
56
+ self._loaded_attrs: set[str] = set()
57
57
 
58
58
  def __setattr__(self, name: str, value: Any) -> None:
59
59
  if isinstance(value, ITDBaseModel) and (client := _getattr(self, '_client')): # ai
60
60
  value._client = client
61
+
61
62
  object.__setattr__(self, name, value)
62
63
 
63
64
  def _post_refresh(self): ...
@@ -80,7 +81,7 @@ class ITDBaseModel:
80
81
  def _fill_from_data(self, data: dict):
81
82
  assert self._validator, 'Unable to use fill_from_data without a validator'
82
83
  validated = self._validator().model_validate(data) # pyright: ignore[reportCallIssue]
83
- self._fields_from_data = validated.model_fields_set
84
+ # self._loaded_attrs = validated.model_fields_set # значения автоматически добавляются через __setattr__
84
85
  for name, value in validated.__dict__.items():
85
86
  setattr(self, name, value)
86
87
 
@@ -102,18 +103,20 @@ class ITDBaseModel:
102
103
  value = _getattr(self, name)
103
104
  if (
104
105
  name.startswith('_') or # приватный аттрибут
105
- name in ('client', 'model_fields_set', 'load_status') or
106
+ name in ('client', 'model_fields_set', 'load_status') or # спец. имя
106
107
  not _getattr(self, '_refreshable') or # не рефрешабельная модель
107
108
  not _getattr(self, 'client').config.auto_load or # отключено в конфиге
108
109
  callable(value) or # функция
109
- self.load_status == LoadStatus.LOADING or
110
- (not _getattr(self, 'client').config.load_comments_from_post and _is_comments_on_post(value, self)) or
110
+ self.load_status == LoadStatus.LOADING or # сейчас загружается (уже вроде как не надо, но пусть будет на всяк)
111
+ (not _getattr(self, 'client').config.load_comments_from_post and _is_comments_on_post(value, self)) or # коменты
112
+ name in self._loaded_attrs or name in self.__dict__ or # было загружено или добавлено через setattr
111
113
  (isinstance(value, ITDBaseModel) and not value._load_with_parent)
112
114
  ):
113
115
  # l.debug('return %s as is', name)
114
116
  return object.__getattribute__(self, name)
115
117
 
116
- if isinstance(value, FieldInfo) or (self.load_status != LoadStatus.FULL and name not in self._fields_from_data):
118
+ if isinstance(value, FieldInfo) or self.load_status != LoadStatus.FULL:
119
+ l.debug('attrs %s', list(self._loaded_attrs))
117
120
  l.info('refresh %s field=%s load_status=%s', self.__class__.__name__, name, self.load_status.value)
118
121
  self.refresh()
119
122
 
@@ -243,7 +246,6 @@ class ITDList[T](ITDBaseModel, list[T]):
243
246
  def __getitem__(self, index: slice) -> list[T]: ...
244
247
 
245
248
  def __getitem__(self, index: int | slice) -> T | list[T]: # pyright: ignore[reportIncompatibleMethodOverride]
246
-
247
249
  if isinstance(index, slice):
248
250
  value: int | None = index.stop
249
251
  else:
@@ -404,7 +406,7 @@ def rate_limit(delay_min: float | None = None, delay_mid: float | None = None, d
404
406
  l.error('too large rate limit')
405
407
  raise
406
408
 
407
- retry_after = getattr(e, 'retry_after', client.config.retry_delay)
409
+ retry_after = getattr(e, 'retry_after', client.config.retry_delay) or 10
408
410
  l.warning('%s on %s: wait %ss', e.__class__.__name__, func.__name__, retry_after)
409
411
  sleep(retry_after)
410
412
 
@@ -65,7 +65,7 @@ class Config:
65
65
 
66
66
  retry_enabled: bool = True
67
67
  retry_delay: float = 10 # delay before next attempt (after rate limit error) if retry_after is not provided in request
68
- retry_max_retries: int | None = None # none for no limit
68
+ retry_max_retries: int | None = 10 # none for no limit
69
69
  retry_exceptions: tuple[type[Exception]] | list[type[Exception]] | None = None
70
70
  retry_max_retry_after: int = 500
71
71
 
@@ -287,7 +287,7 @@ class Client:
287
287
  tuple[list[User], list[Hashtag]]: Результат поиска
288
288
  """
289
289
  res = search(self, query, users_limit, hashtags_limit).json()['data']
290
- return [User._from_dict(user, client=self) for user in res['users']], [Hashtag._from_dict(hashtag, self) for hashtag in res['hashtags']]
290
+ return [User.from_dict(user, client=self) for user in res['users']], [Hashtag._from_dict(hashtag, self) for hashtag in res['hashtags']]
291
291
 
292
292
  def search_users(self, query: str, limit: int = 20) -> list[User]:
293
293
  """Поиск пользователей
@@ -152,12 +152,12 @@ class _CommentValidate(BaseModel, Comment):
152
152
  @classmethod
153
153
  def validate_reply_to(cls, reply_to: dict | None):
154
154
  if reply_to is not None:
155
- return User._from_dict(reply_to)
155
+ return User.from_dict(reply_to)
156
156
 
157
157
  @field_validator('author', mode='plain')
158
158
  @classmethod
159
159
  def validate_author(cls, author: dict):
160
- return User._from_dict(author)
160
+ return User.from_dict(author)
161
161
 
162
162
 
163
163
 
@@ -109,7 +109,7 @@ class _NotificationValidate(BaseModel, Notification):
109
109
  @field_validator('actor', mode='plain')
110
110
  @classmethod
111
111
  def validate_actor(cls, actor: dict):
112
- return User._from_dict(actor)
112
+ return User.from_dict(actor)
113
113
 
114
114
 
115
115
 
@@ -289,6 +289,7 @@ class Post(ITDBaseModel):
289
289
  Returns:
290
290
  Post: Пост
291
291
  """
292
+ # TODO rewrite with from_dict
292
293
  instance = cls.__new__(cls)
293
294
  super(Post, instance).__init__(client)
294
295
 
@@ -311,7 +312,7 @@ class Post(ITDBaseModel):
311
312
  ).json()
312
313
 
313
314
  validated = _PostValidate.model_validate(post)
314
- instance._fields_from_data = validated.model_fields_set
315
+ instance._loaded_attrs = validated.model_fields_set
315
316
  for name, value in validated.__dict__.items():
316
317
  setattr(instance, name, value)
317
318
 
@@ -405,7 +406,7 @@ class Post(ITDBaseModel):
405
406
  Post: Пост
406
407
  """
407
408
  post = repost(client or self.client, self.id, content).json()
408
- if 'reposts_count' in self._fields_from_data:
409
+ if 'reposts_count' in self._loaded_attrs:
409
410
  self.reposts_count += 1
410
411
  if (client or self.client) == self.client:
411
412
  self.is_reposted = True
@@ -429,7 +430,7 @@ class Post(ITDBaseModel):
429
430
  view_post(c, self.id)
430
431
  if c == self.client:
431
432
  self.is_viewed = True
432
- if c.config.post_view_increment and 'views_count' in self._fields_from_data:
433
+ if c.config.post_view_increment and 'views_count' in self._loaded_attrs:
433
434
  self.views_count += 1
434
435
 
435
436
  def pin(self, client: Client | None = None) -> None:
@@ -505,7 +506,7 @@ class Post(ITDBaseModel):
505
506
  Comment: Комментарий
506
507
  """
507
508
  comment = self.comments.new(content, attachments, client or self.client)
508
- if 'comments_count' in self._fields_from_data:
509
+ if 'comments_count' in self._loaded_attrs:
509
510
  self.comments_count += 1
510
511
  return comment
511
512
 
@@ -588,13 +589,13 @@ class _PostValidate(BaseModel, Post): # BaseModel MUST be first or you ll have s
588
589
  return None
589
590
  if isinstance(author, _UserBase):
590
591
  return author
591
- return User._from_dict(author)
592
+ return User.from_dict(author)
592
593
 
593
594
  @field_validator('wall_recipient', mode='plain')
594
595
  @classmethod
595
596
  def validate_wall_recipient(cls, wall_recipient: dict | None):
596
597
  if wall_recipient is not None:
597
- return User._from_dict(wall_recipient)
598
+ return User.from_dict(wall_recipient)
598
599
 
599
600
 
600
601
 
@@ -250,17 +250,6 @@ class User(_UserBase):
250
250
 
251
251
  created_at: datetime | None = Field(None, alias='createdAt') # none if blocked
252
252
 
253
- @classmethod
254
- def _from_dict(cls, data: dict, client: Client | None = None):
255
- instance = cls(data['username'], client)
256
- validated = _UserValidate.model_validate(data)
257
- instance._fields_from_data = validated.model_fields_set
258
- for name, value in validated.__dict__.items():
259
- setattr(instance, name, value)
260
-
261
- instance.load_status = LoadStatus.PARTIALLY
262
- return instance
263
-
264
253
  @classmethod
265
254
  def by_id(cls, id: UUID | str) -> 'User':
266
255
  return cls(to_uuid(id))
@@ -382,13 +371,13 @@ class User(_UserBase):
382
371
  @property
383
372
  def following(self) -> list[User]:
384
373
  if not self._following:
385
- self._following = [User._from_dict(user, client=self.client) for user in get_following(self.client, self._identifier).json()['data']['users']]
374
+ self._following = [User.from_dict(user, client=self.client) for user in get_following(self.client, self._identifier).json()['data']['users']]
386
375
  return self._following
387
376
 
388
377
  @property
389
378
  def followers(self) -> list[User]:
390
379
  if not self._followers:
391
- self._followers = [User._from_dict(user, client=self.client) for user in get_followers(self.client, self._identifier).json()['data']['users']]
380
+ self._followers = [User.from_dict(user, client=self.client) for user in get_followers(self.client, self._identifier).json()['data']['users']]
392
381
  return self._followers
393
382
 
394
383
 
@@ -582,7 +571,7 @@ class Followers(ITDList[User]):
582
571
  return data['pagination']['page'] + 1
583
572
 
584
573
  def _extend(self, objects: list, client: Client):
585
- self.extend([User._from_dict(user, client=client) for user in objects])
574
+ self.extend([User.from_dict(user, client=client) for user in objects])
586
575
 
587
576
  def __setattr__(self, name: str, value) -> None:
588
577
  if name == '_client':
@@ -1,58 +1,58 @@
1
- [build-system]
2
- requires = ["uv_build~=0.11"]
3
- build-backend = "uv_build"
4
-
5
- [tool.uv.build-backend]
6
- module-name = 'itd'
7
- module-root = ''
8
-
9
- [tool.commitizen]
10
- name = "cz_conventional_commits"
11
- tag_format = "v$version"
12
- version_scheme = "semver2"
13
- version_provider = "uv"
14
-
15
- [project]
16
- name = "itd-sdk"
17
- version = "2.4.2"
18
- description = "ITD client for python"
19
- readme = "README.md"
20
- authors = [
21
- { name = "firedotguy", email = "nta16022013@gmail.com" }
22
- ]
23
- classifiers = [
24
- 'Development Status :: 5 - Production/Stable',
25
- 'Natural Language :: Russian',
26
- 'Programming Language :: Python',
27
- 'Programming Language :: Python :: 3',
28
- 'Framework :: Pydantic :: 2'
29
- ]
30
- keywords = ['itd', 'itdsocial']
31
- license = "MIT"
32
- dependencies = [
33
- "requests~=2.32.5",
34
- "pydantic>=2.12.5,<2.14.0",
35
- "sseclient-py~=1.9.0",
36
- ]
37
- requires-python = ">=3.9"
38
-
39
- [project.urls]
40
- Homepage = 'https://itdsdk.qzz.io'
41
- Documentation = 'https://itdsdk.qzz.io/docs'
42
-
43
- [project.optional-dependencies]
44
- filetype = [
45
- "filetype>=1.2.0",
46
- ]
47
- logs = [
48
- "rich>=15.0.0",
49
- ]
50
- date = [
51
- "dateparser>=1.2.2",
52
- ]
53
-
54
- [dependency-groups]
55
- dev = [
56
- "pytest>=8.4.2",
57
- "python-dotenv>=1.2.1",
58
- ]
1
+ [build-system]
2
+ requires = ["uv_build~=0.11"]
3
+ build-backend = "uv_build"
4
+
5
+ [tool.uv.build-backend]
6
+ module-name = 'itd'
7
+ module-root = ''
8
+
9
+ [tool.commitizen]
10
+ name = "cz_conventional_commits"
11
+ tag_format = "v$version"
12
+ version_scheme = "semver2"
13
+ version_provider = "uv"
14
+
15
+ [project]
16
+ name = "itd-sdk"
17
+ version = "2.4.3"
18
+ description = "ITD client for python"
19
+ readme = "README.md"
20
+ authors = [
21
+ { name = "firedotguy", email = "nta16022013@gmail.com" }
22
+ ]
23
+ classifiers = [
24
+ 'Development Status :: 5 - Production/Stable',
25
+ 'Natural Language :: Russian',
26
+ 'Programming Language :: Python',
27
+ 'Programming Language :: Python :: 3',
28
+ 'Framework :: Pydantic :: 2'
29
+ ]
30
+ keywords = ['itd', 'itdsocial']
31
+ license = "MIT"
32
+ dependencies = [
33
+ "requests~=2.32.5",
34
+ "pydantic>=2.12.5,<2.14.0",
35
+ "sseclient-py~=1.9.0",
36
+ ]
37
+ requires-python = ">=3.9"
38
+
39
+ [project.urls]
40
+ Homepage = 'https://itdsdk.qzz.io'
41
+ Documentation = 'https://itdsdk.qzz.io/docs'
42
+
43
+ [project.optional-dependencies]
44
+ filetype = [
45
+ "filetype>=1.2.0",
46
+ ]
47
+ logs = [
48
+ "rich>=15.0.0",
49
+ ]
50
+ date = [
51
+ "dateparser>=1.2.2",
52
+ ]
53
+
54
+ [dependency-groups]
55
+ dev = [
56
+ "pytest>=8.4.2",
57
+ "python-dotenv>=1.2.1",
58
+ ]
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes