Skip to content

Commit

Permalink
Merge pull request #89 from dwikler/fix-comments-PR88
Browse files Browse the repository at this point in the history
Fix comments pr88
  • Loading branch information
sjswerdloff authored Jan 3, 2025
2 parents 7bfc10c + 48fc984 commit bfda7c6
Show file tree
Hide file tree
Showing 12 changed files with 212 additions and 53 deletions.
12 changes: 12 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,15 @@ cython_debug/
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

# Flake8 linting toom configuration file
.flake8

# Personal files and test code snippets
scratchpad/

# Ignore SQLite database files
*.sqlite

# Visual Studio Code settings
.vscode/settings.json
11 changes: 10 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,5 +77,14 @@
"watchscu",
"whatsthis"
],
"python.REPL.enableREPLSmartSend": false
"python.REPL.enableREPLSmartSend": false,
"python.testing.unittestArgs": [
"-v",
"-s",
"./tdwii_plus_examples/tests",
"-p",
"test_*.py",
],
"python.testing.pytestEnabled": false,
"python.testing.unittestEnabled": true
}
12 changes: 8 additions & 4 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ readme = "README.md"
packages = [{include = "tdwii_plus_examples"}]

[tool.poetry.dependencies]
python = ">=3.10, <3.11"
python = ">=3.10, <3.13"
pydicom = "^2.4.0"
pynetdicom = "^2.1.0"
pyside6 = "^6.6.0"
Expand Down
2 changes: 1 addition & 1 deletion tdwii_plus_examples/cstorehandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"BR", "RTBYREC", "RTBRACHYRECORD",
"RT Brachy Treatment Record Storage"),
"1.2.840.10008.5.1.4.1.1.481.7": (
"SR", "SUMREC", "RTSUMRECORD",
"SUM", "SUMREC", "RTSUMRECORD",
"RT Treatment Summary Record Storage"),
"1.2.840.10008.5.1.4.1.1.481.8": (
"RN", "RTIONPLN", "RTIONPLAN",
Expand Down
23 changes: 16 additions & 7 deletions tdwii_plus_examples/cstorescp.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
from argparse import Namespace
import logging

from pydicom.uid import UID, ImplicitVRLittleEndian, AllTransferSyntaxes
from pydicom.uid import (
UID, ImplicitVRLittleEndian, ExplicitVRLittleEndian, AllTransferSyntaxes
)
from pynetdicom import DEFAULT_TRANSFER_SYNTAXES, evt
from pynetdicom.presentation import (
StoragePresentationContexts,
Expand Down Expand Up @@ -87,9 +89,11 @@ def __init__(self,
transfer_syntaxes: list of str/pydicom.uid.UID
A list of transfer syntaxes UIDs or names to support
(names must be valid Transfer Syntax Keywords from PS3.6 Annex A,
invalid UIDs and names will be ignored)
invalid UIDs and names will be ignored).
The order of the transfer syntaxes in the list can be used to set
the preferred syntax to accept when multiple ones are proposed.
Optional, default: None, pynetdicom default transfer syntaxes are
supported
supported with Explicit VR Little Endian as the preferred syntax.
custom_handler: function
A function to handle C-STORE requests
Expand Down Expand Up @@ -217,12 +221,17 @@ def _add_contexts(self):
sop_classes = self._valid_sop_classes
self.logger.debug(f"Supported Storage SOP Classes: {sop_classes}")

if self.transfer_syntaxes is None:
transfer_syntaxes = DEFAULT_TRANSFER_SYNTAXES
if self.transfer_syntaxes is None or not self.transfer_syntaxes:
self.logger.debug("No transfer syntaxes specified, using defaults")
transfer_syntaxes = DEFAULT_TRANSFER_SYNTAXES.copy()
# Make ExplicitVRLittleEndian the preferred transfer syntax
transfer_syntaxes.remove(UID(ExplicitVRLittleEndian))
transfer_syntaxes = [UID(ExplicitVRLittleEndian)] + \
transfer_syntaxes
else:
if ImplicitVRLittleEndian not in self._valid_transfer_syntaxes:
transfer_syntaxes = [ImplicitVRLittleEndian] + \
self._valid_transfer_syntaxes
transfer_syntaxes = self._valid_transfer_syntaxes + [
ImplicitVRLittleEndian]
else:
transfer_syntaxes = self._valid_transfer_syntaxes
self.logger.debug(f"Supported Transfer Syntaxes: {transfer_syntaxes}")
Expand Down
4 changes: 2 additions & 2 deletions tdwii_plus_examples/tests/cli/test_storescp.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def test_main(self, mock_parse_args, MockCStoreSCP):
bind_address='127.0.0.1',
port=12345,
sop_classes=['SecondaryCaptureImageStorage'],
transfer_syntaxes=['ImplicitVRLittleEndian'],
transfer_syntaxes=['ExplicitVRLittleEndian'],
custom_handler='my_handler',
output_directory='/var/tmp/output',
verbose=False,
Expand Down Expand Up @@ -46,7 +46,7 @@ def test_main(self, mock_parse_args, MockCStoreSCP):
port=12345,
logger=logging.getLogger('storescp'),
sop_classes=['SecondaryCaptureImageStorage'],
transfer_syntaxes=['ImplicitVRLittleEndian'],
transfer_syntaxes=['ExplicitVRLittleEndian'],
custom_handler=mock_handler, # Ensure this is the mock function
store_directory='/var/tmp/output'
)
Expand Down
10 changes: 7 additions & 3 deletions tdwii_plus_examples/tests/test_basescp_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import subprocess
import time
import re
import sys
from tdwii_plus_examples.basescp import BaseSCP
from pynetdicom.sop_class import Verification

Expand All @@ -20,10 +21,10 @@ def _add_contexts(self):
class TestBaseSCP(unittest.TestCase):

def setUp(self):
# Set up the logger for the BaseSCP to INFO level
# Set up the logger for the BaseSCP to DEBUG level
# with a memory handler to store up to 100 log messages
self.scp_logger = logging.getLogger('basescp')
self.scp_logger.setLevel(logging.INFO)
self.scp_logger.setLevel(logging.DEBUG)
self.memory_handler = MemoryHandler(100)
self.scp_logger.addHandler(self.memory_handler)

Expand All @@ -43,8 +44,11 @@ def test_run_and_check_log(self):
# Run the SCP
self.scp.run()

# Ensure the correct Python interpreter is used for the subprocess call
python_executable = sys.executable

# Send an echo request using pynetdicom's echoscu.py
subprocess.check_call(['python', '-m', 'pynetdicom', 'echoscu',
subprocess.check_call([python_executable, '-m', 'pynetdicom', 'echoscu',
'localhost', '11112',
'-aet', 'ECHOSCU', '-aec', 'BASE_SCP'])

Expand Down
6 changes: 5 additions & 1 deletion tdwii_plus_examples/tests/test_cechoscp_integration.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import sys
import unittest
import logging
from logging.handlers import MemoryHandler
Expand Down Expand Up @@ -31,8 +32,11 @@ def test_run_and_check_log(self):
# Run the SCP
self.scp.run()

# Ensure the correct Python interpreter is used for the subprocess call
python_executable = sys.executable

# Send an echo request using pynetdicom's echoscu.py
subprocess.check_call(['python', '-m', 'pynetdicom', 'echoscu',
subprocess.check_call([python_executable, '-m', 'pynetdicom', 'echoscu',
'localhost', '11112',
'-aet', 'ECHOSCU', '-aec', 'ECHO_SCP'])

Expand Down
33 changes: 21 additions & 12 deletions tdwii_plus_examples/tests/test_cstorehandler.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import sys
import unittest
import tempfile
import shutil
import os
import logging
from unittest.mock import MagicMock, patch
from parameterized import parameterized
from pydicom.dataset import Dataset, FileMetaDataset
Expand Down Expand Up @@ -34,6 +36,11 @@ class TestHandleCStoreEvent(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.temp_dir = tempfile.mkdtemp()
cls.logger = logging.getLogger("TestHandleCStoreEvent")
handler = logging.StreamHandler()
handler.setLevel(logging.DEBUG)
cls.logger.addHandler(handler)
cls.logger.setLevel(logging.DEBUG)

def setUp(self):
# Create a mock event
Expand Down Expand Up @@ -78,16 +85,16 @@ def test_handle_cstore(self, ignore, output_directory, expected_status,
status_ds = handle_cstore(self.mock_event, mock_args, mock_logger)

# Debugging output
# print(
# "\nTest case parameters:\n ignore = %s"
# "\n output_directory = %s"
# "\n expected_status = 0x%04X" % (
# ignore, mock_args.output_directory, expected_status))
# print(
# "\nTest case results:"
# "\n actual status = 0x%04X"
# "\n logger calls : %s," % (
# status_ds.Status, mock_logger.mock_calls))
self.logger.debug(
"\nTest case parameters:\n ignore = %s"
"\n output_directory = %s"
"\n expected_status = 0x%04X" % (
ignore, mock_args.output_directory, expected_status))
self.logger.debug(
"\nTest case results:"
"\n actual status = 0x%04X"
"\n logger calls : %s," % (
status_ds.Status, mock_logger.mock_calls))

# Check the status
self.assertEqual(status_ds.Status, expected_status)
Expand All @@ -100,8 +107,10 @@ def test_handle_cstore(self, ignore, output_directory, expected_status,
mock_logger.error.assert_called_once_with(
"args.output_directory attribute not present or None")
elif '/invalid/path' in output_directory:
mock_logger.exception.assert_called_once_with(
"Unable to create the output directory: /invalid/path\0")
expected_message = "Unable to create the output directory: /invalid/path\0"
if sys.platform.startswith('win'):
expected_message = expected_message.replace("/invalid/path", "C:/invalid/path")
mock_logger.exception.assert_called_once_with(expected_message)
elif expected_status == 0xC210:
mock_logger.exception.assert_called_once_with(
"Unable to decode the data set and/or the command set")
Expand Down
Loading

0 comments on commit bfda7c6

Please sign in to comment.