Skip to content

Commit

Permalink
fix validated_loads not allowing extra fields to be included
Browse files Browse the repository at this point in the history
  • Loading branch information
mjurbanski-reef committed Jun 13, 2024
1 parent 2ea6ec5 commit 6ded885
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 2 deletions.
9 changes: 8 additions & 1 deletion b2/_internal/_cli/obj_loads.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,19 @@
import io
import json
import logging
import sys
from typing import TypeVar

from b2sdk.v2 import get_b2sdk_doc_urls

try:
import pydantic
from pydantic import TypeAdapter, ValidationError

if sys.version_info < (3, 10):
raise ImportError('pydantic integration is not supported on python<3.10')
# we could support it partially with help of https://github.com/pydantic/pydantic/issues/7873
# but that creates yet another edge case, on old version of Python
except ImportError:
pydantic = None

Expand Down Expand Up @@ -50,6 +56,7 @@ def describe_type(type_) -> str:
def validated_loads(data: str, expected_type: type[T] | None = None) -> T:
val = _UNDEF
if expected_type is not None and pydantic is not None:
expected_type = pydantic.with_config(pydantic.ConfigDict(extra="allow"))(expected_type)
try:
ta = TypeAdapter(expected_type)
except TypeError:
Expand All @@ -62,7 +69,7 @@ def validated_loads(data: str, expected_type: type[T] | None = None) -> T:
val = _UNDEF
else:
try:
val = ta.validate_json(data)
val = ta.validate_json(data,)
except ValidationError as e:
errors = convert_error_to_human_readable(e)
raise argparse.ArgumentTypeError(
Expand Down
31 changes: 30 additions & 1 deletion test/unit/_cli/test_obj_loads.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,18 @@
# License https://www.backblaze.com/using_b2_code.html
#
######################################################################
from __future__ import annotations

import argparse

import pytest

from b2._internal._cli.obj_loads import validated_loads
try:
from typing_extensions import TypedDict
except ImportError:
from typing import TypedDict

from b2._internal._cli.obj_loads import pydantic, validated_loads


@pytest.mark.parametrize(
Expand Down Expand Up @@ -46,3 +53,25 @@ def test_validated_loads(input_, expected_val):
def test_validated_loads__invalid_syntax(input_, error_msg):
with pytest.raises(argparse.ArgumentTypeError, match=error_msg):
validated_loads(input_)


@pytest.fixture
def typed_dict_cls():
class MyTypedDict(TypedDict):
a: int | None
b: str

return MyTypedDict


def test_validated_loads__typed_dict(typed_dict_cls):
input_ = '{"a": 1, "b": "2", "extra": null}'
expected_val = {"a": 1, "b": "2", "extra": None}
assert validated_loads(input_, typed_dict_cls) == expected_val


@pytest.mark.skipif(pydantic is None, reason="pydantic is not enabled")
def test_validated_loads__typed_dict_types_validation(typed_dict_cls):
input_ = '{"a": "abc", "b": 2}'
with pytest.raises(argparse.ArgumentTypeError):
validated_loads(input_, typed_dict_cls)

0 comments on commit 6ded885

Please sign in to comment.