Skip to content

Commit 53df1b1

Browse files
[STYLE] Cleanup for release (- WIP PR #454 -)
Changes in file multicast/__init__.py: * added some documentation * style tweaks Changes in file multicast/__main__.py: * added some documentation * style tweaks Changes in file multicast/recv.py: * added some documentation * style tweaks Changes in file multicast/skt.py: * style tweaks Changes in file tests/MulticastUDPClient.py: * style tweaks Changes in file tests/__init__.py: * added some documentation * style tweaks Changes in file tests/context.py: * added some documentation * style tweaks Changes in file tests/test_extra.py: * added some documentation Changes in file tests/test_fuzz.py: * added some documentation Changes in file tests/test_hear_server.py: * added some documentation * style tweaks Changes in file tests/test_hear_server_activate.py: * added some documentation * style tweaks Changes in file tests/test_usage.py: * added some documentation * style tweaks
1 parent b7caec8 commit 53df1b1

File tree

12 files changed

+259
-32
lines changed

12 files changed

+259
-32
lines changed

multicast/__init__.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,15 @@
3535
"""exceptions""",
3636
"""exceptions.CommandExecutionError""", # skipcq: PYL-E0603 -- imports ok
3737
"""exceptions.ShutdownCommandReceived""", # skipcq: PYL-E0603 -- imports ok
38-
"""exceptions.get_exit_code_from_exception""",
39-
"""exceptions.exit_on_exception""",
38+
"""exceptions.get_exit_code_from_exception""", # skipcq: PYL-E0603 -- imports ok
39+
"""exceptions.exit_on_exception""", # skipcq: PYL-E0603 -- imports ok
4040
"""get_exit_code_from_exception""",
4141
"""exit_on_exception""",
4242
"""env""",
4343
"""skt""",
44-
"""skt.__package__""",
45-
"""skt.__module__""",
46-
"""skt.__name__""",
44+
"""skt.__package__""", # skipcq: PYL-E0603 -- shadow imports ok
45+
"""skt.__module__""", # skipcq: PYL-E0603 -- shadow imports ok
46+
"""skt.__name__""", # skipcq: PYL-E0603 -- shadow imports ok
4747
"""skt.__file__""", # skipcq: PYL-E0603 -- shadow imports ok
4848
"""skt.genSocket""", # skipcq: PYL-E0603 -- shadow imports ok
4949
"""skt.genSocket.__func__""", # skipcq: PYL-E0603 -- shadow imports ok

multicast/__main__.py

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,24 @@ class McastNope(mtool):
245245

246246
@classmethod
247247
def setupArgs(cls, parser):
248+
"""
249+
Sets up command-line arguments for the trivial subclass implementation of mtool.
250+
251+
This method is intended to be overridden by subclasses to define
252+
specific command-line arguments. It takes a parser object as an
253+
argument, which is typically an instance of `argparse.ArgumentParser`.
254+
255+
Args:
256+
parser (argparse.ArgumentParser): The argument parser to which
257+
the arguments should be added.
258+
259+
Returns:
260+
None: This method does not return a value.
261+
262+
Note:
263+
This is trivial implementation make this an optional abstract method. Subclasses may
264+
choose to implement it or leave it as a no-op.
265+
"""
248266
pass # skipcq: PTC-W0049 - optional abstract method
249267

250268
@staticmethod
@@ -396,7 +414,14 @@ def setupArgs(cls, parser):
396414
Will attempt to add hear args.
397415
398416
Both HEAR and RECV use the same arguments, and are differentiated only by the global,
399-
'--daemon' argument during dispatch.
417+
'--daemon' argument during dispatch. The remaining arguments are:
418+
419+
| Arguments | Notes |
420+
|-----------|------------------------------------------------------------|
421+
| --deamon | Enable use of HEAR, otherwise use RECV if omitted |
422+
| --group | multicast group (ip address) to bind-to for the udp socket |
423+
| --groups | multicast groups to join (should include the bind group) |
424+
| --port | The UDP port number to listen/filter on for the udp socket |
400425
401426
Testing:
402427
@@ -582,6 +607,12 @@ class McastDispatch(mtool):
582607

583608
@classmethod
584609
def setupArgs(cls, parser) -> None:
610+
"""
611+
Will attempt to add each subcomponent's args.
612+
613+
As the dispatch tool, this is more of a proxy implementation to call the sub-components
614+
own setupArgs.
615+
"""
585616
if parser is not None: # pragma: no branch
586617
for sub_tool in sorted(TASK_OPTIONS.keys()):
587618
sub_parser = parser.add_parser(sub_tool, help="...")
@@ -619,12 +650,12 @@ def doStep(self, *args, **kwargs) -> tuple:
619650
(argz, _) = type(self).parseArgs(*args)
620651
service_cmd = argz.cmd_tool
621652
argz.__dict__.__delitem__("cmd_tool")
622-
_TOOL_MSG = (self.useTool(service_cmd, **argz.__dict__))
653+
_TOOL_MSG = (self.useTool(service_cmd, **argz.__dict__)) # skipcq: PYL-C0325
623654
if _TOOL_MSG[0]:
624655
_response = (0, _TOOL_MSG)
625656
else:
626657
_response = (70, _TOOL_MSG)
627-
if (sys.stdout.isatty()): # pragma: no cover
658+
if sys.stdout.isatty(): # pragma: no cover
628659
print(str(_TOOL_MSG))
629660
except Exception as _cause: # pragma: no branch
630661
exit_code = exceptions.get_exit_code_from_exception(_cause)

multicast/recv.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,7 @@ def tryrecv(msgbuffer: list, chunk: bytes, sock: _socket.socket) -> str:
481481
482482
"""
483483
chunk = sock.recv(multicast._MCAST_DEFAULT_BUFFER_SIZE) # skipcq: PYL-W0212 - module ok
484-
if not (chunk is None): # pragma: no branch
484+
if not (chunk is None): # skipcq: PYL-C0325 -- avoids flake E714 anti-pattern
485485
msgbuffer += str(chunk, encoding='utf8') # pragma: no cover
486486
chunk = None # pragma: no cover
487487
return msgbuffer
@@ -504,14 +504,14 @@ def recvstep(msgbuffer: list, chunk: bytes, sock: _socket.socket) -> str:
504504
try:
505505
msgbuffer = tryrecv(msgbuffer, chunk, sock)
506506
except KeyboardInterrupt: # pragma: no branch
507-
if (sys.stdout.isatty()): # pragma: no cover
507+
if sys.stdout.isatty(): # pragma: no cover
508508
module_logger.warning("User Interrupted")
509509
except OSError: # pragma: no branch
510510
module_logger.debug("[CWE-440] Nothing happened. There seems to have been an OS error.")
511511
finally:
512512
if sock: # pragma: no branch
513513
sock = multicast.endSocket(sock)
514-
if not (chunk is None): # pragma: no branch
514+
if not (chunk is None): # skipcq: PYL-C0325 -- avoids flake E714 anti-pattern
515515
msgbuffer += str(chunk, encoding='utf8') # pragma: no cover
516516
chunk = None # pragma: no cover
517517
# about 969 bytes in base64 encoded as chars

multicast/skt.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ def genSocket() -> _socket.socket:
205205
"""
206206
sock = _socket.socket(_socket.AF_INET, _socket.SOCK_DGRAM, _socket.IPPROTO_UDP)
207207
sock.setsockopt(_socket.SOL_SOCKET, _socket.SO_REUSEADDR, 1)
208-
if (hasattr(_socket, 'IP_MULTICAST_TTL')): # pragma: no branch
208+
if hasattr(_socket, 'IP_MULTICAST_TTL'): # pragma: no branch
209209
sock.setsockopt(_socket.IPPROTO_IP, _socket.IP_MULTICAST_TTL, _MCAST_DEFAULT_TTL)
210210
sock.settimeout(_MCAST_DEFAULT_TTL)
211211
return sock

tests/MulticastUDPClient.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ def say(address: str, port: int, sock: socket.socket, msg: str) -> None: # prag
309309
sock.sendto(bytes(msg + "\n", "utf-8"), (address, port)) # pragma: no cover
310310
received = str(sock.recv(1024), "utf-8") # pragma: no cover
311311
sp = " " * 4 # pragma: no cover
312-
if (sys.stdout.isatty()): # pragma: no cover
312+
if sys.stdout.isatty(): # pragma: no cover
313313
print(f"Sent: {sp}{msg}") # skipcq: PYL-C0209 - must remain compatible
314314
print(f"Received: {received}") # skipcq: PYL-C0209 - must remain compatible
315315

tests/__init__.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,32 @@
8383
import logging
8484
try:
8585
class ANSIColors:
86+
"""
87+
A class that defines ANSI color codes for terminal output.
88+
89+
This class contains ANSI escape sequences for various colors and a
90+
mapping of logging levels to their corresponding colors. It also
91+
includes a nested class for a colored stream handler that formats
92+
log messages with the appropriate colors based on their severity.
93+
94+
Attributes:
95+
BLACK (str): ANSI code for black text.
96+
RED (str): ANSI code for red text.
97+
GREEN (str): ANSI code for green text.
98+
YELLOW (str): ANSI code for yellow text.
99+
BLUE (str): ANSI code for blue text.
100+
MAGENTA (str): ANSI code for magenta text.
101+
CYAN (str): ANSI code for cyan text.
102+
GREY (str): ANSI code for grey text.
103+
AMBER (str): ANSI code for amber text.
104+
REDBG (str): ANSI code for red background.
105+
ENDC (str): ANSI code to reset text formatting.
106+
107+
logging_color (dict): A dictionary mapping logging levels to their
108+
corresponding ANSI color codes.
109+
logging_level (dict): A dictionary mapping logging levels to their
110+
corresponding logging module constants.
111+
"""
86112
# Define ANSI color codes
87113
BLACK = """\033[30m"""
88114
RED = """\033[31m"""
@@ -112,7 +138,30 @@ class ANSIColors:
112138
}
113139

114140
class ColoredStreamHandler(logging.StreamHandler):
141+
"""
142+
A custom logging handler that outputs with color formatting based on the log level.
143+
144+
This handler checks if the output stream is a terminal and applies
145+
the appropriate ANSI color codes to the log messages. If the output
146+
is not a terminal, it outputs plain text without color.
147+
148+
Methods:
149+
emit(record: logging.LogRecord) -> None:
150+
Formats and writes the log message to the stream with
151+
appropriate color based on the log level.
152+
"""
153+
115154
def emit(self, record: logging.LogRecord) -> None:
155+
"""
156+
Formats and writes the log message to the stream with color.
157+
158+
Args:
159+
record (logging.LogRecord): The log record containing
160+
information about the log event.
161+
162+
Raises:
163+
ValueError: If the log level is invalid or not recognized.
164+
"""
116165
# Get the log level as a string
117166
loglevel = record.levelname.lower()
118167
# Validate the log level
@@ -429,6 +478,21 @@ def get_test_suite(
429478

430479
# Helper function to add test cases to suite
431480
def add_test_cases(test_cases: list) -> None:
481+
"""
482+
Adds a list of test cases to the test suite.
483+
484+
This function iterates over the provided list of test cases. If a test case
485+
is an instance of unittest.TestSuite, it adds the entire suite to the
486+
main suite. If the test case is a class, it loads the tests from that
487+
class and adds them to the main suite.
488+
489+
Args:
490+
test_cases (list): A list of test cases or test suites to be added
491+
to the main test suite.
492+
493+
Returns:
494+
None: This function does not return a value.
495+
"""
432496
for test_case in test_cases:
433497
if isinstance(test_case, unittest.TestSuite):
434498
# Handle doctests

tests/context.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ def markWithMetaTag(*marks: str) -> callable:
181181
except ImportError:
182182
pytest_available = False
183183

184-
def decorator(cls) -> any:
184+
def decorator(cls) -> any: # skipcq: PY-D0003 -- decorator ok
185185
if pytest_available:
186186
for mark in marks:
187187
cls = pytest.mark.__getattr__(mark)(cls)
@@ -263,7 +263,8 @@ def __check_cov_before_py():
263263
thepython = str(f"{str(thecov)} run -p") # skipcq: TCV-002
264264
else: # pragma: no branch
265265
try:
266-
import coverage as coverage
266+
# pylint: disable=cyclic-import - skipcq: PYL-R0401, PYL-C0414
267+
import coverage as coverage # skipcq: PYL-C0414
267268
if coverage.__name__ is not None:
268269
thepython = str("{} -m coverage run -p").format(str(sys.executable))
269270
except Exception:
@@ -1072,7 +1073,7 @@ def setUp(self) -> None:
10721073
self.skipTest(self.NO_PYTHON_ERROR) # skipcq: TCV-002
10731074
self._the_test_port = self._always_generate_random_port_WHEN_called()
10741075

1075-
def _should_get_package_version_WHEN_valid(self) -> None:
1076+
def _should_get_package_version_WHEN_valid(self) -> packaging.version.Version:
10761077
"""
10771078
Retrieve the current version of the package.
10781079
@@ -1085,6 +1086,7 @@ def _should_get_package_version_WHEN_valid(self) -> None:
10851086
ImportError -- If the multicast package cannot be imported.
10861087
10871088
"""
1089+
parsed_version: packaging.version.Version = None
10881090
try:
10891091
self.assertIsNotNone(multicast.__module__, "Version will be effectively None.")
10901092
self.assertIsNotNone(multicast.__version__, "Version is not valid.")
@@ -1100,9 +1102,10 @@ def _should_get_package_version_WHEN_valid(self) -> None:
11001102
len(parsed_version.release) >= 2,
11011103
"Version must have at least major.minor components."
11021104
)
1103-
return parsed_version
11041105
except ImportError:
11051106
self.fail("Failed to import the multicast package to retrieve version.")
1107+
finally:
1108+
return parsed_version
11061109

11071110
@unittest.skipUnless(True, "Insanity Test. Good luck debugging.")
11081111
def test_absolute_truth_and_meaning(self) -> None:

tests/test_extra.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ def onlyIfHasDocs(has_docs: bool) -> callable:
107107
True
108108
109109
"""
110-
def decorator(cls: callable) -> callable:
110+
def decorator(cls: callable) -> callable: # skipcq: PY-D0003 -- decorator ok
111111
if not has_docs:
112112
# Create an empty class with a method that returns None
113113
return type(cls.__name__, (object,), {

tests/test_fuzz.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ def onlyIfHasHypothesis(has_hypothesis: bool) -> callable:
9191
callable: A decorator function that returns either the original class or a dummy class
9292
with a placeholder method, depending on the has_hypothesis flag.
9393
"""
94-
def decorator(cls: callable) -> callable:
94+
def decorator(cls: callable) -> callable: # skipcq: PY-D0003 -- decorator ok
9595
if not has_hypothesis:
9696
# Create an empty class with a method that returns None
9797
return type(cls.__name__, (object,), {

0 commit comments

Comments
 (0)