Initial commit
This commit is contained in:
2
dist/dicom2pacs.app/Contents/Resources/lib/python3.13/pydicom/sr/__init__.py
vendored
Executable file
2
dist/dicom2pacs.app/Contents/Resources/lib/python3.13/pydicom/sr/__init__.py
vendored
Executable file
@@ -0,0 +1,2 @@
|
||||
from pydicom.sr.codedict import codes, Collection, Concepts
|
||||
from pydicom.sr.coding import Code
|
||||
BIN
dist/dicom2pacs.app/Contents/Resources/lib/python3.13/pydicom/sr/__pycache__/__init__.cpython-313.pyc
vendored
Executable file
BIN
dist/dicom2pacs.app/Contents/Resources/lib/python3.13/pydicom/sr/__pycache__/__init__.cpython-313.pyc
vendored
Executable file
Binary file not shown.
BIN
dist/dicom2pacs.app/Contents/Resources/lib/python3.13/pydicom/sr/__pycache__/_cid_dict.cpython-313.pyc
vendored
Executable file
BIN
dist/dicom2pacs.app/Contents/Resources/lib/python3.13/pydicom/sr/__pycache__/_cid_dict.cpython-313.pyc
vendored
Executable file
Binary file not shown.
BIN
dist/dicom2pacs.app/Contents/Resources/lib/python3.13/pydicom/sr/__pycache__/_concepts_dict.cpython-313.pyc
vendored
Executable file
BIN
dist/dicom2pacs.app/Contents/Resources/lib/python3.13/pydicom/sr/__pycache__/_concepts_dict.cpython-313.pyc
vendored
Executable file
Binary file not shown.
BIN
dist/dicom2pacs.app/Contents/Resources/lib/python3.13/pydicom/sr/__pycache__/_snomed_dict.cpython-313.pyc
vendored
Executable file
BIN
dist/dicom2pacs.app/Contents/Resources/lib/python3.13/pydicom/sr/__pycache__/_snomed_dict.cpython-313.pyc
vendored
Executable file
Binary file not shown.
BIN
dist/dicom2pacs.app/Contents/Resources/lib/python3.13/pydicom/sr/__pycache__/codedict.cpython-313.pyc
vendored
Executable file
BIN
dist/dicom2pacs.app/Contents/Resources/lib/python3.13/pydicom/sr/__pycache__/codedict.cpython-313.pyc
vendored
Executable file
Binary file not shown.
BIN
dist/dicom2pacs.app/Contents/Resources/lib/python3.13/pydicom/sr/__pycache__/coding.cpython-313.pyc
vendored
Executable file
BIN
dist/dicom2pacs.app/Contents/Resources/lib/python3.13/pydicom/sr/__pycache__/coding.cpython-313.pyc
vendored
Executable file
Binary file not shown.
33092
dist/dicom2pacs.app/Contents/Resources/lib/python3.13/pydicom/sr/_cid_dict.py
vendored
Executable file
33092
dist/dicom2pacs.app/Contents/Resources/lib/python3.13/pydicom/sr/_cid_dict.py
vendored
Executable file
File diff suppressed because it is too large
Load Diff
40960
dist/dicom2pacs.app/Contents/Resources/lib/python3.13/pydicom/sr/_concepts_dict.py
vendored
Executable file
40960
dist/dicom2pacs.app/Contents/Resources/lib/python3.13/pydicom/sr/_concepts_dict.py
vendored
Executable file
File diff suppressed because it is too large
Load Diff
15994
dist/dicom2pacs.app/Contents/Resources/lib/python3.13/pydicom/sr/_snomed_dict.py
vendored
Executable file
15994
dist/dicom2pacs.app/Contents/Resources/lib/python3.13/pydicom/sr/_snomed_dict.py
vendored
Executable file
File diff suppressed because it is too large
Load Diff
348
dist/dicom2pacs.app/Contents/Resources/lib/python3.13/pydicom/sr/codedict.py
vendored
Executable file
348
dist/dicom2pacs.app/Contents/Resources/lib/python3.13/pydicom/sr/codedict.py
vendored
Executable file
@@ -0,0 +1,348 @@
|
||||
# Copyright 2008-2024 pydicom authors. See LICENSE file for details.
|
||||
"""Access code dictionary information"""
|
||||
|
||||
from itertools import chain
|
||||
import inspect
|
||||
from typing import cast, Any
|
||||
from collections.abc import KeysView, Iterable
|
||||
|
||||
from pydicom.sr.coding import Code
|
||||
from pydicom.sr._concepts_dict import concepts as CONCEPTS
|
||||
from pydicom.sr._cid_dict import name_for_cid, cid_concepts as CID_CONCEPTS
|
||||
|
||||
|
||||
# Reverse lookup for cid names
|
||||
cid_for_name = {v: k for k, v in name_for_cid.items()}
|
||||
|
||||
|
||||
def _filtered(source: Iterable[str], filters: Iterable[str]) -> list[str]:
|
||||
"""Return a sorted list of filtered str.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
source : Iterable[str]
|
||||
The iterable of str to be filtered.
|
||||
filters : Iterable[str]
|
||||
An iterable containing patterns for which values are to be included
|
||||
in the results.
|
||||
|
||||
Returns
|
||||
-------
|
||||
List[str]
|
||||
A sorted list of unique values from `source`, filtered by including
|
||||
case-insensitive partial or full matches against the values
|
||||
in `filters`.
|
||||
"""
|
||||
if not filters:
|
||||
return sorted(set(source))
|
||||
|
||||
filters = [f.lower() for f in filters]
|
||||
|
||||
return sorted(
|
||||
set(val for val in source if any((f in val.lower()) for f in filters))
|
||||
)
|
||||
|
||||
|
||||
CIDValueType = dict[str, tuple[str, list[int]]]
|
||||
ConceptsType = dict[str, CIDValueType]
|
||||
SnomedMappingType = dict[str, dict[str, str]]
|
||||
|
||||
|
||||
class Collection:
|
||||
"""Interface for a collection of concepts, such as SNOMED-CT, or a DICOM CID.
|
||||
|
||||
.. versionadded:: 3.0
|
||||
"""
|
||||
|
||||
repr_format = "{} = {}"
|
||||
|
||||
def __init__(self, name: str) -> None:
|
||||
"""Create a new collection.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : str
|
||||
The name of the collection, should either be a key in the
|
||||
``sr._concepts_dict.concepts`` :class:`dict` or a CID name for
|
||||
a CID in ``sr._cid_dict.cid_concepts`` such as ``"CID1234"``.
|
||||
"""
|
||||
if not name.upper().startswith("CID"):
|
||||
self._name = name
|
||||
# dict[str, dict[str, tuple(str, list[int])]]
|
||||
# {'ACEInhibitor': {'41549009': ('ACE inhibitor', [3760])},
|
||||
self._scheme_data = CONCEPTS[name]
|
||||
else:
|
||||
self._name = f"CID{name[3:]}"
|
||||
# dict[str, list[str]]
|
||||
# {'SCT': ['Pericardium', 'Pleura', 'LeftPleura', 'RightPleura']}
|
||||
self._cid_data = CID_CONCEPTS[int(name[3:])]
|
||||
|
||||
self._concepts: dict[str, Code] = {}
|
||||
|
||||
@property
|
||||
def concepts(self) -> dict[str, Code]:
|
||||
"""Return a :class:`dict` of {SR identifiers: codes}"""
|
||||
if not self._concepts:
|
||||
self._concepts = {name: getattr(self, name) for name in self.dir()}
|
||||
|
||||
return self._concepts
|
||||
|
||||
def __contains__(self, item: str | Code) -> bool:
|
||||
"""Checks whether a given code is a member of the collection.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
item : pydicom.sr.coding.Code | str
|
||||
The code to check for as either the code or the corresponding
|
||||
keyword.
|
||||
|
||||
Returns
|
||||
-------
|
||||
bool
|
||||
Whether the collection contains the `code`
|
||||
"""
|
||||
if isinstance(item, str):
|
||||
try:
|
||||
code = getattr(self, item)
|
||||
except AttributeError:
|
||||
return False
|
||||
else:
|
||||
code = item
|
||||
|
||||
return code in self.concepts.values()
|
||||
|
||||
def __dir__(self) -> list[str]:
|
||||
"""Return a list of available concept keywords.
|
||||
|
||||
List of attributes is used, for example, in auto-completion in editors
|
||||
or command-line environments.
|
||||
"""
|
||||
meths = {v[0] for v in inspect.getmembers(type(self), inspect.isroutine)}
|
||||
props = {v[0] for v in inspect.getmembers(type(self), inspect.isdatadescriptor)}
|
||||
sr_names = set(self.dir())
|
||||
|
||||
return sorted(props | meths | sr_names)
|
||||
|
||||
def dir(self, *filters: str) -> list[str]:
|
||||
"""Return an sorted list of concept keywords based on a partial match.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
filters : str
|
||||
Zero or more string arguments to the function. Used for
|
||||
case-insensitive match to any part of the SR keyword.
|
||||
|
||||
Returns
|
||||
-------
|
||||
list of str
|
||||
The matching keywords. If no `filters` are used then all
|
||||
keywords are returned.
|
||||
"""
|
||||
# CID_CONCEPTS: Dict[int, Dict[str, List[str]]]
|
||||
if self.is_cid:
|
||||
return _filtered(chain.from_iterable(self._cid_data.values()), filters)
|
||||
|
||||
return _filtered(self._scheme_data, filters)
|
||||
|
||||
def __getattr__(self, name: str) -> Code:
|
||||
"""Return the :class:`~pydicom.sr.Code` corresponding to `name`.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : str
|
||||
A camel case version of the concept's code meaning, such as
|
||||
``"FontanelOfSkull" in the SCT coding scheme.
|
||||
|
||||
Returns
|
||||
-------
|
||||
pydicom.sr.Code
|
||||
The :class:`~pydicom.sr.Code` corresponding to `name`.
|
||||
"""
|
||||
if self.name.startswith("CID"):
|
||||
# Try DICOM's CID collections
|
||||
matches = [
|
||||
scheme
|
||||
for scheme, keywords in self._cid_data.items()
|
||||
if name in keywords
|
||||
]
|
||||
if not matches:
|
||||
raise AttributeError(
|
||||
f"No matching code for keyword '{name}' in {self.name}"
|
||||
)
|
||||
|
||||
if len(matches) > 1:
|
||||
# Shouldn't happen, but just in case
|
||||
raise RuntimeError(
|
||||
f"Multiple schemes found to contain the keyword '{name}' in "
|
||||
f"{self.name}: {', '.join(matches)}"
|
||||
)
|
||||
|
||||
scheme = matches[0]
|
||||
identifiers = cast(CIDValueType, CONCEPTS[scheme][name])
|
||||
|
||||
if len(identifiers) == 1:
|
||||
code, val = list(identifiers.items())[0]
|
||||
else:
|
||||
cid = int(self.name[3:])
|
||||
_matches = [
|
||||
(code, val) for code, val in identifiers.items() if cid in val[1]
|
||||
]
|
||||
if len(_matches) > 1:
|
||||
# Shouldn't happen, but just in case
|
||||
codes = ", ".join(v[0] for v in _matches)
|
||||
raise RuntimeError(
|
||||
f"Multiple codes found for keyword '{name}' in {self.name}: "
|
||||
f"{codes}"
|
||||
)
|
||||
|
||||
code, val = _matches[0]
|
||||
|
||||
return Code(value=code, meaning=val[0], scheme_designator=scheme)
|
||||
|
||||
# Try concept collections such as SCT, DCM, etc
|
||||
try:
|
||||
entries = cast(CIDValueType, self._scheme_data[name])
|
||||
except KeyError:
|
||||
raise AttributeError(
|
||||
f"No matching code for keyword '{name}' in scheme '{self.name}'"
|
||||
)
|
||||
|
||||
if len(entries) > 1:
|
||||
# val is {"code": ("meaning", [cid1, cid2, ...], "code": ...}
|
||||
code_values = ", ".join(entries.keys())
|
||||
raise RuntimeError(
|
||||
f"Multiple codes found for keyword '{name}' in scheme '{self.name}': "
|
||||
f"{code_values}"
|
||||
)
|
||||
|
||||
code = list(entries.keys())[0] # get first and only
|
||||
meaning, cids = entries[code]
|
||||
|
||||
return Code(value=code, meaning=meaning, scheme_designator=self.name)
|
||||
|
||||
@property
|
||||
def is_cid(self) -> bool:
|
||||
"""Return ``True`` if the collection is one of the DICOM CIDs"""
|
||||
return self.name.startswith("CID")
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""Return the name of the collection."""
|
||||
return self._name
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""Return a representation of the collection."""
|
||||
concepts = [
|
||||
self.repr_format.format(name, concept)
|
||||
for name, concept in self.concepts.items()
|
||||
]
|
||||
|
||||
return f"{self.name}\n" + "\n".join(concepts)
|
||||
|
||||
@property
|
||||
def scheme_designator(self) -> str:
|
||||
"""Return the scheme designator for the collection."""
|
||||
return self.name
|
||||
|
||||
def __str__(self) -> str:
|
||||
"""Return a string representation of the collection."""
|
||||
len_names = max(len(n) for n in self.concepts.keys()) + 2
|
||||
len_codes = max(len(c[0]) for c in self.concepts.values()) + 2
|
||||
len_schemes = max(len(c[1]) for c in self.concepts.values()) + 2
|
||||
|
||||
# Ensure each column is at least X characters wide
|
||||
len_names = max(len_names, 11)
|
||||
len_codes = max(len_codes, 6)
|
||||
len_schemes = max(len_schemes, 8)
|
||||
|
||||
if self.is_cid:
|
||||
fmt = f"{{:{len_names}}} {{:{len_codes}}} {{:{len_schemes}}} {{}}"
|
||||
|
||||
s = [self.name]
|
||||
s.append(fmt.format("Attribute", "Code", "Scheme", "Meaning"))
|
||||
s.append(fmt.format("---------", "----", "------", "-------"))
|
||||
s.append(
|
||||
"\n".join(
|
||||
fmt.format(name, *concept)
|
||||
for name, concept in self.concepts.items()
|
||||
)
|
||||
)
|
||||
else:
|
||||
fmt = f"{{:{len_names}}} {{:{len_codes}}} {{}}"
|
||||
|
||||
s = [f"Scheme: {self.name}"]
|
||||
s.append(fmt.format("Attribute", "Code", "Meaning"))
|
||||
s.append(fmt.format("---------", "----", "-------"))
|
||||
|
||||
s.append(
|
||||
"\n".join(
|
||||
fmt.format(name, concept[0], concept[2])
|
||||
for name, concept in self.concepts.items()
|
||||
)
|
||||
)
|
||||
|
||||
return "\n".join(s)
|
||||
|
||||
def trait_names(self) -> list[str]:
|
||||
"""Return a list of valid names for auto-completion code.
|
||||
|
||||
Used in IPython, so that data element names can be found and offered
|
||||
for autocompletion on the IPython command line.
|
||||
"""
|
||||
return dir(self)
|
||||
|
||||
|
||||
class Concepts:
|
||||
"""Management class for the available concept collections.
|
||||
|
||||
.. versionadded:: 3.0
|
||||
"""
|
||||
|
||||
def __init__(self, collections: list[Collection]) -> None:
|
||||
"""Create a new concepts management class instance.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
collections : list[Collection]
|
||||
A list of the available concept collections.
|
||||
"""
|
||||
self._collections = {c.name: c for c in collections}
|
||||
|
||||
@property
|
||||
def collections(self) -> KeysView[str]:
|
||||
"""Return the names of the available concept collections."""
|
||||
return self._collections.keys()
|
||||
|
||||
def __getattr__(self, name: str) -> Any:
|
||||
"""Return the concept collection corresponding to `name`.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : str
|
||||
The scheme designator or CID name for the collection to be returned.
|
||||
"""
|
||||
if name.upper().startswith("CID"):
|
||||
name = f"CID{name[3:]}"
|
||||
|
||||
if name in self._collections:
|
||||
return self._collections[name]
|
||||
|
||||
raise AttributeError(
|
||||
f"'{type(self).__name__}' object has no attribute '{name}'"
|
||||
)
|
||||
|
||||
def schemes(self) -> list[str]:
|
||||
"""Return a list of available scheme designations."""
|
||||
return [c for c in self._collections.keys() if not c.startswith("CID")]
|
||||
|
||||
def CIDs(self) -> list[str]:
|
||||
"""Return a list of available CID names."""
|
||||
return [c for c in self._collections.keys() if c.startswith("CID")]
|
||||
|
||||
|
||||
# Named concept collections like SNOMED-CT, etc
|
||||
_collections = [Collection(designator) for designator in CONCEPTS]
|
||||
# DICOM CIDs
|
||||
_collections.extend(Collection(f"CID{cid}") for cid in name_for_cid)
|
||||
|
||||
codes = Concepts(_collections)
|
||||
65
dist/dicom2pacs.app/Contents/Resources/lib/python3.13/pydicom/sr/coding.py
vendored
Executable file
65
dist/dicom2pacs.app/Contents/Resources/lib/python3.13/pydicom/sr/coding.py
vendored
Executable file
@@ -0,0 +1,65 @@
|
||||
# Copyright 2008-2021 pydicom authors. See LICENSE file for details.
|
||||
|
||||
from typing import NamedTuple, Any
|
||||
|
||||
from pydicom.sr._snomed_dict import mapping as snomed_mapping
|
||||
|
||||
|
||||
class Code(NamedTuple):
|
||||
"""Namedtuple for representation of a coded concept consisting of the
|
||||
actual code *value*, the coding *scheme designator*, the code *meaning*
|
||||
(and optionally the coding *scheme version*).
|
||||
|
||||
..versionadded: 1.4
|
||||
"""
|
||||
|
||||
value: str
|
||||
scheme_designator: str
|
||||
meaning: str
|
||||
scheme_version: str | None = None
|
||||
|
||||
def __hash__(self) -> int:
|
||||
return hash(self.scheme_designator + self.value)
|
||||
|
||||
def __eq__(self, other: Any) -> Any:
|
||||
if self.scheme_designator == "SRT" and self.value in snomed_mapping["SRT"]:
|
||||
self_mapped = Code(
|
||||
value=snomed_mapping["SRT"][self.value],
|
||||
meaning="",
|
||||
scheme_designator="SCT",
|
||||
scheme_version=self.scheme_version,
|
||||
)
|
||||
else:
|
||||
self_mapped = Code(
|
||||
value=self.value,
|
||||
meaning="",
|
||||
scheme_designator=self.scheme_designator,
|
||||
scheme_version=self.scheme_version,
|
||||
)
|
||||
|
||||
if other.scheme_designator == "SRT" and other.value in snomed_mapping["SRT"]:
|
||||
other_mapped = Code(
|
||||
value=snomed_mapping["SRT"][other.value],
|
||||
meaning="",
|
||||
scheme_designator="SCT",
|
||||
scheme_version=other.scheme_version,
|
||||
)
|
||||
else:
|
||||
other_mapped = Code(
|
||||
value=other.value,
|
||||
meaning="",
|
||||
scheme_designator=other.scheme_designator,
|
||||
scheme_version=other.scheme_version,
|
||||
)
|
||||
|
||||
return (
|
||||
self_mapped.value == other_mapped.value
|
||||
and self_mapped.scheme_designator == other_mapped.scheme_designator
|
||||
and self_mapped.scheme_version == other_mapped.scheme_version
|
||||
)
|
||||
|
||||
def __ne__(self, other: Any) -> Any:
|
||||
return not (self == other)
|
||||
|
||||
|
||||
Code.__new__.__defaults__ = (None,)
|
||||
Reference in New Issue
Block a user