ymdantic 0.2.0__tar.gz → 0.2.2__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 (139) hide show
  1. ymdantic-0.2.2/.github/workflows/tests.yml +104 -0
  2. {ymdantic-0.2.0 → ymdantic-0.2.2}/.pre-commit-config.yaml +5 -0
  3. {ymdantic-0.2.0 → ymdantic-0.2.2}/PKG-INFO +9 -23
  4. {ymdantic-0.2.0 → ymdantic-0.2.2}/README.md +7 -21
  5. ymdantic-0.2.2/examples/chart.py +32 -0
  6. {ymdantic-0.2.0 → ymdantic-0.2.2}/pyproject.toml +2 -2
  7. ymdantic-0.2.2/tests/account/test_settings.py +25 -0
  8. ymdantic-0.2.2/tests/search/test_search_instant_mixed.py +141 -0
  9. {ymdantic-0.2.0 → ymdantic-0.2.2}/tests/tracks/test_get_track.py +1 -1
  10. ymdantic-0.2.2/tests/tracks/test_get_track_file_info.py +21 -0
  11. {ymdantic-0.2.0 → ymdantic-0.2.2}/tests/tracks/test_get_tracks.py +2 -2
  12. ymdantic-0.2.2/uv.lock +1162 -0
  13. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/adapters/pydantic_factory.py +8 -4
  14. ymdantic-0.2.2/ymdantic/adapters/to_query_params.py +19 -0
  15. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/client/session/aiohttp_client.py +62 -28
  16. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/client/yandex_music.py +87 -7
  17. ymdantic-0.2.2/ymdantic/exceptions/__init__.py +7 -0
  18. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/mixins.py +15 -2
  19. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/__init__.py +9 -0
  20. ymdantic-0.2.2/ymdantic/models/account/__init__.py +3 -0
  21. ymdantic-0.2.2/ymdantic/models/account/settings.py +86 -0
  22. ymdantic-0.2.2/ymdantic/models/agent.py +11 -0
  23. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/albums/album.py +23 -2
  24. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/artists/artist.py +8 -3
  25. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/artists/ratings.py +3 -3
  26. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/artists/social_link.py +3 -3
  27. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/base.py +11 -1
  28. ymdantic-0.2.2/ymdantic/models/concerts/__init__.py +0 -0
  29. ymdantic-0.2.2/ymdantic/models/content_restrictions.py +13 -0
  30. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/cover.py +21 -0
  31. ymdantic-0.2.2/ymdantic/models/custom_wave.py +31 -0
  32. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/landing/album.py +9 -4
  33. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/landing/artist.py +5 -0
  34. ymdantic-0.2.2/ymdantic/models/landing/chart.py +9 -0
  35. ymdantic-0.2.2/ymdantic/models/landing/cover.py +24 -0
  36. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/landing/editorial/new_releases.py +2 -2
  37. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/landing/in_style.py +4 -4
  38. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/landing/playlist.py +2 -2
  39. ymdantic-0.2.2/ymdantic/models/landing/waves.py +76 -0
  40. ymdantic-0.2.2/ymdantic/models/landing3/chart.py +21 -0
  41. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/playlists/playlist.py +61 -57
  42. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/playlists/track.py +2 -0
  43. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/s3.py +1 -1
  44. ymdantic-0.2.2/ymdantic/models/search/__init__.py +6 -0
  45. ymdantic-0.2.2/ymdantic/models/search/base.py +76 -0
  46. ymdantic-0.2.2/ymdantic/models/search/results.py +60 -0
  47. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/tracks/__init__.py +4 -2
  48. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/tracks/album.py +1 -0
  49. ymdantic-0.2.2/ymdantic/models/tracks/file_info.py +80 -0
  50. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/tracks/track.py +2 -1
  51. ymdantic-0.2.2/ymdantic/models/trailer.py +8 -0
  52. ymdantic-0.2.2/ymdantic/py.typed +0 -0
  53. ymdantic-0.2.0/.github/workflows/tests.yml +0 -35
  54. ymdantic-0.2.0/examples/chart.py +0 -23
  55. ymdantic-0.2.0/uv.lock +0 -1205
  56. ymdantic-0.2.0/ymdantic/exceptions/__init__.py +0 -3
  57. ymdantic-0.2.0/ymdantic/models/custom_wave.py +0 -18
  58. ymdantic-0.2.0/ymdantic/models/landing/chart.py +0 -30
  59. ymdantic-0.2.0/ymdantic/models/landing/cover.py +0 -44
  60. ymdantic-0.2.0/ymdantic/models/landing/waves.py +0 -47
  61. ymdantic-0.2.0/ymdantic/models/landing3/chart.py +0 -56
  62. {ymdantic-0.2.0 → ymdantic-0.2.2}/.editorconfig +0 -0
  63. {ymdantic-0.2.0 → ymdantic-0.2.2}/.github/workflows/pypi-release.yml +0 -0
  64. {ymdantic-0.2.0 → ymdantic-0.2.2}/.gitignore +0 -0
  65. {ymdantic-0.2.0 → ymdantic-0.2.2}/LICENSE +0 -0
  66. {ymdantic-0.2.0 → ymdantic-0.2.2}/tests/__init__.py +0 -0
  67. {ymdantic-0.2.0/tests/tracks → ymdantic-0.2.2/tests/account}/__init__.py +0 -0
  68. {ymdantic-0.2.0 → ymdantic-0.2.2}/tests/conftest.py +0 -0
  69. {ymdantic-0.2.0/ymdantic/models/clips → ymdantic-0.2.2/tests/search}/__init__.py +0 -0
  70. {ymdantic-0.2.0/ymdantic/models/concerts → ymdantic-0.2.2/tests/tracks}/__init__.py +0 -0
  71. {ymdantic-0.2.0 → ymdantic-0.2.2}/tests/tracks/test_get_track_download_info.py +0 -0
  72. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/__init__.py +0 -0
  73. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/adapters/__init__.py +0 -0
  74. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/adapters/to_camel.py +0 -0
  75. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/client/__init__.py +0 -0
  76. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/client/session/__init__.py +0 -0
  77. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/client/session/aiohttp_method.py +0 -0
  78. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/enums/__init__.py +0 -0
  79. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/enums/editorial_artists.py +0 -0
  80. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/enums/editorial_compilation.py +0 -0
  81. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/enums/editorial_new_releases.py +0 -0
  82. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/enums/editorial_promotion.py +0 -0
  83. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/enums/language.py +0 -0
  84. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/enums/open_playlist.py +0 -0
  85. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/enums/special.py +0 -0
  86. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/exceptions/custom_exceptions.py +0 -0
  87. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/action_button.py +0 -0
  88. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/albums/__init__.py +0 -0
  89. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/albums/label.py +0 -0
  90. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/artists/__init__.py +0 -0
  91. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/artists/artist_data.py +0 -0
  92. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/artists/artist_track_chart_position.py +0 -0
  93. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/artists/band_link_scanner_link.py +0 -0
  94. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/artists/concert.py +0 -0
  95. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/artists/counts.py +0 -0
  96. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/artists/description.py +0 -0
  97. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/artists/extra_action.py +0 -0
  98. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/artists/video.py +0 -0
  99. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/chart_position.py +0 -0
  100. /ymdantic-0.2.0/ymdantic/py.typed → /ymdantic-0.2.2/ymdantic/models/clips/__init__.py +0 -0
  101. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/clips/clip.py +0 -0
  102. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/concerts/city_case_forms.py +0 -0
  103. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/concerts/concert.py +0 -0
  104. {ymdantic-0.2.0/ymdantic/models/tracks → ymdantic-0.2.2/ymdantic/models}/derived_colors.py +0 -0
  105. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/error.py +0 -0
  106. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/landing/__init__.py +0 -0
  107. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/landing/chart_block.py +0 -0
  108. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/landing/editorial/__init__.py +0 -0
  109. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/landing/editorial/response.py +0 -0
  110. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/landing/liked_playlist.py +0 -0
  111. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/landing/open_playlist.py +0 -0
  112. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/landing/personal_playlist.py +0 -0
  113. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/landing/promotion.py +0 -0
  114. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/landing/skeleton/__init__.py +0 -0
  115. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/landing/skeleton/skeleton_response.py +0 -0
  116. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/landing/skeleton/tab_block.py +0 -0
  117. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/landing/skeleton/tab_data.py +0 -0
  118. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/landing/skeleton/tab_source.py +0 -0
  119. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/landing/skeleton/tabs_block.py +0 -0
  120. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/landing/skeleton/tabs_source.py +0 -0
  121. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/landing/special.py +0 -0
  122. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/landing/view_all_action.py +0 -0
  123. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/landing3/__init__.py +0 -0
  124. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/landing3/block.py +0 -0
  125. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/landing3/menu.py +0 -0
  126. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/pager.py +0 -0
  127. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/playlists/__init__.py +0 -0
  128. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/playlists/cover.py +0 -0
  129. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/playlists/owner.py +0 -0
  130. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/playlists/tag.py +0 -0
  131. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/response.py +0 -0
  132. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/theme.py +0 -0
  133. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/tracks/download_info.py +0 -0
  134. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/tracks/fade.py +0 -0
  135. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/tracks/lyrics_info.py +0 -0
  136. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/tracks/major.py +0 -0
  137. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/tracks/podcast.py +0 -0
  138. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/tracks/position.py +0 -0
  139. {ymdantic-0.2.0 → ymdantic-0.2.2}/ymdantic/models/tracks/r128.py +0 -0
@@ -0,0 +1,104 @@
1
+ name: Testing YMdantic
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+ pull_request_target:
7
+ types: [opened, synchronize, reopened]
8
+
9
+ jobs:
10
+ lint:
11
+ if: github.event_name != 'pull_request_target'
12
+ runs-on: ubuntu-latest
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ python-version: ["3.12", "3.13", "3.14"]
17
+ check:
18
+ - name: Ruff format
19
+ cmd: ruff format --diff
20
+ - name: Ruff check
21
+ cmd: ruff check ymdantic tests
22
+ - name: Mypy
23
+ cmd: mypy ymdantic tests
24
+
25
+ name: "${{ matrix.check.name }} (py${{ matrix.python-version }})"
26
+
27
+ steps:
28
+ - uses: actions/checkout@v6
29
+
30
+ - name: Install uv
31
+ uses: astral-sh/setup-uv@v7
32
+ with:
33
+ version: "0.9.17"
34
+ python-version: ${{ matrix.python-version }}
35
+ enable-cache: true
36
+
37
+ - name: Install deps
38
+ run: uv sync --locked --all-groups
39
+
40
+ - name: Run check
41
+ run: uv run ${{ matrix.check.cmd }}
42
+
43
+ test_push:
44
+ if: github.event_name == 'push'
45
+ runs-on: ubuntu-latest
46
+ strategy:
47
+ fail-fast: false
48
+ matrix:
49
+ python-version: ["3.12", "3.13", "3.14"]
50
+
51
+ name: "Pytest push (py${{ matrix.python-version }})"
52
+
53
+ steps:
54
+ - uses: actions/checkout@v6
55
+
56
+ - name: Install uv
57
+ uses: astral-sh/setup-uv@v7
58
+ with:
59
+ version: "0.9.17"
60
+ python-version: ${{ matrix.python-version }}
61
+ enable-cache: true
62
+
63
+ - name: Install deps
64
+ run: uv sync --locked --all-groups
65
+
66
+ - name: Run Pytest
67
+ env:
68
+ YM_TOKEN: ${{ secrets.YM_TOKEN }}
69
+ run: uv run pytest -vv tests
70
+
71
+ test_pr_approved:
72
+ if: github.event_name == 'pull_request_target'
73
+ runs-on: ubuntu-latest
74
+ environment: pull_requests
75
+ strategy:
76
+ fail-fast: false
77
+ matrix:
78
+ python-version: ["3.12", "3.13", "3.14"]
79
+
80
+ name: "Pytest PR approved (py${{ matrix.python-version }})"
81
+
82
+ permissions:
83
+ contents: read
84
+ pull-requests: read
85
+
86
+ steps:
87
+ - uses: actions/checkout@v6
88
+ with:
89
+ ref: ${{ github.event.pull_request.head.sha }}
90
+
91
+ - name: Install uv
92
+ uses: astral-sh/setup-uv@v7
93
+ with:
94
+ version: "0.9.17"
95
+ python-version: ${{ matrix.python-version }}
96
+ enable-cache: true
97
+
98
+ - name: Install deps
99
+ run: uv sync --locked --all-groups
100
+
101
+ - name: Run Pytest
102
+ env:
103
+ YM_TOKEN: ${{ secrets.YM_TOKEN }}
104
+ run: uv run pytest -vv tests
@@ -1,4 +1,9 @@
1
1
  repos:
2
+ - repo: https://github.com/astral-sh/uv-pre-commit
3
+ rev: 0.9.7
4
+ hooks:
5
+ - id: uv-lock
6
+
2
7
  - repo: https://github.com/pre-commit/pre-commit-hooks
3
8
  rev: v6.0.0
4
9
  hooks:
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ymdantic
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: Фреймворк предоставляющий доступ к API Яндекс Музыки (с Pydantic валидацией)
5
5
  Author-email: KatantDev <vlad26@mail.ru>
6
6
  License-File: LICENSE
7
- Requires-Python: <3.14,>=3.10
7
+ Requires-Python: <3.15,>=3.12
8
8
  Requires-Dist: aiohttp<4,>=3.9.0
9
9
  Requires-Dist: certifi<2026,>=2025
10
10
  Requires-Dist: dataclass-rest>=0.5.0
@@ -18,7 +18,7 @@ Description-Content-Type: text/markdown
18
18
  **YMDantic** - это клиентская библиотека на Python для работы с API Yandex Music.
19
19
  Она позволяет получать информацию о треках, альбомах, плейлистах и других объектах сервиса.
20
20
 
21
- Особенностью библиотеки является использование [Pydantic](https://pydantic-docs.helpmanual.io/) для валидации и сериализации данных.
21
+ Особенностью библиотеки является использование [Pydantic](https://docs.pydantic.dev/) для валидации и сериализации данных.
22
22
 
23
23
  ## Технологии
24
24
  Проект написан на Python и использует следующие библиотеки:
@@ -27,7 +27,7 @@ Description-Content-Type: text/markdown
27
27
  - Pydantic для валидации и сериализации данных
28
28
 
29
29
  ## Установка и использование
30
- Для установки библиотеки используйте pip/poetry:
30
+ Для установки библиотеки используйте pip/poetry/uv:
31
31
 
32
32
  ```bash
33
33
  pip install ymdantic
@@ -36,23 +36,9 @@ pip install ymdantic
36
36
  ```bash
37
37
  poetry add ymdantic
38
38
  ```
39
-
40
- ## Пример использования
41
- Получаем список чартов и выводим треки
42
-
43
- ```python
44
- import asyncio
45
- from ymdantic import YMClient
46
-
47
-
48
- async def get_chart(client: YMClient) -> None:
49
- chart_block = await client.get_chart()
50
- print(chart_block.title, end="\n\n")
51
- print("Треки в чарте:")
52
- for playlist_track in chart_block.chart.tracks:
53
- print(f"{playlist_track.track.artists_names} - {playlist_track.track.title}")
54
-
55
-
56
- if __name__ == "__main__":
57
- asyncio.run(get_chart(client=YMClient(token="y0_123")))
39
+ или
40
+ ```bash
41
+ uv add ymdantic
58
42
  ```
43
+
44
+ ## [Примеры использования](https://github.com/KatantDev/YMdantic/tree/main/examples)
@@ -4,7 +4,7 @@
4
4
  **YMDantic** - это клиентская библиотека на Python для работы с API Yandex Music.
5
5
  Она позволяет получать информацию о треках, альбомах, плейлистах и других объектах сервиса.
6
6
 
7
- Особенностью библиотеки является использование [Pydantic](https://pydantic-docs.helpmanual.io/) для валидации и сериализации данных.
7
+ Особенностью библиотеки является использование [Pydantic](https://docs.pydantic.dev/) для валидации и сериализации данных.
8
8
 
9
9
  ## Технологии
10
10
  Проект написан на Python и использует следующие библиотеки:
@@ -13,7 +13,7 @@
13
13
  - Pydantic для валидации и сериализации данных
14
14
 
15
15
  ## Установка и использование
16
- Для установки библиотеки используйте pip/poetry:
16
+ Для установки библиотеки используйте pip/poetry/uv:
17
17
 
18
18
  ```bash
19
19
  pip install ymdantic
@@ -22,23 +22,9 @@ pip install ymdantic
22
22
  ```bash
23
23
  poetry add ymdantic
24
24
  ```
25
-
26
- ## Пример использования
27
- Получаем список чартов и выводим треки
28
-
29
- ```python
30
- import asyncio
31
- from ymdantic import YMClient
32
-
33
-
34
- async def get_chart(client: YMClient) -> None:
35
- chart_block = await client.get_chart()
36
- print(chart_block.title, end="\n\n")
37
- print("Треки в чарте:")
38
- for playlist_track in chart_block.chart.tracks:
39
- print(f"{playlist_track.track.artists_names} - {playlist_track.track.title}")
40
-
41
-
42
- if __name__ == "__main__":
43
- asyncio.run(get_chart(client=YMClient(token="y0_123")))
25
+ или
26
+ ```bash
27
+ uv add ymdantic
44
28
  ```
29
+
30
+ ## [Примеры использования](https://github.com/KatantDev/YMdantic/tree/main/examples)
@@ -0,0 +1,32 @@
1
+ import asyncio
2
+ import os
3
+
4
+ from ymdantic import YMClient
5
+
6
+ TOKEN = os.environ["TOKEN"]
7
+
8
+
9
+ async def get_chart() -> None:
10
+ """Получаем чарт и выводим треки в консоль."""
11
+ client = YMClient(token=TOKEN)
12
+
13
+ chart_block = await client.get_chart()
14
+ print(chart_block.title)
15
+ for index, playlist_track in enumerate(chart_block.chart.tracks, start=1):
16
+ track = playlist_track.track
17
+ if track.available:
18
+ download_info = await track.get_download_info_direct()
19
+ direct_url = download_info[-1].direct_url
20
+ else:
21
+ direct_url = "Недоступен для скачивания"
22
+ print(
23
+ f"{index}. "
24
+ f"{playlist_track.track.artists_names} - {playlist_track.track.title}\n"
25
+ f"({direct_url})\n",
26
+ )
27
+
28
+ await client.close()
29
+
30
+
31
+ if __name__ == "__main__":
32
+ asyncio.run(get_chart())
@@ -1,9 +1,9 @@
1
1
  [project]
2
2
  name = "ymdantic"
3
- version = "0.2.0"
3
+ version = "0.2.2"
4
4
  description = "Фреймворк предоставляющий доступ к API Яндекс Музыки (с Pydantic валидацией)"
5
5
  authors = [{ name = "KatantDev", email = "vlad26@mail.ru" }]
6
- requires-python = ">=3.10,<3.14"
6
+ requires-python = ">=3.12,<3.15"
7
7
  readme = "README.md"
8
8
  dependencies = [
9
9
  "aiohttp>=3.9.0,<4",
@@ -0,0 +1,25 @@
1
+ import pytest
2
+ from ymdantic import YMClient
3
+ from ymdantic.models.account import SetAccountSettingsParams
4
+
5
+
6
+ @pytest.mark.anyio
7
+ async def test_set_account_settings_direct(client: YMClient) -> None:
8
+ old_settings = await client.get_account_settings()
9
+
10
+ settings = await client.set_account_settings_request(
11
+ SetAccountSettingsParams(
12
+ auto_play_radio=not old_settings.auto_play_radio,
13
+ ),
14
+ )
15
+ assert settings.result.auto_play_radio != old_settings.auto_play_radio
16
+
17
+
18
+ @pytest.mark.anyio
19
+ async def test_set_account_settings(client: YMClient) -> None:
20
+ old_settings = await client.get_account_settings()
21
+
22
+ settings = await client.set_account_settings(
23
+ auto_play_radio=not old_settings.auto_play_radio,
24
+ )
25
+ assert settings.auto_play_radio != old_settings.auto_play_radio
@@ -0,0 +1,141 @@
1
+ import pytest
2
+ from ymdantic import YMClient
3
+ from ymdantic.models.search.results import (
4
+ AlbumSearchResult,
5
+ ArtistSearchResult,
6
+ TrackSearchResult,
7
+ )
8
+
9
+ XOLIDAYBOY_ARTIST_ID = 10878798
10
+
11
+
12
+ @pytest.mark.anyio
13
+ async def test_search_instant_mixed(client: YMClient) -> None:
14
+ response = await client.search_instant_mixed(text="xolidayboy")
15
+ assert response.text == "xolidayboy"
16
+ assert len(response.results) > 0
17
+ assert response.total > 0
18
+ assert response.per_page > 0
19
+ assert isinstance(response.search_request_id, str)
20
+ assert isinstance(response.misspell_corrected, bool)
21
+
22
+
23
+ @pytest.mark.anyio
24
+ async def test_search_has_artist_result(client: YMClient) -> None:
25
+ response = await client.search_instant_mixed(text="xolidayboy")
26
+ artist_results = [r for r in response.results if isinstance(r, ArtistSearchResult)]
27
+ assert len(artist_results) > 0, (
28
+ "Expected at least one artist result for 'xolidayboy'"
29
+ )
30
+ artist = artist_results[0].artist
31
+ assert artist.id == XOLIDAYBOY_ARTIST_ID
32
+ assert artist.name.lower() == "xolidayboy"
33
+
34
+
35
+ @pytest.mark.anyio
36
+ async def test_search_has_track_results(client: YMClient) -> None:
37
+ response = await client.search_instant_mixed(text="xolidayboy")
38
+ track_results = [r for r in response.results if isinstance(r, TrackSearchResult)]
39
+ assert len(track_results) > 0, "Expected at least one track result for 'xolidayboy'"
40
+ for track_result in track_results:
41
+ track = track_result.track
42
+ assert track.id > 0
43
+ assert track.title
44
+
45
+
46
+ @pytest.mark.anyio
47
+ async def test_search_result_types(client: YMClient) -> None:
48
+ response = await client.search_instant_mixed(text="xolidayboy")
49
+ for result in response.results:
50
+ expected_types = (
51
+ "track",
52
+ "artist",
53
+ "album",
54
+ "podcast_episode",
55
+ "playlist",
56
+ )
57
+ assert result.type in expected_types
58
+
59
+
60
+ @pytest.mark.anyio
61
+ async def test_search_with_filter_artist(client: YMClient) -> None:
62
+ response = await client.search_instant_mixed(
63
+ text="xolidayboy",
64
+ filter="artist",
65
+ )
66
+ assert len(response.results) > 0
67
+ for result in response.results:
68
+ assert isinstance(result, ArtistSearchResult)
69
+ assert result.type == "artist"
70
+
71
+
72
+ @pytest.mark.anyio
73
+ async def test_search_with_filter_track(client: YMClient) -> None:
74
+ response = await client.search_instant_mixed(
75
+ text="xolidayboy",
76
+ filter="track",
77
+ )
78
+ assert len(response.results) > 0
79
+ for result in response.results:
80
+ assert isinstance(result, TrackSearchResult)
81
+ assert result.type == "track"
82
+
83
+
84
+ @pytest.mark.anyio
85
+ async def test_search_with_filter_album(client: YMClient) -> None:
86
+ response = await client.search_instant_mixed(
87
+ text="xolidayboy",
88
+ filter="album",
89
+ )
90
+ assert len(response.results) > 0
91
+ for result in response.results:
92
+ assert isinstance(result, AlbumSearchResult)
93
+ assert result.type == "album"
94
+
95
+
96
+ @pytest.mark.anyio
97
+ async def test_search_filters_present(client: YMClient) -> None:
98
+ response = await client.search_instant_mixed(text="xolidayboy")
99
+ assert len(response.filters) > 0
100
+ for f in response.filters:
101
+ assert f.id
102
+ assert f.display_name
103
+
104
+
105
+ @pytest.mark.anyio
106
+ async def test_search_nocorrect(client: YMClient) -> None:
107
+ response = await client.search_instant_mixed(
108
+ text="xolidayboy",
109
+ nocorrect=True,
110
+ )
111
+ assert response.misspell_corrected is False
112
+ assert response.text == "xolidayboy"
113
+
114
+
115
+ @pytest.mark.anyio
116
+ async def test_search_with_page_size(client: YMClient) -> None:
117
+ page_size = 5
118
+ response = await client.search_instant_mixed(
119
+ text="xolidayboy",
120
+ page_size=page_size,
121
+ )
122
+ assert response.per_page == page_size
123
+ assert len(response.results) <= page_size
124
+
125
+
126
+ @pytest.mark.anyio
127
+ async def test_search_misspelled_query(client: YMClient) -> None:
128
+ response = await client.search_instant_mixed(text="холидейбой")
129
+ assert len(response.results) > 0
130
+ artist_results = [r for r in response.results if isinstance(r, ArtistSearchResult)]
131
+ if artist_results:
132
+ assert any(a.artist.id == XOLIDAYBOY_ARTIST_ID for a in artist_results)
133
+
134
+
135
+ @pytest.mark.anyio
136
+ async def test_search_gibberish_returns_no_results(client: YMClient) -> None:
137
+ response = await client.search_instant_mixed(
138
+ text="zzzqqq999xxx888jjj777",
139
+ )
140
+ assert response.total == 0
141
+ assert len(response.results) == 0
@@ -3,7 +3,7 @@ import secrets
3
3
 
4
4
  import pytest
5
5
  from ymdantic import YMClient
6
- from ymdantic.exceptions.custom_exceptions import YMTrackNotFoundError
6
+ from ymdantic.exceptions import YMTrackNotFoundError
7
7
  from ymdantic.models import Podcast, Track, UnavailablePodcast, UnavailableTrack
8
8
 
9
9
 
@@ -0,0 +1,21 @@
1
+ import pytest
2
+ from ymdantic import YMClient
3
+ from ymdantic.models.tracks.file_info import FileInfo
4
+
5
+
6
+ @pytest.mark.anyio
7
+ async def test_get_available_track_file_info_nq(client: YMClient) -> None:
8
+ track_id = 83313323
9
+
10
+ result = await client.get_track_file_info(track_id=track_id)
11
+ assert isinstance(result, FileInfo)
12
+ assert result.quality == "nq"
13
+
14
+
15
+ @pytest.mark.anyio
16
+ async def test_get_available_track_file_info_lossless(client: YMClient) -> None:
17
+ track_id = 117708948
18
+
19
+ result = await client.get_track_file_info(track_id=track_id)
20
+ assert isinstance(result, FileInfo)
21
+ assert result.quality == "lossless"
@@ -1,6 +1,6 @@
1
1
  import asyncio
2
2
  import secrets
3
- from typing import TypedDict
3
+ from typing import Type, TypedDict
4
4
 
5
5
  import pytest
6
6
  from ymdantic import YMClient
@@ -14,7 +14,7 @@ class TrackExpected(TypedDict):
14
14
 
15
15
  type: str
16
16
  available: bool
17
- instance_type: type[BaseTrack]
17
+ instance_type: Type[BaseTrack]
18
18
 
19
19
 
20
20
  @pytest.mark.anyio