Coverage for install/scipp/_binding.py: 30%
57 statements
« prev ^ index » next coverage.py v7.4.0, created at 2024-04-28 01:28 +0000
« prev ^ index » next coverage.py v7.4.0, created at 2024-04-28 01:28 +0000
1# SPDX-License-Identifier: BSD-3-Clause
2# Copyright (c) 2023 Scipp contributors (https://github.com/scipp)
3# @author Jan-Lukas Wynen
5import types
7from ._scipp import core
9_dict_likes = [
10 core.Dataset,
11 core.Coords,
12 core.Masks,
13 core._BinsMeta,
14 core._BinsCoords,
15 core._BinsMasks,
16 core._BinsAttrs,
17]
20def _get(self, key, default=None):
21 """
22 Return the value for key if key is in present, else default.
23 """
24 try:
25 return self[key]
26 except KeyError:
27 return default
30def bind_get():
31 for cls in _dict_likes:
32 method = _convert_to_method(name='get', func=_get, abbreviate_doc=False)
33 method.__doc__ = (
34 "Get the value associated with the " "provided key or the default value."
35 )
36 cls.get = method
39def _expect_dimensionless_or_unitless(x):
40 if x.unit is not None and x.unit != core.units.dimensionless:
41 raise core.UnitError(f'Expected unit dimensionless or no unit, got {x.unit}.')
44def _expect_no_variance(x):
45 if x.variance is not None:
46 raise core.VariancesError('Expected input without variances.')
49def _int_dunder(self) -> int:
50 _expect_dimensionless_or_unitless(self)
51 _expect_no_variance(self)
52 return int(self.value)
55def _float_dunder(self) -> float:
56 _expect_dimensionless_or_unitless(self)
57 _expect_no_variance(self)
58 return float(self.value)
61def bind_conversion_to_builtin(cls):
62 cls.__int__ = _convert_to_method(name='__int__', func=_int_dunder)
63 cls.__float__ = _convert_to_method(name='__float__', func=_float_dunder)
66class _NoDefaultType:
67 def __repr__(self):
68 return 'NotSpecified'
71_NoDefault = _NoDefaultType()
74def _pop(self, key, default=_NoDefault):
75 """
76 Remove and return an element.
78 If key is not found, default is returned if given, otherwise KeyError is raised.
79 """
80 if key not in self and default is not _NoDefault:
81 return default
82 return self._pop(key)
85def bind_pop():
86 for cls in _dict_likes:
87 bind_function_as_method(cls=cls, name='pop', func=_pop, abbreviate_doc=False)
90def bind_functions_as_methods(cls, namespace, func_names):
91 for func_name, func in ((n, namespace[n]) for n in func_names):
92 bind_function_as_method(cls=cls, name=func_name, func=func)
95def bind_function_as_method(*, cls, name, func, abbreviate_doc=True):
96 setattr(
97 cls,
98 name,
99 _convert_to_method(name=name, func=func, abbreviate_doc=abbreviate_doc),
100 )
103def _convert_to_method(*, name, func, abbreviate_doc=True):
104 method = types.FunctionType(
105 func.__code__, func.__globals__, name, func.__defaults__, func.__closure__
106 )
107 method.__kwdefaults__ = func.__kwdefaults__
108 method.__annotations__ = func.__annotations__
109 if func.__doc__ is not None:
110 # Extract the summary from the docstring.
111 # This relies on check W293 in flake8 to avoid implementing a more
112 # sophisticate / expensive parser that running during import of scipp.
113 # Line feeds are replaced because they mess with the
114 # reST parser of autosummary.
115 if abbreviate_doc:
116 method.__doc__ = (
117 func.__doc__.split('\n\n', 1)[0].replace('\n', ' ')
118 + f'\n\n:seealso: Details in :py:meth:`scipp.{name}`'
119 )
120 else:
121 method.__doc__ = func.__doc__
122 if hasattr(func, '__wrapped__'):
123 method.__wrapped__ = func.__wrapped__
124 return method