Merge branch 'typehints_config_configmaterial' into 'development'

05 Typehints config configmaterial

See merge request damask/DAMASK!461
This commit is contained in:
Martin Diehl 2022-02-01 07:30:00 +00:00
commit ad74f5dbe1
3 changed files with 79 additions and 38 deletions

View File

@ -2,25 +2,34 @@ import copy
from io import StringIO
from collections.abc import Iterable
import abc
from pathlib import Path
from typing import Union, Dict, Any, Type, TypeVar
import numpy as np
import yaml
from ._typehints import FileHandle
from . import Rotation
MyType = TypeVar('MyType', bound='Config')
class NiceDumper(yaml.SafeDumper):
"""Make YAML readable for humans."""
def write_line_break(self, data=None):
def write_line_break(self,
data: str = None):
super().write_line_break(data)
if len(self.indents) == 1:
super().write_line_break()
def increase_indent(self, flow=False, indentless=False):
def increase_indent(self,
flow: bool = False,
indentless: bool = False):
return super().increase_indent(flow, False)
def represent_data(self, data):
def represent_data(self,
data: Any):
"""Cast Config objects and its subclasses to dict."""
if isinstance(data, dict) and type(data) != dict:
return self.represent_data(dict(data))
@ -31,14 +40,17 @@ class NiceDumper(yaml.SafeDumper):
else:
return super().represent_data(data)
def ignore_aliases(self, data):
def ignore_aliases(self,
data: Any) -> bool:
"""Do not use references to existing objects."""
return True
class Config(dict):
"""YAML-based configuration."""
def __init__(self,yml=None,**kwargs):
def __init__(self,
yml: Union[str, Dict[str, Any]] = None,
**kwargs):
"""Initialize from YAML, dict, or key=value pairs."""
if isinstance(yml,str):
kwargs.update(yaml.safe_load(yml))
@ -47,7 +59,7 @@ class Config(dict):
super().__init__(**kwargs)
def __repr__(self):
def __repr__(self) -> str:
"""Show as in file."""
output = StringIO()
self.save(output)
@ -55,14 +67,15 @@ class Config(dict):
return ''.join(output.readlines())
def __copy__(self):
def __copy__(self: MyType) -> MyType:
"""Create deep copy."""
return copy.deepcopy(self)
copy = __copy__
def __or__(self,other):
def __or__(self: MyType,
other) -> MyType:
"""
Update configuration with contents of other.
@ -76,18 +89,24 @@ class Config(dict):
updated : damask.Config
Updated configuration.
Note
----
This functionality is a backport for Python 3.8
"""
duplicate = self.copy()
duplicate.update(other)
return duplicate
def __ior__(self,other):
def __ior__(self: MyType,
other) -> MyType:
"""Update configuration with contents of other."""
return self.__or__(other)
def delete(self,keys):
def delete(self: MyType,
keys: Union[Iterable, str]) -> MyType:
"""
Remove configuration keys.
@ -109,7 +128,8 @@ class Config(dict):
@classmethod
def load(cls,fname):
def load(cls: Type[MyType],
fname: FileHandle) -> MyType:
"""
Load from yaml file.
@ -124,14 +144,15 @@ class Config(dict):
Configuration from file.
"""
try:
if isinstance(fname, (str, Path)):
fhandle = open(fname)
except TypeError:
else:
fhandle = fname
return cls(yaml.safe_load(fhandle))
def save(self,fname,**kwargs):
def save(self,
fname: FileHandle,
**kwargs):
"""
Save to yaml file.
@ -143,9 +164,9 @@ class Config(dict):
Keyword arguments parsed to yaml.dump.
"""
try:
if isinstance(fname, (str, Path)):
fhandle = open(fname,'w',newline='\n')
except TypeError:
else:
fhandle = fname
if 'width' not in kwargs:

View File

@ -1,10 +1,14 @@
import numpy as np
import h5py
from typing import Sequence, Dict, Any, Collection
from ._typehints import FileHandle
from . import Config
from . import Rotation
from . import Orientation
from . import util
from . import Table
class ConfigMaterial(Config):
"""
@ -17,7 +21,9 @@ class ConfigMaterial(Config):
"""
def __init__(self,d=None,**kwargs):
def __init__(self,
d: Dict[str, Any] = None,
**kwargs):
"""
New material configuration.
@ -30,6 +36,7 @@ class ConfigMaterial(Config):
Initial content specified as pairs of key=value.
"""
default: Collection
if d is None:
for section, default in {'material':[],'homogenization':{},'phase':{}}.items():
if section not in kwargs: kwargs.update({section:default})
@ -37,7 +44,9 @@ class ConfigMaterial(Config):
super().__init__(d,**kwargs)
def save(self,fname='material.yaml',**kwargs):
def save(self,
fname: FileHandle = 'material.yaml',
**kwargs):
"""
Save to yaml file.
@ -53,7 +62,8 @@ class ConfigMaterial(Config):
@classmethod
def load(cls,fname='material.yaml'):
def load(cls,
fname: FileHandle = 'material.yaml') -> 'ConfigMaterial':
"""
Load from yaml file.
@ -72,10 +82,14 @@ class ConfigMaterial(Config):
@staticmethod
def load_DREAM3D(fname,
grain_data=None,cell_data=None,cell_ensemble_data='CellEnsembleData',
phases='Phases',Euler_angles='EulerAngles',phase_names='PhaseName',
base_group=None):
def load_DREAM3D(fname: str,
grain_data: str = None,
cell_data: str = None,
cell_ensemble_data: str = 'CellEnsembleData',
phases: str = 'Phases',
Euler_angles: str = 'EulerAngles',
phase_names: str = 'PhaseName',
base_group: str = None) -> 'ConfigMaterial':
"""
Load DREAM.3D (HDF5) file.
@ -154,7 +168,8 @@ class ConfigMaterial(Config):
@staticmethod
def from_table(table,**kwargs):
def from_table(table: Table,
**kwargs) -> 'ConfigMaterial':
"""
Generate from an ASCII table.
@ -207,7 +222,7 @@ class ConfigMaterial(Config):
@property
def is_complete(self):
def is_complete(self) -> bool:
"""
Check for completeness.
@ -267,12 +282,11 @@ class ConfigMaterial(Config):
if homogenization - set(self['homogenization']):
print(f'Homogenization(s) {homogenization-set(self["homogenization"])} missing')
ok = False
return ok
@property
def is_valid(self):
def is_valid(self) -> bool:
"""
Check for valid content.
@ -316,7 +330,10 @@ class ConfigMaterial(Config):
return ok
def material_rename_phase(self,mapping,ID=None,constituent=None):
def material_rename_phase(self,
mapping: Dict[str, str],
ID: Sequence[int] = None,
constituent: Sequence[int] = None) -> 'ConfigMaterial':
"""
Change phase name in material.
@ -347,7 +364,9 @@ class ConfigMaterial(Config):
return dup
def material_rename_homogenization(self,mapping,ID=None):
def material_rename_homogenization(self,
mapping: Dict[str, str],
ID: Sequence[int] = None) -> 'ConfigMaterial':
"""
Change homogenization name in material.
@ -374,7 +393,8 @@ class ConfigMaterial(Config):
return dup
def material_add(self,**kwargs):
def material_add(self,
**kwargs: Any) -> 'ConfigMaterial':
"""
Add material entries.
@ -453,7 +473,7 @@ class ConfigMaterial(Config):
N = max(N,s[0]) if len(s)>0 else N
n = max(n,s[1]) if len(s)>1 else n
mat = [{'constituents':[{} for _ in range(n)]} for _ in range(N)]
mat: Sequence[dict] = [{'constituents':[{} for _ in range(n)]} for _ in range(N)]
if 'v' not in kwargs:
shaped['v'] = np.broadcast_to(1/n,(N,n))

View File

@ -9,7 +9,7 @@ import re
import fractions
from collections import abc
from functools import reduce
from typing import Union, Tuple, Iterable, Callable, Dict, List, Any, Literal, Optional
from typing import Union, Tuple, Iterable, Callable, Dict, List, Any, Literal, SupportsIndex, Sequence
from pathlib import Path
import numpy as np
@ -427,7 +427,7 @@ def hybrid_IA(dist: np.ndarray,
def shapeshifter(fro: Tuple[int, ...],
to: Tuple[int, ...],
mode: Literal['left','right'] = 'left',
keep_ones: bool = False) -> Tuple[Optional[int], ...]:
keep_ones: bool = False) -> Sequence[SupportsIndex]:
"""
Return dimensions that reshape 'fro' to become broadcastable to 'to'.
@ -483,14 +483,14 @@ def shapeshifter(fro: Tuple[int, ...],
grp = match.groups()
except AssertionError:
raise ValueError(f'Shapes can not be shifted {fro} --> {to}')
fill: Tuple[Optional[int], ...] = ()
fill: Any = ()
for g,d in zip(grp,fro+(None,)):
fill += (1,)*g.count(',')+(d,)
return fill[:-1]
def shapeblender(a: Tuple[int, ...],
b: Tuple[int, ...]) -> Tuple[int, ...]:
b: Tuple[int, ...]) -> Sequence[SupportsIndex]:
"""
Return a shape that overlaps the rightmost entries of 'a' with the leftmost of 'b'.