util.extend_docstring: proper layout for extended class (incl. current return type)
This commit is contained in:
parent
dff8a5a7f9
commit
5017aabcea
|
@ -94,7 +94,7 @@ class Orientation(Rotation,Crystal):
|
|||
|
||||
"""
|
||||
|
||||
@util.extend_docstring(_parameter_doc)
|
||||
@util.extend_docstring(extra_parameters=_parameter_doc)
|
||||
def __init__(self,
|
||||
rotation: Union[FloatSequence, Rotation] = np.array([1.,0.,0.,0.]),
|
||||
*,
|
||||
|
@ -300,84 +300,95 @@ class Orientation(Rotation,Crystal):
|
|||
|
||||
|
||||
@classmethod
|
||||
@util.extended_docstring(Rotation.from_random, _parameter_doc)
|
||||
@util.extend_docstring(Rotation.from_random,
|
||||
extra_parameters=_parameter_doc)
|
||||
def from_random(cls, **kwargs) -> 'Orientation':
|
||||
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_random)
|
||||
return cls(rotation=Rotation.from_random(**kwargs_rot),**kwargs_ori)
|
||||
|
||||
|
||||
@classmethod
|
||||
@util.extended_docstring(Rotation.from_quaternion,_parameter_doc)
|
||||
@util.extend_docstring(Rotation.from_quaternion,
|
||||
extra_parameters=_parameter_doc)
|
||||
def from_quaternion(cls, **kwargs) -> 'Orientation':
|
||||
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_quaternion)
|
||||
return cls(rotation=Rotation.from_quaternion(**kwargs_rot),**kwargs_ori)
|
||||
|
||||
|
||||
@classmethod
|
||||
@util.extended_docstring(Rotation.from_Euler_angles,_parameter_doc)
|
||||
@util.extend_docstring(Rotation.from_Euler_angles,
|
||||
extra_parameters=_parameter_doc)
|
||||
def from_Euler_angles(cls, **kwargs) -> 'Orientation':
|
||||
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_Euler_angles)
|
||||
return cls(rotation=Rotation.from_Euler_angles(**kwargs_rot),**kwargs_ori)
|
||||
|
||||
|
||||
@classmethod
|
||||
@util.extended_docstring(Rotation.from_axis_angle,_parameter_doc)
|
||||
@util.extend_docstring(Rotation.from_axis_angle,
|
||||
extra_parameters=_parameter_doc)
|
||||
def from_axis_angle(cls, **kwargs) -> 'Orientation':
|
||||
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_axis_angle)
|
||||
return cls(rotation=Rotation.from_axis_angle(**kwargs_rot),**kwargs_ori)
|
||||
|
||||
|
||||
@classmethod
|
||||
@util.extended_docstring(Rotation.from_basis,_parameter_doc)
|
||||
@util.extend_docstring(Rotation.from_basis,
|
||||
extra_parameters=_parameter_doc)
|
||||
def from_basis(cls, **kwargs) -> 'Orientation':
|
||||
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_basis)
|
||||
return cls(rotation=Rotation.from_basis(**kwargs_rot),**kwargs_ori)
|
||||
|
||||
|
||||
@classmethod
|
||||
@util.extended_docstring(Rotation.from_matrix,_parameter_doc)
|
||||
@util.extend_docstring(Rotation.from_matrix,
|
||||
extra_parameters=_parameter_doc)
|
||||
def from_matrix(cls, **kwargs) -> 'Orientation':
|
||||
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_matrix)
|
||||
return cls(rotation=Rotation.from_matrix(**kwargs_rot),**kwargs_ori)
|
||||
|
||||
|
||||
@classmethod
|
||||
@util.extended_docstring(Rotation.from_Rodrigues_vector,_parameter_doc)
|
||||
@util.extend_docstring(Rotation.from_Rodrigues_vector,
|
||||
extra_parameters=_parameter_doc)
|
||||
def from_Rodrigues_vector(cls, **kwargs) -> 'Orientation':
|
||||
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_Rodrigues_vector)
|
||||
return cls(rotation=Rotation.from_Rodrigues_vector(**kwargs_rot),**kwargs_ori)
|
||||
|
||||
|
||||
@classmethod
|
||||
@util.extended_docstring(Rotation.from_homochoric,_parameter_doc)
|
||||
@util.extend_docstring(Rotation.from_homochoric,
|
||||
extra_parameters=_parameter_doc)
|
||||
def from_homochoric(cls, **kwargs) -> 'Orientation':
|
||||
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_homochoric)
|
||||
return cls(rotation=Rotation.from_homochoric(**kwargs_rot),**kwargs_ori)
|
||||
|
||||
|
||||
@classmethod
|
||||
@util.extended_docstring(Rotation.from_cubochoric,_parameter_doc)
|
||||
@util.extend_docstring(Rotation.from_cubochoric,
|
||||
extra_parameters=_parameter_doc)
|
||||
def from_cubochoric(cls, **kwargs) -> 'Orientation':
|
||||
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_cubochoric)
|
||||
return cls(rotation=Rotation.from_cubochoric(**kwargs_rot),**kwargs_ori)
|
||||
|
||||
|
||||
@classmethod
|
||||
@util.extended_docstring(Rotation.from_spherical_component,_parameter_doc)
|
||||
@util.extend_docstring(Rotation.from_spherical_component,
|
||||
extra_parameters=_parameter_doc)
|
||||
def from_spherical_component(cls, **kwargs) -> 'Orientation':
|
||||
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_spherical_component)
|
||||
return cls(rotation=Rotation.from_spherical_component(**kwargs_rot),**kwargs_ori)
|
||||
|
||||
|
||||
@classmethod
|
||||
@util.extended_docstring(Rotation.from_fiber_component,_parameter_doc)
|
||||
@util.extend_docstring(Rotation.from_fiber_component,
|
||||
extra_parameters=_parameter_doc)
|
||||
def from_fiber_component(cls, **kwargs) -> 'Orientation':
|
||||
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_fiber_component)
|
||||
return cls(rotation=Rotation.from_fiber_component(**kwargs_rot),**kwargs_ori)
|
||||
|
||||
|
||||
@classmethod
|
||||
@util.extend_docstring(_parameter_doc)
|
||||
@util.extend_docstring(extra_parameters=_parameter_doc)
|
||||
def from_directions(cls,
|
||||
uvw: FloatSequence,
|
||||
hkl: FloatSequence,
|
||||
|
@ -392,6 +403,10 @@ class Orientation(Rotation,Crystal):
|
|||
hkl : numpy.ndarray, shape (...,3)
|
||||
Lattice plane normal aligned with lab frame z-direction.
|
||||
|
||||
Returns
|
||||
-------
|
||||
new : damask.Orientation
|
||||
|
||||
"""
|
||||
o = cls(**kwargs)
|
||||
x = o.to_frame(uvw=uvw)
|
||||
|
@ -538,8 +553,7 @@ class Orientation(Rotation,Crystal):
|
|||
|
||||
Notes
|
||||
-----
|
||||
Currently requires same crystal family for both orientations.
|
||||
For extension to cases with differing symmetry see A. Heinz and P. Neumann 1991 and 10.1107/S0021889808016373.
|
||||
Requires same crystal family for both orientations.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
@ -569,6 +583,8 @@ class Orientation(Rotation,Crystal):
|
|||
>>> plt.show()
|
||||
|
||||
"""
|
||||
# For extension to cases with differing symmetry see
|
||||
# https://doi.org/10.1107/S0021889808016373 and https://doi.org/10.1107/S0108767391006864
|
||||
if self.family != other.family:
|
||||
raise NotImplementedError('disorientation between different crystal families')
|
||||
|
||||
|
|
|
@ -732,7 +732,7 @@ class Rotation:
|
|||
Returns
|
||||
-------
|
||||
x : numpy.ndarray, shape (...,3)
|
||||
Cubochoric vector (x_1, x_2, x_3) with max(x_i) < 1/2*π^(2/3).
|
||||
Cubochoric vector (x_1, x_2, x_3) with max(x_i) < 1/2*π^(2/3).
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
@ -768,6 +768,10 @@ class Rotation:
|
|||
P : int ∈ {-1,1}, optional
|
||||
Sign convention. Defaults to -1.
|
||||
|
||||
Returns
|
||||
-------
|
||||
new : damask.Rotation
|
||||
|
||||
"""
|
||||
qu = np.array(q,dtype=float)
|
||||
if qu.shape[:-2:-1] != (4,): raise ValueError('invalid shape')
|
||||
|
@ -800,6 +804,10 @@ class Rotation:
|
|||
degrees : bool, optional
|
||||
Euler angles are given in degrees. Defaults to False.
|
||||
|
||||
Returns
|
||||
-------
|
||||
new : damask.Rotation
|
||||
|
||||
Notes
|
||||
-----
|
||||
Bunge Euler angles correspond to a rotation axis sequence of z–x'–z''.
|
||||
|
@ -834,6 +842,10 @@ class Rotation:
|
|||
P : int ∈ {-1,1}, optional
|
||||
Sign convention. Defaults to -1.
|
||||
|
||||
Returns
|
||||
-------
|
||||
new : damask.Rotation
|
||||
|
||||
"""
|
||||
ax = np.array(axis_angle,dtype=float)
|
||||
if ax.shape[:-2:-1] != (4,): raise ValueError('invalid shape')
|
||||
|
@ -898,6 +910,10 @@ class Rotation:
|
|||
R : numpy.ndarray, shape (...,3,3)
|
||||
Rotation matrix with det(R) = 1 and R.T ∙ R = I.
|
||||
|
||||
Returns
|
||||
-------
|
||||
new : damask.Rotation
|
||||
|
||||
"""
|
||||
return Rotation.from_basis(R)
|
||||
|
||||
|
@ -914,6 +930,10 @@ class Rotation:
|
|||
b : numpy.ndarray, shape (...,2,3)
|
||||
Corresponding three-dimensional vectors of second basis.
|
||||
|
||||
Returns
|
||||
-------
|
||||
new : damask.Rotation
|
||||
|
||||
"""
|
||||
a_ = np.array(a,dtype=float)
|
||||
b_ = np.array(b,dtype=float)
|
||||
|
@ -946,6 +966,10 @@ class Rotation:
|
|||
P : int ∈ {-1,1}, optional
|
||||
Sign convention. Defaults to -1.
|
||||
|
||||
Returns
|
||||
-------
|
||||
new : damask.Rotation
|
||||
|
||||
"""
|
||||
ro = np.array(rho,dtype=float)
|
||||
if ro.shape[:-2:-1] != (4,): raise ValueError('invalid shape')
|
||||
|
@ -974,6 +998,10 @@ class Rotation:
|
|||
P : int ∈ {-1,1}, optional
|
||||
Sign convention. Defaults to -1.
|
||||
|
||||
Returns
|
||||
-------
|
||||
new : damask.Rotation
|
||||
|
||||
"""
|
||||
ho = np.array(h,dtype=float)
|
||||
if ho.shape[:-2:-1] != (3,): raise ValueError('invalid shape')
|
||||
|
@ -999,6 +1027,10 @@ class Rotation:
|
|||
P : int ∈ {-1,1}, optional
|
||||
Sign convention. Defaults to -1.
|
||||
|
||||
Returns
|
||||
-------
|
||||
new : damask.Rotation
|
||||
|
||||
"""
|
||||
cu = np.array(x,dtype=float)
|
||||
if cu.shape[:-2:-1] != (3,): raise ValueError('invalid shape')
|
||||
|
@ -1025,6 +1057,10 @@ class Rotation:
|
|||
A seed to initialize the BitGenerator.
|
||||
Defaults to None, i.e. unpredictable entropy will be pulled from the OS.
|
||||
|
||||
Returns
|
||||
-------
|
||||
new : damask.Rotation
|
||||
|
||||
"""
|
||||
rng = np.random.default_rng(rng_seed)
|
||||
r = rng.random(3 if shape is None else tuple(shape)+(3,) if hasattr(shape, '__iter__') else (shape,3)) # type: ignore
|
||||
|
@ -1066,6 +1102,10 @@ class Rotation:
|
|||
A seed to initialize the BitGenerator.
|
||||
Defaults to None, i.e. unpredictable entropy will be pulled from the OS.
|
||||
|
||||
Returns
|
||||
-------
|
||||
new : damask.Rotation
|
||||
|
||||
Notes
|
||||
-----
|
||||
Due to the distortion of Euler space in the vicinity of ϕ = 0, probability densities, p, defined on
|
||||
|
@ -1150,7 +1190,7 @@ class Rotation:
|
|||
sigma: float = 0.,
|
||||
shape: Union[int, IntSequence] = None,
|
||||
degrees: bool = False,
|
||||
rng_seed: NumpyRngSeed = None):
|
||||
rng_seed: NumpyRngSeed = None) -> 'Rotation':
|
||||
"""
|
||||
Initialize with samples from a Gaussian distribution around a given direction.
|
||||
|
||||
|
@ -1173,6 +1213,10 @@ class Rotation:
|
|||
A seed to initialize the BitGenerator.
|
||||
Defaults to None, i.e. unpredictable entropy will be pulled from the OS.
|
||||
|
||||
Returns
|
||||
-------
|
||||
new : damask.Rotation
|
||||
|
||||
Notes
|
||||
-----
|
||||
The crystal direction for (θ=0,φ=0) is [0 0 1],
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
"""Functionality for generation of seed points for Voronoi or Laguerre tessellation."""
|
||||
|
||||
from typing import Tuple as _Tuple
|
||||
|
|
|
@ -210,6 +210,14 @@ def open_text(fname: _FileHandle,
|
|||
open(_Path(fname).expanduser(),mode,newline=('\n' if mode == 'w' else None))
|
||||
|
||||
|
||||
def execution_stamp(class_name: str,
|
||||
function_name: str = None) -> str:
|
||||
"""Timestamp the execution of a (function within a) class."""
|
||||
now = _datetime.datetime.now().astimezone().strftime('%Y-%m-%d %H:%M:%S%z')
|
||||
_function_name = '' if function_name is None else f'.{function_name}'
|
||||
return f'damask.{class_name}{_function_name} v{_version} ({now})'
|
||||
|
||||
|
||||
def natural_sort(key: str) -> _List[_Union[int, str]]:
|
||||
"""
|
||||
Natural sort.
|
||||
|
@ -403,13 +411,6 @@ def project_equal_area(vector: _np.ndarray,
|
|||
return _np.roll(_np.block([v[...,:2]/_np.sqrt(1.0+_np.abs(v[...,2:3])),_np.zeros_like(v[...,2:3])]),
|
||||
-shift if keepdims else 0,axis=-1)[...,:3 if keepdims else 2]
|
||||
|
||||
def execution_stamp(class_name: str,
|
||||
function_name: str = None) -> str:
|
||||
"""Timestamp the execution of a (function within a) class."""
|
||||
now = _datetime.datetime.now().astimezone().strftime('%Y-%m-%d %H:%M:%S%z')
|
||||
_function_name = '' if function_name is None else f'.{function_name}'
|
||||
return f'damask.{class_name}{_function_name} v{_version} ({now})'
|
||||
|
||||
|
||||
def hybrid_IA(dist: _np.ndarray,
|
||||
N: int,
|
||||
|
@ -486,18 +487,18 @@ def shapeshifter(fro: _Tuple[int, ...],
|
|||
final_shape: _List[int] = []
|
||||
index = 0
|
||||
for i,item in enumerate(_to):
|
||||
if item==_fro[index]:
|
||||
if item == _fro[index]:
|
||||
final_shape.append(item)
|
||||
index+=1
|
||||
else:
|
||||
final_shape.append(1)
|
||||
if _fro[index]==1 and not keep_ones:
|
||||
if _fro[index] == 1 and not keep_ones:
|
||||
index+=1
|
||||
if index==len(_fro):
|
||||
if index == len(_fro):
|
||||
final_shape = final_shape+[1]*(len(_to)-i-1)
|
||||
break
|
||||
if index!=len(_fro): raise ValueError(f'shapes cannot be shifted {fro} --> {to}')
|
||||
return tuple(final_shape[::-1] if mode=='left' else final_shape)
|
||||
if index != len(_fro): raise ValueError(f'shapes cannot be shifted {fro} --> {to}')
|
||||
return tuple(final_shape[::-1] if mode == 'left' else final_shape)
|
||||
|
||||
def shapeblender(a: _Tuple[int, ...],
|
||||
b: _Tuple[int, ...]) -> _Tuple[int, ...]:
|
||||
|
@ -528,37 +529,82 @@ def shapeblender(a: _Tuple[int, ...],
|
|||
return a + b[i:]
|
||||
|
||||
|
||||
def extend_docstring(extra_docstring: str) -> _Callable:
|
||||
def _docstringer(docstring: _Union[str, _Callable],
|
||||
extra_parameters: str = None,
|
||||
# extra_examples: str = None,
|
||||
# extra_notes: str = None,
|
||||
return_type: _Union[str, _Callable] = None) -> str:
|
||||
"""
|
||||
Decorator: Append to function's docstring.
|
||||
Extend a docstring.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
extra_docstring : str
|
||||
Docstring to append.
|
||||
docstring : str or callable, optional
|
||||
Docstring (of callable) to extend.
|
||||
extra_parameters : str, optional
|
||||
Additional information to append to Parameters section.
|
||||
return_type : str or callable, optional
|
||||
Type of return variable.
|
||||
|
||||
"""
|
||||
def _decorator(func):
|
||||
func.__doc__ += extra_docstring
|
||||
return func
|
||||
return _decorator
|
||||
docstring_ = str( docstring if isinstance(docstring,str)
|
||||
else docstring.__doc__ if hasattr(docstring,'__doc__')
|
||||
else '')
|
||||
d = dict(Parameters=extra_parameters,
|
||||
# Examples=extra_examples,
|
||||
# Notes=extra_notes,
|
||||
)
|
||||
for key,extra in [(k,v) for (k,v) in d.items() if v is not None]:
|
||||
if not (heading := _re.search(fr'^([ ]*){key}\s*\n\1{"-"*len(key)}',
|
||||
docstring_,flags=_re.MULTILINE)):
|
||||
raise RuntimeError(f"Docstring {docstring_} lacks a correctly formatted {key} section to insert values into")
|
||||
content = [line for line in extra.split('\n') if line.strip()]
|
||||
indent = len(heading.group(1))
|
||||
shift = min([len(line)-len(line.lstrip(' '))-indent for line in content])
|
||||
extra = '\n'.join([(line[shift:] if shift > 0 else
|
||||
f'{" "*-shift}{line}') for line in content])
|
||||
docstring_ = _re.sub(fr'(^([ ]*){key}\s*\n\2{"-"*len(key)}[\n ]*[A-Za-z0-9 ]*: ([^\n]+\n)*)',
|
||||
fr'\1{extra}\n',
|
||||
docstring_,flags=_re.MULTILINE)
|
||||
|
||||
if return_type is None:
|
||||
return docstring_
|
||||
else:
|
||||
if isinstance(return_type,str):
|
||||
return_type_ = return_type
|
||||
else:
|
||||
return_class = return_type.__annotations__.get('return','')
|
||||
return_type_ = (_sys.modules[return_type.__module__].__name__.split('.')[0]
|
||||
+'.'
|
||||
+(return_class.__name__ if not isinstance(return_class,str) else return_class)
|
||||
)
|
||||
|
||||
def extended_docstring(f: _Callable,
|
||||
extra_docstring: str) -> _Callable:
|
||||
return _re.sub(r'(^([ ]*)Returns\s*\n\2-------\s*\n[ ]*[A-Za-z0-9 ]*: )(.*)\n',
|
||||
fr'\1{return_type_}\n',
|
||||
docstring_,flags=_re.MULTILINE)
|
||||
|
||||
def extend_docstring(docstring: _Union[str, _Callable] = None,
|
||||
extra_parameters: str = None) -> _Callable:
|
||||
"""
|
||||
Decorator: Combine another function's docstring with a given docstring.
|
||||
Decorator: Extend the function's docstring.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
f : function
|
||||
Function of which the docstring is taken.
|
||||
extra_docstring : str
|
||||
Docstring to append.
|
||||
docstring : str or callable, optional
|
||||
Docstring to extend. Defaults to that of decorated function.
|
||||
extra_parameters : str, optional
|
||||
Additional information to append to Parameters section.
|
||||
|
||||
Notes
|
||||
-----
|
||||
Return type will become own type if docstring is callable.
|
||||
|
||||
"""
|
||||
def _decorator(func):
|
||||
func.__doc__ = f.__doc__ + extra_docstring
|
||||
func.__doc__ = _docstringer(func.__doc__ if docstring is None else docstring,
|
||||
extra_parameters,
|
||||
func if isinstance(docstring,_Callable) else None,
|
||||
)
|
||||
return func
|
||||
return _decorator
|
||||
|
||||
|
@ -649,7 +695,6 @@ def Bravais_to_Miller(*,
|
|||
[0,0,0,1]]))
|
||||
return _np.einsum('il,...l',basis,axis)
|
||||
|
||||
|
||||
def Miller_to_Bravais(*,
|
||||
uvw: _np.ndarray = None,
|
||||
hkl: _np.ndarray = None) -> _np.ndarray:
|
||||
|
@ -706,7 +751,6 @@ def dict_prune(d: _Dict) -> _Dict:
|
|||
|
||||
return new
|
||||
|
||||
|
||||
def dict_flatten(d: _Dict) -> _Dict:
|
||||
"""
|
||||
Recursively remove keys of single-entry dictionaries.
|
||||
|
|
|
@ -8,7 +8,6 @@ import h5py
|
|||
|
||||
from damask import util
|
||||
|
||||
|
||||
class TestUtil:
|
||||
|
||||
@pytest.mark.xfail(sys.platform == 'win32', reason='echo is not a Windows command')
|
||||
|
@ -208,3 +207,128 @@ class TestUtil:
|
|||
@pytest.mark.parametrize('kw_Miller,kw_Bravais',[('uvw','uvtw'),('hkl','hkil')])
|
||||
def test_Bravais_Miller_Bravais(self,vector,kw_Miller,kw_Bravais):
|
||||
assert np.all(vector == util.Miller_to_Bravais(**{kw_Miller:util.Bravais_to_Miller(**{kw_Bravais:vector})}))
|
||||
|
||||
|
||||
@pytest.mark.parametrize('extra_parameters',["""
|
||||
p2 : str, optional
|
||||
p2 description 1
|
||||
p2 description 2
|
||||
""",
|
||||
"""
|
||||
|
||||
p2 : str, optional
|
||||
p2 description 1
|
||||
p2 description 2
|
||||
|
||||
""",
|
||||
"""
|
||||
p2 : str, optional
|
||||
p2 description 1
|
||||
p2 description 2
|
||||
"""])
|
||||
@pytest.mark.parametrize('invalid_docstring',["""
|
||||
Function description
|
||||
|
||||
Parameters ----------
|
||||
p0 : numpy.ndarray, shape (...,4)
|
||||
p0 description 1
|
||||
p0 description 2
|
||||
p1 : int, optional
|
||||
p1 description
|
||||
|
||||
Remaining description
|
||||
""",
|
||||
"""
|
||||
Function description
|
||||
|
||||
Parameters
|
||||
----------
|
||||
p0 : numpy.ndarray, shape (...,4)
|
||||
p0 description 1
|
||||
p0 description 2
|
||||
p1 : int, optional
|
||||
p1 description
|
||||
|
||||
Remaining description
|
||||
""",])
|
||||
def test_extend_docstring_parameters(self,extra_parameters,invalid_docstring):
|
||||
test_docstring = """
|
||||
Function description
|
||||
|
||||
Parameters
|
||||
----------
|
||||
p0 : numpy.ndarray, shape (...,4)
|
||||
p0 description 1
|
||||
p0 description 2
|
||||
p1 : int, optional
|
||||
p1 description
|
||||
|
||||
Remaining description
|
||||
"""
|
||||
invalid_docstring = """
|
||||
Function description
|
||||
|
||||
Parameters ----------
|
||||
p0 : numpy.ndarray, shape (...,4)
|
||||
p0 description 1
|
||||
p0 description 2
|
||||
p1 : int, optional
|
||||
p1 description
|
||||
|
||||
Remaining description
|
||||
"""
|
||||
expected = """
|
||||
Function description
|
||||
|
||||
Parameters
|
||||
----------
|
||||
p0 : numpy.ndarray, shape (...,4)
|
||||
p0 description 1
|
||||
p0 description 2
|
||||
p1 : int, optional
|
||||
p1 description
|
||||
p2 : str, optional
|
||||
p2 description 1
|
||||
p2 description 2
|
||||
|
||||
Remaining description
|
||||
""".split("\n")
|
||||
assert expected == util._docstringer(test_docstring,extra_parameters).split('\n')
|
||||
with pytest.raises(RuntimeError):
|
||||
util._docstringer(invalid_docstring,extra_parameters)
|
||||
|
||||
def test_replace_docstring_return_type(self):
|
||||
class TestClassOriginal:
|
||||
pass
|
||||
|
||||
def original_func() -> TestClassOriginal:
|
||||
pass
|
||||
|
||||
class TestClassDecorated:
|
||||
def decorated_func_bound(self) -> 'TestClassDecorated':
|
||||
pass
|
||||
|
||||
def decorated_func() -> TestClassDecorated:
|
||||
pass
|
||||
|
||||
original_func.__doc__ = """
|
||||
Function description/Parameters
|
||||
|
||||
Returns
|
||||
-------
|
||||
Return value : test_util.TestClassOriginal
|
||||
|
||||
Remaining description
|
||||
"""
|
||||
|
||||
expected = """
|
||||
Function description/Parameters
|
||||
|
||||
Returns
|
||||
-------
|
||||
Return value : test_util.TestClassDecorated
|
||||
|
||||
Remaining description
|
||||
"""
|
||||
assert expected == util._docstringer(original_func,return_type=decorated_func)
|
||||
assert expected == util._docstringer(original_func,return_type=TestClassDecorated.decorated_func_bound)
|
||||
|
|
Loading…
Reference in New Issue