diff --git a/docs/user_guide/source/api_high/python.rst b/docs/user_guide/source/api_high/python.rst index b6cfb2ff31..a3ee2a01a7 100644 --- a/docs/user_guide/source/api_high/python.rst +++ b/docs/user_guide/source/api_high/python.rst @@ -93,11 +93,17 @@ Python Read "step-by-step" example When reading in stepping mode with the for-in directive, as in the example above, use the step handler (``fstep``) inside the loop rather than the global handler (``fh``) -File class API +High Level API -------------- -.. automodule:: adios2 - :members: open +.. autoclass:: adios2::Stream + :members: + +.. autoclass:: adios2::FileReader + :members: + +.. autoclass:: adios2::Variable + :members: -.. autoclass:: adios2::File +.. autoclass:: adios2::Attribute :members: diff --git a/docs/user_guide/source/conf.py b/docs/user_guide/source/conf.py index 5314e8498c..8be02fe068 100644 --- a/docs/user_guide/source/conf.py +++ b/docs/user_guide/source/conf.py @@ -30,6 +30,7 @@ import os sys.path.insert(0, os.path.abspath('../../../../bindings/Python')) +sys.path.insert(0, os.path.abspath('../../../../python')) extensions = [ 'sphinx.ext.todo', diff --git a/pyproject.toml b/pyproject.toml index 57eefd83fb..3758bbfe84 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -80,3 +80,6 @@ ADIOS2_INSTALL_GENERATE_CONFIG = "OFF" line-length = 99 target-version = ['py38', 'py39', 'py310'] include = 'python/adios2/.*.py|testing/adios2/python/.*.py' + +[tool.pylint] +disable = ['E0401', 'W0102', 'R0904', 'R0913'] diff --git a/python/adios2/__init__.py b/python/adios2/__init__.py index e682d99952..b20f684d70 100644 --- a/python/adios2/__init__.py +++ b/python/adios2/__init__.py @@ -1,4 +1,8 @@ -#!/usr/bin/python3 +""" ADIOS2 high-level API module +License: + Distributed under the OSI-approved Apache License, Version 2.0. See + accompanying file Copyright.txt for details. +""" import adios2.bindings @@ -12,4 +16,5 @@ from adios2.file_reader import * from adios2.bindings import LocalValueDim +__license__ = "Apache-2.0" __version__ = adios2.bindings.__version__ diff --git a/python/adios2/adios.py b/python/adios2/adios.py index f952ec7091..ccf4704db8 100644 --- a/python/adios2/adios.py +++ b/python/adios2/adios.py @@ -1,3 +1,8 @@ +"""License: + Distributed under the OSI-approved Apache License, Version 2.0. See + accompanying file Copyright.txt for details. +""" + from adios2.io import IO from adios2.operator import Operator diff --git a/python/adios2/attribute.py b/python/adios2/attribute.py index 7dfc0deb62..8740a23ae3 100644 --- a/python/adios2/attribute.py +++ b/python/adios2/attribute.py @@ -1,9 +1,23 @@ -import adios2.bindings +"""License: + Distributed under the OSI-approved Apache License, Version 2.0. See + accompanying file Copyright.txt for details. +""" class Attribute: + """High level representation of the Attribute class in the adios2.bindings""" + def __init__(self, io, name, *args, **kwargs): - self._impl = io.DefineAttribute(name, *args, **kwargs) + self.impl = io.DefineAttribute(name, *args, **kwargs) + + @property + def impl(self): + """Bindings implementation of the class""" + return self._impl + + @impl.setter + def impl(self, implementation): + self._impl = implementation def __eq__(self, other): if isinstance(other, Attribute): @@ -11,13 +25,37 @@ def __eq__(self, other): return False def name(self): - return self._impl.Name() + """ + Name of the Attribute + + Returns: + Name of the Attribute as a str. + """ + return self.impl.Name() def type(self): - return self._impl.Type() + """ + Type of the Attribute + + Returns: + Type of the Attribute as a str. + """ + return self.impl.Type() def data(self): - return self._impl.Data() + """ + Content of the Attribute + + Returns: + Content of the Attribute as a non string. + """ + return self.impl.Data() def data_string(self): - return self._impl.DataString() + """ + Content of the Attribute + + Returns: + Content of the Attribute as a str. + """ + return self.impl.DataString() diff --git a/python/adios2/file_reader.py b/python/adios2/file_reader.py index 8fe5d18aa3..15b48e52dc 100644 --- a/python/adios2/file_reader.py +++ b/python/adios2/file_reader.py @@ -1,13 +1,18 @@ +"""License: + Distributed under the OSI-approved Apache License, Version 2.0. See + accompanying file Copyright.txt for details. +""" + from adios2.adios import Adios from adios2.stream import Stream -import adios2.bindings as bindings - -import numpy as np +from adios2 import bindings class FileReader(Stream): + """High level implementation of the FileReader class for read Random access mode""" + def __repr__(self): - return f"" + return f"" def __init__(self, path, comm=None, engine_type="BPStream", config_file=None): self._adios = Adios(comm) @@ -17,4 +22,5 @@ def __init__(self, path, comm=None, engine_type="BPStream", config_file=None): self._engine = self._io.open(path, self._mode) def variables(self): + """Returns the list of variables contained in the opened file""" return [self._io.inquire_variable(var) for var in self.available_variables()] diff --git a/python/adios2/io.py b/python/adios2/io.py index bd6db6775f..55dbc5c5ec 100644 --- a/python/adios2/io.py +++ b/python/adios2/io.py @@ -1,3 +1,8 @@ +"""License: + Distributed under the OSI-approved Apache License, Version 2.0. See + accompanying file Copyright.txt for details. +""" + import numpy as np import adios2.bindings as bindings from adios2.attribute import Attribute @@ -59,10 +64,16 @@ def define_variable( count=[], isConstantDims=False, ): + var_impl = None if isinstance(content, np.ndarray): - return Variable(self._impl, name, content, shape, start, count, isConstantDims) + var_impl = self._impl.DefineVariable( + name, content, shape, start, count, isConstantDims + ) + else: - return Variable(self._impl, name) + var_impl = self._impl.DefineVariable(name) + + return Variable(var_impl) def inquire_variable(self, name): var = None diff --git a/python/adios2/operator.py b/python/adios2/operator.py index a5cc568c54..fb3e70d187 100644 --- a/python/adios2/operator.py +++ b/python/adios2/operator.py @@ -1,17 +1,45 @@ -import adios2.bindings +"""License: + Distributed under the OSI-approved Apache License, Version 2.0. See + accompanying file Copyright.txt for details. +""" + class Operator: - def __init__(self, impl, name): - self._impl = impl + """High level representation of the Attribute class in the adios2.bindings""" + + def __init__(self, implementation, name): + self.impl = implementation self._name = name + @property + def impl(self): + """Bindings implementation of the class""" + return self._impl + + @impl.setter + def impl(self, implementation): + self._impl = implementation + def __eq__(self, other): if isinstance(other, Operator): return self._name == other._name return False def get_parameters(self): - return self._impl.Parameters() + """ + Get parameters associated to this Operator + + Returns: + dict: parameters + """ + return self.impl.Parameters() def set_parameter(self, key, value): - self._impl.SetParameter(key, value) + """ + Set parameter associated to this Operator + + Args: + str: key + str: value + """ + self.impl.SetParameter(key, value) diff --git a/python/adios2/stream.py b/python/adios2/stream.py index 1c2bb05749..11d971fcfc 100644 --- a/python/adios2/stream.py +++ b/python/adios2/stream.py @@ -1,15 +1,16 @@ +"""License: + Distributed under the OSI-approved Apache License, Version 2.0. See + accompanying file Copyright.txt for details. +""" + from adios2.adios import Adios -import adios2.bindings as bindings +from adios2 import bindings import numpy as np -def open(name, mode, engine_type="BPStream", config_file=None): - """Stream object open""" - return Stream(name, mode, engine_type) - - def type_adios_to_numpy(name): + """Translation between numpy and adios2 types""" return { "char": np.int8, "int8_t": np.int8, @@ -26,8 +27,21 @@ def type_adios_to_numpy(name): class Stream: + """High level implementation of the Stream class from the core API""" + def __init__(self, path, mode="r", comm=None, engine_type="BPStream", config_file=None): - self._adios = Adios(comm) + # pylint: disable=E1121 + if config_file: + if comm: + self._adios = Adios(config_file, comm) + else: + self._adios = Adios(config_file) + else: + if comm: + self._adios = Adios(comm) + else: + self._adios = Adios() + # pylint: enable=E1121 self._io_name = f"stream:{path}:engine_type:{engine_type}" self._io = self._adios.declare_io(self._io_name) @@ -44,18 +58,22 @@ def __init__(self, path, mode="r", comm=None, engine_type="BPStream", config_fil @property def mode(self): + """Selected open mode""" return self._mode @property def adios(self): + """Selected open mode""" return self._adios @property def io(self): + """Selected open mode""" return self._io @property def engine(self): + """Selected open mode""" return self._engine def __repr__(self): @@ -153,6 +171,9 @@ def available_attributes(self): return self._io.available_attributes() def define_variable(self, name): + """ + Define new variable without specifying its type and content. + """ return self._io.define_variable(name) def write(self, name, content, shape=[], start=[], count=[], operations=None): @@ -299,8 +320,8 @@ def read_attribute(self, name, variable_name="", separator="/"): if attribute.type() == "string": return attribute.data_string() - else: - return attribute.data() + + return attribute.data() def read_attribute_string(self, name, variable_name="", separator="/"): """ @@ -329,6 +350,14 @@ def read_attribute_string(self, name, variable_name="", separator="/"): return attribute.data_string() def begin_step(self): + """ + Write mode: advances to the next step. Convenient when declaring + variable attributes as advancing to the next step is not attached + to any variable. + + Read mode: in streaming mode releases the current step (no effect + in file based engines) + """ self._engine.begin_step() def end_step(self): @@ -365,6 +394,18 @@ def current_step(self): return self._engine.current_step() def steps(self, num_steps=0): + """ + Returns an interator that can be use to itererate throught the steps. + In each iteration begin_step() and end_step() will be internally called. + + Write Mode: num_steps is a mandatory argument and should specify the number + of steps. + + Read Mode: num_steps should not be used and there will be as much iterations + as steps exits. + + IMPORTANT NOTE: Do not use with ReadRandomAccess mode. + """ if num_steps > 0: self.max_steps = num_steps else: @@ -373,5 +414,6 @@ def steps(self, num_steps=0): self.index = 0 return self - def num_steps(self, num_steps=0): + def num_steps(self): + """READ MODE ONLY. Return the number of steps available.""" return self._engine.steps() diff --git a/python/adios2/variable.py b/python/adios2/variable.py index e72c8d7f40..d06fa12932 100644 --- a/python/adios2/variable.py +++ b/python/adios2/variable.py @@ -1,9 +1,23 @@ -import adios2.bindings +"""License: + Distributed under the OSI-approved Apache License, Version 2.0. See + accompanying file Copyright.txt for details. +""" class Variable: - def __init__(self, io, name, *args, **kwargs): - self._impl = io.DefineVariable(name, *args, **kwargs) + """High level representation of the Attribute class in the adios2.bindings""" + + def __init__(self, implementation): + self.impl = implementation + + @property + def impl(self): + """Bindings implementation of the class""" + return self._impl + + @impl.setter + def impl(self, implementation): + self._impl = implementation def __eq__(self, other): if isinstance(other, Variable): @@ -11,61 +25,185 @@ def __eq__(self, other): return False def block_id(self): - return self._impl.BlockID() + """ + BlockID of this variable. + + Returns: + int: BlockID of this variable. + """ + return self.impl.BlockID() def count(self): - return self._impl.Count() + """ + Current selected count for this variable. + + Returns: + int: Current selected count. + """ + return self.impl.Count() def selection_size(self): - return self._impl.SelectionSize() + """ + Current selection size selected for this variable. + + Returns: + int: Current selection size selected. + """ + return self.impl.SelectionSize() def set_block_selection(self, block_id): - self._impl.SetBlockSelection(block_id) + """ + Set BlockID for this variable. + + Args: + block_id (int): Selected BlockID. + """ + self.impl.SetBlockSelection(block_id) def set_selection(self, selection): - self._impl.SetSelection(selection) + """ + Set selection for this variable. + + Args: + selection (list): list of the shape [[start], [count]], note that start and + count can contain more than one element. + """ + self.impl.SetSelection(selection) def set_shape(self, shape): - self._impl.SetShape(shape) + """ + Set Shape (dimensions) for this variable + + Args: + shape (list): desired shape (dimensions). + """ + self.impl.SetShape(shape) def set_step_selection(self, step_selection): - self._impl.SetStepSelection(step_selection) + """ + Set current step selection (For RRA or ReadRandomAccess) + + Args: + step_selection (list): On the form of [start, count]. + """ + self.impl.SetStepSelection(step_selection) def shape(self, step=0): - return self._impl.Shape(step) + """ + Get the shape assigned to the given step for this variable. + + Args: + step (int): Desired step + + Returns: + list: shape of the specified step in the form of [start, count]. + """ + return self.impl.Shape(step) def shape_id(self): - return self._impl.ShapeID() + """ + Get the ShapeID assigned to this variable. + + Returns: + int: ShapeID assigned to this variable. + """ + return self.impl.ShapeID() def type(self): - return self._impl.Type() + """ + Type of the Variable + + Returns: + str: Type of the Variable. + """ + return self.impl.Type() def single_value(self): - return bool(self._impl.SingleValue()) + """ + Check if this variable is a single value. + + Returns: + bool: true if this variable is a single value. + """ + return bool(self.impl.SingleValue()) def sizeof(self): - return self._impl.Sizeof() + """ + Size in bytes of the contents of the variable. + + Returns: + int: size in bytes of the contents. + """ + return self.impl.Sizeof() def start(self): - return self._impl.Start() + """ + The current selected start of the variable. + + Returns: + int: The current selected start of the variable. + """ + return self.impl.Start() def steps(self): - return self._impl.Steps() + """ + The current selected steps of the variable. + + Returns: + int: The current selected steps of the variable. + """ + return self.impl.Steps() def steps_start(self): - return self._impl.StepsStart() + """ + The avaliable start step, this is needed variables can start + at any time step. This is for ReadRandomAccess. + + Returns: + int: the starting step of for this Variable. + """ + return self.impl.StepsStart() def name(self): - return self._impl.Name() + """ + Name of the Variable + + Returns: + str: Name of the Variable. + """ + return self.impl.Name() def add_operation_string(self, name, params={}): - return self._impl.AddOperation(name, params) + """ + Add an operation (operator) as a string + + Args: + name (str): name of the operation. + params (dict): parameters as a form of a dict for the operation. + """ + return self.impl.AddOperation(name, params) def add_operation(self, op, params={}): - return self._impl.AddOperation(op._impl, params) + """ + Add an operation (operator). + + Args: + name (Operator): name of the operation. + params (dict): parameters as a form of a dict for the operation. + """ + return self.impl.AddOperation(op.impl, params) def operations(self): - return self._impl.Operations() + """ + Current operations (operators) assigned to this Variable. + + Returns: + list(Operators): operators assigned. + """ + return self.impl.Operations() def remove_operations(self): - self._impl.RemoveOperations() + """ + Remove operations (operators) assigned to this Variable. + """ + self.impl.RemoveOperations()