Skip to content
This repository was archived by the owner on Jan 1, 2025. It is now read-only.

Commit 9b1c716

Browse files
authored
Lint Python code and add standard linter settings (#84)
* keybind improvements add `IsRebindable` and `IsHidden` fields, along with per-bind callback `OnPress` * inital linting pass * stricter linting * stricter linting settings seperate commit so they're easy to revert * fix circular import don't worry I tested 🙂 * remove deprecated unrealsdk reference
1 parent 0e480d1 commit 9b1c716

12 files changed

+299
-162
lines changed

Mods/ModMenu/DeprecationHelper.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
import unrealsdk
22
import functools
3-
from typing import Any, Callable, Dict, List, Optional, Set
3+
from typing import Any, Callable, Dict, List, Optional, Set, Tuple
4+
5+
__all__: Tuple[str, ...] = (
6+
"Deprecated",
7+
"NameChangeMsg",
8+
"PrintWarning",
9+
)
410

511
_printed_deprecation_warnings: Set[str] = set()
612

Mods/ModMenu/HookManager.py

+33-21
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,25 @@
33
import unrealsdk
44
import functools
55
import weakref
6-
from typing import Any, Callable, Optional, Union
7-
from inspect import signature, Parameter
6+
from inspect import Parameter, signature
7+
from typing import Any, Callable, Tuple, Union
88

9+
__all__: Tuple[str, ...] = (
10+
"AnyHook",
11+
"Hook",
12+
"HookFunction",
13+
"HookMethod",
14+
"RegisterHooks",
15+
"RemoveHooks",
16+
)
917

10-
_HookFunction = Callable[[unrealsdk.UObject, unrealsdk.UFunction, unrealsdk.FStruct], Any]
11-
_HookMethod = Callable[[object, unrealsdk.UObject, unrealsdk.UFunction, unrealsdk.FStruct], Any]
12-
_HookAny = Union[_HookFunction, _HookMethod]
1318

19+
HookFunction = Callable[[unrealsdk.UObject, unrealsdk.UFunction, unrealsdk.FStruct], Any]
20+
HookMethod = Callable[[object, unrealsdk.UObject, unrealsdk.UFunction, unrealsdk.FStruct], Any]
21+
AnyHook = Union[HookFunction, HookMethod]
1422

15-
def Hook(target: str, name: str = "{0}.{1}") -> Callable[[_HookAny], _HookAny]:
23+
24+
def Hook(target: str, name: str = "{0}.{1}") -> Callable[[AnyHook], AnyHook]:
1625
"""
1726
A decorator for functions that should be invoked in response to an Unreal Engine method's
1827
invokation.
@@ -47,7 +56,7 @@ def Hook(target: str, name: str = "{0}.{1}") -> Callable[[_HookAny], _HookAny]:
4756
qualified name, separated by a ".". Argument `{1}` will contain the `id()` of the
4857
function or mod instance.
4958
"""
50-
def apply_hook(function: _HookAny) -> _HookAny:
59+
def apply_hook(function: AnyHook) -> AnyHook:
5160
# If the function has four parameters, it should be a method.
5261
params = signature(function).parameters
5362
is_method = (len(params) == 4)
@@ -56,45 +65,48 @@ def apply_hook(function: _HookAny) -> _HookAny:
5665
# initial setup on it now.
5766
hook_targets = getattr(function, "HookTargets", None)
5867
if hook_targets is None:
59-
paramException = ValueError("Hook functions must have the signature ([self,] caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct)")
68+
param_exception = ValueError(
69+
"Hook functions must have the signature"
70+
" ([self,] caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct)"
71+
)
6072

6173
# If the function is an instance method, create a mutable list of the parameters and
6274
# remove the `self` one, so we may check the remaining ones same as a non-method.
63-
params = list(params.values())
75+
param_list = list(params.values())
6476
if is_method:
65-
del params[0]
77+
del param_list[0]
6678
# If the function has neither 4 nor 3 parameters, it is invalid.
67-
elif len(params) != 3:
68-
raise paramException
79+
elif len(param_list) != 3:
80+
raise param_exception
6981
# If the functions parameters do not accept positional arguments, it is invalid.
70-
for param in params:
82+
for param in param_list:
7183
if Parameter.POSITIONAL_ONLY != param.kind != Parameter.POSITIONAL_OR_KEYWORD:
72-
raise paramException
84+
raise param_exception
7385

7486
# If the function is a method, store the name format string on it for formatting with
7587
# future instances. If it's a simple function, format its name for use now.
76-
function.HookName = name if is_method else name.format(
88+
function.HookName = name if is_method else name.format( # type: ignore
7789
f"{function.__module__}.{function.__qualname__}", id(function)
7890
)
7991

8092
# With the function now known as valid, create its set of targets.
81-
hook_targets = function.HookTargets = set()
93+
hook_targets = function.HookTargets = set() # type: ignore
8294

8395
hook_targets.add(target)
8496

8597
if not is_method:
86-
unrealsdk.RunHook(target, function.HookName, function)
98+
unrealsdk.RunHook(target, function.HookName, function) # type: ignore
8799

88100
return function
89101
return apply_hook
90102

91103

92-
def _create_method_wrapper(obj_ref: weakref.ReferenceType[object], obj_function: _HookMethod) -> _HookFunction:
104+
def _create_method_wrapper(obj_ref: weakref.ReferenceType[object], obj_function: HookMethod) -> HookFunction:
93105
"""Return a "true" function for the given bound method, passable to `unrealsdk.RegisterHook`."""
94106
@functools.wraps(obj_function)
95107
def method_wrapper(caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct) -> Any:
96108
obj = obj_ref()
97-
method = obj_function.__get__(obj, type(obj))
109+
method = obj_function.__get__(obj, type(obj)) # type: ignore
98110
return method(caller, obj_function, params)
99111
return method_wrapper
100112

@@ -130,12 +142,12 @@ def RegisterHooks(obj: object) -> None:
130142
setattr(obj, attribute_name, method_wrapper)
131143

132144
# Format the provided hook name.
133-
method_wrapper.HookName = function.HookName.format(
145+
method_wrapper.HookName = function.HookName.format( # type: ignore
134146
f"{function.__module__}.{function.__qualname__}", id(obj)
135147
)
136148

137149
for target in hook_targets:
138-
unrealsdk.RunHook(target, method_wrapper.HookName, method_wrapper)
150+
unrealsdk.RunHook(target, method_wrapper.HookName, method_wrapper) # type: ignore
139151

140152

141153
def RemoveHooks(obj: object) -> None:

Mods/ModMenu/KeybindManager.py

+15-9
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
import unrealsdk
2-
import inspect
32
import functools
3+
import inspect
44
from dataclasses import dataclass, field
55
from enum import IntEnum
6-
from typing import Callable, ClassVar, Dict, Optional, Union
6+
from typing import Callable, ClassVar, Dict, Optional, Tuple, Union
77

88
from . import DeprecationHelper as dh
9-
from . import MenuManager
10-
from . import ModObjects
11-
from . import SettingsManager
9+
from . import MenuManager, ModObjects, SettingsManager
10+
11+
__all__: Tuple[str, ...] = (
12+
"InputEvent",
13+
"Keybind",
14+
"KeybindCallback",
15+
)
1216

1317

1418
class InputEvent(IntEnum):
@@ -358,10 +362,12 @@ def HandleInputKey(caller: unrealsdk.UObject, function: unrealsdk.UFunction, par
358362
if caller != dialog:
359363
return True
360364

361-
if params.uevent == InputEvent.Released:
362-
if params.ukey in ("Escape", "XboxTypeS_B", "XboxTypeS_Back"):
363-
dialog.Close()
364-
unrealsdk.RemoveHook("WillowGame.WillowGFxDialogBox.HandleInputKey", "ModMenu.KeybindManager")
365+
if (
366+
params.uevent == InputEvent.Released
367+
and params.ukey in ("Escape", "XboxTypeS_B", "XboxTypeS_Back")
368+
):
369+
dialog.Close()
370+
unrealsdk.RemoveHook("WillowGame.WillowGFxDialogBox.HandleInputKey", "ModMenu.KeybindManager")
365371
return True
366372

367373
unrealsdk.RunHook("WillowGame.WillowGFxDialogBox.HandleInputKey", "ModMenu.KeybindManager", HandleInputKey)

Mods/ModMenu/MenuManager.py

+16-11
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@
55
import sys
66
import webbrowser
77
from functools import cmp_to_key
8-
from typing import Dict, List, Set
8+
from typing import Dict, List, Set, Tuple
99

10-
from Mods import ModMenu
10+
from . import VERSION_MAJOR, VERSION_MINOR
1111
from . import DeprecationHelper as dh
12-
from . import KeybindManager
13-
from . import ModObjects
12+
from . import KeybindManager, ModObjects
13+
14+
__all__: Tuple[str, ...] = ()
15+
1416

1517
_MODS_EVENT_ID: int = 1417
1618
_MODS_MENU_NAME: str = "MODS"
@@ -61,7 +63,7 @@ class _General(ModObjects.SDKMod):
6163
"\n"
6264
"See below for options.\n"
6365
)
64-
Version: str = f"{ModMenu.VERSION_MAJOR}.{ModMenu.VERSION_MINOR}"
66+
Version: str = f"{VERSION_MAJOR}.{VERSION_MINOR}"
6567

6668
Types: ModObjects.ModTypes = ModObjects.ModTypes.All
6769

@@ -250,7 +252,7 @@ def _ShopInputKey(caller: unrealsdk.UObject, function: unrealsdk.UFunction, para
250252
if key in ("Escape", "Up", "Down", "W", "S"):
251253
return True
252254

253-
if event == KeybindManager.InputEvent.Pressed or event == KeybindManager.InputEvent.Repeat:
255+
if event in (KeybindManager.InputEvent.Pressed, KeybindManager.InputEvent.Repeat):
254256
# These two are bugged on gearbox's end, we manually fix them
255257
if key == "PageUp":
256258
caller.ScrollDescription(True)
@@ -358,9 +360,12 @@ def _SharedHandleInputKey(caller: unrealsdk.UObject, function: unrealsdk.UFuncti
358360
This function is called on pretty much all key input events on the main menu. We use it to open
359361
the dlc menu when you press "M".
360362
"""
361-
if params.ukey == "M" and params.uevent == KeybindManager.InputEvent.Released:
362-
if not caller.IsOverlayMenuOpen():
363-
caller.CheckDownloadableContentListCompleted(caller.WPCOwner.GetMyControllerId(), True)
363+
if (
364+
params.ukey == "M"
365+
and params.uevent == KeybindManager.InputEvent.Released
366+
and not caller.IsOverlayMenuOpen()
367+
):
368+
caller.CheckDownloadableContentListCompleted(caller.WPCOwner.GetMyControllerId(), True)
364369
return True
365370

366371

@@ -381,8 +386,8 @@ def _FrontEndUpdateTooltips(caller: unrealsdk.UObject, function: unrealsdk.UFunc
381386
# There's no easy len() :/
382387
count = 0
383388
if caller.TheList is not None:
384-
for i in caller.TheList.DataProviderStack:
385-
count += 1
389+
for _ in caller.TheList.DataProviderStack:
390+
count += 1 # noqa: SIM113
386391
if count <= 1:
387392
cancel = caller.DisconnectString
388393
tooltip += caller.TooltipSpacing + caller.CancelTooltip.replace("%PLAYER1", cancel)

Mods/ModMenu/ModObjects.py

+24-16
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,20 @@
66
import sys
77
from abc import ABCMeta
88
from os import path
9-
from typing import Any, Callable, Dict, List, Optional, Sequence, Set, Tuple
9+
from typing import Any, Callable, Dict, List, Optional, Sequence, Set, Tuple, cast
10+
11+
from . import HookManager, KeybindManager, NetworkManager, OptionManager, SettingsManager
12+
13+
__all__: Tuple[str, ...] = (
14+
"EnabledSaveType",
15+
"Game",
16+
"ModPriorities",
17+
"Mods",
18+
"ModTypes",
19+
"RegisterMod",
20+
"SDKMod",
21+
)
1022

11-
from . import HookManager
12-
from . import KeybindManager
13-
from . import NetworkManager
14-
from . import OptionManager
15-
from . import SettingsManager
1623

1724
Mods: List[SDKMod] = []
1825

@@ -118,10 +125,10 @@ def __init__(cls, name: str, bases: Tuple[type, ...], attrs: Dict[str, Any]) ->
118125
for function in functions:
119126
method_sender = NetworkManager._find_method_sender(function)
120127
if method_sender is not None:
121-
if method_sender._is_server:
122-
cls._server_functions.add(method_sender)
123-
if method_sender._is_client:
124-
cls._client_functions.add(method_sender)
128+
if method_sender._is_server: # type: ignore
129+
cls._server_functions.add(method_sender) # type: ignore
130+
if method_sender._is_client: # type: ignore
131+
cls._client_functions.add(method_sender) # type: ignore
125132

126133

127134
class SDKMod(metaclass=_ModMeta):
@@ -245,9 +252,8 @@ def SettingsInputPressed(self, action: str) -> None:
245252
action: The name of the action.
246253
"""
247254
# Even though we removed these from `SettingsInputs`, need this check for auto enable
248-
if Game.GetCurrent() not in self.SupportedGames:
249-
if action in ("Enable", "Disable"):
250-
return
255+
if Game.GetCurrent() not in self.SupportedGames and action in ("Enable", "Disable"):
256+
return
251257

252258
if action == "Enable":
253259
if not self.IsEnabled:
@@ -302,11 +308,12 @@ def ModOptionChanged(self, option: OptionManager.Options.Base, new_value: Any) -
302308
pass
303309

304310
@staticmethod
305-
def NetworkSerialize(arguments: dict) -> str:
311+
def NetworkSerialize(arguments: NetworkManager.NetworkArgsDict) -> str:
306312
"""
307313
Called when instances of this class invoke methods decorated with `@ModMenu.ServerMethod`
308314
or `@ModMenu.ClientMethod`, performing the serialization of any arguments passed to said
309315
methods. The default implementation uses `json.dumps()`.
316+
310317
Arguments:
311318
arguments:
312319
The arguments that need to be serialized. The top-level object passed will be a
@@ -317,15 +324,16 @@ def NetworkSerialize(arguments: dict) -> str:
317324
return json.dumps(arguments)
318325

319326
@staticmethod
320-
def NetworkDeserialize(serialized: str) -> dict:
327+
def NetworkDeserialize(serialized: str) -> NetworkManager.NetworkArgsDict:
321328
"""
322329
Called when instances of this class receive requests for methods decorated with
323330
`@ModMenu.ServerMethod` or `@ModMenu.ClientMethod`, performing the deserialization of any
324331
arguments passed to said methods. The default implementation uses `json.loads()`.
332+
325333
Arguments:
326334
serialized:
327335
The string containing the serialized arguments as returned by 'NetworkSerialize'.
328336
Returns:
329337
The deserialized arguments in the same format as they were passed to `NetworkSerialize`.
330338
"""
331-
return json.loads(serialized)
339+
return cast(NetworkManager.NetworkArgsDict, json.loads(serialized))

0 commit comments

Comments
 (0)