From ba9b99c533fbc82786df1baf57d3fbc60f677bd1 Mon Sep 17 00:00:00 2001 From: Danipulok Date: Mon, 17 Nov 2025 21:59:30 +0200 Subject: [PATCH 1/5] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20raise=20`ValueError`?= =?UTF-8?q?=20instead=20of=20`AttributeError`=20on=20wrong=20`S3Path`=20va?= =?UTF-8?q?lue?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pydantic_extra_types/s3.py | 11 ++++++----- tests/test_s3.py | 14 ++++++++++++++ 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/pydantic_extra_types/s3.py b/pydantic_extra_types/s3.py index b58068c..61c1119 100644 --- a/pydantic_extra_types/s3.py +++ b/pydantic_extra_types/s3.py @@ -40,14 +40,15 @@ class TestModel(BaseModel): ``` """ - patt: ClassVar[str] = r'^s3://([^/]+)/(.*?([^/]+)/?)$' + patt: ClassVar[re.Pattern[str]] = re.compile(r'^s3://([^/]+)/(.*?([^/]+)/?)$') def __init__(self, value: str) -> None: self.value = value - groups: tuple[str, str, str] = re.match(self.patt, self.value).groups() # type: ignore - self.bucket: str = groups[0] - self.key: str = groups[1] - self.last_key: str = groups[2] + match = self.patt.match(self.value) + if match is None: + raise ValueError(f'Invalid S3 path: {value!r}') + groups: tuple[str, str, str] = match.groups() + self.bucket, self.key, self.last_key = groups def __str__(self) -> str: # pragma: no cover return self.value diff --git a/tests/test_s3.py b/tests/test_s3.py index abfb1e4..c636b0e 100644 --- a/tests/test_s3.py +++ b/tests/test_s3.py @@ -150,3 +150,17 @@ def test_s3(raw: str, bucket: str, key: str, last_key: str): def test_wrong_s3(): with pytest.raises(ValidationError): S3Check(path='s3/ok') + + +@pytest.mark.parametrize( + 'invalid_path', + [ + 's3/ok', + 'not-an-s3-path', + 's3://bucket-only', + ], +) +def test_wrong_s3_raises_value_error(invalid_path: str): + """Test that invalid S3 paths raise ValueError.""" + with pytest.raises(ValueError, match='Invalid S3 path'): + S3Path(invalid_path) From 8ef391a500b4088f5e04ef5137d61164767c1f73 Mon Sep 17 00:00:00 2001 From: Danipulok Date: Mon, 17 Nov 2025 22:03:11 +0200 Subject: [PATCH 2/5] fix linter warning --- pydantic_extra_types/s3.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pydantic_extra_types/s3.py b/pydantic_extra_types/s3.py index 61c1119..fdc5507 100644 --- a/pydantic_extra_types/s3.py +++ b/pydantic_extra_types/s3.py @@ -8,7 +8,7 @@ from __future__ import annotations import re -from typing import Any, ClassVar +from typing import Any, cast, ClassVar from pydantic import GetCoreSchemaHandler from pydantic_core import core_schema @@ -47,7 +47,7 @@ def __init__(self, value: str) -> None: match = self.patt.match(self.value) if match is None: raise ValueError(f'Invalid S3 path: {value!r}') - groups: tuple[str, str, str] = match.groups() + groups = cast(tuple[str, str, str], match.groups()) self.bucket, self.key, self.last_key = groups def __str__(self) -> str: # pragma: no cover From 8b0f348e0e0fe64479cb8deb3075b2bdb84c2d08 Mon Sep 17 00:00:00 2001 From: Danipulok Date: Mon, 17 Nov 2025 22:07:52 +0200 Subject: [PATCH 3/5] fix linters --- pydantic_extra_types/s3.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pydantic_extra_types/s3.py b/pydantic_extra_types/s3.py index fdc5507..e7f9615 100644 --- a/pydantic_extra_types/s3.py +++ b/pydantic_extra_types/s3.py @@ -8,7 +8,7 @@ from __future__ import annotations import re -from typing import Any, cast, ClassVar +from typing import Any, ClassVar from pydantic import GetCoreSchemaHandler from pydantic_core import core_schema @@ -47,8 +47,9 @@ def __init__(self, value: str) -> None: match = self.patt.match(self.value) if match is None: raise ValueError(f'Invalid S3 path: {value!r}') - groups = cast(tuple[str, str, str], match.groups()) - self.bucket, self.key, self.last_key = groups + self.bucket: str = match.group(1) + self._key: str = match.group(2) + self.last_key: str = match.group(3) def __str__(self) -> str: # pragma: no cover return self.value From 852d1d5f40b61189f2293347796605321229acd0 Mon Sep 17 00:00:00 2001 From: Danipulok Date: Mon, 17 Nov 2025 22:10:08 +0200 Subject: [PATCH 4/5] fix linters --- pydantic_extra_types/s3.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pydantic_extra_types/s3.py b/pydantic_extra_types/s3.py index e7f9615..a0af692 100644 --- a/pydantic_extra_types/s3.py +++ b/pydantic_extra_types/s3.py @@ -48,7 +48,7 @@ def __init__(self, value: str) -> None: if match is None: raise ValueError(f'Invalid S3 path: {value!r}') self.bucket: str = match.group(1) - self._key: str = match.group(2) + self.key: str = match.group(2) self.last_key: str = match.group(3) def __str__(self) -> str: # pragma: no cover From da206498cc48525ac532341ab4c58b12feea2be8 Mon Sep 17 00:00:00 2001 From: Danipulok Date: Tue, 18 Nov 2025 20:11:56 +0200 Subject: [PATCH 5/5] remove deprecated field_name parameter --- pydantic_extra_types/s3.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pydantic_extra_types/s3.py b/pydantic_extra_types/s3.py index a0af692..eaf1254 100644 --- a/pydantic_extra_types/s3.py +++ b/pydantic_extra_types/s3.py @@ -67,5 +67,4 @@ def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaH return core_schema.with_info_after_validator_function( cls._validate, core_schema.str_schema(pattern=cls.patt), - field_name=cls.__class__.__name__, )