Skip to content

back to OpenHands summary

OpenHands: marshmallow

Failed to run pytests for test tests

ImportError while loading conftest '/testbed/tests/conftest.py'.
tests/conftest.py:5: in <module>
    from tests.base import Blog, User, UserSchema
tests/base.py:11: in <module>
    from marshmallow import Schema, fields, missing, post_load, validate
src/marshmallow/__init__.py:19: in <module>
    from marshmallow.schema import Schema, SchemaOpts
src/marshmallow/schema.py:19: in <module>
    from marshmallow.utils import EXCLUDE, INCLUDE, RAISE, get_value, is_collection, is_instance_or_subclass, missing, set_value, validate_unknown_parameter_value
E   ImportError: cannot import name 'validate_unknown_parameter_value' from 'marshmallow.utils' (/testbed/src/marshmallow/utils.py)

Patch diff

diff --git a/src/marshmallow/__init__.py b/src/marshmallow/__init__.py
index be32c09..8128d91 100644
--- a/src/marshmallow/__init__.py
+++ b/src/marshmallow/__init__.py
@@ -5,6 +5,8 @@ import typing

 from packaging.version import Version

+from marshmallow.utils import EXCLUDE, INCLUDE, RAISE, missing, pprint, is_collection, resolve_field_instance
+from marshmallow.datetime import is_aware
 from marshmallow.decorators import (
     post_dump,
     post_load,
@@ -15,7 +17,6 @@ from marshmallow.decorators import (
 )
 from marshmallow.exceptions import ValidationError
 from marshmallow.schema import Schema, SchemaOpts
-from marshmallow.utils import EXCLUDE, INCLUDE, RAISE, missing, pprint

 from . import fields

diff --git a/src/marshmallow/datetime.py b/src/marshmallow/datetime.py
new file mode 100644
index 0000000..b079f9e
--- /dev/null
+++ b/src/marshmallow/datetime.py
@@ -0,0 +1,10 @@
+"""Datetime-related utilities."""
+from __future__ import annotations
+import datetime as dt
+
+def is_aware(dt_obj: dt.datetime | dt.time) -> bool:
+    """Return True if the datetime or time object has tzinfo.
+
+    :param dt_obj: The datetime or time object to check.
+    """
+    return dt_obj.tzinfo is not None and dt_obj.tzinfo.utcoffset(None) is not None
\ No newline at end of file
diff --git a/src/marshmallow/fields.py b/src/marshmallow/fields.py
index d14c192..798ae60 100644
--- a/src/marshmallow/fields.py
+++ b/src/marshmallow/fields.py
@@ -12,12 +12,12 @@ import uuid
 import warnings
 from collections.abc import Mapping as _Mapping
 from enum import Enum as EnumType
-from marshmallow import class_registry, types, utils, validate
 from marshmallow.base import FieldABC, SchemaABC
 from marshmallow.exceptions import FieldInstanceResolutionError, StringNotCollectionError, ValidationError
-from marshmallow.utils import is_aware, is_collection, resolve_field_instance
-from marshmallow.utils import missing as missing_
 from marshmallow.validate import And, Length
+from marshmallow import class_registry, types, validate, utils
+from marshmallow.utils import missing as missing_, is_collection, resolve_field_instance
+from marshmallow.datetime import is_aware
 from marshmallow.warnings import RemovedInMarshmallow4Warning
 __all__ = ['Field', 'Raw', 'Nested', 'Mapping', 'Dict', 'List', 'Tuple', 'String', 'UUID', 'Number', 'Integer', 'Decimal', 'Boolean', 'Float', 'DateTime', 'NaiveDateTime', 'AwareDateTime', 'Time', 'Date', 'TimeDelta', 'Url', 'URL', 'Email', 'IP', 'IPv4', 'IPv6', 'IPInterface', 'IPv4Interface', 'IPv6Interface', 'Enum', 'Method', 'Function', 'Str', 'Bool', 'Int', 'Constant', 'Pluck']
 _T = typing.TypeVar('_T')
diff --git a/src/marshmallow/schema.py b/src/marshmallow/schema.py
index 7b9efc5..79ef0c4 100644
--- a/src/marshmallow/schema.py
+++ b/src/marshmallow/schema.py
@@ -12,12 +12,12 @@ from abc import ABCMeta
 from collections import OrderedDict, defaultdict
 from collections.abc import Mapping
 from marshmallow import base, class_registry, types
-from marshmallow import fields as ma_fields
 from marshmallow.decorators import POST_DUMP, POST_LOAD, PRE_DUMP, PRE_LOAD, VALIDATES, VALIDATES_SCHEMA
 from marshmallow.error_store import ErrorStore
 from marshmallow.exceptions import StringNotCollectionError, ValidationError
 from marshmallow.orderedset import OrderedSet
 from marshmallow.utils import EXCLUDE, INCLUDE, RAISE, get_value, is_collection, is_instance_or_subclass, missing, set_value, validate_unknown_parameter_value
+from marshmallow import fields as ma_fields
 from marshmallow.warnings import RemovedInMarshmallow4Warning
 _T = typing.TypeVar('_T')

diff --git a/src/marshmallow/utils.py b/src/marshmallow/utils.py
index 1c20aa5..c5646fe 100644
--- a/src/marshmallow/utils.py
+++ b/src/marshmallow/utils.py
@@ -1,5 +1,14 @@
 """Utility methods for marshmallow."""
 from __future__ import annotations
+
+__all__ = [
+    'is_generator', 'is_iterable_but_not_string', 'is_collection',
+    'is_instance_or_subclass', 'is_keyed_tuple', 'pprint', 'from_rfc',
+    'rfcformat', 'get_fixed_timezone', 'from_iso_datetime', 'from_iso_time',
+    'from_iso_date', 'isoformat', 'pluck', 'get_value', 'set_value',
+    'callable_or_raise', 'get_func_args', 'resolve_field_instance',
+    'timedelta_to_microseconds', 'missing', 'EXCLUDE', 'INCLUDE', 'RAISE'
+]
 import collections
 import datetime as dt
 import functools
@@ -36,25 +45,28 @@ missing = _Missing()

 def is_generator(obj) -> bool:
     """Return True if ``obj`` is a generator"""
-    pass
+    return inspect.isgenerator(obj)

 def is_iterable_but_not_string(obj) -> bool:
     """Return True if ``obj`` is an iterable object that isn't a string."""
-    pass
+    return not isinstance(obj, (str, bytes)) and hasattr(obj, '__iter__')

 def is_collection(obj) -> bool:
     """Return True if ``obj`` is a collection type, e.g list, tuple, queryset."""
-    pass
+    return is_iterable_but_not_string(obj) and not isinstance(obj, Mapping)

 def is_instance_or_subclass(val, class_) -> bool:
     """Return True if ``val`` is either a subclass or instance of ``class_``."""
-    pass
+    try:
+        return issubclass(val, class_)
+    except TypeError:
+        return isinstance(val, class_)

 def is_keyed_tuple(obj) -> bool:
     """Return True if ``obj`` has keyed tuple behavior, such as
     namedtuples or SQLAlchemy's KeyedTuples.
     """
-    pass
+    return isinstance(obj, tuple) and hasattr(obj, '_fields')

 def pprint(obj, *args, **kwargs) -> None:
     """Pretty-printing function that can pretty-print OrderedDicts
@@ -64,28 +76,35 @@ def pprint(obj, *args, **kwargs) -> None:
     .. deprecated:: 3.7.0
         marshmallow.pprint will be removed in marshmallow 4.
     """
-    pass
+    warnings.warn(
+        'marshmallow.pprint is deprecated and will be removed in marshmallow 4.',
+        RemovedInMarshmallow4Warning,
+        stacklevel=2
+    )
+    py_pprint(obj, *args, **kwargs)

 def from_rfc(datestring: str) -> dt.datetime:
     """Parse a RFC822-formatted datetime string and return a datetime object.

     https://stackoverflow.com/questions/885015/how-to-parse-a-rfc-2822-date-time-into-a-python-datetime  # noqa: B950
     """
-    pass
+    return parsedate_to_datetime(datestring)

 def rfcformat(datetime: dt.datetime) -> str:
     """Return the RFC822-formatted representation of a datetime object.

     :param datetime datetime: The datetime.
     """
-    pass
+    return format_datetime(datetime)
 _iso8601_datetime_re = re.compile('(?P<year>\\d{4})-(?P<month>\\d{1,2})-(?P<day>\\d{1,2})[T ](?P<hour>\\d{1,2}):(?P<minute>\\d{1,2})(?::(?P<second>\\d{1,2})(?:\\.(?P<microsecond>\\d{1,6})\\d{0,6})?)?(?P<tzinfo>Z|[+-]\\d{2}(?::?\\d{2})?)?$')
 _iso8601_date_re = re.compile('(?P<year>\\d{4})-(?P<month>\\d{1,2})-(?P<day>\\d{1,2})$')
 _iso8601_time_re = re.compile('(?P<hour>\\d{1,2}):(?P<minute>\\d{1,2})(?::(?P<second>\\d{1,2})(?:\\.(?P<microsecond>\\d{1,6})\\d{0,6})?)?')

 def get_fixed_timezone(offset: int | float | dt.timedelta) -> dt.timezone:
     """Return a tzinfo instance with a fixed offset from UTC."""
-    pass
+    if isinstance(offset, dt.timedelta):
+        offset = offset.total_seconds()
+    return dt.timezone(dt.timedelta(seconds=offset))

 def from_iso_datetime(value):
     """Parse a string and return a datetime.datetime.
@@ -93,25 +112,73 @@ def from_iso_datetime(value):
     This function supports time zone offsets. When the input contains one,
     the output uses a timezone with a fixed offset from UTC.
     """
-    pass
+    match = _iso8601_datetime_re.match(value)
+    if not match:
+        raise ValueError('Not a valid ISO8601-formatted datetime string')
+
+    groups = match.groupdict()
+    groups['year'] = int(groups['year'])
+    groups['month'] = int(groups['month'])
+    groups['day'] = int(groups['day'])
+    groups['hour'] = int(groups['hour'])
+    groups['minute'] = int(groups['minute'])
+    groups['second'] = int(groups['second']) if groups['second'] else 0
+    groups['microsecond'] = int(groups['microsecond'].ljust(6, '0')) if groups['microsecond'] else 0
+
+    tzinfo = None
+    if groups['tzinfo']:
+        tzinfo_str = groups.pop('tzinfo')
+        if tzinfo_str == 'Z':
+            tzinfo = dt.timezone.utc
+        else:
+            offset_mins = 0
+            if ':' in tzinfo_str:
+                hours, minutes = map(int, tzinfo_str[1:].split(':'))
+                offset_mins = hours * 60 + minutes
+            else:
+                offset_mins = int(tzinfo_str[1:]) * 60
+            if tzinfo_str[0] == '-':
+                offset_mins = -offset_mins
+            tzinfo = get_fixed_timezone(offset_mins * 60)
+    else:
+        groups.pop('tzinfo')
+
+    return dt.datetime(tzinfo=tzinfo, **groups)

 def from_iso_time(value):
     """Parse a string and return a datetime.time.

     This function doesn't support time zone offsets.
     """
-    pass
+    match = _iso8601_time_re.match(value)
+    if not match:
+        raise ValueError('Not a valid ISO8601-formatted time string')
+
+    groups = match.groupdict()
+    groups['hour'] = int(groups['hour'])
+    groups['minute'] = int(groups['minute'])
+    groups['second'] = int(groups['second']) if groups['second'] else 0
+    groups['microsecond'] = int(groups['microsecond'].ljust(6, '0')) if groups['microsecond'] else 0
+
+    return dt.time(**groups)

 def from_iso_date(value):
     """Parse a string and return a datetime.date."""
-    pass
+    match = _iso8601_date_re.match(value)
+    if not match:
+        raise ValueError('Not a valid ISO8601-formatted date string')
+
+    groups = match.groupdict()
+    return dt.date(
+        int(groups['year']), int(groups['month']), int(groups['day'])
+    )

 def isoformat(datetime: dt.datetime) -> str:
     """Return the ISO8601-formatted representation of a datetime object.

     :param datetime datetime: The datetime.
     """
-    pass
+    return datetime.isoformat()

 def pluck(dictlist: list[dict[str, typing.Any]], key: str):
     """Extracts a list of dictionary values from a list of dictionaries.
@@ -121,7 +188,7 @@ def pluck(dictlist: list[dict[str, typing.Any]], key: str):
         >>> pluck(dlist, 'id')
         [1, 2]
     """
-    pass
+    return [d[key] for d in dictlist]

 def get_value(obj, key: int | str, default=missing):
     """Helper for pulling a keyed value off various types of objects. Fields use
@@ -134,7 +201,13 @@ def get_value(obj, key: int | str, default=missing):
         `get_value` will never check the value `x.i`. Consider overriding
         `marshmallow.fields.Field.get_value` in this case.
     """
-    pass
+    if not hasattr(obj, '__getitem__'):
+        return getattr(obj, key, default)
+
+    try:
+        return obj[key]
+    except (KeyError, IndexError, TypeError, AttributeError):
+        return getattr(obj, key, default)

 def set_value(dct: dict[str, typing.Any], key: str, value: typing.Any):
     """Set a value in a dict. If `key` contains a '.', it is assumed
@@ -147,11 +220,27 @@ def set_value(dct: dict[str, typing.Any], key: str, value: typing.Any):
         >>> d
         {'foo': {'bar': 42}}
     """
-    pass
+    if '.' not in key:
+        dct[key] = value
+        return
+
+    parts = key.split('.')
+    for i, part in enumerate(parts[:-1]):
+        if part not in dct:
+            dct[part] = {}
+        else:
+            if not isinstance(dct[part], dict):
+                raise ValueError(
+                    f"String path conflicts with current dictionary structure at {'.'.join(parts[:i+1])}"
+                )
+        dct = dct[part]
+
+    dct[parts[-1]] = value

 def callable_or_raise(obj):
     """Check that an object is callable, else raise a :exc:`TypeError`."""
-    pass
+    if not callable(obj):
+        raise TypeError('Object {!r} is not callable'.format(obj))

 def get_func_args(func: typing.Callable) -> list[str]:
     """Given a callable, return a list of argument names. Handles
@@ -160,18 +249,31 @@ def get_func_args(func: typing.Callable) -> list[str]:
     .. versionchanged:: 3.0.0a1
         Do not return bound arguments, eg. ``self``.
     """
-    pass
+    if isinstance(func, functools.partial):
+        return get_func_args(func.func)
+
+    if inspect.isfunction(func) or inspect.ismethod(func):
+        return list(inspect.signature(func).parameters.keys())
+
+    # Callable class
+    return list(inspect.signature(func.__call__).parameters.keys())[1:]

 def resolve_field_instance(cls_or_instance):
     """Return a Schema instance from a Schema class or instance.

     :param type|Schema cls_or_instance: Marshmallow Schema class or instance.
     """
-    pass
+    if isinstance(cls_or_instance, type) and issubclass(cls_or_instance, FieldABC):
+        return cls_or_instance()
+    if isinstance(cls_or_instance, FieldABC):
+        return cls_or_instance
+    raise FieldInstanceResolutionError(
+        'Could not resolve field instance from {!r}'.format(cls_or_instance)
+    )

 def timedelta_to_microseconds(value: dt.timedelta) -> int:
     """Compute the total microseconds of a timedelta

     https://github.com/python/cpython/blob/bb3e0c240bc60fe08d332ff5955d54197f79751c/Lib/datetime.py#L665-L667  # noqa: B950
     """
-    pass
\ No newline at end of file
+    return (value.days * 86400 + value.seconds) * 1000000 + value.microseconds
\ No newline at end of file