deezer-oauth-cli 1.4.0__tar.gz → 1.5.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 (26) hide show
  1. {deezer_oauth_cli-1.4.0 → deezer_oauth_cli-1.5.0}/PKG-INFO +16 -19
  2. {deezer_oauth_cli-1.4.0 → deezer_oauth_cli-1.5.0}/README.md +2 -2
  3. {deezer_oauth_cli-1.4.0 → deezer_oauth_cli-1.5.0}/pyproject.toml +43 -35
  4. deezer_oauth_cli-1.5.0/setup.cfg +4 -0
  5. deezer_oauth_cli-1.5.0/setup.py +9 -0
  6. deezer_oauth_cli-1.5.0/src/deezer_oauth/__init__.py +1 -0
  7. deezer_oauth_cli-1.5.0/src/deezer_oauth_cli.egg-info/PKG-INFO +125 -0
  8. deezer_oauth_cli-1.5.0/src/deezer_oauth_cli.egg-info/SOURCES.txt +23 -0
  9. deezer_oauth_cli-1.5.0/src/deezer_oauth_cli.egg-info/dependency_links.txt +1 -0
  10. deezer_oauth_cli-1.5.0/src/deezer_oauth_cli.egg-info/entry_points.txt +2 -0
  11. deezer_oauth_cli-1.5.0/src/deezer_oauth_cli.egg-info/requires.txt +3 -0
  12. deezer_oauth_cli-1.5.0/src/deezer_oauth_cli.egg-info/top_level.txt +1 -0
  13. deezer_oauth_cli-1.5.0/tests/test_client.py +32 -0
  14. deezer_oauth_cli-1.5.0/tests/test_dunder_main.py +12 -0
  15. deezer_oauth_cli-1.5.0/tests/test_files.py +50 -0
  16. deezer_oauth_cli-1.5.0/tests/test_main.py +18 -0
  17. deezer_oauth_cli-1.5.0/tests/test_server.py +120 -0
  18. deezer_oauth_cli-1.4.0/src/deezer_oauth/__init__.py +0 -1
  19. {deezer_oauth_cli-1.4.0 → deezer_oauth_cli-1.5.0}/LICENSE +0 -0
  20. {deezer_oauth_cli-1.4.0 → deezer_oauth_cli-1.5.0}/src/deezer_oauth/__main__.py +0 -0
  21. {deezer_oauth_cli-1.4.0 → deezer_oauth_cli-1.5.0}/src/deezer_oauth/client.py +0 -0
  22. {deezer_oauth_cli-1.4.0 → deezer_oauth_cli-1.5.0}/src/deezer_oauth/constants.py +0 -0
  23. {deezer_oauth_cli-1.4.0 → deezer_oauth_cli-1.5.0}/src/deezer_oauth/files.py +0 -0
  24. {deezer_oauth_cli-1.4.0 → deezer_oauth_cli-1.5.0}/src/deezer_oauth/main.py +0 -0
  25. {deezer_oauth_cli-1.4.0 → deezer_oauth_cli-1.5.0}/src/deezer_oauth/py.typed +0 -0
  26. {deezer_oauth_cli-1.4.0 → deezer_oauth_cli-1.5.0}/src/deezer_oauth/server.py +0 -0
@@ -1,34 +1,32 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: deezer-oauth-cli
3
- Version: 1.4.0
3
+ Version: 1.5.0
4
4
  Summary: A small CLI to quickly obtain an API token for Deezer API.
5
- Home-page: https://github.com/browniebroke/deezer-oauth-cli
5
+ Author-email: Bruno Alla <alla.brunoo@gmail.com>
6
6
  License: MIT
7
- Author: Bruno Alla
8
- Author-email: alla.brunoo@gmail.com
9
- Requires-Python: >=3.9,<4.0
7
+ Project-URL: Bug Tracker, https://github.com/browniebroke/deezer-oauth-cli/issues
8
+ Project-URL: Changelog, https://github.com/browniebroke/deezer-oauth-cli/blob/main/CHANGELOG.md
9
+ Project-URL: documentation, https://github.com/browniebroke/deezer-oauth-cli/blob/main/README.md
10
+ Project-URL: Mastodon, https://fosstodon.org/@browniebroke
11
+ Project-URL: repository, https://github.com/browniebroke/deezer-oauth-cli
12
+ Project-URL: Twitter, https://twitter.com/_BrunoAlla
10
13
  Classifier: Development Status :: 2 - Pre-Alpha
11
14
  Classifier: Intended Audience :: Developers
12
- Classifier: License :: OSI Approved :: MIT License
13
15
  Classifier: Natural Language :: English
14
16
  Classifier: Operating System :: OS Independent
15
- Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3 :: Only
16
18
  Classifier: Programming Language :: Python :: 3.9
17
19
  Classifier: Programming Language :: Python :: 3.10
18
20
  Classifier: Programming Language :: Python :: 3.11
19
21
  Classifier: Programming Language :: Python :: 3.12
20
22
  Classifier: Programming Language :: Python :: 3.13
21
23
  Classifier: Topic :: Software Development :: Libraries
22
- Requires-Dist: httpx (>=0.27.0)
23
- Requires-Dist: rich (>=10)
24
- Requires-Dist: typer[all] (>=0.12.0)
25
- Project-URL: Bug Tracker, https://github.com/browniebroke/deezer-oauth-cli/issues
26
- Project-URL: Changelog, https://github.com/browniebroke/deezer-oauth-cli/blob/main/CHANGELOG.md
27
- Project-URL: Documentation, https://github.com/browniebroke/deezer-oauth-cli/blob/main/README.md
28
- Project-URL: Mastodon, https://fosstodon.org/@browniebroke
29
- Project-URL: Repository, https://github.com/browniebroke/deezer-oauth-cli
30
- Project-URL: Twitter, https://twitter.com/_BrunoAlla
24
+ Requires-Python: >=3.9
31
25
  Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+ Requires-Dist: httpx<0.28,>=0.27
28
+ Requires-Dist: rich>=10
29
+ Requires-Dist: typer[all]>=0.12
32
30
 
33
31
  # Deezer OAuth CLI
34
32
 
@@ -41,8 +39,8 @@ Description-Content-Type: text/markdown
41
39
  </a>
42
40
  </p>
43
41
  <p align="center">
44
- <a href="https://python-poetry.org/">
45
- <img src="https://img.shields.io/endpoint?url=https://python-poetry.org/badge/v0.json" alt="Poetry">
42
+ <a href="https://github.com/astral-sh/uv">
43
+ <img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json" alt="uv">
46
44
  </a>
47
45
  <a href="https://github.com/astral-sh/ruff">
48
46
  <img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json" alt="Ruff">
@@ -125,4 +123,3 @@ This package was created with
125
123
  [Cookiecutter](https://github.com/audreyr/cookiecutter) and the
126
124
  [browniebroke/cookiecutter-pypackage](https://github.com/browniebroke/cookiecutter-pypackage)
127
125
  project template.
128
-
@@ -9,8 +9,8 @@
9
9
  </a>
10
10
  </p>
11
11
  <p align="center">
12
- <a href="https://python-poetry.org/">
13
- <img src="https://img.shields.io/endpoint?url=https://python-poetry.org/badge/v0.json" alt="Poetry">
12
+ <a href="https://github.com/astral-sh/uv">
13
+ <img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json" alt="uv">
14
14
  </a>
15
15
  <a href="https://github.com/astral-sh/ruff">
16
16
  <img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json" alt="Ruff">
@@ -1,49 +1,52 @@
1
1
  [build-system]
2
- build-backend = "poetry.core.masonry.api"
3
- requires = [ "poetry-core>=1" ]
2
+ build-backend = "setuptools.build_meta"
3
+ requires = [ "setuptools" ]
4
4
 
5
- [tool.poetry]
5
+ [project]
6
6
  name = "deezer-oauth-cli"
7
- version = "1.4.0"
7
+ version = "1.5.0"
8
8
  description = "A small CLI to quickly obtain an API token for Deezer API."
9
- authors = [ "Bruno Alla <alla.brunoo@gmail.com>" ]
10
- license = "MIT"
11
9
  readme = "README.md"
12
- repository = "https://github.com/browniebroke/deezer-oauth-cli"
13
- documentation = "https://github.com/browniebroke/deezer-oauth-cli/blob/main/README.md"
10
+ license = { text = "MIT" }
11
+ authors = [
12
+ { name = "Bruno Alla", email = "alla.brunoo@gmail.com" },
13
+ ]
14
+ requires-python = ">=3.9"
14
15
  classifiers = [
15
16
  "Development Status :: 2 - Pre-Alpha",
16
17
  "Intended Audience :: Developers",
17
18
  "Natural Language :: English",
18
19
  "Operating System :: OS Independent",
19
- "Topic :: Software Development :: Libraries",
20
+ "Programming Language :: Python :: 3 :: Only",
21
+ "Programming Language :: Python :: 3.9",
22
+ "Programming Language :: Python :: 3.10",
23
+ "Programming Language :: Python :: 3.11",
20
24
  "Programming Language :: Python :: 3.12",
25
+ "Programming Language :: Python :: 3.13",
26
+ "Topic :: Software Development :: Libraries",
21
27
  ]
22
- packages = [
23
- { include = "deezer_oauth", from = "src" },
24
- ]
25
-
26
- [tool.poetry.urls]
27
- "Bug Tracker" = "https://github.com/browniebroke/deezer-oauth-cli/issues"
28
- "Changelog" = "https://github.com/browniebroke/deezer-oauth-cli/blob/main/CHANGELOG.md"
29
- "Twitter" = "https://twitter.com/_BrunoAlla"
30
- "Mastodon" = "https://fosstodon.org/@browniebroke"
31
28
 
32
- [tool.poetry.scripts]
33
- deezer-oauth = "deezer_oauth.main:app"
34
-
35
- [tool.poetry.dependencies]
36
- python = "^3.9"
37
- httpx = ">=0.27.0"
38
- rich = ">=10"
39
- typer = { extras = [ "all" ], version = ">=0.12.0" }
40
-
41
- [tool.poetry.group.dev.dependencies]
42
- pyfakefs = "^5.0"
43
- pytest = "^8.0.0"
44
- pytest-cov = "^5.0.0"
45
- pytest-mock = "^3.6"
46
- respx = "^0.21.1"
29
+ dependencies = [
30
+ "httpx>=0.27,<0.28",
31
+ "rich>=10",
32
+ "typer[all]>=0.12",
33
+ ]
34
+ urls."Bug Tracker" = "https://github.com/browniebroke/deezer-oauth-cli/issues"
35
+ urls.Changelog = "https://github.com/browniebroke/deezer-oauth-cli/blob/main/CHANGELOG.md"
36
+ urls.documentation = "https://github.com/browniebroke/deezer-oauth-cli/blob/main/README.md"
37
+ urls.Mastodon = "https://fosstodon.org/@browniebroke"
38
+ urls.repository = "https://github.com/browniebroke/deezer-oauth-cli"
39
+ urls.Twitter = "https://twitter.com/_BrunoAlla"
40
+ scripts.deezer-oauth = "deezer_oauth.main:app"
41
+
42
+ [dependency-groups]
43
+ dev = [
44
+ "pyfakefs>=5,<6",
45
+ "pytest>=8,<9",
46
+ "pytest-cov>=6,<7",
47
+ "pytest-mock>=3.6,<4",
48
+ "respx>=0.21.1,<1",
49
+ ]
47
50
 
48
51
  [tool.ruff]
49
52
  target-version = "py39"
@@ -111,11 +114,16 @@ module = "tests.*"
111
114
  allow_untyped_defs = true
112
115
 
113
116
  [tool.semantic_release]
114
- version_toml = [ "pyproject.toml:tool.poetry.version" ]
117
+ version_toml = [ "pyproject.toml:project.version" ]
115
118
  version_variables = [
116
119
  "src/deezer_oauth/__init__.py:__version__",
117
120
  ]
118
- build_command = "pip install poetry && poetry build"
121
+ build_command = """
122
+ pip install uv
123
+ uv lock
124
+ git add uv.lock
125
+ uv build
126
+ """
119
127
 
120
128
  [tool.semantic_release.changelog]
121
129
  exclude_commit_patterns = [
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env python
2
+
3
+ # This is a shim to allow GitHub to detect the package, build is done with poetry
4
+ # Taken from https://github.com/Textualize/rich
5
+
6
+ import setuptools
7
+
8
+ if __name__ == "__main__":
9
+ setuptools.setup(name="deezer-oauth-cli")
@@ -0,0 +1 @@
1
+ __version__ = "1.5.0"
@@ -0,0 +1,125 @@
1
+ Metadata-Version: 2.1
2
+ Name: deezer-oauth-cli
3
+ Version: 1.5.0
4
+ Summary: A small CLI to quickly obtain an API token for Deezer API.
5
+ Author-email: Bruno Alla <alla.brunoo@gmail.com>
6
+ License: MIT
7
+ Project-URL: Bug Tracker, https://github.com/browniebroke/deezer-oauth-cli/issues
8
+ Project-URL: Changelog, https://github.com/browniebroke/deezer-oauth-cli/blob/main/CHANGELOG.md
9
+ Project-URL: documentation, https://github.com/browniebroke/deezer-oauth-cli/blob/main/README.md
10
+ Project-URL: Mastodon, https://fosstodon.org/@browniebroke
11
+ Project-URL: repository, https://github.com/browniebroke/deezer-oauth-cli
12
+ Project-URL: Twitter, https://twitter.com/_BrunoAlla
13
+ Classifier: Development Status :: 2 - Pre-Alpha
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Natural Language :: English
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Topic :: Software Development :: Libraries
24
+ Requires-Python: >=3.9
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+ Requires-Dist: httpx<0.28,>=0.27
28
+ Requires-Dist: rich>=10
29
+ Requires-Dist: typer[all]>=0.12
30
+
31
+ # Deezer OAuth CLI
32
+
33
+ <p align="center">
34
+ <a href="https://github.com/browniebroke/deezer-oauth-cli/actions/workflows/ci.yml?query=branch%3Amain">
35
+ <img src="https://img.shields.io/github/actions/workflow/status/browniebroke/deezer-oauth-cli/ci.yml?branch=main&label=CI&logo=github&style=flat-square" alt="CI Status" >
36
+ </a>
37
+ <a href="https://codecov.io/gh/browniebroke/deezer-oauth-cli">
38
+ <img src="https://img.shields.io/codecov/c/github/browniebroke/deezer-oauth-cli.svg?logo=codecov&logoColor=fff&style=flat-square" alt="Test coverage percentage">
39
+ </a>
40
+ </p>
41
+ <p align="center">
42
+ <a href="https://github.com/astral-sh/uv">
43
+ <img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json" alt="uv">
44
+ </a>
45
+ <a href="https://github.com/astral-sh/ruff">
46
+ <img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json" alt="Ruff">
47
+ </a>
48
+ <a href="https://github.com/pre-commit/pre-commit">
49
+ <img src="https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white&style=flat-square" alt="pre-commit">
50
+ </a>
51
+ </p>
52
+ <p align="center">
53
+ <a href="https://pypi.org/project/deezer-oauth-cli/">
54
+ <img src="https://img.shields.io/pypi/v/deezer-oauth-cli.svg?logo=python&logoColor=fff&style=flat-square" alt="PyPI Version">
55
+ </a>
56
+ <img src="https://img.shields.io/pypi/pyversions/deezer-oauth-cli.svg?style=flat-square&logo=python&amp;logoColor=fff" alt="Supported Python versions">
57
+ <img src="https://img.shields.io/pypi/l/deezer-oauth-cli.svg?style=flat-square" alt="License">
58
+ </p>
59
+
60
+ ---
61
+
62
+ **Source Code**: <a href="https://github.com/browniebroke/deezer-oauth-cli" target="_blank">https://github.com/browniebroke/deezer-oauth-cli</a>
63
+
64
+ ---
65
+
66
+ A small CLI to quickly obtain an API token for the Deezer API.
67
+
68
+ Obtaining API token to develop API applications can be complicated and sometimes feel like a chicken and egg situation: it's hard to play with the API without a token, but it can be difficult to get a token without an application to do the OAuth flow.
69
+
70
+ Given the app ID and secret, this tool lets you quickly get an API token.
71
+
72
+ ## Installation
73
+
74
+ Install this via pip (or your favourite package manager):
75
+
76
+ `pip install deezer-oauth-cli`
77
+
78
+ ## Usage
79
+
80
+ Before starting to use this tool, you first need to declare your Deezer app in [their developer portal](https://developers.deezer.com). Create a new app with the following Redirect URL: `http://localhost:8080/oauth/return`.
81
+
82
+ Once created, Deezer will generate an application ID and secret key for you, that's the 2 parameters that you need to run this tool:
83
+
84
+ ```shell
85
+ $ deezer-oauth APP_ID APP_SECRET
86
+ ```
87
+
88
+ This will:
89
+
90
+ - Spin up a webserver in the background running at `http://localhost:8080`.
91
+ - Open your browser to grant authorisation access to your Deezer account.
92
+ - Redirect to a page showing the API token & expiry.
93
+ - Write the token to a `.env` file.
94
+
95
+ ## Contributors ✨
96
+
97
+ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
98
+
99
+ <!-- prettier-ignore-start -->
100
+ <!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
101
+ <!-- prettier-ignore-start -->
102
+ <!-- markdownlint-disable -->
103
+ <table>
104
+ <tbody>
105
+ <tr>
106
+ <td align="center"><a href="https://browniebroke.com/"><img src="https://avatars.githubusercontent.com/u/861044?v=4?s=80" width="80px;" alt="Bruno Alla"/><br /><sub><b>Bruno Alla</b></sub></a><br /><a href="https://github.com/browniebroke/deezer-oauth-cli/commits?author=browniebroke" title="Code">💻</a> <a href="#ideas-browniebroke" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/browniebroke/deezer-oauth-cli/commits?author=browniebroke" title="Documentation">📖</a></td>
107
+ <td align="center"><a href="https://github.com/prndrbr"><img src="https://avatars.githubusercontent.com/u/96344856?v=4?s=80" width="80px;" alt="Pierre"/><br /><sub><b>Pierre</b></sub></a><br /><a href="https://github.com/browniebroke/deezer-oauth-cli/commits?author=prndrbr" title="Code">💻</a></td>
108
+ </tr>
109
+ </tbody>
110
+ </table>
111
+
112
+ <!-- markdownlint-restore -->
113
+ <!-- prettier-ignore-end -->
114
+
115
+ <!-- ALL-CONTRIBUTORS-LIST:END -->
116
+ <!-- prettier-ignore-end -->
117
+
118
+ This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
119
+
120
+ ## Credits
121
+
122
+ This package was created with
123
+ [Cookiecutter](https://github.com/audreyr/cookiecutter) and the
124
+ [browniebroke/cookiecutter-pypackage](https://github.com/browniebroke/cookiecutter-pypackage)
125
+ project template.
@@ -0,0 +1,23 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ setup.py
5
+ src/deezer_oauth/__init__.py
6
+ src/deezer_oauth/__main__.py
7
+ src/deezer_oauth/client.py
8
+ src/deezer_oauth/constants.py
9
+ src/deezer_oauth/files.py
10
+ src/deezer_oauth/main.py
11
+ src/deezer_oauth/py.typed
12
+ src/deezer_oauth/server.py
13
+ src/deezer_oauth_cli.egg-info/PKG-INFO
14
+ src/deezer_oauth_cli.egg-info/SOURCES.txt
15
+ src/deezer_oauth_cli.egg-info/dependency_links.txt
16
+ src/deezer_oauth_cli.egg-info/entry_points.txt
17
+ src/deezer_oauth_cli.egg-info/requires.txt
18
+ src/deezer_oauth_cli.egg-info/top_level.txt
19
+ tests/test_client.py
20
+ tests/test_dunder_main.py
21
+ tests/test_files.py
22
+ tests/test_main.py
23
+ tests/test_server.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ deezer-oauth = deezer_oauth.main:app
@@ -0,0 +1,3 @@
1
+ httpx<0.28,>=0.27
2
+ rich>=10
3
+ typer[all]>=0.12
@@ -0,0 +1,32 @@
1
+ import httpx
2
+ import pytest
3
+ import respx
4
+
5
+ from deezer_oauth.client import OAuthDancer
6
+
7
+
8
+ class TestOAuthDancer:
9
+ def test_get_auth_page(self) -> None:
10
+ dancer = OAuthDancer(app_id="1234", app_secret="dzr-secret") # noqa S106
11
+ url = dancer.get_auth_page()
12
+ assert url == (
13
+ "https://connect.deezer.com/oauth/auth.php"
14
+ "?app_id=1234"
15
+ "&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Foauth%2Freturn"
16
+ "&perms=basic_access%2Cemail%2Cmanage_library%2Cmanage_community"
17
+ "%2Cdelete_library%2Clistening_history"
18
+ )
19
+
20
+ @pytest.mark.respx(base_url="https://connect.deezer.com")
21
+ def test_get_token(self, respx_mock: respx.MockRouter) -> None:
22
+ get_token_route: respx.Route = respx_mock.get("/oauth/access_token.php")
23
+ get_token_route.mock(
24
+ return_value=httpx.Response(
25
+ status_code=200,
26
+ text="access_token=blah&expires=1234",
27
+ )
28
+ )
29
+ dancer = OAuthDancer(app_id="abcd", app_secret="secret") # noqa S106
30
+ result = dancer.get_token("my-personal-code")
31
+ assert result == {"access_token": "blah", "expires": "1234"}
32
+ assert get_token_route.call_count == 1
@@ -0,0 +1,12 @@
1
+ import subprocess
2
+ import sys
3
+
4
+
5
+ def test_can_run_as_python_module():
6
+ result = subprocess.run( # noqa: S603
7
+ [sys.executable, "-m", "deezer_oauth", "--help"],
8
+ check=True,
9
+ capture_output=True,
10
+ )
11
+ assert result.returncode == 0
12
+ assert b"deezer-oauth [OPTIONS]" in result.stdout
@@ -0,0 +1,50 @@
1
+ from pathlib import Path
2
+
3
+ import pytest
4
+
5
+ from deezer_oauth.files import write_env_file
6
+
7
+
8
+ class TestWriteEnvFile:
9
+ def test_create(self, fs):
10
+ env_file = Path(".env")
11
+ assert not env_file.exists()
12
+ write_env_file("qwerty")
13
+ assert env_file.exists()
14
+ assert env_file.read_text("utf-8") == "API_TOKEN=qwerty\n"
15
+
16
+ @pytest.mark.parametrize(
17
+ ("before", "after"),
18
+ [
19
+ (
20
+ "SOMETHING=test\n",
21
+ "SOMETHING=test\nAPI_TOKEN=new\n",
22
+ ),
23
+ (
24
+ "SOMETHING=test\nAPI_TOKEN=old\n",
25
+ "SOMETHING=test\nAPI_TOKEN=new\n",
26
+ ),
27
+ (
28
+ "OTHER_API_TOKEN=test\nAPI_TOKEN=old\n",
29
+ "OTHER_API_TOKEN=test\nAPI_TOKEN=new\n",
30
+ ),
31
+ (
32
+ "API_TOKEN=old\nTHING=test",
33
+ "API_TOKEN=new\nTHING=test\n",
34
+ ),
35
+ (
36
+ "API_TOKEN=old\n",
37
+ "API_TOKEN=new\n",
38
+ ),
39
+ (
40
+ "API_TOKEN=old",
41
+ "API_TOKEN=new\n",
42
+ ),
43
+ ],
44
+ )
45
+ def test_update(self, before, after):
46
+ env_file = Path(".env")
47
+ env_file.write_text(before)
48
+ write_env_file("new")
49
+ assert env_file.exists()
50
+ assert env_file.read_text() == after
@@ -0,0 +1,18 @@
1
+ from typer.testing import CliRunner
2
+
3
+ from deezer_oauth.main import app
4
+
5
+ runner = CliRunner()
6
+
7
+
8
+ def test_no_arguments():
9
+ result = runner.invoke(app)
10
+ assert result.exit_code == 2
11
+ assert "Error" in result.stdout
12
+ assert "Missing argument 'APP_ID'." in result.stdout
13
+
14
+
15
+ def test_help():
16
+ result = runner.invoke(app, ["--help"])
17
+ assert result.exit_code == 0
18
+ assert "Obtain an API token from Deezer." in result.stdout
@@ -0,0 +1,120 @@
1
+ import http.client
2
+ import sys
3
+ import threading
4
+
5
+ if sys.version_info < (3, 10):
6
+ from test.support import threading_cleanup, threading_setup
7
+ else:
8
+ from test.support.threading_helper import threading_cleanup, threading_setup
9
+
10
+ import pytest
11
+
12
+ from deezer_oauth.client import OAuthDancer
13
+ from deezer_oauth.server import LocalHTTPServer, LocalRequestHandler, run_server
14
+
15
+
16
+ class TestRunServer:
17
+ def test_run_ok(self, mocker):
18
+ serve_forever = mocker.patch("deezer_oauth.server.HTTPServer.serve_forever")
19
+ server_close = mocker.patch("deezer_oauth.server.HTTPServer.server_close")
20
+ run_server(OAuthDancer("a", "b"))
21
+ serve_forever.assert_called_once()
22
+ server_close.assert_called_once()
23
+
24
+ @pytest.mark.parametrize("exception_class", [KeyboardInterrupt, SystemExit])
25
+ def test_interrupted(self, mocker, exception_class):
26
+ mocker.patch("deezer_oauth.server.HTTPServer.__init__")
27
+ serve_forever = mocker.patch(
28
+ "deezer_oauth.server.HTTPServer.serve_forever",
29
+ side_effect=exception_class(),
30
+ )
31
+ server_close = mocker.patch("deezer_oauth.server.HTTPServer.server_close")
32
+ run_server(OAuthDancer("a", "b"))
33
+ serve_forever.assert_called_once()
34
+ server_close.assert_called_once()
35
+
36
+
37
+ class ServerWrapperThread(threading.Thread):
38
+ """
39
+ Run a server in a separate thread.
40
+
41
+ Forked from a similar class from the stdlib that can be found at:
42
+ test.test_httpservers#TestServerThread
43
+ """
44
+
45
+ server: LocalHTTPServer
46
+
47
+ def __init__(self, test_class):
48
+ threading.Thread.__init__(self)
49
+ self.test_class = test_class
50
+
51
+ def run(self):
52
+ self.server = LocalHTTPServer(
53
+ OAuthDancer("a", "b"),
54
+ ("localhost", 0),
55
+ LocalRequestHandler,
56
+ )
57
+ self.test_class.host, self.test_class.port = self.server.socket.getsockname()
58
+ self.test_class.server_started.set()
59
+ self.test_class = None
60
+ try:
61
+ self.server.serve_forever(0.05)
62
+ finally:
63
+ self.server.server_close()
64
+
65
+ def stop(self):
66
+ self.server.shutdown()
67
+ self.join()
68
+
69
+
70
+ class TestLocalRequestHandler:
71
+ host: str
72
+ port: int
73
+ server_started: threading.Event
74
+
75
+ @pytest.fixture
76
+ def http_server(self):
77
+ _threads = threading_setup()
78
+ self.server_started = threading.Event()
79
+ thread = ServerWrapperThread(self)
80
+ thread.start()
81
+ self.server_started.wait()
82
+ yield
83
+ thread.stop()
84
+ # clear assignment to avoid dangling thread
85
+ thread = None # type: ignore[assignment]
86
+ threading_cleanup(*_threads)
87
+
88
+ def request(self, uri, method="GET"):
89
+ self.connection = http.client.HTTPConnection(self.host, self.port)
90
+ self.connection.request(method, uri)
91
+ return self.connection.getresponse()
92
+
93
+ def test_default_route(self, http_server):
94
+ response = self.request("/")
95
+ assert isinstance(response, http.client.HTTPResponse)
96
+ assert response.status == 200
97
+ body = response.read().decode()
98
+ assert "<title>Deezer API OAuth dancer</title>" in body
99
+ assert "Start Oauth Flow" in body
100
+
101
+ def test_return_route_no_query_string(self, http_server):
102
+ response = self.request("/oauth/return")
103
+ assert isinstance(response, http.client.HTTPResponse)
104
+ assert response.status == 400
105
+ body = response.read().decode()
106
+ assert "Invalid request: missing query parameters" in body
107
+
108
+ def test_return_route_with_query_string(self, http_server, mocker):
109
+ mocker.patch(
110
+ "deezer_oauth.client.OAuthDancer.get_token",
111
+ return_value={"access_token": "something", "expires": 12345},
112
+ )
113
+ write_env_file = mocker.patch("deezer_oauth.server.write_env_file")
114
+ response = self.request("/oauth/return?code=abcdef")
115
+ assert isinstance(response, http.client.HTTPResponse)
116
+ assert response.status == 200
117
+ body = response.read().decode()
118
+ assert "Token: something" in body
119
+ assert "Expires: 12345" in body
120
+ write_env_file.assert_called()
@@ -1 +0,0 @@
1
- __version__ = "1.4.0"