Skip to content

Commit 32588e2

Browse files
committed
Change base class of GoogleCloudHealthcareURL from attr to dataclass.
1 parent 1ea17e5 commit 32588e2

File tree

2 files changed

+42
-20
lines changed

2 files changed

+42
-20
lines changed

src/dicomweb_client/uri.py

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""Utilities for DICOMweb URI manipulation."""
2-
import attr
2+
import dataclasses
33
import enum
44
import re
55
from typing import Optional, Sequence, Tuple
@@ -27,14 +27,22 @@ class URISuffix(enum.Enum):
2727
_REGEX_UID = re.compile(r'[0-9]+([.][0-9]+)*')
2828
_REGEX_PERMISSIVE_UID = re.compile(r'[^/@]+')
2929
# Used for Project ID and Location validation in `GoogleCloudHealthcareURL`.
30-
_REGEX_ID_1 = r'[\w-]+'
31-
_ATTR_VALIDATOR_ID_1 = attr.validators.matches_re(_REGEX_ID_1)
30+
_REGEX_ID_1 = re.compile(r'[\w-]+')
3231
# Used for Dataset ID and DICOM Store ID validation in
3332
# `GoogleCloudHealthcareURL`.
34-
_REGEX_ID_2 = r'[\w.-]+'
35-
_ATTR_VALIDATOR_ID_2 = attr.validators.matches_re(_REGEX_ID_2)
33+
_REGEX_ID_2 = re.compile(r'[\w.-]+')
34+
# Regex for the DICOM Store suffix for the Google Cloud Healthcare API endpoint.
35+
_STORE_REGEX = re.compile(
36+
(r'projects/(%s)/locations/(%s)/datasets/(%s)/'
37+
r'dicomStores/(%s)/dicomWeb$') % (_REGEX_ID_1.pattern,
38+
_REGEX_ID_1.pattern,
39+
_REGEX_ID_2.pattern,
40+
_REGEX_ID_2.pattern))
3641
# The URL for the Google Cloud Healthcare API endpoint.
3742
_CHC_API_URL = 'https://healthcare.googleapis.com/v1'
43+
# Cloud Healthcare validation error.
44+
_CHC_API_ERROR_TMPL = ('`{attribute}` must match regex {regex}. Actual value: '
45+
'{value!r}')
3846

3947

4048
class URI:
@@ -476,7 +484,7 @@ def from_string(cls,
476484
return uri
477485

478486

479-
@attr.s(frozen=True)
487+
@dataclasses.dataclass(eq=True, frozen=True)
480488
class GoogleCloudHealthcareURL:
481489
"""Base URL container for DICOM Stores under the `Google Cloud Healthcare API`_.
482490
@@ -506,10 +514,27 @@ class GoogleCloudHealthcareURL:
506514
The ID of the `DICOM Store
507515
<https://cloud.google.com/healthcare/docs/concepts/dicom#dicom_stores>`_.
508516
"""
509-
project_id = attr.ib(type=str, validator=_ATTR_VALIDATOR_ID_1)
510-
location = attr.ib(type=str, validator=_ATTR_VALIDATOR_ID_1)
511-
dataset_id = attr.ib(type=str, validator=_ATTR_VALIDATOR_ID_2)
512-
dicom_store_id = attr.ib(type=str, validator=_ATTR_VALIDATOR_ID_2)
517+
project_id: str
518+
location: str
519+
dataset_id: str
520+
dicom_store_id: str
521+
522+
def __post_init__(self) -> None:
523+
"""Performs input sanity checks."""
524+
if _REGEX_ID_1.fullmatch(self.project_id) is None:
525+
raise ValueError(_CHC_API_ERROR_TMPL.format(
526+
attribute='project_id', regex=_REGEX_ID_1, value=self.project_id))
527+
if _REGEX_ID_1.fullmatch(self.location) is None:
528+
raise ValueError(_CHC_API_ERROR_TMPL.format(
529+
attribute='location', regex=_REGEX_ID_1, value=self.location))
530+
if _REGEX_ID_2.fullmatch(self.dataset_id) is None:
531+
raise ValueError(_CHC_API_ERROR_TMPL.format(
532+
attribute='dataset_id', regex=_REGEX_ID_2, value=self.dataset_id))
533+
if _REGEX_ID_2.fullmatch(self.dicom_store_id) is None:
534+
raise ValueError(_CHC_API_ERROR_TMPL.format(
535+
attribute='dicom_store_id',
536+
regex=_REGEX_ID_2,
537+
value=self.dicom_store_id))
513538

514539
def __str__(self) -> str:
515540
"""Returns a string URL for use as :py:attr:`URI.base_url`.
@@ -544,10 +569,7 @@ def from_string(cls, base_url: str) -> 'GoogleCloudHealthcareURL':
544569
raise ValueError('Invalid CHC API v1 URL: {base_url!r}')
545570
resource_suffix = base_url[len(_CHC_API_URL) + 1:]
546571

547-
store_regex = (r'projects/(%s)/locations/(%s)/datasets/(%s)/'
548-
r'dicomStores/(%s)/dicomWeb$') % (
549-
_REGEX_ID_1, _REGEX_ID_1, _REGEX_ID_2, _REGEX_ID_2)
550-
store_match = re.match(store_regex, resource_suffix)
572+
store_match = _STORE_REGEX.match(resource_suffix)
551573
if store_match is None:
552574
raise ValueError(
553575
'Invalid CHC API v1 DICOM Store name: {resource_suffix!r}')

tests/test_uri.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -499,21 +499,21 @@ def test_chc_dicom_store_str():
499499
@pytest.mark.parametrize('name', ['hmmm.1', '#95', '43/'])
500500
def test_chc_invalid_project_or_location(name):
501501
"""Tests for bad `project_id`, `location`."""
502-
with pytest.raises(ValueError):
502+
with pytest.raises(ValueError, match='project_id'):
503503
GoogleCloudHealthcareURL(name, _LOCATION, _DATASET_ID, _DICOM_STORE_ID)
504-
with pytest.raises(ValueError):
504+
with pytest.raises(ValueError, match='location'):
505505
GoogleCloudHealthcareURL(
506506
_PROJECT_ID, name, _DATASET_ID, _DICOM_STORE_ID)
507507

508508

509509
@pytest.mark.parametrize('name', ['hmmm.!', '#95', '43/'])
510510
def test_chc_invalid_dataset_or_store(name):
511511
"""Tests for bad `dataset_id`, `dicom_store_id`."""
512-
with pytest.raises(ValueError):
513-
GoogleCloudHealthcareURL(name, _LOCATION, _DATASET_ID, _DICOM_STORE_ID)
514-
with pytest.raises(ValueError):
512+
with pytest.raises(ValueError, match='dataset_id'):
513+
GoogleCloudHealthcareURL(_PROJECT_ID, _LOCATION, name, _DICOM_STORE_ID)
514+
with pytest.raises(ValueError, match='dicom_store_id'):
515515
GoogleCloudHealthcareURL(
516-
_PROJECT_ID, name, _DATASET_ID, _DICOM_STORE_ID)
516+
_PROJECT_ID, _LOCATION, _DATASET_ID, name)
517517

518518

519519
@pytest.mark.parametrize('url', [f'{_CHC_API_URL}beta', 'https://some.url'])

0 commit comments

Comments
 (0)