Skip to content

Commit 4048765

Browse files
authored
Merge pull request #1023 from hardbyte/refactor-util-py
Slightly refactor util.py
2 parents 53b9a5a + f4eabd7 commit 4048765

File tree

3 files changed

+47
-50
lines changed

3 files changed

+47
-50
lines changed

can/typechecking.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
StringPathLike = typing.Union[str, "os.PathLike[str]"]
3232
AcceptedIOType = typing.Optional[typing.Union[FileLike, StringPathLike]]
3333

34-
BusConfig = typing.NewType("BusConfig", dict)
34+
BusConfig = typing.NewType("BusConfig", typing.Dict[str, typing.Any])
3535

3636
AutoDetectedConfig = mypy_extensions.TypedDict(
3737
"AutoDetectedConfig", {"interface": str, "channel": Channel}

can/util.py

Lines changed: 43 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
"""
22
Utilities and configuration file parsing.
33
"""
4+
45
import functools
56
import warnings
6-
from typing import Dict, Optional, Union
7+
from typing import Any, Callable, cast, Dict, Iterable, Tuple, Optional, Union
78
from time import time, perf_counter, get_clock_info
8-
9-
from can import typechecking
10-
119
import json
1210
import os
1311
import os.path
@@ -18,6 +16,7 @@
1816

1917
import can
2018
from can.interfaces import VALID_INTERFACES
19+
from can import typechecking
2120

2221
log = logging.getLogger("can.util")
2322

@@ -89,9 +88,8 @@ def load_environment_config(context: Optional[str] = None) -> Dict[str, str]:
8988
"bitrate": "CAN_BITRATE",
9089
}
9190

92-
context_suffix = "_{}".format(context) if context else ""
93-
94-
can_config_key = "CAN_CONFIG" + context_suffix
91+
context_suffix = f"_{context}" if context else ""
92+
can_config_key = f"CAN_CONFIG{context_suffix}"
9593
config: Dict[str, str] = json.loads(os.environ.get(can_config_key, "{}"))
9694

9795
for key, val in mapper.items():
@@ -104,7 +102,7 @@ def load_environment_config(context: Optional[str] = None) -> Dict[str, str]:
104102

105103
def load_config(
106104
path: Optional[typechecking.AcceptedIOType] = None,
107-
config=None,
105+
config: Optional[Dict[str, Any]] = None,
108106
context: Optional[str] = None,
109107
) -> typechecking.BusConfig:
110108
"""
@@ -158,16 +156,19 @@ def load_config(
158156
config = {}
159157

160158
# use the given dict for default values
161-
config_sources = [
162-
given_config,
163-
can.rc,
164-
lambda _context: load_environment_config( # pylint: disable=unnecessary-lambda
165-
_context
166-
),
167-
lambda _context: load_environment_config(),
168-
lambda _context: load_file_config(path, _context),
169-
lambda _context: load_file_config(path),
170-
]
159+
config_sources = cast(
160+
Iterable[Union[Dict[str, Any], Callable[[Any], Dict[str, Any]]]],
161+
[
162+
given_config,
163+
can.rc,
164+
lambda _context: load_environment_config( # pylint: disable=unnecessary-lambda
165+
_context
166+
),
167+
lambda _context: load_environment_config(),
168+
lambda _context: load_file_config(path, _context),
169+
lambda _context: load_file_config(path),
170+
],
171+
)
171172

172173
# Slightly complex here to only search for the file config if required
173174
for cfg in config_sources:
@@ -189,9 +190,7 @@ def load_config(
189190
config[key] = None
190191

191192
if config["interface"] not in VALID_INTERFACES:
192-
raise NotImplementedError(
193-
"Invalid CAN Bus Type - {}".format(config["interface"])
194-
)
193+
raise NotImplementedError(f'Invalid CAN Bus Type "{config["interface"]}"')
195194

196195
if "bitrate" in config:
197196
config["bitrate"] = int(config["bitrate"])
@@ -216,30 +215,33 @@ def load_config(
216215
timing_conf[key] = int(config[key], base=0)
217216
del config[key]
218217
if timing_conf:
219-
timing_conf["bitrate"] = config.get("bitrate")
218+
timing_conf["bitrate"] = config["bitrate"]
220219
config["timing"] = can.BitTiming(**timing_conf)
221220

222-
can.log.debug("can config: {}".format(config))
223-
return config
221+
can.log.debug("can config: %s", config)
222+
223+
return cast(typechecking.BusConfig, config)
224+
224225

226+
def set_logging_level(level_name: str) -> None:
227+
"""Set the logging level for the `"can"` logger.
225228
226-
def set_logging_level(level_name: Optional[str] = None):
227-
"""Set the logging level for the "can" logger.
228-
Expects one of: 'critical', 'error', 'warning', 'info', 'debug', 'subdebug'
229+
:param level_name: One of: `'critical'`, `'error'`, `'warning'`, `'info'`,
230+
`'debug'`, `'subdebug'`, or the value `None` (=default). Defaults to `'debug'`.
229231
"""
230232
can_logger = logging.getLogger("can")
231233

232234
try:
233-
can_logger.setLevel(getattr(logging, level_name.upper())) # type: ignore
235+
can_logger.setLevel(getattr(logging, level_name.upper()))
234236
except AttributeError:
235237
can_logger.setLevel(logging.DEBUG)
236-
log.debug("Logging set to {}".format(level_name))
238+
log.debug("Logging set to %s", level_name)
237239

238240

239241
def len2dlc(length: int) -> int:
240242
"""Calculate the DLC from data length.
241243
242-
:param int length: Length in number of bytes (0-64)
244+
:param length: Length in number of bytes (0-64)
243245
244246
:returns: DLC (0-15)
245247
"""
@@ -261,20 +263,17 @@ def dlc2len(dlc: int) -> int:
261263
return CAN_FD_DLC[dlc] if dlc <= 15 else 64
262264

263265

264-
def channel2int(channel: Optional[Union[typechecking.Channel]]) -> Optional[int]:
266+
def channel2int(channel: Optional[typechecking.Channel]) -> Optional[int]:
265267
"""Try to convert the channel to an integer.
266268
267269
:param channel:
268-
Channel string (e.g. can0, CAN1) or integer
270+
Channel string (e.g. `"can0"`, `"CAN1"`) or an integer
269271
270-
:returns: Channel integer or `None` if unsuccessful
272+
:returns: Channel integer or ``None`` if unsuccessful
271273
"""
272-
if channel is None:
273-
return None
274274
if isinstance(channel, int):
275275
return channel
276-
# String and byte objects have a lower() method
277-
if hasattr(channel, "lower"):
276+
if isinstance(channel, str):
278277
match = re.match(r".*(\d+)$", channel)
279278
if match:
280279
return int(match.group(1))
@@ -299,35 +298,33 @@ def library_function(new_arg):
299298
def deco(f):
300299
@functools.wraps(f)
301300
def wrapper(*args, **kwargs):
302-
rename_kwargs(f.__name__, kwargs, aliases)
301+
_rename_kwargs(f.__name__, kwargs, aliases)
303302
return f(*args, **kwargs)
304303

305304
return wrapper
306305

307306
return deco
308307

309308

310-
def rename_kwargs(func_name, kwargs, aliases):
309+
def _rename_kwargs(
310+
func_name: str, kwargs: Dict[str, str], aliases: Dict[str, str]
311+
) -> None:
311312
"""Helper function for `deprecated_args_alias`"""
312313
for alias, new in aliases.items():
313314
if alias in kwargs:
314315
value = kwargs.pop(alias)
315316
if new is not None:
316-
warnings.warn(
317-
"{} is deprecated; use {}".format(alias, new), DeprecationWarning
318-
)
317+
warnings.warn(f"{alias} is deprecated; use {new}", DeprecationWarning)
319318
if new in kwargs:
320319
raise TypeError(
321-
"{} received both {} (deprecated) and {}".format(
322-
func_name, alias, new
323-
)
320+
f"{func_name} received both {alias} (deprecated) and {new}"
324321
)
325322
kwargs[new] = value
326323
else:
327324
warnings.warn("{} is deprecated".format(alias), DeprecationWarning)
328325

329326

330-
def time_perfcounter_correlation():
327+
def time_perfcounter_correlation() -> Tuple[float, float]:
331328
"""Get the `perf_counter` value nearest to when time.time() is updated
332329
333330
Computed if the default timer used by `time.time` on this platform has a resolution

test/test_util.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import unittest
22
import warnings
33

4-
from can.util import rename_kwargs
4+
from can.util import _rename_kwargs
55

66

77
class RenameKwargsTest(unittest.TestCase):
@@ -11,7 +11,7 @@ def _test(self, kwargs, aliases):
1111

1212
# Test that we do get the DeprecationWarning when called with deprecated kwargs
1313
with self.assertWarnsRegex(DeprecationWarning, "is deprecated"):
14-
rename_kwargs("unit_test", kwargs, aliases)
14+
_rename_kwargs("unit_test", kwargs, aliases)
1515

1616
# Test that the aliases contains the deprecated values and
1717
# the obsolete kwargs have been removed
@@ -23,7 +23,7 @@ def _test(self, kwargs, aliases):
2323
# Cause all warnings to always be triggered.
2424
warnings.simplefilter("error", DeprecationWarning)
2525
try:
26-
rename_kwargs("unit_test", kwargs, aliases)
26+
_rename_kwargs("unit_test", kwargs, aliases)
2727
finally:
2828
warnings.resetwarnings()
2929

0 commit comments

Comments
 (0)