Skip to content

Commit

Permalink
fixes #49 and black format, fixed typing issues
Browse files Browse the repository at this point in the history
  • Loading branch information
Dronakurl committed Dec 11, 2023
1 parent ff390c1 commit 92f2bab
Show file tree
Hide file tree
Showing 8 changed files with 235 additions and 160 deletions.
13 changes: 6 additions & 7 deletions doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
# All configuration values have a default; values that are commented out
# serve to show the default.
import pathlib
import sys

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
Expand Down Expand Up @@ -110,14 +109,14 @@ def about_package(init_posixpath: pathlib.Path) -> dict:
html_theme = "sphinx_rtd_theme"

html_theme_options = {
'collapse_navigation': False,
'display_version': True,
'logo_only': True,
'navigation_depth': 3,
"collapse_navigation": False,
"display_version": True,
"logo_only": True,
"navigation_depth": 3,
}

html_logo = '_static/img/omc_logo.svg'
html_static_path = ['_static']
html_logo = "_static/img/omc_logo.svg"
html_static_path = ["_static"]
html_css_files = ["css/custom.css"]

smartquotes_action = "qe" # renders only quotes and ellipses (...) but not dashes (option: D)
Expand Down
2 changes: 1 addition & 1 deletion sdds/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@
write = write_sdds


__all__ = [read, SddsFile, write, __version__]
__all__ = ["read", "SddsFile", "write", "__version__"]
84 changes: 54 additions & 30 deletions sdds/classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
Implementation are based on documentation at:
https://ops.aps.anl.gov/manuals/SDDStoolkit/SDDStoolkitsu2.html
"""
from typing import Any, Tuple, List, Iterator, Optional, Dict, ClassVar
from dataclasses import dataclass, fields
import logging
import warnings
from dataclasses import dataclass, fields
from typing import Any, ClassVar, Dict, Iterator, List, Optional, Tuple

LOGGER = logging.getLogger(__name__)

Expand All @@ -20,27 +21,31 @@
ENCODING = "utf-8"
ENCODING_LEN = 1

ENDIAN = {'little': '<', 'big': '>'}
ENDIAN = {"little": "<", "big": ">"}

NUMTYPES = {"float": "f", "double": "d", "short": "i2",
"long": "i4", "llong": "i8", "char": "i1", "boolean": "i1",
"string": "s"}
NUMTYPES_SIZES = {"float": 4, "double": 8, "short": 2,
"long": 4, "llong": 8, "char": 1, "boolean": 1}
NUMTYPES_CAST = {"float": float, "double": float, "short": int,
"long": int, "llong": int, "char": str, "boolean": int}
NUMTYPES = {
"float": "f",
"double": "d",
"short": "i2",
"long": "i4",
"llong": "i8",
"char": "i1",
"boolean": "i1",
"string": "s",
}
NUMTYPES_SIZES = {"float": 4, "double": 8, "short": 2, "long": 4, "llong": 8, "char": 1, "boolean": 1}
NUMTYPES_CAST = {"float": float, "double": float, "short": int, "long": int, "llong": int, "char": str, "boolean": int}


def get_dtype_str(type_: str, endianness: str = 'big', length: int = None):
if length is None:
length = ''
return f"{ENDIAN[endianness]}{length}{NUMTYPES[type_]}"
def get_dtype_str(type_: str, endianness: str = "big", length: Optional[int] = None):
return f"{ENDIAN[endianness]}{length if length is not None else ''}{NUMTYPES[type_]}"


##############################################################################
# Classes
##############################################################################


@dataclass
class Description:
"""
Expand All @@ -51,17 +56,22 @@ class Description:
contents, is intended to formally specify the type of data stored in a data set. Most
frequently, the contents field is used to record the name of the program that created or most
recently modified the file.
Fields:
text (str): Optional. Informal description intended for humans.
contents (str): Optional. Formal specification of the type of data stored in a data set.
"""

text: Optional[str] = None
contents: Optional[str] = None
TAG: ClassVar[str] = "&description"

def __repr__(self):
return f"<SDDS Description Container>"
return "<SDDS Description Container>"

def get_key_value_string(self) -> str:
warnings.warn("no implemented yet")
return ""


@dataclass
Expand All @@ -75,10 +85,11 @@ class Include:
Fields:
filename (str): Name of the file to be read containing header lines.
"""

filename: str

def __repr__(self):
return f"<SDDS Include Container>"
return "<SDDS Include Container>"

def __str__(self):
return f"Include: {self.filename:s}"
Expand Down Expand Up @@ -106,12 +117,14 @@ class Definition:
(e.g. for ASCII in SDDS or other formats). NOT IMPLEMENTED!
"""

name: str
type: str
symbol: Optional[str] = None
units: Optional[str] = None
description: Optional[str] = None
format: Optional[str] = None
TAG: ClassVar[Optional[str]] = None

def __post_init__(self):
# Fix types (probably strings from reading files) by using the type-hints
Expand All @@ -130,20 +143,19 @@ def __post_init__(self):
continue

# find the proper type from type-hint:
hinted_type = next(t for t in hinted_type.__args__
if not isinstance(t, type(None)))
hinted_type = next(t for t in hinted_type.__args__ if not isinstance(t, type(None)))

if isinstance(value, hinted_type):
# all is fine
continue

LOGGER.debug(f"converting {field.name}: "
f"{type(value).__name__} -> {hinted_type.__name__}")
LOGGER.debug(f"converting {field.name}: " f"{type(value).__name__} -> {hinted_type.__name__}")
setattr(self, field.name, hinted_type(value))

def get_key_value_string(self) -> str:
""" Return a string with comma separated key=value pairs.
Hint: `ClassVars` (like ``TAG``) are ignored in `fields`.
"""Return a string with comma separated key=value pairs.
Hint: `ClassVars` (like ``TAG``) are ignored in `fields`.
"""
field_values = {field.name: getattr(self, field.name) for field in fields(self)}
return ", ".join([f"{key}={value}" for key, value in field_values.items() if value is not None])
Expand All @@ -152,7 +164,7 @@ def __repr__(self):
return f"<SDDS {self.__class__.__name__} '{self.name}'>"

def __str__(self):
return f"<{self.__class__.__name__} ({getattr(self, 'TAG', 'no tag')})> {self.get_key_value_string()}"
return f"<{self.__class__.__name__} ({self.TAG or 'no tag'})> {self.get_key_value_string()}"


@dataclass
Expand All @@ -163,6 +175,7 @@ class Column(Definition):
This optional command defines a column that will appear in the tabular data section of each
data page.
"""

TAG: ClassVar[str] = "&column"


Expand All @@ -181,6 +194,7 @@ class Parameter(Definition):
This feature is for convenience only;
the parameter thus defined is treated like any other.
"""

TAG: ClassVar[str] = "&parameter"
fixed_value: Optional[str] = None

Expand All @@ -203,6 +217,7 @@ class Array(Definition):
dimensions (int): Optional. Gives the number of dimensions in the array.
If not given, defaults to ``1`` upon reading.
"""

TAG: ClassVar[str] = "&array"
field_length: Optional[int] = None
group_name: Optional[str] = None
Expand All @@ -220,12 +235,17 @@ class Data:
Fields:
mode (str): File/Data mode. Either “binary” or "ascii".
"""

mode: str
TAG: ClassVar[str] = "&data"

def __repr__(self):
return f"<SDDS {self.mode} Data Container>"

def get_key_value_string(self) -> str:
warnings.warn("no implemented yet")
return ""


class SddsFile:
"""
Expand Down Expand Up @@ -257,14 +277,19 @@ class SddsFile:
values (dict[str, Any]): Values of the data, mapped to their name.
"""

version: str # This should always be "SDDS1"
description: Optional[Description]
definitions: Dict[str, Definition]
values: Dict[str, Any]

def __init__(self, version: str, description: Optional[Description],
definitions_list: List[Definition],
values_list: List[Any]) -> None:
def __init__(
self,
version: str,
description: Optional[Description],
definitions_list: List[Definition],
values_list: List[Any],
) -> None:
self.version = version

name_list = [definition.name for definition in definitions_list]
Expand All @@ -273,8 +298,7 @@ def __init__(self, version: str, description: Optional[Description],

self.description = description
self.definitions = {definition.name: definition for definition in definitions_list}
self.values = {definition.name: value for definition, value
in zip(definitions_list, values_list)}
self.values = {definition.name: value for definition, value in zip(definitions_list, values_list)}

def __getitem__(self, name: str) -> Tuple[Definition, Any]:
return self.definitions[name], self.values[name]
Expand All @@ -284,7 +308,7 @@ def __iter__(self) -> Iterator[Tuple[Definition, Any]]:
yield self[def_name]

def __repr__(self):
return f"<SDDS-File Object>"
return "<SDDS-File Object>"

def __str__(self):
return f"SDDS-File ({self.version})" # TODO make something nice
Loading

0 comments on commit 92f2bab

Please sign in to comment.