steam-client 2.1.0.dev0__tar.gz → 3.0.0.dev0__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.
- {steam-client-2.1.0.dev0/steam_client.egg-info → steam_client-3.0.0.dev0}/PKG-INFO +5 -2
- {steam-client-2.1.0.dev0 → steam_client-3.0.0.dev0}/pyproject.toml +4 -4
- {steam-client-2.1.0.dev0 → steam_client-3.0.0.dev0}/steam_client/app.py +2 -2
- {steam-client-2.1.0.dev0 → steam_client-3.0.0.dev0}/steam_client/commands.py +10 -10
- {steam-client-2.1.0.dev0 → steam_client-3.0.0.dev0}/steam_client/game.py +29 -12
- {steam-client-2.1.0.dev0 → steam_client-3.0.0.dev0}/steam_client/library.py +2 -3
- {steam-client-2.1.0.dev0 → steam_client-3.0.0.dev0}/steam_client/library_directory.py +0 -3
- {steam-client-2.1.0.dev0 → steam_client-3.0.0.dev0}/steam_client/utils.py +7 -3
- {steam-client-2.1.0.dev0 → steam_client-3.0.0.dev0/steam_client.egg-info}/PKG-INFO +5 -2
- {steam-client-2.1.0.dev0 → steam_client-3.0.0.dev0}/steam_client.egg-info/SOURCES.txt +6 -1
- steam_client-3.0.0.dev0/tests/test_commands.py +61 -0
- steam_client-3.0.0.dev0/tests/test_game.py +61 -0
- steam_client-3.0.0.dev0/tests/test_login_users.py +112 -0
- steam_client-3.0.0.dev0/tests/test_shortcut.py +69 -0
- steam_client-3.0.0.dev0/tests/test_steam.py +34 -0
- {steam-client-2.1.0.dev0 → steam_client-3.0.0.dev0}/LICENSE +0 -0
- {steam-client-2.1.0.dev0 → steam_client-3.0.0.dev0}/setup.cfg +0 -0
- {steam-client-2.1.0.dev0 → steam_client-3.0.0.dev0}/setup.py +0 -0
- {steam-client-2.1.0.dev0 → steam_client-3.0.0.dev0}/steam_client/__init__.py +0 -0
- {steam-client-2.1.0.dev0 → steam_client-3.0.0.dev0}/steam_client/login_users.py +0 -0
- {steam-client-2.1.0.dev0 → steam_client-3.0.0.dev0}/steam_client/py.typed +0 -0
- {steam-client-2.1.0.dev0 → steam_client-3.0.0.dev0}/steam_client/shortcut.py +0 -0
- {steam-client-2.1.0.dev0 → steam_client-3.0.0.dev0}/steam_client/steam.py +0 -0
- {steam-client-2.1.0.dev0 → steam_client-3.0.0.dev0}/steam_client/web_api.py +0 -0
- {steam-client-2.1.0.dev0 → steam_client-3.0.0.dev0}/steam_client.egg-info/dependency_links.txt +0 -0
- {steam-client-2.1.0.dev0 → steam_client-3.0.0.dev0}/steam_client.egg-info/requires.txt +0 -0
- {steam-client-2.1.0.dev0 → steam_client-3.0.0.dev0}/steam_client.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: steam-client
|
|
3
|
-
Version:
|
|
3
|
+
Version: 3.0.0.dev0
|
|
4
4
|
Summary: Steam client library for Python
|
|
5
5
|
Author-email: William McAllister <dev.garulf@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -11,3 +11,6 @@ Classifier: Programming Language :: Python :: 3 :: Only
|
|
|
11
11
|
Requires-Python: >=3.8
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
13
|
License-File: LICENSE
|
|
14
|
+
Requires-Dist: vdf>=3.4
|
|
15
|
+
Requires-Dist: pycrc>=0.10.0
|
|
16
|
+
Dynamic: license-file
|
|
@@ -6,7 +6,7 @@ name = "steam-client"
|
|
|
6
6
|
authors = [
|
|
7
7
|
{name = "William McAllister", email = "dev.garulf@gmail.com"}
|
|
8
8
|
]
|
|
9
|
-
version = "
|
|
9
|
+
version = "3.0.0-dev.0"
|
|
10
10
|
description = "Steam client library for Python"
|
|
11
11
|
readme = "README.md"
|
|
12
12
|
requires-python = ">=3.8"
|
|
@@ -31,7 +31,9 @@ packages = ["steam_client"]
|
|
|
31
31
|
"steam_client" = ["py.typed"]
|
|
32
32
|
|
|
33
33
|
[tool.bumpversion]
|
|
34
|
-
current_version = "
|
|
34
|
+
current_version = "3.0.0-dev.0"
|
|
35
|
+
search = "version = \"{current_version}\""
|
|
36
|
+
replace = "version = \"{new_version}\""
|
|
35
37
|
parse = """(?x)
|
|
36
38
|
(?P<major>[0-9]+)
|
|
37
39
|
\\.(?P<minor>[0-9]+)
|
|
@@ -45,8 +47,6 @@ serialize = [
|
|
|
45
47
|
"{major}.{minor}.{patch}-{label}.{label_n}",
|
|
46
48
|
"{major}.{minor}.{patch}",
|
|
47
49
|
]
|
|
48
|
-
search = "version = '{current_version}'"
|
|
49
|
-
replace = "version = '{new_version}'"
|
|
50
50
|
tag = true
|
|
51
51
|
allow_dirty = false
|
|
52
52
|
commit = true
|
|
@@ -4,7 +4,7 @@ from pathlib import Path
|
|
|
4
4
|
from typing import TYPE_CHECKING
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
from .commands import Commands
|
|
7
|
+
from .commands import Commands
|
|
8
8
|
|
|
9
9
|
if TYPE_CHECKING:
|
|
10
10
|
from .steam import Steam
|
|
@@ -31,7 +31,7 @@ class App(ABC):
|
|
|
31
31
|
|
|
32
32
|
@property
|
|
33
33
|
@abstractmethod
|
|
34
|
-
def icon(self) -> Path:
|
|
34
|
+
def icon(self) -> Path | None:
|
|
35
35
|
"""Returns the path to the icon image."""
|
|
36
36
|
pass
|
|
37
37
|
|
|
@@ -4,6 +4,7 @@ from enum import StrEnum
|
|
|
4
4
|
|
|
5
5
|
SCHEME = 'steam'
|
|
6
6
|
|
|
7
|
+
|
|
7
8
|
class SteamWindows(StrEnum):
|
|
8
9
|
"""Enumeration of Steam client windows."""
|
|
9
10
|
MAIN = 'main'
|
|
@@ -19,8 +20,9 @@ class SteamWindows(StrEnum):
|
|
|
19
20
|
TOOLS = 'tools'
|
|
20
21
|
CONSOLE = 'console'
|
|
21
22
|
|
|
23
|
+
|
|
22
24
|
class Command():
|
|
23
|
-
|
|
25
|
+
|
|
24
26
|
def __init__(self, scheme: str):
|
|
25
27
|
self._scheme = scheme
|
|
26
28
|
|
|
@@ -38,32 +40,30 @@ class Commands:
|
|
|
38
40
|
def __init__(self):
|
|
39
41
|
self._command = Command(SCHEME)
|
|
40
42
|
|
|
41
|
-
def run_game_id(self, app_id: str) ->
|
|
43
|
+
def run_game_id(self, app_id: str) -> None:
|
|
42
44
|
"""Launches game with the specified ID in the Steam client."""
|
|
43
45
|
self._command(['rungameid'], app_id)
|
|
44
46
|
|
|
45
|
-
def store(self, app_id: str) ->
|
|
47
|
+
def store(self, app_id: str) -> None:
|
|
46
48
|
"""Opens the game's store page in the Steam client."""
|
|
47
49
|
self._command(['store'], app_id)
|
|
48
50
|
|
|
49
|
-
def install(self, app_id: str) ->
|
|
51
|
+
def install(self, app_id: str) -> None:
|
|
50
52
|
"""Opens the game's install prompt in the Steam client."""
|
|
51
53
|
self._command(['install'], app_id)
|
|
52
54
|
|
|
53
|
-
def uninstall(self, app_id: str) ->
|
|
55
|
+
def uninstall(self, app_id: str) -> None:
|
|
54
56
|
"""Opens the game's uninstall prompt in the Steam client."""
|
|
55
57
|
self._command(['uninstall'], app_id)
|
|
56
58
|
|
|
57
|
-
def update_news(self, app_id: str) ->
|
|
59
|
+
def update_news(self, app_id: str) -> None:
|
|
58
60
|
"""Opens the game's update news in the Steam client."""
|
|
59
61
|
self._command(['updatenews'], app_id)
|
|
60
62
|
|
|
61
|
-
def open(self, window: SteamWindows) ->
|
|
63
|
+
def open(self, window: SteamWindows) -> None:
|
|
62
64
|
"""Opens the specified window in the Steam client."""
|
|
63
65
|
self._command(['open'], window)
|
|
64
66
|
|
|
65
|
-
def open_url(self, url: str) ->
|
|
67
|
+
def open_url(self, url: str) -> None:
|
|
66
68
|
"""Opens the specified URL in the Steam client."""
|
|
67
69
|
self._command(['openurl'], url)
|
|
68
|
-
|
|
69
|
-
|
|
@@ -3,7 +3,7 @@ import functools
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
from typing import TYPE_CHECKING
|
|
5
5
|
|
|
6
|
-
import vdf
|
|
6
|
+
import vdf # type: ignore
|
|
7
7
|
|
|
8
8
|
if TYPE_CHECKING:
|
|
9
9
|
from .steam import Steam
|
|
@@ -13,13 +13,13 @@ from .app import App
|
|
|
13
13
|
|
|
14
14
|
UNKNOWN_GAME_NAME = 'UNKNOWN'
|
|
15
15
|
|
|
16
|
-
ASSETS =
|
|
16
|
+
ASSETS = frozenset({
|
|
17
17
|
"header.jpg",
|
|
18
18
|
"library_600x900.jpg",
|
|
19
19
|
"library_hero.jpg",
|
|
20
20
|
"library_hero_blur.jpg",
|
|
21
21
|
"logo.png"
|
|
22
|
-
|
|
22
|
+
})
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
class SteamGame(App):
|
|
@@ -28,10 +28,16 @@ class SteamGame(App):
|
|
|
28
28
|
def __init__(self, steam: Steam, library_path: str, appid: str):
|
|
29
29
|
self.library_path = library_path
|
|
30
30
|
self._appid = appid
|
|
31
|
+
self._icon: Path | None = None
|
|
32
|
+
self._name: str | None = None
|
|
31
33
|
super().__init__(steam)
|
|
32
34
|
|
|
33
35
|
def __repr__(self) -> str:
|
|
34
|
-
return
|
|
36
|
+
return (
|
|
37
|
+
f'Game(steam={self._steam.__repr__()}, '
|
|
38
|
+
f'library_path={self.library_path.__repr__()}, '
|
|
39
|
+
f'appid={self.appid.__repr__()})'
|
|
40
|
+
)
|
|
35
41
|
|
|
36
42
|
@property
|
|
37
43
|
def asset_dir(self) -> Path:
|
|
@@ -39,12 +45,18 @@ class SteamGame(App):
|
|
|
39
45
|
return Path(self._steam.library_cache).joinpath(self.appid)
|
|
40
46
|
|
|
41
47
|
@property
|
|
42
|
-
def icon(self) -> Path:
|
|
48
|
+
def icon(self) -> Path | None:
|
|
43
49
|
"""Returns the path to the icon image."""
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
50
|
+
if self._icon is None:
|
|
51
|
+
self._icon = next(
|
|
52
|
+
(
|
|
53
|
+
asset
|
|
54
|
+
for asset in self.asset_dir.iterdir()
|
|
55
|
+
if asset.is_file() and asset.name not in ASSETS
|
|
56
|
+
),
|
|
57
|
+
None,
|
|
58
|
+
)
|
|
59
|
+
return self._icon
|
|
48
60
|
|
|
49
61
|
@property
|
|
50
62
|
def header(self) -> Path:
|
|
@@ -81,9 +93,14 @@ class SteamGame(App):
|
|
|
81
93
|
except FileNotFoundError:
|
|
82
94
|
return {}
|
|
83
95
|
|
|
84
|
-
@
|
|
96
|
+
@property
|
|
85
97
|
def name(self) -> str:
|
|
86
98
|
"""Returns the name of the game."""
|
|
99
|
+
if self._name is None:
|
|
100
|
+
self._name = self._get_name_from_manifest()
|
|
101
|
+
return self._name
|
|
102
|
+
|
|
103
|
+
def _get_name_from_manifest(self) -> str:
|
|
87
104
|
try:
|
|
88
105
|
return self._manifest['AppState']['name']
|
|
89
106
|
except KeyError:
|
|
@@ -96,8 +113,8 @@ class SteamGame(App):
|
|
|
96
113
|
|
|
97
114
|
def open_store_page(self):
|
|
98
115
|
"""Opens the game's store page in the Steam client."""
|
|
99
|
-
self.
|
|
116
|
+
self._commands.store(self.appid)
|
|
100
117
|
|
|
101
118
|
def uninstall(self):
|
|
102
119
|
"""Uninstalls the game."""
|
|
103
|
-
self.
|
|
120
|
+
self._commands.uninstall(self.appid)
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
-
from pathlib import Path
|
|
3
2
|
import hashlib
|
|
4
3
|
from typing import TYPE_CHECKING, List, Optional, Union
|
|
5
4
|
|
|
6
|
-
import vdf
|
|
5
|
+
import vdf # type: ignore
|
|
7
6
|
|
|
8
7
|
from steam_client.shortcut import Shortcut
|
|
9
8
|
|
|
@@ -70,7 +69,7 @@ class Library:
|
|
|
70
69
|
def shortcuts(self) -> List[Shortcut]:
|
|
71
70
|
"""Returns the Non-Steam shortcuts from the Steam library."""
|
|
72
71
|
shortcuts = []
|
|
73
|
-
for user in self._steam.
|
|
72
|
+
for user in self._steam.users:
|
|
74
73
|
shortcuts.extend(user.shortcuts())
|
|
75
74
|
return shortcuts
|
|
76
75
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import importlib
|
|
2
|
+
import sys
|
|
3
3
|
|
|
4
4
|
from .steam import Steam
|
|
5
5
|
|
|
@@ -9,7 +9,11 @@ STEAM_SUB_KEY = r'SOFTWARE\WOW6432Node\Valve\Steam'
|
|
|
9
9
|
|
|
10
10
|
def get_steam_from_registry() -> str:
|
|
11
11
|
"""Returns the Steam install path from the Windows registry."""
|
|
12
|
-
|
|
12
|
+
if sys.platform != "win32":
|
|
13
|
+
raise OSError("Windows registry is only available on Windows")
|
|
14
|
+
|
|
15
|
+
reg = importlib.import_module("winreg")
|
|
16
|
+
with reg.OpenKey(reg.HKEY_LOCAL_MACHINE, STEAM_SUB_KEY) as hkey:
|
|
13
17
|
return reg.QueryValueEx(hkey, "InstallPath")[0]
|
|
14
18
|
|
|
15
19
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: steam-client
|
|
3
|
-
Version:
|
|
3
|
+
Version: 3.0.0.dev0
|
|
4
4
|
Summary: Steam client library for Python
|
|
5
5
|
Author-email: William McAllister <dev.garulf@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -11,3 +11,6 @@ Classifier: Programming Language :: Python :: 3 :: Only
|
|
|
11
11
|
Requires-Python: >=3.8
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
13
|
License-File: LICENSE
|
|
14
|
+
Requires-Dist: vdf>=3.4
|
|
15
|
+
Requires-Dist: pycrc>=0.10.0
|
|
16
|
+
Dynamic: license-file
|
|
@@ -17,4 +17,9 @@ steam_client.egg-info/PKG-INFO
|
|
|
17
17
|
steam_client.egg-info/SOURCES.txt
|
|
18
18
|
steam_client.egg-info/dependency_links.txt
|
|
19
19
|
steam_client.egg-info/requires.txt
|
|
20
|
-
steam_client.egg-info/top_level.txt
|
|
20
|
+
steam_client.egg-info/top_level.txt
|
|
21
|
+
tests/test_commands.py
|
|
22
|
+
tests/test_game.py
|
|
23
|
+
tests/test_login_users.py
|
|
24
|
+
tests/test_shortcut.py
|
|
25
|
+
tests/test_steam.py
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
from unittest.mock import patch
|
|
2
|
+
|
|
3
|
+
from steam_client.commands import Command, Commands, SteamWindows, SCHEME
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class TestCommand:
|
|
7
|
+
def setup_method(self):
|
|
8
|
+
self.command = Command(SCHEME)
|
|
9
|
+
|
|
10
|
+
def test_create_uri_single_path(self):
|
|
11
|
+
uri = self.command._create_uri(["rungameid"], "12345")
|
|
12
|
+
assert uri == "steam://rungameid/12345"
|
|
13
|
+
|
|
14
|
+
def test_create_uri_multi_path(self):
|
|
15
|
+
uri = self.command._create_uri(["store", "app"], "67890")
|
|
16
|
+
assert uri == "steam://store/app/67890"
|
|
17
|
+
|
|
18
|
+
def test_call_opens_browser(self):
|
|
19
|
+
with patch("webbrowser.open") as mock_open:
|
|
20
|
+
self.command(["rungameid"], "12345")
|
|
21
|
+
mock_open.assert_called_once_with("steam://rungameid/12345")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class TestCommands:
|
|
25
|
+
def setup_method(self):
|
|
26
|
+
self.commands = Commands()
|
|
27
|
+
|
|
28
|
+
def test_run_game_id(self):
|
|
29
|
+
with patch("webbrowser.open") as mock_open:
|
|
30
|
+
self.commands.run_game_id("12345")
|
|
31
|
+
mock_open.assert_called_once_with("steam://rungameid/12345")
|
|
32
|
+
|
|
33
|
+
def test_store(self):
|
|
34
|
+
with patch("webbrowser.open") as mock_open:
|
|
35
|
+
self.commands.store("12345")
|
|
36
|
+
mock_open.assert_called_once_with("steam://store/12345")
|
|
37
|
+
|
|
38
|
+
def test_install(self):
|
|
39
|
+
with patch("webbrowser.open") as mock_open:
|
|
40
|
+
self.commands.install("12345")
|
|
41
|
+
mock_open.assert_called_once_with("steam://install/12345")
|
|
42
|
+
|
|
43
|
+
def test_uninstall(self):
|
|
44
|
+
with patch("webbrowser.open") as mock_open:
|
|
45
|
+
self.commands.uninstall("12345")
|
|
46
|
+
mock_open.assert_called_once_with("steam://uninstall/12345")
|
|
47
|
+
|
|
48
|
+
def test_update_news(self):
|
|
49
|
+
with patch("webbrowser.open") as mock_open:
|
|
50
|
+
self.commands.update_news("12345")
|
|
51
|
+
mock_open.assert_called_once_with("steam://updatenews/12345")
|
|
52
|
+
|
|
53
|
+
def test_open_window(self):
|
|
54
|
+
with patch("webbrowser.open") as mock_open:
|
|
55
|
+
self.commands.open(SteamWindows.SETTINGS)
|
|
56
|
+
mock_open.assert_called_once_with(f"steam://open/{SteamWindows.SETTINGS}")
|
|
57
|
+
|
|
58
|
+
def test_open_url(self):
|
|
59
|
+
with patch("webbrowser.open") as mock_open:
|
|
60
|
+
self.commands.open_url("https://store.steampowered.com")
|
|
61
|
+
mock_open.assert_called_once_with("steam://openurl/https://store.steampowered.com")
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
import pytest
|
|
3
|
+
|
|
4
|
+
from steam_client.game import SteamGame, UNKNOWN_GAME_NAME
|
|
5
|
+
|
|
6
|
+
LIBRARY_PATH = "/library"
|
|
7
|
+
APPID = "12345"
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@pytest.fixture
|
|
11
|
+
def game(steam):
|
|
12
|
+
return SteamGame(steam, LIBRARY_PATH, APPID)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def test_game_appid(game):
|
|
16
|
+
assert game.appid == APPID
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def test_game_repr(game, steam):
|
|
20
|
+
r = repr(game)
|
|
21
|
+
assert APPID in r
|
|
22
|
+
assert LIBRARY_PATH in r
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def test_manifest_path(game):
|
|
26
|
+
assert game.manifest_path == Path(LIBRARY_PATH) / "steamapps" / f"appmanifest_{APPID}.acf"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def test_asset_dir(game):
|
|
30
|
+
assert game.asset_dir == Path("/fake/steam/appcache/librarycache") / APPID
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def test_header(game):
|
|
34
|
+
assert game.header == Path("/fake/steam/appcache/librarycache") / f"{APPID}_header.jpg"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def test_grid(game):
|
|
38
|
+
assert game.grid == Path("/fake/steam/appcache/librarycache") / f"{APPID}_library_600x900.jpg"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def test_hero(game):
|
|
42
|
+
assert game.hero == Path("/fake/steam/appcache/librarycache") / f"{APPID}_library_hero.jpg"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_hero_blur(game):
|
|
46
|
+
assert game.hero_blur == Path("/fake/steam/appcache/librarycache") / f"{APPID}_library_hero_blur.jpg"
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def test_game_name_from_manifest(game):
|
|
50
|
+
game.__dict__["_manifest"] = {"AppState": {"name": "Portal 2"}}
|
|
51
|
+
assert game.name == "Portal 2"
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def test_game_name_unknown_when_manifest_missing_key(game):
|
|
55
|
+
game.__dict__["_manifest"] = {}
|
|
56
|
+
assert game.name == UNKNOWN_GAME_NAME
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def test_game_name_unknown_when_manifest_empty(game):
|
|
60
|
+
game.__dict__["_manifest"] = {"AppState": {}}
|
|
61
|
+
assert game.name == UNKNOWN_GAME_NAME
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from unittest.mock import MagicMock, patch
|
|
3
|
+
|
|
4
|
+
from steam_client.login_users import LoginUser, LoginUsers, User, UserData, STEAM64_OFFSET
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
FAKE_STEAM_ID3 = 12345678
|
|
8
|
+
FAKE_USER_ID = STEAM64_OFFSET + FAKE_STEAM_ID3
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def test_login_user_is_most_recent(login_user):
|
|
12
|
+
assert login_user.is_most_recent is True
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def test_login_user_not_most_recent(steam, user_data):
|
|
16
|
+
data = UserData(
|
|
17
|
+
AccountName=user_data.AccountName,
|
|
18
|
+
PersonaName=user_data.PersonaName,
|
|
19
|
+
RememberPassword=user_data.RememberPassword,
|
|
20
|
+
WantsOfflineMode=user_data.WantsOfflineMode,
|
|
21
|
+
SkipOfflineModeWarning=user_data.SkipOfflineModeWarning,
|
|
22
|
+
AllowAutoLogin=user_data.AllowAutoLogin,
|
|
23
|
+
MostRecent="0",
|
|
24
|
+
Timestamp=user_data.Timestamp,
|
|
25
|
+
)
|
|
26
|
+
user = User(id=FAKE_USER_ID, data=data)
|
|
27
|
+
lu = LoginUser(steam, user)
|
|
28
|
+
assert lu.is_most_recent is False
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def test_steam_id3(login_user):
|
|
32
|
+
assert login_user.steam_id3 == FAKE_STEAM_ID3
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def test_user_data_dir(login_user):
|
|
36
|
+
assert login_user.user_data_dir == Path("/fake/steam/userdata") / str(FAKE_STEAM_ID3)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def test_config(login_user):
|
|
40
|
+
assert login_user.config == login_user.user_data_dir / "config"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def test_shortcuts_file(login_user):
|
|
44
|
+
assert login_user.shortcuts_file == login_user.config / "shortcuts.vdf"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_grid_path(login_user):
|
|
48
|
+
assert login_user.grid_path == login_user.user_data_dir / "config" / "grid"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def test_shortcuts_parses_vdf(steam, login_user):
|
|
52
|
+
fake_shortcut_data = {
|
|
53
|
+
"shortcuts": {
|
|
54
|
+
"0": {
|
|
55
|
+
"appid": 0,
|
|
56
|
+
"appname": "My Game",
|
|
57
|
+
"exe": "/path/game.exe",
|
|
58
|
+
"StartDir": "/path",
|
|
59
|
+
"LaunchOptions": "",
|
|
60
|
+
"icon": "",
|
|
61
|
+
"tags": {},
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
with patch("builtins.open", MagicMock()), \
|
|
66
|
+
patch("vdf.binary_load", return_value=fake_shortcut_data):
|
|
67
|
+
shortcuts = login_user.shortcuts()
|
|
68
|
+
assert len(shortcuts) == 1
|
|
69
|
+
assert shortcuts[0].name == "My Game"
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def test_login_users_most_recent(steam, user_data):
|
|
73
|
+
recent_user = User(id=FAKE_USER_ID, data=user_data)
|
|
74
|
+
not_recent_data = UserData(
|
|
75
|
+
AccountName="other",
|
|
76
|
+
PersonaName="Other",
|
|
77
|
+
RememberPassword="0",
|
|
78
|
+
WantsOfflineMode="0",
|
|
79
|
+
SkipOfflineModeWarning="0",
|
|
80
|
+
AllowAutoLogin="0",
|
|
81
|
+
MostRecent="0",
|
|
82
|
+
Timestamp="0",
|
|
83
|
+
)
|
|
84
|
+
not_recent_user = User(id=FAKE_USER_ID + 1, data=not_recent_data)
|
|
85
|
+
users = [LoginUser(steam, recent_user), LoginUser(steam, not_recent_user)]
|
|
86
|
+
|
|
87
|
+
with patch.object(LoginUsers, "users", return_value=users):
|
|
88
|
+
lu = LoginUsers(steam)
|
|
89
|
+
most_recent = lu.most_recent_user()
|
|
90
|
+
|
|
91
|
+
assert most_recent is not None
|
|
92
|
+
assert most_recent.is_most_recent is True
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def test_login_users_most_recent_none_when_no_recent(steam, user_data):
|
|
96
|
+
data = UserData(
|
|
97
|
+
AccountName="other",
|
|
98
|
+
PersonaName="Other",
|
|
99
|
+
RememberPassword="0",
|
|
100
|
+
WantsOfflineMode="0",
|
|
101
|
+
SkipOfflineModeWarning="0",
|
|
102
|
+
AllowAutoLogin="0",
|
|
103
|
+
MostRecent="0",
|
|
104
|
+
Timestamp="0",
|
|
105
|
+
)
|
|
106
|
+
users = [LoginUser(steam, User(id=FAKE_USER_ID, data=data))]
|
|
107
|
+
|
|
108
|
+
with patch.object(LoginUsers, "users", return_value=users):
|
|
109
|
+
lu = LoginUsers(steam)
|
|
110
|
+
most_recent = lu.most_recent_user()
|
|
111
|
+
|
|
112
|
+
assert most_recent is None
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
import pytest
|
|
3
|
+
|
|
4
|
+
import pycrc.algorithms as crc
|
|
5
|
+
|
|
6
|
+
from steam_client.shortcut import Shortcut
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@pytest.fixture
|
|
10
|
+
def shortcut(steam, login_user, shortcut_entry):
|
|
11
|
+
return Shortcut(steam, login_user, shortcut_entry)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _compute_appid(exe: str, appname: str) -> str:
|
|
15
|
+
algorithm = crc.Crc(
|
|
16
|
+
width=32,
|
|
17
|
+
poly=0x04C11DB7,
|
|
18
|
+
reflect_in=True,
|
|
19
|
+
xor_in=0xFFFFFFFF,
|
|
20
|
+
reflect_out=True,
|
|
21
|
+
xor_out=0xFFFFFFFF,
|
|
22
|
+
)
|
|
23
|
+
input_string = exe + appname
|
|
24
|
+
top_32 = algorithm.bit_by_bit(input_string) | 0x80000000
|
|
25
|
+
full_64 = (top_32 << 32) | 0x02000000
|
|
26
|
+
return str(full_64)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def test_shortcut_name(shortcut):
|
|
30
|
+
assert shortcut.name == "Test Game"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def test_shortcut_appid_is_string(shortcut):
|
|
34
|
+
assert isinstance(shortcut.appid, str)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def test_shortcut_appid_matches_crc(shortcut, shortcut_entry):
|
|
38
|
+
expected = _compute_appid(shortcut_entry["exe"], shortcut_entry["appname"])
|
|
39
|
+
assert shortcut.appid == expected
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def test_shortcut_short_id(shortcut):
|
|
43
|
+
expected = str(int(shortcut.appid) >> 32)
|
|
44
|
+
assert shortcut._short_id() == expected
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_shortcut_icon_uses_data_icon(shortcut, shortcut_entry):
|
|
48
|
+
assert shortcut.icon == Path(shortcut_entry["icon"])
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def test_shortcut_header(shortcut, login_user):
|
|
52
|
+
short_id = shortcut._short_id()
|
|
53
|
+
assert shortcut.header == login_user.grid_path / f"{short_id}.png"
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def test_shortcut_grid(shortcut, login_user):
|
|
57
|
+
short_id = shortcut._short_id()
|
|
58
|
+
assert shortcut.grid == login_user.grid_path / f"{short_id}p.png"
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def test_shortcut_hero(shortcut, login_user):
|
|
62
|
+
short_id = shortcut._short_id()
|
|
63
|
+
assert shortcut.hero == login_user.grid_path / f"{short_id}_hero.png"
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def test_shortcut_repr(shortcut):
|
|
67
|
+
r = repr(shortcut)
|
|
68
|
+
assert "Shortcut" in r
|
|
69
|
+
assert "Test Game" in r
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from steam_client.steam import Steam, WIN_STEAM_PATH
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_steam_default_path():
|
|
7
|
+
s = Steam()
|
|
8
|
+
assert s.base_path == WIN_STEAM_PATH
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def test_steam_custom_path():
|
|
12
|
+
s = Steam("/custom/path")
|
|
13
|
+
assert s.base_path == "/custom/path"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def test_steam_repr():
|
|
17
|
+
s = Steam("/custom/path")
|
|
18
|
+
assert repr(s) == "Steam(base_path='/custom/path')"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def test_app_cache(steam):
|
|
22
|
+
assert steam.app_cache == Path("/fake/steam/appcache")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def test_user_data(steam):
|
|
26
|
+
assert steam.user_data == Path("/fake/steam/userdata")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def test_library_folders(steam):
|
|
30
|
+
assert steam.library_folders == Path("/fake/steam/config/libraryfolders.vdf")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def test_library_cache(steam):
|
|
34
|
+
assert steam.library_cache == Path("/fake/steam/appcache/librarycache")
|
|
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
|
{steam-client-2.1.0.dev0 → steam_client-3.0.0.dev0}/steam_client.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|