nano-dev-utils 0.3.5__tar.gz → 0.4.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.

Potentially problematic release.


This version of nano-dev-utils might be problematic. Click here for more details.

Files changed (21) hide show
  1. {nano_dev_utils-0.3.5 → nano_dev_utils-0.4.2}/.idea/workspace.xml +50 -17
  2. {nano_dev_utils-0.3.5 → nano_dev_utils-0.4.2}/PKG-INFO +36 -27
  3. {nano_dev_utils-0.3.5 → nano_dev_utils-0.4.2}/README.md +35 -26
  4. {nano_dev_utils-0.3.5 → nano_dev_utils-0.4.2}/pyproject.toml +1 -1
  5. {nano_dev_utils-0.3.5 → nano_dev_utils-0.4.2}/src/nano_dev_utils/release_ports.py +2 -7
  6. nano_dev_utils-0.4.2/src/nano_dev_utils/timers.py +39 -0
  7. {nano_dev_utils-0.3.5 → nano_dev_utils-0.4.2}/tests/testing_release_ports.py +4 -3
  8. nano_dev_utils-0.3.5/src/nano_dev_utils/timers.py +0 -35
  9. {nano_dev_utils-0.3.5 → nano_dev_utils-0.4.2}/.gitignore +0 -0
  10. {nano_dev_utils-0.3.5 → nano_dev_utils-0.4.2}/.idea/.gitignore +0 -0
  11. {nano_dev_utils-0.3.5 → nano_dev_utils-0.4.2}/.idea/inspectionProfiles/profiles_settings.xml +0 -0
  12. {nano_dev_utils-0.3.5 → nano_dev_utils-0.4.2}/.idea/misc.xml +0 -0
  13. {nano_dev_utils-0.3.5 → nano_dev_utils-0.4.2}/.idea/modules.xml +0 -0
  14. {nano_dev_utils-0.3.5 → nano_dev_utils-0.4.2}/.idea/nano_dev_utils.iml +0 -0
  15. {nano_dev_utils-0.3.5 → nano_dev_utils-0.4.2}/.idea/vcs.xml +0 -0
  16. {nano_dev_utils-0.3.5 → nano_dev_utils-0.4.2}/LICENSE.md +0 -0
  17. {nano_dev_utils-0.3.5 → nano_dev_utils-0.4.2}/src/nano_dev_utils/__init__.py +0 -0
  18. {nano_dev_utils-0.3.5 → nano_dev_utils-0.4.2}/src/nano_dev_utils/dynamic_importer.py +0 -0
  19. {nano_dev_utils-0.3.5 → nano_dev_utils-0.4.2}/tests/__init__.py +0 -0
  20. {nano_dev_utils-0.3.5 → nano_dev_utils-0.4.2}/tests/testing_dynamic_importer.py +0 -0
  21. {nano_dev_utils-0.3.5 → nano_dev_utils-0.4.2}/tests/testing_timer.py +0 -0
@@ -4,9 +4,7 @@
4
4
  <option name="autoReloadType" value="SELECTIVE" />
5
5
  </component>
6
6
  <component name="ChangeListManager">
7
- <list default="true" id="96bbbefe-efb6-42c4-93da-e069ac3e654f" name="Changes" comment="minor update">
8
- <change beforePath="$PROJECT_DIR$/README.md" beforeDir="false" afterPath="$PROJECT_DIR$/README.md" afterDir="false" />
9
- </list>
7
+ <list default="true" id="96bbbefe-efb6-42c4-93da-e069ac3e654f" name="Changes" comment="release_ports unittests - minor update" />
10
8
  <option name="SHOW_DIALOG" value="false" />
11
9
  <option name="HIGHLIGHT_CONFLICTS" value="true" />
12
10
  <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
@@ -29,18 +27,18 @@
29
27
  <option name="showLibraryContents" value="true" />
30
28
  <option name="showMembers" value="true" />
31
29
  </component>
32
- <component name="PropertiesComponent"><![CDATA[{
33
- "keyToString": {
34
- "Python tests.Python tests in testing_release_ports.py.executor": "Run",
35
- "Python tests.Python tests in testing_timer.py.executor": "Run",
36
- "Python tests.Python tests in tests.executor": "Run",
37
- "RunOnceActivity.ShowReadmeOnStart": "true",
38
- "git-widget-placeholder": "master",
39
- "ignore.virus.scanning.warn.message": "true",
40
- "last_opened_file_path": "C:/GitHubWS/nano_dev_utils",
41
- "settings.editor.selected.configurable": "com.jetbrains.python.configuration.PyActiveSdkModuleConfigurable"
30
+ <component name="PropertiesComponent">{
31
+ &quot;keyToString&quot;: {
32
+ &quot;Python tests.Python tests in testing_release_ports.py.executor&quot;: &quot;Run&quot;,
33
+ &quot;Python tests.Python tests in testing_timer.py.executor&quot;: &quot;Run&quot;,
34
+ &quot;Python tests.Python tests in tests.executor&quot;: &quot;Run&quot;,
35
+ &quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
36
+ &quot;git-widget-placeholder&quot;: &quot;master&quot;,
37
+ &quot;ignore.virus.scanning.warn.message&quot;: &quot;true&quot;,
38
+ &quot;last_opened_file_path&quot;: &quot;C:/GitHubWS/nano_dev_utils&quot;,
39
+ &quot;settings.editor.selected.configurable&quot;: &quot;com.jetbrains.python.configuration.PyActiveSdkModuleConfigurable&quot;
42
40
  }
43
- }]]></component>
41
+ }</component>
44
42
  <component name="RunManager" selected="Python tests.Python tests in tests">
45
43
  <configuration name="Python tests in testing_release_ports.py" type="tests" factoryName="Autodetect" temporary="true" nameIsGenerated="true">
46
44
  <module name="nano_dev_utils" />
@@ -90,8 +88,8 @@
90
88
  <recent_temporary>
91
89
  <list>
92
90
  <item itemvalue="Python tests.Python tests in tests" />
93
- <item itemvalue="Python tests.Python tests in testing_timer.py" />
94
91
  <item itemvalue="Python tests.Python tests in testing_release_ports.py" />
92
+ <item itemvalue="Python tests.Python tests in testing_timer.py" />
95
93
  <item itemvalue="Python tests.Python tests in testing_release_ports.py" />
96
94
  </list>
97
95
  </recent_temporary>
@@ -240,7 +238,39 @@
240
238
  <option name="project" value="LOCAL" />
241
239
  <updated>1745715934159</updated>
242
240
  </task>
243
- <option name="localTasksCounter" value="17" />
241
+ <task id="LOCAL-00017" summary="readme typo fixes">
242
+ <option name="closed" value="true" />
243
+ <created>1745716694896</created>
244
+ <option name="number" value="00017" />
245
+ <option name="presentableId" value="LOCAL-00017" />
246
+ <option name="project" value="LOCAL" />
247
+ <updated>1745716694896</updated>
248
+ </task>
249
+ <task id="LOCAL-00018" summary="minor update">
250
+ <option name="closed" value="true" />
251
+ <created>1745716727869</created>
252
+ <option name="number" value="00018" />
253
+ <option name="presentableId" value="LOCAL-00018" />
254
+ <option name="project" value="LOCAL" />
255
+ <updated>1745716727869</updated>
256
+ </task>
257
+ <task id="LOCAL-00019" summary="release_ports: Externalizing logger's config to a user's app. &#10;timers: improve code, docstring and type hinting&#10;README updates IAW with the above changes &#10;Version update: 0.4.0">
258
+ <option name="closed" value="true" />
259
+ <created>1745763645981</created>
260
+ <option name="number" value="00019" />
261
+ <option name="presentableId" value="LOCAL-00019" />
262
+ <option name="project" value="LOCAL" />
263
+ <updated>1745763645981</updated>
264
+ </task>
265
+ <task id="LOCAL-00020" summary="release_ports unittests - minor update">
266
+ <option name="closed" value="true" />
267
+ <created>1745767183156</created>
268
+ <option name="number" value="00020" />
269
+ <option name="presentableId" value="LOCAL-00020" />
270
+ <option name="project" value="LOCAL" />
271
+ <updated>1745767183156</updated>
272
+ </task>
273
+ <option name="localTasksCounter" value="21" />
244
274
  <servers />
245
275
  </component>
246
276
  <component name="Vcs.Log.Tabs.Properties">
@@ -267,7 +297,10 @@
267
297
  <MESSAGE value="dunder init update" />
268
298
  <MESSAGE value="fixed authors and url for pip show" />
269
299
  <MESSAGE value="version update" />
300
+ <MESSAGE value="readme typo fixes" />
270
301
  <MESSAGE value="minor update" />
271
- <option name="LAST_COMMIT_MESSAGE" value="minor update" />
302
+ <MESSAGE value="release_ports: Externalizing logger's config to a user's app. &#10;timers: improve code, docstring and type hinting&#10;README updates IAW with the above changes &#10;Version update: 0.4.0" />
303
+ <MESSAGE value="release_ports unittests - minor update" />
304
+ <option name="LAST_COMMIT_MESSAGE" value="release_ports unittests - minor update" />
272
305
  </component>
273
306
  </project>
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nano_dev_utils
3
- Version: 0.3.5
3
+ Version: 0.4.2
4
4
  Summary: A collection of small Python utilities for developers.
5
5
  Project-URL: Homepage, https://github.com/yaronday/nano_utils
6
6
  Project-URL: Issues, https://github.com/yaronday/nano_utils/issues
@@ -24,22 +24,23 @@ This module provides a `Timer` class for measuring the execution time of code bl
24
24
 
25
25
  #### `Timer` Class
26
26
 
27
- * **`__init__(self, precision=4, verbose=False)`**: Initializes a `Timer` instance.
28
- * `precision` (int, optional): The number of decimal places to record and
27
+ * **`__init__(self, precision: int = 4, verbose: bool = False)`**: Initializes a `Timer` instance.
28
+ * `precision`: The number of decimal places to record and
29
29
  display time durations. Defaults to 4.
30
- * `verbose` (bool, optional): If `True`, the function's arguments (args) and keyword arguments (kwargs)
31
- will be included in the printed timing output. Defaults to `False`.
30
+ * `verbose`: Optionally displays the function's positional arguments (args) and keyword arguments (kwargs).
31
+ Defaults to `False`.
32
32
 
33
- * **`timeit(self, func)`**: A decorator that measures the execution time of the decorated function.
34
- * When the decorated function is called, this decorator records the start and end times,
35
- * calculates the total execution time, prints the function name and execution time.
36
- * (optionally including arguments if `verbose` is `True`), and returns the result of the original function.
33
+ * **`timeit(self, func: Callable[P, R]) -> Callable[P, R]`**:
34
+ Decorator that times function execution with automatic unit scaling.
35
+ * When the decorated function is called, this decorator records the start and end times,
36
+ calculates the total execution time, prints the function name and execution
37
+ time (optionally including arguments), and returns the result of the original function.
37
38
 
38
39
  #### Example Usage:
39
40
 
40
41
  ```python
41
42
  import time
42
- from src.nano_dev_utils.timers import Timer
43
+ from nano_dev_utils.timers import Timer
43
44
 
44
45
  timer = Timer(precision=6, verbose=True)
45
46
 
@@ -66,13 +67,13 @@ This module provides an `Importer` class for lazy loading and caching module imp
66
67
  * **`import_mod_from_lib(self, library: str, module_name: str) -> ModuleType | Any`**: Lazily imports a module from a specified library and caches it.
67
68
  * `library` (str): The name of the library (e.g., "os", "requests").
68
69
  * `module_name` (str): The name of the module to import within the library (e.g., "path", "get").
69
- * Returns the imported module. If the module has already been imported, it returns the cached instance.
70
+ * Returns the imported module. If the module has already been imported, it returns a cached instance.
70
71
  * Raises `ImportError` if the module cannot be found.
71
72
 
72
73
  #### Example Usage:
73
74
 
74
75
  ```python
75
- from src.nano_dev_utils.dynamic_importer import Importer
76
+ from nano_dev_utils.dynamic_importer import Importer
76
77
 
77
78
  importer = Importer()
78
79
 
@@ -90,34 +91,42 @@ print(f"Imported os.path again (cached): {os_path_again}")
90
91
  ### `release_ports.py`
91
92
 
92
93
  This module provides a `PortsRelease` class to identify and release processes
93
- listening on specified TCP ports. It supports Windows, Linux, and macOS.
94
+ listening on specified TCP ports.
95
+ It supports Windows, Linux, and macOS.
94
96
 
95
97
  #### `PortsRelease` Class
96
98
 
97
- * **`__init__(self, default_ports: Optional[list[int]] = None)`**:
99
+ * **`__init__(self, default_ports: list[int] | None = None)`**:
98
100
  * Initializes a `PortsRelease` instance.
99
- * `default_ports` (`list[int]`, *optional*): A list of default ports to manage.
100
- * If not provided, it defaults to `[6277, 6274]`.
101
+ * `default_ports`: A list of default ports to manage. If not provided, it defaults to `[6277, 6274]`.
101
102
 
102
- * **`get_pid_by_port(port: int) -> Optional[int]`**: A static method that attempts to
103
- * find the process ID (PID) listening on the given `port`. It uses platform-specific
104
- commands (`netstat`, `ss`, `lsof`). Returns the PID if found, otherwise `None`.
103
+ * **`get_pid_by_port(self, port: int) -> int | None`**: A static method that attempts to find
104
+ a process ID (PID) listening on a given `port`.
105
+ * It uses platform-specific commands (`netstat`, `ss`, `lsof`).
106
+ * Returns the PID if found, otherwise `None`.
105
107
 
106
- * **`kill_process(pid: int) -> bool`**: A static method that attempts to kill the process
107
- with the given `pid`. It uses platform-specific commands (`taskkill`, `kill -9`).
108
+ * **`kill_process(self, pid: int) -> bool`**: A static method that attempts to kill the process
109
+ with the given `pid`.
110
+ * It uses platform-specific commands (`taskkill`, `kill -9`).
108
111
  * Returns `True` if the process was successfully killed, `False` otherwise.
109
112
 
110
- * **`release_all(self, ports: Optional[list[int]] = None) -> None`**: Releases all processes
111
- * listening on the specified `ports`.
112
- * `ports` (`list[int]`, *optional*): A list of ports to release. If `None`, it uses the
113
- `default_ports` defined during initialization.
114
- * For each port, it first tries to get the PID and then attempts to kill the process.
113
+ * **`release_all(self, ports: list[int] | None = None) -> None`**: Releases all processes listening on the specified `ports`.
114
+ * `ports`: A list of ports to release.
115
+ * If `None`, it uses the `default_ports` defined during initialization.
116
+ * For each port, it first tries to get the PID and then attempts to kill the process.
115
117
  * It logs the actions and any errors encountered. Invalid port numbers in the provided list are skipped.
116
118
 
117
119
  #### Example Usage:
118
120
 
119
121
  ```python
120
- from src.nano_dev_utils.release_ports import PortsRelease
122
+ import logging
123
+ from nano_dev_utils import PortsRelease
124
+
125
+ # in case you're interested in logging
126
+ logging.basicConfig(filename='port release.log',
127
+ level=logging.INFO, # specify here desire level, e.g. DEBUG etc.
128
+ format='%(asctime)s - %(levelname)s: %(message)s',
129
+ datefmt='%d-%m-%Y %H:%M:%S')
121
130
 
122
131
  # Create an instance with default ports
123
132
  port_releaser = PortsRelease()
@@ -10,22 +10,23 @@ This module provides a `Timer` class for measuring the execution time of code bl
10
10
 
11
11
  #### `Timer` Class
12
12
 
13
- * **`__init__(self, precision=4, verbose=False)`**: Initializes a `Timer` instance.
14
- * `precision` (int, optional): The number of decimal places to record and
13
+ * **`__init__(self, precision: int = 4, verbose: bool = False)`**: Initializes a `Timer` instance.
14
+ * `precision`: The number of decimal places to record and
15
15
  display time durations. Defaults to 4.
16
- * `verbose` (bool, optional): If `True`, the function's arguments (args) and keyword arguments (kwargs)
17
- will be included in the printed timing output. Defaults to `False`.
16
+ * `verbose`: Optionally displays the function's positional arguments (args) and keyword arguments (kwargs).
17
+ Defaults to `False`.
18
18
 
19
- * **`timeit(self, func)`**: A decorator that measures the execution time of the decorated function.
20
- * When the decorated function is called, this decorator records the start and end times,
21
- * calculates the total execution time, prints the function name and execution time.
22
- * (optionally including arguments if `verbose` is `True`), and returns the result of the original function.
19
+ * **`timeit(self, func: Callable[P, R]) -> Callable[P, R]`**:
20
+ Decorator that times function execution with automatic unit scaling.
21
+ * When the decorated function is called, this decorator records the start and end times,
22
+ calculates the total execution time, prints the function name and execution
23
+ time (optionally including arguments), and returns the result of the original function.
23
24
 
24
25
  #### Example Usage:
25
26
 
26
27
  ```python
27
28
  import time
28
- from src.nano_dev_utils.timers import Timer
29
+ from nano_dev_utils.timers import Timer
29
30
 
30
31
  timer = Timer(precision=6, verbose=True)
31
32
 
@@ -52,13 +53,13 @@ This module provides an `Importer` class for lazy loading and caching module imp
52
53
  * **`import_mod_from_lib(self, library: str, module_name: str) -> ModuleType | Any`**: Lazily imports a module from a specified library and caches it.
53
54
  * `library` (str): The name of the library (e.g., "os", "requests").
54
55
  * `module_name` (str): The name of the module to import within the library (e.g., "path", "get").
55
- * Returns the imported module. If the module has already been imported, it returns the cached instance.
56
+ * Returns the imported module. If the module has already been imported, it returns a cached instance.
56
57
  * Raises `ImportError` if the module cannot be found.
57
58
 
58
59
  #### Example Usage:
59
60
 
60
61
  ```python
61
- from src.nano_dev_utils.dynamic_importer import Importer
62
+ from nano_dev_utils.dynamic_importer import Importer
62
63
 
63
64
  importer = Importer()
64
65
 
@@ -76,34 +77,42 @@ print(f"Imported os.path again (cached): {os_path_again}")
76
77
  ### `release_ports.py`
77
78
 
78
79
  This module provides a `PortsRelease` class to identify and release processes
79
- listening on specified TCP ports. It supports Windows, Linux, and macOS.
80
+ listening on specified TCP ports.
81
+ It supports Windows, Linux, and macOS.
80
82
 
81
83
  #### `PortsRelease` Class
82
84
 
83
- * **`__init__(self, default_ports: Optional[list[int]] = None)`**:
85
+ * **`__init__(self, default_ports: list[int] | None = None)`**:
84
86
  * Initializes a `PortsRelease` instance.
85
- * `default_ports` (`list[int]`, *optional*): A list of default ports to manage.
86
- * If not provided, it defaults to `[6277, 6274]`.
87
+ * `default_ports`: A list of default ports to manage. If not provided, it defaults to `[6277, 6274]`.
87
88
 
88
- * **`get_pid_by_port(port: int) -> Optional[int]`**: A static method that attempts to
89
- * find the process ID (PID) listening on the given `port`. It uses platform-specific
90
- commands (`netstat`, `ss`, `lsof`). Returns the PID if found, otherwise `None`.
89
+ * **`get_pid_by_port(self, port: int) -> int | None`**: A static method that attempts to find
90
+ a process ID (PID) listening on a given `port`.
91
+ * It uses platform-specific commands (`netstat`, `ss`, `lsof`).
92
+ * Returns the PID if found, otherwise `None`.
91
93
 
92
- * **`kill_process(pid: int) -> bool`**: A static method that attempts to kill the process
93
- with the given `pid`. It uses platform-specific commands (`taskkill`, `kill -9`).
94
+ * **`kill_process(self, pid: int) -> bool`**: A static method that attempts to kill the process
95
+ with the given `pid`.
96
+ * It uses platform-specific commands (`taskkill`, `kill -9`).
94
97
  * Returns `True` if the process was successfully killed, `False` otherwise.
95
98
 
96
- * **`release_all(self, ports: Optional[list[int]] = None) -> None`**: Releases all processes
97
- * listening on the specified `ports`.
98
- * `ports` (`list[int]`, *optional*): A list of ports to release. If `None`, it uses the
99
- `default_ports` defined during initialization.
100
- * For each port, it first tries to get the PID and then attempts to kill the process.
99
+ * **`release_all(self, ports: list[int] | None = None) -> None`**: Releases all processes listening on the specified `ports`.
100
+ * `ports`: A list of ports to release.
101
+ * If `None`, it uses the `default_ports` defined during initialization.
102
+ * For each port, it first tries to get the PID and then attempts to kill the process.
101
103
  * It logs the actions and any errors encountered. Invalid port numbers in the provided list are skipped.
102
104
 
103
105
  #### Example Usage:
104
106
 
105
107
  ```python
106
- from src.nano_dev_utils.release_ports import PortsRelease
108
+ import logging
109
+ from nano_dev_utils import PortsRelease
110
+
111
+ # in case you're interested in logging
112
+ logging.basicConfig(filename='port release.log',
113
+ level=logging.INFO, # specify here desire level, e.g. DEBUG etc.
114
+ format='%(asctime)s - %(levelname)s: %(message)s',
115
+ datefmt='%d-%m-%Y %H:%M:%S')
107
116
 
108
117
  # Create an instance with default ports
109
118
  port_releaser = PortsRelease()
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "nano_dev_utils"
3
- version = "0.3.5"
3
+ version = "0.4.2"
4
4
 
5
5
  authors = [
6
6
  { name="Yaron Dayan", email="yaronday77@gmail.com" },
@@ -2,12 +2,8 @@ import platform
2
2
  import subprocess
3
3
  import logging
4
4
 
5
-
6
- logging.basicConfig(filename='port release.log',
7
- level=logging.INFO,
8
- format='%(asctime)s - %(levelname)s: %(message)s',
9
- datefmt='%d-%m-%Y %H:%M:%S')
10
5
  lgr = logging.getLogger(__name__)
6
+ """Module-level logger. Configure using logging.basicConfig() in your application."""
11
7
 
12
8
  PROXY_SERVER = 6277
13
9
  INSPECTOR_CLIENT = 6274
@@ -152,5 +148,4 @@ class PortsRelease:
152
148
  else:
153
149
  lgr.error(self._log_terminate_failed(pid=pid, port=port))
154
150
  except Exception as e:
155
- lgr.error(self._log_unexpected_error(e))
156
-
151
+ lgr.error(self._log_unexpected_error(e))
@@ -0,0 +1,39 @@
1
+ from functools import wraps
2
+ import time
3
+ from typing import Callable, ParamSpec, TypeVar
4
+ P = ParamSpec('P')
5
+ R = TypeVar('R')
6
+
7
+
8
+ class Timer:
9
+ def __init__(self, precision=4, verbose=False):
10
+ self.precision = precision
11
+ self.verbose = verbose
12
+ self.units = [
13
+ (1e9, 's'),
14
+ (1e6, 'ms'),
15
+ (1e3, 'μs'),
16
+ (1.0, 'ns')
17
+ ]
18
+
19
+ def timeit(self, func: Callable[P, R]) -> Callable[P, R]:
20
+ """Decorator that times function execution with automatic unit scaling."""
21
+ @wraps(func)
22
+ def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
23
+ start = time.perf_counter_ns()
24
+ result = func(*args, **kwargs)
25
+ elapsed = time.perf_counter_ns() - start
26
+
27
+ value = elapsed
28
+ unit = 'ns'
29
+
30
+ for divisor, unit in self.units:
31
+ if elapsed >= divisor or unit == 'ns':
32
+ value = elapsed / divisor
33
+ break
34
+
35
+ extra_info = f'{args} {kwargs} ' if self.verbose else ''
36
+ print(f'{func.__name__} {extra_info}took {value:.{self.precision}f} [{unit}]')
37
+ return result
38
+
39
+ return wrapper
@@ -173,12 +173,13 @@ class TestPortsRelease(unittest.TestCase):
173
173
 
174
174
  def test_get_pid_by_port_unexpected_exception(self):
175
175
  with patch('platform.system', return_value='Linux'):
176
- with patch('subprocess.Popen', side_effect=Exception("Unexpected")):
176
+ err = Exception("Unexpected")
177
+ with patch('subprocess.Popen', side_effect=err):
177
178
  port = 1234
178
179
  pid = self.ports_release.get_pid_by_port(port)
179
180
  self.assertIsNone(pid)
180
- self.mock_logger.error.assert_called_once_with("An unexpected "
181
- "error occurred: Unexpected")
181
+ self.mock_logger.error.assert_called_once_with(f'An unexpected '
182
+ f'error occurred: {err}')
182
183
 
183
184
  def test_kill_process_success(self):
184
185
  with patch('platform.system', return_value='Linux'):
@@ -1,35 +0,0 @@
1
- from functools import wraps
2
- import time
3
-
4
-
5
- class Timer:
6
- def __init__(self, precision=4, verbose=False):
7
- self.precision = precision
8
- self.verbose = verbose
9
-
10
- def timeit(self, func):
11
- @wraps(func)
12
- def timeit_wrapper(*args, **kwargs):
13
- start_time = time.perf_counter_ns()
14
- result = func(*args, **kwargs)
15
- end_time = time.perf_counter_ns()
16
- total_ns = end_time - start_time
17
-
18
- if total_ns < 1_000: # 1μs
19
- value = total_ns
20
- unit = "ns"
21
- elif total_ns < 1_000_000: # < 1ms
22
- value = total_ns / 1_000
23
- unit = "μs"
24
- elif total_ns < 1_000_000_000: # < 1s
25
- value = total_ns / 1_000_000
26
- unit = "ms"
27
- else:
28
- value = total_ns / 1_000_000_000
29
- unit = "s"
30
-
31
- extra_info = f'{args} {kwargs} ' if self.verbose else ''
32
- print(f'{func.__name__} {extra_info}took {value:.{self.precision}f} [{unit}]')
33
- return result
34
-
35
- return timeit_wrapper