ezmsg-baseproc 1.0__tar.gz → 1.0.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.
- {ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/.github/workflows/docs.yml +4 -4
- {ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/PKG-INFO +1 -1
- {ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/src/ezmsg/baseproc/__version__.py +2 -2
- {ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/src/ezmsg/baseproc/util/profile.py +20 -11
- ezmsg_baseproc-1.0.2/tests/test_profile.py +189 -0
- {ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/.github/workflows/python-publish.yml +0 -0
- {ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/.github/workflows/python-tests.yml +0 -0
- {ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/.gitignore +0 -0
- {ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/.pre-commit-config.yaml +0 -0
- {ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/LICENSE +0 -0
- {ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/README.md +0 -0
- {ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/docs/Makefile +0 -0
- {ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/docs/make.bat +0 -0
- {ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/docs/source/_templates/autosummary/module.rst +0 -0
- {ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/docs/source/api/index.rst +0 -0
- {ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/docs/source/conf.py +0 -0
- {ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/docs/source/guides/ProcessorsBase.md +0 -0
- {ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/docs/source/guides/how-tos/processors/adaptive.rst +0 -0
- {ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/docs/source/guides/how-tos/processors/checkpoint.rst +0 -0
- {ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/docs/source/guides/how-tos/processors/composite.rst +0 -0
- {ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/docs/source/guides/how-tos/processors/content-processors.rst +0 -0
- {ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/docs/source/guides/how-tos/processors/processor.rst +0 -0
- {ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/docs/source/guides/how-tos/processors/standalone.rst +0 -0
- {ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/docs/source/guides/how-tos/processors/stateful.rst +0 -0
- {ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/docs/source/guides/how-tos/processors/unit.rst +0 -0
- {ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/docs/source/index.rst +0 -0
- {ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/examples/example.py +0 -0
- {ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/pyproject.toml +0 -0
- {ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/src/ezmsg/baseproc/__init__.py +0 -0
- {ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/src/ezmsg/baseproc/composite.py +0 -0
- {ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/src/ezmsg/baseproc/processor.py +0 -0
- {ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/src/ezmsg/baseproc/protocols.py +0 -0
- {ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/src/ezmsg/baseproc/stateful.py +0 -0
- {ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/src/ezmsg/baseproc/units.py +0 -0
- {ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/src/ezmsg/baseproc/util/__init__.py +0 -0
- {ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/src/ezmsg/baseproc/util/asio.py +0 -0
- {ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/src/ezmsg/baseproc/util/message.py +0 -0
- {ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/src/ezmsg/baseproc/util/typeresolution.py +0 -0
- {ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/tests/test_baseproc.py +0 -0
|
@@ -4,12 +4,12 @@ on:
|
|
|
4
4
|
push:
|
|
5
5
|
branches:
|
|
6
6
|
- main
|
|
7
|
-
tags:
|
|
8
|
-
- 'v*'
|
|
9
7
|
pull_request:
|
|
10
8
|
branches:
|
|
11
9
|
- main
|
|
12
10
|
- dev
|
|
11
|
+
release:
|
|
12
|
+
types: [published]
|
|
13
13
|
workflow_dispatch:
|
|
14
14
|
|
|
15
15
|
permissions:
|
|
@@ -53,8 +53,8 @@ jobs:
|
|
|
53
53
|
path: 'docs/build/html'
|
|
54
54
|
|
|
55
55
|
deploy:
|
|
56
|
-
# Only deploy
|
|
57
|
-
if: github.event_name == '
|
|
56
|
+
# Only deploy when a release is published
|
|
57
|
+
if: github.event_name == 'release'
|
|
58
58
|
environment:
|
|
59
59
|
name: github-pages
|
|
60
60
|
url: ${{ steps.deployment.outputs.page_url }}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ezmsg-baseproc
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 1.0.2
|
|
4
4
|
Summary: Base processor classes and protocols for ezmsg signal processing pipelines
|
|
5
5
|
Author-email: Griffin Milsap <griffin.milsap@gmail.com>, Preston Peranich <pperanich@gmail.com>, Chadwick Boulay <chadwick.boulay@gmail.com>, Kyle McGraw <kmcgraw@blackrockneuro.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '1.0'
|
|
32
|
-
__version_tuple__ = version_tuple = (1, 0)
|
|
31
|
+
__version__ = version = '1.0.2'
|
|
32
|
+
__version_tuple__ = version_tuple = (1, 0, 2)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -31,20 +31,29 @@ def _setup_logger(append: bool = False) -> logging.Logger:
|
|
|
31
31
|
write_header = True
|
|
32
32
|
if logpath.exists() and logpath.is_file():
|
|
33
33
|
if append:
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
try:
|
|
35
|
+
with open(logpath) as f:
|
|
36
|
+
first_line = f.readline().rstrip()
|
|
37
|
+
if first_line == HEADER:
|
|
38
|
+
write_header = False
|
|
39
|
+
else:
|
|
40
|
+
# Remove the file if appending, but headers do not match
|
|
41
|
+
ezmsg_logger = logging.getLogger("ezmsg")
|
|
42
|
+
ezmsg_logger.warning(
|
|
43
|
+
"Profiling header mismatch: please make sure to use the same version of "
|
|
44
|
+
"ezmsg for all processes."
|
|
45
|
+
)
|
|
46
|
+
logpath.unlink()
|
|
47
|
+
except (PermissionError, OSError):
|
|
48
|
+
# On Windows, file may be locked by another process - just append
|
|
37
49
|
write_header = False
|
|
38
|
-
else:
|
|
39
|
-
# Remove the file if appending, but headers do not match
|
|
40
|
-
ezmsg_logger = logging.getLogger("ezmsg")
|
|
41
|
-
ezmsg_logger.warning(
|
|
42
|
-
"Profiling header mismatch: please make sure to use the same version of ezmsg for all processes."
|
|
43
|
-
)
|
|
44
|
-
logpath.unlink()
|
|
45
50
|
else:
|
|
46
51
|
# Remove the file if not appending
|
|
47
|
-
|
|
52
|
+
try:
|
|
53
|
+
logpath.unlink()
|
|
54
|
+
except (PermissionError, OSError):
|
|
55
|
+
# On Windows, file may be locked by another process - continue anyway
|
|
56
|
+
pass
|
|
48
57
|
|
|
49
58
|
# Create a logger with the name "ezprofile"
|
|
50
59
|
_logger = logging.getLogger("ezprofile")
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from unittest.mock import patch
|
|
6
|
+
|
|
7
|
+
import pytest
|
|
8
|
+
|
|
9
|
+
from ezmsg.baseproc.util.profile import (
|
|
10
|
+
HEADER,
|
|
11
|
+
_setup_logger,
|
|
12
|
+
get_logger_path,
|
|
13
|
+
profile_method,
|
|
14
|
+
profile_subpub,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def test_logger_creation():
|
|
19
|
+
"""Test that the ezprofile logger is created when importing from ezmsg.baseproc.util.profile."""
|
|
20
|
+
logger_name = "ezprofile"
|
|
21
|
+
assert logger_name in logging.Logger.manager.loggerDict
|
|
22
|
+
logger = logging.getLogger(logger_name)
|
|
23
|
+
assert logger.level == logging.INFO
|
|
24
|
+
assert len(logger.handlers) == 1
|
|
25
|
+
handler = logger.handlers[0]
|
|
26
|
+
assert isinstance(handler, logging.FileHandler)
|
|
27
|
+
assert handler.level == logging.DEBUG
|
|
28
|
+
assert Path(handler.baseFilename) == get_logger_path()
|
|
29
|
+
|
|
30
|
+
# Remove and close all handlers
|
|
31
|
+
logger.removeHandler(handler)
|
|
32
|
+
handler.close()
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@pytest.fixture
|
|
36
|
+
def mock_env():
|
|
37
|
+
"""Fixture to mock environment variables."""
|
|
38
|
+
with patch.dict(os.environ, {"EZMSG_PROFILE": "test_profiler.log", "EZMSG_LOGLEVEL": "DEBUG"}):
|
|
39
|
+
yield
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@pytest.fixture
|
|
43
|
+
def mock_logger_path(mock_env):
|
|
44
|
+
"""Fixture to mock the logger path."""
|
|
45
|
+
logpath = get_logger_path()
|
|
46
|
+
yield logpath
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def test_logger_not_append(mock_logger_path):
|
|
50
|
+
"""Test that the logger creates a new file if append==False."""
|
|
51
|
+
some_text = "Some,Previous,Logger,Text"
|
|
52
|
+
correct_header = HEADER
|
|
53
|
+
|
|
54
|
+
# Create a file with some text
|
|
55
|
+
test_logpath = mock_logger_path
|
|
56
|
+
with open(test_logpath, "w") as f:
|
|
57
|
+
f.truncate(0)
|
|
58
|
+
f.write(some_text + "\n")
|
|
59
|
+
|
|
60
|
+
logger = _setup_logger(append=False)
|
|
61
|
+
assert mock_logger_path.exists() and mock_logger_path.is_file()
|
|
62
|
+
assert logger.name == "ezprofile"
|
|
63
|
+
assert logger.level == logging.DEBUG
|
|
64
|
+
assert len(logger.handlers) == 1
|
|
65
|
+
handler = logger.handlers[0]
|
|
66
|
+
assert isinstance(handler, logging.FileHandler)
|
|
67
|
+
assert handler.level == logging.DEBUG
|
|
68
|
+
assert Path(handler.baseFilename) == test_logpath
|
|
69
|
+
|
|
70
|
+
with open(mock_logger_path, "r") as f:
|
|
71
|
+
first_line = f.readline().strip()
|
|
72
|
+
assert first_line == correct_header
|
|
73
|
+
|
|
74
|
+
# Clean up the logger file handler
|
|
75
|
+
logger.removeHandler(handler)
|
|
76
|
+
handler.close()
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def test_logger_append_header_mismatch(mock_logger_path):
|
|
80
|
+
"""Test that the logger deletes the file if the header mismatches when append=True."""
|
|
81
|
+
incorrect_header = "Incorrect,Header,Format"
|
|
82
|
+
correct_header = HEADER
|
|
83
|
+
|
|
84
|
+
# Create a file with an incorrect header
|
|
85
|
+
test_logpath = mock_logger_path
|
|
86
|
+
with open(test_logpath, "w") as f:
|
|
87
|
+
f.truncate(0)
|
|
88
|
+
f.write(incorrect_header + "\n")
|
|
89
|
+
|
|
90
|
+
logger = _setup_logger(append=True)
|
|
91
|
+
|
|
92
|
+
# Assert that the file was deleted and recreated
|
|
93
|
+
assert test_logpath.exists()
|
|
94
|
+
with open(test_logpath, "r") as f:
|
|
95
|
+
first_line = f.readline().strip()
|
|
96
|
+
assert first_line == correct_header
|
|
97
|
+
|
|
98
|
+
# Clean up the logger handlers
|
|
99
|
+
handlers = logger.handlers
|
|
100
|
+
for handler in handlers:
|
|
101
|
+
logger.removeHandler(handler)
|
|
102
|
+
handler.close()
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def test_logger_append_header_match(mock_logger_path):
|
|
106
|
+
"""Test that the logger correctly appends to the logfile if append=True and the header is correct."""
|
|
107
|
+
correct_header = HEADER
|
|
108
|
+
next_line = "Some,New,Logger,Text"
|
|
109
|
+
|
|
110
|
+
# Create a file with the correct header
|
|
111
|
+
test_logpath = mock_logger_path
|
|
112
|
+
with open(test_logpath, "w") as f:
|
|
113
|
+
f.truncate(0)
|
|
114
|
+
f.write(correct_header + "\n")
|
|
115
|
+
f.write(next_line + "\n")
|
|
116
|
+
|
|
117
|
+
logger = _setup_logger(append=True)
|
|
118
|
+
logger.debug("Some,Added,Logger,Text")
|
|
119
|
+
|
|
120
|
+
# Assert that the file was appended to
|
|
121
|
+
assert test_logpath.exists()
|
|
122
|
+
with open(test_logpath, "r") as f:
|
|
123
|
+
first_line = f.readline().strip()
|
|
124
|
+
second_line = f.readline().strip()
|
|
125
|
+
third_line = f.readline().strip()
|
|
126
|
+
assert first_line == correct_header
|
|
127
|
+
assert second_line == next_line
|
|
128
|
+
assert "Some,Added,Logger,Text" in third_line
|
|
129
|
+
|
|
130
|
+
# Clean up the logger handlers
|
|
131
|
+
handlers = logger.handlers
|
|
132
|
+
for handler in handlers:
|
|
133
|
+
if isinstance(handler, logging.FileHandler):
|
|
134
|
+
logger.removeHandler(handler)
|
|
135
|
+
handler.close()
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def test_profile_method_decorator():
|
|
139
|
+
"""Test the profile_method decorator."""
|
|
140
|
+
|
|
141
|
+
class DummyClass:
|
|
142
|
+
address = "dummy_address"
|
|
143
|
+
|
|
144
|
+
@profile_method(trace_oldest=True)
|
|
145
|
+
def sample_method(self, x, y):
|
|
146
|
+
return x + y
|
|
147
|
+
|
|
148
|
+
instance = DummyClass()
|
|
149
|
+
|
|
150
|
+
with patch("ezmsg.baseproc.util.profile.logger") as mock_logger:
|
|
151
|
+
result = instance.sample_method(2, 3)
|
|
152
|
+
assert result == 5
|
|
153
|
+
|
|
154
|
+
# Assert the logger was called
|
|
155
|
+
mock_logger.debug.assert_called()
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
@pytest.mark.asyncio
|
|
159
|
+
async def test_profile_subpub_decorator(mock_logger_path):
|
|
160
|
+
"""Test the profile_subpub decorator."""
|
|
161
|
+
test_logpath = mock_logger_path
|
|
162
|
+
_setup_logger()
|
|
163
|
+
|
|
164
|
+
class DummyUnit:
|
|
165
|
+
address = "dummy_address"
|
|
166
|
+
|
|
167
|
+
@profile_subpub(trace_oldest=True)
|
|
168
|
+
async def sample_subpub(self, msg):
|
|
169
|
+
yield "stream", msg
|
|
170
|
+
|
|
171
|
+
unit = DummyUnit()
|
|
172
|
+
|
|
173
|
+
async for stream, obj in unit.sample_subpub("message"):
|
|
174
|
+
# Assert the generator yields correctly
|
|
175
|
+
assert stream == "stream"
|
|
176
|
+
assert obj == "message"
|
|
177
|
+
|
|
178
|
+
# Assert the logger was called and printed in the correct format
|
|
179
|
+
with open(test_logpath, "r") as f:
|
|
180
|
+
f.readline()
|
|
181
|
+
second_line = f.readline().strip()
|
|
182
|
+
log_text = second_line.split(",")
|
|
183
|
+
assert len(log_text) == 6
|
|
184
|
+
datetime.strptime(log_text[0], "%Y-%m-%dT%H:%M:%S%z") # Will throw if format is incorrect
|
|
185
|
+
assert log_text[1].endswith("test_profile.DummyUnit")
|
|
186
|
+
assert log_text[2] == "dummy_address"
|
|
187
|
+
assert log_text[3] == "None"
|
|
188
|
+
float(log_text[4]) # Will throw if not float
|
|
189
|
+
float(log_text[5]) # Will throw if not float
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/docs/source/guides/how-tos/processors/adaptive.rst
RENAMED
|
File without changes
|
{ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/docs/source/guides/how-tos/processors/checkpoint.rst
RENAMED
|
File without changes
|
{ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/docs/source/guides/how-tos/processors/composite.rst
RENAMED
|
File without changes
|
|
File without changes
|
{ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/docs/source/guides/how-tos/processors/processor.rst
RENAMED
|
File without changes
|
{ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/docs/source/guides/how-tos/processors/standalone.rst
RENAMED
|
File without changes
|
{ezmsg_baseproc-1.0 → ezmsg_baseproc-1.0.2}/docs/source/guides/how-tos/processors/stateful.rst
RENAMED
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|