From d1c8d41ec2f6d1133af076b3c25bedc994f23d02 Mon Sep 17 00:00:00 2001 From: Oliver Beckstein Date: Wed, 8 Jul 2026 14:05:45 -0700 Subject: [PATCH 1/2] fixed initialization of DXClasses - updated init signature of OpenDX.DXClass to include name and components - consistently use super() in DXClass-child classes - use zero-arg super() calls --- CHANGELOG | 10 ++++++++++ gridData/OpenDX.py | 40 +++++++++++++++++++++------------------- 2 files changed, 31 insertions(+), 19 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 0beb1f0..45ce4fb 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -13,6 +13,16 @@ The rules for this file: * accompany each entry with github issue/PR number (Issue #xyz) ------------------------------------------------------------------------------- +MM/DD/2026 orbeckst + + * 1.3.0 + + Changes + + * update init signature for OpenDX.DXClass to include name and components + as optional kwargs to streamline init in child classes (PR #179) + + 05/22/2026 orbeckst, spyke7 * 1.2.0 diff --git a/gridData/OpenDX.py b/gridData/OpenDX.py index 5cf2617..a6e4d63 100644 --- a/gridData/OpenDX.py +++ b/gridData/OpenDX.py @@ -229,12 +229,12 @@ def _gzip_open(filename, mode="rt"): class DXclass(object): """'class' object as defined by OpenDX""" - def __init__(self, classid): + def __init__(self, classid, name=None, component=None): """id is the object number""" self.id = classid # serial number of the object - self.name = None # name of the DXclass - self.component = None # component type - self.D = None # dimensions + self.name = name # name of the DXclass + self.component = component # component type + self.D = 3 # dimensions def write(self, stream, optstring="", quote=False): """write the 'object' line; additional args are packed in string""" @@ -279,12 +279,13 @@ class gridpositions(DXclass): def __init__(self, classid, shape=None, origin=None, delta=None, **kwargs): if shape is None or origin is None or delta is None: raise ValueError("all keyword arguments are required") - self.id = classid - self.name = "gridpositions" - self.component = "positions" + super().__init__(classid, + name="gridpositions", + component="positions") self.shape = numpy.asarray(shape) # D dimensional shape self.origin = numpy.asarray(origin) # D vector self.rank = len(self.shape) # D === rank + assert self.rank == self.D, "DXClass is only used for 3D arrays" self.delta = numpy.asarray(delta) # DxD array of grid spacings # gridDataFormats actually provides a simple 1D array with the deltas because only @@ -301,7 +302,7 @@ def __init__(self, classid, shape=None, origin=None, delta=None, **kwargs): ) def write(self, stream): - super(gridpositions, self).write( + super().write( stream, ("counts " + self.ndformat(" %d")) % tuple(self.shape) ) self._write_line(stream, "origin %f %f %f\n" % tuple(self.origin)) @@ -329,9 +330,9 @@ class gridconnections(DXclass): def __init__(self, classid, shape=None, **kwargs): if shape is None: raise ValueError("all keyword arguments are required") - self.id = classid - self.name = "gridconnections" - self.component = "connections" + super().__init__(classid, + name="gridconnections", + component="connections") self.shape = numpy.asarray(shape) # D dimensional shape def write(self, stream): @@ -410,9 +411,9 @@ def __init__(self, classid, array=None, type=None, typequote='"', **kwargs): """ if array is None: raise ValueError("array keyword argument is required") - self.id = classid - self.name = "array" - self.component = "data" + super().__init__(classid, + name="array", + component="data") # detect type https://github.com/MDAnalysis/GridDataFormats/issues/35 if type is None: self.array = numpy.asarray(array) @@ -464,7 +465,7 @@ def write(self, stream): ).format(self.type, list(self.dx_types.keys())) ) typelabel = self.typequote + self.type + self.typequote - super(array, self).write( + super().write( stream, "type {0} rank 0 items {1} data follows".format(typelabel, self.array.size), ) @@ -544,6 +545,10 @@ def __init__(self, classid="0", components=None, comments=None): dx = OpenDX.field('density',[gridpoints,gridconnections,array]) """ + super().__init__(classid, # can be an arbitrary string + name="field", + component=None, # cannot be a component of a field + ) if components is None: components = dict(positions=None, connections=None, data=None) if comments is None: @@ -553,9 +558,6 @@ def __init__(self, classid="0", components=None, comments=None): ] elif type(comments) is not list: comments = [str(comments)] - self.id = classid # can be an arbitrary string - self.name = "field" - self.component = None # cannot be a component of a field self.components = components self.comments = comments @@ -647,7 +649,7 @@ def write(self, filename): for component, object in self.sorted_components(): object.write(outfile) # the field object itself - super(field, self).write(outfile, quote=True) + super().write(outfile, quote=True) for component, object in self.sorted_components(): self._write_line( outfile, 'component "%s" value %s\n' % (component, str(object.id)) From 824b4af3e807098497c857d64870132e738e4529 Mon Sep 17 00:00:00 2001 From: Oliver Beckstein Date: Wed, 8 Jul 2026 14:11:17 -0700 Subject: [PATCH 2/2] reformatted OpenDX.py with black --- gridData/OpenDX.py | 44 ++++++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/gridData/OpenDX.py b/gridData/OpenDX.py index a6e4d63..3e5e9bc 100644 --- a/gridData/OpenDX.py +++ b/gridData/OpenDX.py @@ -202,6 +202,7 @@ :members: """ + import numpy import re import gzip @@ -279,9 +280,7 @@ class gridpositions(DXclass): def __init__(self, classid, shape=None, origin=None, delta=None, **kwargs): if shape is None or origin is None or delta is None: raise ValueError("all keyword arguments are required") - super().__init__(classid, - name="gridpositions", - component="positions") + super().__init__(classid, name="gridpositions", component="positions") self.shape = numpy.asarray(shape) # D dimensional shape self.origin = numpy.asarray(origin) # D vector self.rank = len(self.shape) # D === rank @@ -302,9 +301,7 @@ def __init__(self, classid, shape=None, origin=None, delta=None, **kwargs): ) def write(self, stream): - super().write( - stream, ("counts " + self.ndformat(" %d")) % tuple(self.shape) - ) + super().write(stream, ("counts " + self.ndformat(" %d")) % tuple(self.shape)) self._write_line(stream, "origin %f %f %f\n" % tuple(self.origin)) for delta in self.delta: self._write_line( @@ -330,9 +327,7 @@ class gridconnections(DXclass): def __init__(self, classid, shape=None, **kwargs): if shape is None: raise ValueError("all keyword arguments are required") - super().__init__(classid, - name="gridconnections", - component="connections") + super().__init__(classid, name="gridconnections", component="connections") self.shape = numpy.asarray(shape) # D dimensional shape def write(self, stream): @@ -411,9 +406,7 @@ def __init__(self, classid, array=None, type=None, typequote='"', **kwargs): """ if array is None: raise ValueError("array keyword argument is required") - super().__init__(classid, - name="array", - component="data") + super().__init__(classid, name="array", component="data") # detect type https://github.com/MDAnalysis/GridDataFormats/issues/35 if type is None: self.array = numpy.asarray(array) @@ -545,10 +538,11 @@ def __init__(self, classid="0", components=None, comments=None): dx = OpenDX.field('density',[gridpoints,gridconnections,array]) """ - super().__init__(classid, # can be an arbitrary string - name="field", - component=None, # cannot be a component of a field - ) + super().__init__( + classid, # can be an arbitrary string + name="field", + component=None, # cannot be a component of a field + ) if components is None: components = dict(positions=None, connections=None, data=None) if comments is None: @@ -586,8 +580,8 @@ def from_grid(cls, grid, type=None, typequote='"', **kwargs): ------- field OpenDX field wrapper - - + + .. versionadded:: 1.2.0 """ comments = [ @@ -614,10 +608,10 @@ def from_grid(cls, grid, type=None, typequote='"', **kwargs): @property def native(self): """Return native object - + The "native" object is the :class:`gridData.OpenDX.field` itself. - - + + .. versionadded:: 1.2.0 """ return self @@ -685,9 +679,11 @@ def read(self, stream): except (UnicodeDecodeError, RecursionError) as err: # parser got confused, likely not a valid file # (RecursionError was only observed on Windows) - raise ValueError("DX file could not be read. " - "The original error was\n" - f" {err.__class__.__name__}: {err}") + raise ValueError( + "DX file could not be read. " + "The original error was\n" + f" {err.__class__.__name__}: {err}" + ) def add(self, component, DXobj): """add a component to the field"""