dcmspec 0.2.1__tar.gz → 0.2.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.
Files changed (48) hide show
  1. dcmspec-0.2.2/CHANGELOG.md +44 -0
  2. {dcmspec-0.2.1 → dcmspec-0.2.2}/PKG-INFO +5 -2
  3. {dcmspec-0.2.1 → dcmspec-0.2.2}/README.md +4 -1
  4. {dcmspec-0.2.1 → dcmspec-0.2.2}/pyproject.toml +12 -18
  5. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/apps/ui/iod_explorer/iod_explorer.py +40 -40
  6. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/dom_table_spec_parser.py +3 -3
  7. dcmspec-0.2.1/CHANGELOG.md +0 -29
  8. {dcmspec-0.2.1 → dcmspec-0.2.2}/LICENSE +0 -0
  9. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/.DS_Store +0 -0
  10. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/__init__.py +0 -0
  11. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/apps/.DS_Store +0 -0
  12. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/apps/__init__.py +0 -0
  13. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/apps/cli/__init__.py +0 -0
  14. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/apps/cli/dataelements.py +0 -0
  15. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/apps/cli/iodattributes.py +0 -0
  16. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/apps/cli/iodmodules.py +0 -0
  17. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/apps/cli/modattributes.py +0 -0
  18. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/apps/cli/tdwiicontent.py +0 -0
  19. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/apps/cli/uidvalues.py +0 -0
  20. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/apps/cli/upsdimseattributes.py +0 -0
  21. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/apps/cli/upsioddimseattributes.py +0 -0
  22. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/apps/ui/iod_explorer/README.md +0 -0
  23. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/apps/ui/iod_explorer/__init__.py +0 -0
  24. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/apps/ui/iod_explorer/config/README.md +0 -0
  25. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/apps/ui/iod_explorer/config/iod_explorer_config.json +0 -0
  26. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/apps/ui/iod_explorer/config/iod_explorer_config_debug.json +0 -0
  27. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/apps/ui/iod_explorer/config/iod_explorer_config_example.json +0 -0
  28. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/apps/ui/iod_explorer/config/iod_explorer_config_minimal_logging.json +0 -0
  29. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/config.py +0 -0
  30. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/csv_table_spec_parser.py +0 -0
  31. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/doc_handler.py +0 -0
  32. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/dom_utils.py +0 -0
  33. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/iod_spec_builder.py +0 -0
  34. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/iod_spec_printer.py +0 -0
  35. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/json_spec_store.py +0 -0
  36. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/module_registry.py +0 -0
  37. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/pdf_doc_handler.py +0 -0
  38. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/progress.py +0 -0
  39. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/service_attribute_defaults.py +0 -0
  40. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/service_attribute_model.py +0 -0
  41. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/spec_factory.py +0 -0
  42. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/spec_merger.py +0 -0
  43. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/spec_model.py +0 -0
  44. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/spec_parser.py +0 -0
  45. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/spec_printer.py +0 -0
  46. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/spec_store.py +0 -0
  47. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/ups_xhtml_doc_handler.py +0 -0
  48. {dcmspec-0.2.1 → dcmspec-0.2.2}/src/dcmspec/xhtml_doc_handler.py +0 -0
@@ -0,0 +1,44 @@
1
+ # Release Notes
2
+
3
+ These release notes summarize key changes, improvements, and breaking updates for each version of **dcmspec**.
4
+
5
+ ## [0.2.2] - 2025-09-25
6
+
7
+ ### Fixed
8
+
9
+ - Fix CONTRIBUTING.md link in README for PyPI compatibility
10
+ - Remove focus border and misleading text cursor in iod-explorer details panel
11
+
12
+ ### Changed
13
+
14
+ - Update README: add PyPI and Python version badges
15
+ - Replace Unicode ▶ with ASCII > in status bar for compatibility
16
+ - Improve DICOM Modules usage condition parsing using regex for robustness to missing spaces
17
+ - Add PR template to remind contributors to check the target branch and check tests and docs were updated
18
+ - Move detailed table parsing logs to DEBUG level for less verbose INFO output
19
+
20
+ ## [0.2.1] - 2025-09-19
21
+
22
+ ### Fixed
23
+
24
+ - Sanitize node and attribute names to remove "/" in DOMTableSpecParser ([#56](https://github.com/dwikler/dcmspec/issues/56))
25
+
26
+ ### Changed
27
+
28
+ - Major project restructure: move CLI and UI apps to new `apps/cli` and `apps/ui` folders
29
+ - Improve installation instructions and documentation
30
+ - Prepare and publish the package to [PyPI](https://pypi.org/project/dcmspec/)
31
+
32
+ ## [0.2.0] - 2025-09-13
33
+
34
+ ### Changed
35
+
36
+ - **Breaking change:** `IODSpecBuilder.build_from_url` now returns a tuple `(iod_model, module_models)` instead of just the IOD model. All callers must be updated to unpack the tuple
37
+ - Update CLI and UI applications to support new return value
38
+ - Add registry mode to `IODSpecBuilder` for efficient module model sharing
39
+
40
+ ## [0.1.0] - 2025-05-25
41
+
42
+ ### Added
43
+
44
+ - Initial release
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dcmspec
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Summary: Toolkit for extracting, parsing, and processing DICOM specifications.
5
5
  License: Apache-2.0
6
6
  License-File: LICENSE
@@ -43,6 +43,9 @@ Project-URL: Source, https://github.com/dwikler/dcmspec
43
43
  Description-Content-Type: text/markdown
44
44
 
45
45
  [![tests](https://github.com/dwikler/dcmspec/actions/workflows/test.yml/badge.svg)](https://github.com/dwikler/dcmspec/actions/workflows/test.yml)
46
+ [![PyPI version](https://badge.fury.io/py/dcmspec.svg)](https://badge.fury.io/py/dcmspec)
47
+ [![Python versions](https://img.shields.io/pypi/pyversions/dcmspec.svg)](https://pypi.org/project/dcmspec/)
48
+ [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.17206999.svg)](https://doi.org/10.5281/zenodo.17206999)
46
49
 
47
50
  # dcmspec
48
51
 
@@ -112,7 +115,7 @@ See [Configuration & Caching](https://dwikler.github.io/dcmspec/configuration/)
112
115
 
113
116
  ## Contributing
114
117
 
115
- See [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines and instructions on how to contribute to the project.
118
+ See [CONTRIBUTING.md](https://github.com/dwikler/dcmspec/blob/main/CONTRIBUTING.md) for guidelines and instructions on how to contribute to the project.
116
119
 
117
120
  ## Similar Projects
118
121
 
@@ -1,4 +1,7 @@
1
1
  [![tests](https://github.com/dwikler/dcmspec/actions/workflows/test.yml/badge.svg)](https://github.com/dwikler/dcmspec/actions/workflows/test.yml)
2
+ [![PyPI version](https://badge.fury.io/py/dcmspec.svg)](https://badge.fury.io/py/dcmspec)
3
+ [![Python versions](https://img.shields.io/pypi/pyversions/dcmspec.svg)](https://pypi.org/project/dcmspec/)
4
+ [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.17206999.svg)](https://doi.org/10.5281/zenodo.17206999)
2
5
 
3
6
  # dcmspec
4
7
 
@@ -68,7 +71,7 @@ See [Configuration & Caching](https://dwikler.github.io/dcmspec/configuration/)
68
71
 
69
72
  ## Contributing
70
73
 
71
- See [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines and instructions on how to contribute to the project.
74
+ See [CONTRIBUTING.md](https://github.com/dwikler/dcmspec/blob/main/CONTRIBUTING.md) for guidelines and instructions on how to contribute to the project.
72
75
 
73
76
  ## Similar Projects
74
77
 
@@ -1,11 +1,9 @@
1
1
  [project]
2
2
  name = "dcmspec"
3
- version = "0.2.1"
3
+ version = "0.2.2"
4
4
  description = "Toolkit for extracting, parsing, and processing DICOM specifications."
5
- authors = [
6
- {name = "David Wikler",email = "david.wikler@ulb.be"}
7
- ]
8
- license = {text = "Apache-2.0"}
5
+ authors = [{ name = "David Wikler", email = "david.wikler@ulb.be" }]
6
+ license = { text = "Apache-2.0" }
9
7
  readme = "README.md"
10
8
  requires-python = ">=3.10,<4.0"
11
9
  keywords = ["DICOM", "python"]
@@ -51,23 +49,15 @@ pdf = [
51
49
  gui = ["tkhtmlview (>=0.3.1,<0.4.0)"]
52
50
 
53
51
  [tool.poetry]
54
- packages = [{include = "dcmspec", from = "src"}]
55
- include = [
56
- "README.md",
57
- "LICENSE",
58
- "CHANGELOG.md",
59
- "src/dcmspec/*"
60
- ]
61
- exclude = [
62
- "src/dcmspec/tests/*",
63
- "src/dcmspec/.DS_Store",
64
- ]
52
+ packages = [{ include = "dcmspec", from = "src" }]
53
+ include = ["README.md", "LICENSE", "CHANGELOG.md", "src/dcmspec/*"]
54
+ exclude = ["src/dcmspec/tests/*", "src/dcmspec/.DS_Store"]
65
55
 
66
56
  [tool.poetry.group.dev.dependencies]
67
57
  pytest = "^8.3.5"
68
58
  pytest-cov = "^6.1.1"
69
59
  mkdocs = "^1.6.1"
70
- mkdocstrings = {extras = ["python"], version = "^0.29.1"}
60
+ mkdocstrings = { extras = ["python"], version = "^0.29.1" }
71
61
  mkdocs-material = "^9.6.14"
72
62
 
73
63
  [build-system]
@@ -87,4 +77,8 @@ iod-explorer = "dcmspec.apps.ui.iod_explorer.iod_explorer:main"
87
77
 
88
78
  [tool.ruff]
89
79
  line-length = 120
90
- select = ["E", "F", "D"] # E includes line-too-long (E501), D includes docstrings checks
80
+ select = [
81
+ "E",
82
+ "F",
83
+ "D",
84
+ ] # E includes line-too-long (E501), D includes docstrings checks
@@ -28,36 +28,6 @@ PART3_TOC_URL = "https://dicom.nema.org/medical/dicom/current/output/chtml/part0
28
28
  # Canonical DICOM Part 3 HTML URL
29
29
  PART3_HTML_URL = "https://dicom.nema.org/medical/dicom/current/output/html/part03.html"
30
30
 
31
-
32
- class StatusManager:
33
- """Handles status bar messaging with consistent logic."""
34
-
35
- def __init__(self, status_var):
36
- """Initialize the StatusManager.
37
-
38
- Args:
39
- status_var: A tkinter StringVar or similar object used to update the status bar text.
40
-
41
- """
42
- self.status_var = status_var
43
-
44
- def show_count_status(self, count: int):
45
- """Show count-based status when no selection."""
46
- message = f"Showing {count} IODs"
47
- self.status_var.set(message)
48
-
49
- def show_selection_status(self, title: str, iod_type: str, is_iod: bool = True):
50
- """Show selection-based status when item selected."""
51
- if is_iod:
52
- self.status_var.set(f"{title} {iod_type} • Click ▶ to expand")
53
- else:
54
- self.status_var.set(f"{iod_type}: {title}")
55
-
56
- def show_loading_status(self, message: str):
57
- """Show loading status."""
58
- self.status_var.set(message)
59
-
60
-
61
31
  def load_app_config() -> Config:
62
32
  """Load app-specific configuration with priority search order.
63
33
 
@@ -78,8 +48,6 @@ def load_app_config() -> Config:
78
48
  Config: Configuration object with app-specific settings.
79
49
 
80
50
  """
81
- import os
82
-
83
51
  # Look for app-specific config file in several locations (highest priority)
84
52
  app_config_locations = [
85
53
  "iod_explorer_config.json", # Current directory
@@ -142,6 +110,34 @@ def setup_logger(config: Config) -> logging.Logger:
142
110
 
143
111
  return logger
144
112
 
113
+ class StatusManager:
114
+ """Handles status bar messaging with consistent logic."""
115
+
116
+ def __init__(self, status_var):
117
+ """Initialize the StatusManager.
118
+
119
+ Args:
120
+ status_var: A tkinter StringVar or similar object used to update the status bar text.
121
+
122
+ """
123
+ self.status_var = status_var
124
+
125
+ def show_count_status(self, count: int):
126
+ """Show count-based status when no selection."""
127
+ message = f"Showing {count} IODs"
128
+ self.status_var.set(message)
129
+
130
+ def show_selection_status(self, title: str, iod_type: str, is_iod: bool = True):
131
+ """Show selection-based status when item selected."""
132
+ if is_iod:
133
+ self.status_var.set(f"{title} {iod_type} • Click > to expand")
134
+ else:
135
+ self.status_var.set(f"{iod_type}: {title}")
136
+
137
+ def show_loading_status(self, message: str):
138
+ """Show loading status."""
139
+ self.status_var.set(message)
140
+
145
141
 
146
142
  class IODExplorer:
147
143
  """Main window for the IOD Explorer application."""
@@ -207,7 +203,7 @@ class IODExplorer:
207
203
  y = (screen_height - window_height) // 2
208
204
  self.root.geometry(f"{window_width}x{window_height}+{x}+{y}")
209
205
 
210
- def setup_ui(self):
206
+ def setup_ui(self):
211
207
  """Set up the user interface."""
212
208
  # Create main frame
213
209
  main_frame = ttk.Frame(self.root)
@@ -248,7 +244,7 @@ class IODExplorer:
248
244
  details_label_header.pack(side=tk.LEFT)
249
245
 
250
246
  # Left frame for treeview
251
- left_frame = ttk.Frame(left_panel)
247
+ left_frame = ttk.Frame(left_panel) # sourcery skip: extract-duplicate-method
252
248
  left_frame.pack(fill=tk.BOTH, expand=True)
253
249
 
254
250
  # Configure grid for treeview area
@@ -329,11 +325,14 @@ class IODExplorer:
329
325
  f'</div>'
330
326
  ),
331
327
  width=50,
332
- height=30
333
- )
328
+ height=30,
329
+ highlightthickness=0,
330
+ )
331
+
334
332
  self.details_text.grid(row=0, column=0, sticky="nsew")
335
333
  self.details_font_family = selected_font # Store for later use
336
334
  self.details_font_size = 10
335
+ self.details_text.config(cursor="arrow")
337
336
 
338
337
  # Add scrollbars that match the treeview style
339
338
  details_scroll_y = ttk.Scrollbar(right_frame, orient=tk.VERTICAL, command=self.details_text.yview)
@@ -710,11 +709,12 @@ class IODExplorer:
710
709
  elif usage.startswith("U"):
711
710
  return "User Optional (U)"
712
711
  elif usage.startswith("C"):
713
- if len(usage) > 1 and " - " in usage:
714
- conditional_part = usage[usage.find(" - ") + 3:]
715
- return f"Conditional (C) - {conditional_part}"
712
+ match = re.match(r"^C\s*-?\s*(.*)$", usage)
713
+ condition = match[1].strip() if match and match[1] else ""
714
+ if condition:
715
+ return f"Conditional (C) - {condition}"
716
716
  else:
717
- return "Conditional (C)"
717
+ return "Conditional (C) - Condition not found"
718
718
  else:
719
719
  return usage
720
720
 
@@ -161,7 +161,7 @@ class DOMTableSpecParser(SpecParser):
161
161
  root: The root node of the tree representation of the specification table.
162
162
 
163
163
  """
164
- self.logger.info(f"Nesting Level: {table_nesting_level}, Parsing table with id {table_id}")
164
+ self.logger.debug(f"Nesting Level: {table_nesting_level}, Parsing table with id {table_id}")
165
165
 
166
166
  if unformatted_list is None:
167
167
  num_columns = max(column_to_attr.keys()) + 1
@@ -208,7 +208,7 @@ class DOMTableSpecParser(SpecParser):
208
208
  progress_observer=progress_observer if table_nesting_level == 0 else None,
209
209
  )
210
210
 
211
- self.logger.info(f"Nesting Level: {table_nesting_level}, Table parsed successfully")
211
+ self.logger.debug(f"Nesting Level: {table_nesting_level}, Table parsed successfully")
212
212
 
213
213
  return root
214
214
 
@@ -777,7 +777,7 @@ class DOMTableSpecParser(SpecParser):
777
777
  for col_idx in column_to_attr
778
778
  if col_idx < len(cells)
779
779
  )
780
- self.logger.info(f"Extracted Header: {header}")
780
+ self.logger.debug(f"Extracted Header: {header}")
781
781
  return header
782
782
 
783
783
  def _clean_extracted_text(self, text: str) -> str:
@@ -1,29 +0,0 @@
1
- # Release Notes
2
-
3
- These release notes summarize key changes, improvements, and breaking updates for each version of **dcmspec**.
4
-
5
- ## [0.2.1] - 2025-09-19
6
-
7
- ### Fixed
8
-
9
- - Sanitize node and attribute names to remove "/" in DOMTableSpecParser ([#56](https://github.com/dwikler/dcmspec/issues/56))
10
-
11
- ### Changed
12
-
13
- - Major project restructure: moved CLI and UI apps to new `apps/cli` and `apps/ui` folders
14
- - Improved installation instructions and documentation
15
- - Prepared and published the package to [PyPI](https://pypi.org/project/dcmspec/)
16
-
17
- ## [0.2.0] - 2025-09-13
18
-
19
- ### Changed
20
-
21
- - **Breaking change:** `IODSpecBuilder.build_from_url` now returns a tuple `(iod_model, module_models)` instead of just the IOD model. All callers must be updated to unpack the tuple.
22
- - Updated CLI and UI applications to support new return value.
23
- - Added registry mode to `IODSpecBuilder` for efficient module model sharing.
24
-
25
- ## [0.1.0] - 2025-05-25
26
-
27
- ### Added
28
-
29
- - Initial release.
File without changes
File without changes
File without changes
File without changes
File without changes