11"""BaseCompoment."""
2- from abc import abstractmethod
2+ from __future__ import annotations
33import os
44from copy import deepcopy
55from weakref import ref
66import numpy as np
77import h5py
88
9- from deepfield .field .parse_utils .ecl_binary import read_ecl_bin
10-
11- from .utils import get_single_path
12-
139from .decorators import apply_to_each_input
1410from .parse_utils import read_array
1511
12+ from typing import TYPE_CHECKING , Callable , Sequence , TypedDict , override
13+
14+ if TYPE_CHECKING :
15+ from .field import Field
16+
17+ class DumpDict (TypedDict ):
18+ attributes : Sequence [Attribute ]
19+ state : State
20+ field : Field | None
21+
1622class Attribute ():
17- def __init__ (self , name = None , section = None , kw = None , custom_loader = None , postprocess = None , not_present = None ,
23+ def __init__ (self , name : str | None = None , section = None , kw = None , custom_loader = None , postprocess = None , not_present = None ,
1824 binary_file = None , binary_section = None , binary_process = None ):
1925
2026 if name is not None :
21- self .name = name
27+ self .name : str = name
2228 else :
2329 if kw is None :
2430 raise ValueError ('Either name or section should be provided.' )
@@ -42,16 +48,19 @@ def __init__(self, name=None, section=None, kw=None, custom_loader=None, postpro
4248 self ._binary_file = binary_file
4349 self ._binary_section = binary_section
4450 self ._binary_process = binary_process
51+ self ._component : Callable [[], BaseComponent | None ] | None = None
4552
4653 def _load_value (self , data , binary_data , logger ):
54+ if self .component is None :
55+ raise ValueError ('Attribute should be associated with `BaseComponent` object.' )
4756 if self ._binary_file is not None :
4857 val = self ._load_ecl_binary_value (binary_data , logger )
4958 else :
5059 val = None
5160 if val is not None :
5261 self ._value = val
62+ self .component .state .binary_attributes .append (self .name )
5363 return self
54- __import__ ('pdb' ).set_trace ()
5564 if self ._custom_loader is not None :
5665 self ._value = self ._custom_loader (data )
5766 return self
@@ -86,6 +95,18 @@ def value(self):
8695 @value .setter
8796 def value (self , value ):
8897 self ._value = value
98+ @property
99+ def component (self ) -> BaseComponent | None :
100+ if self ._component is None :
101+ return None
102+ else :
103+ return self ._component ()
104+ @component .setter
105+ def component (self , value : BaseComponent | None ):
106+ if value is None :
107+ self ._component = value
108+ return None
109+ self ._component = ref (value )
89110
90111MAX_STRLEN = 40
91112
@@ -108,24 +129,22 @@ def __repr__(self):
108129class BaseComponent :
109130 """Base class for components of geological model."""
110131
111- _attributes_to_load = []
132+ _attributes_to_load : list [ Attribute ] = []
112133 def __init__ (self , dump = None , field = None ):
113134 self ._field = None
114135 if dump is not None :
115136 self ._attributes = dump ['attributes' ]
116137 self .field = dump ['field' ]
117138 self ._state = dump ['state' ]
139+ for att in self ._attributes :
140+ att .component = self
118141 return None
119- self ._attributes = []
142+ self ._attributes : list [ Attribute ] = []
120143 self ._state = State ()
121- # self._class_name = kwargs.pop('class_name', self.__class__.__name__)
122144 self .field = field
123- # for k, v in kwargs.items():
124- # if k != 'field':
125- # setattr(self, k, v)
126145
127146 @property
128- def field (self ):
147+ def field (self ) -> Field :
129148 """Field associated with the component."""
130149 return self ._field ()
131150
@@ -139,22 +158,22 @@ def field(self, field):
139158 return self
140159
141160 @property
142- def attributes (self ):
161+ def attributes (self ) -> Sequence [ str ] :
143162 """Array of attributes."""
144163 return tuple ((attr .name for attr in self ._attributes ))
145164
146165 @property
147166 def empty (self ):
148167 """True if component is empty else False."""
149- return not self ._data
168+ return not self ._attributes
150169
151170 def keys (self ):
152171 """Array of attributes."""
153- return self ._data . keys ( )
172+ return ( attr . name for attr in self ._attributes )
154173
155174 def values (self ):
156175 """Returns a generator of attribute's data."""
157- return self ._data . values ( )
176+ return ( attr . value for attr in self ._attributes )
158177
159178 def items (self ):
160179 """Returns pairs of attribute's names and data."""
@@ -202,7 +221,7 @@ def __getattr__(self, key):
202221 if key .upper () == attr .name :
203222 return attr .value
204223 raise AttributeError ("{} has no attribute {}" .format (self .class_name , key ))
205- def dump_dict (self ):
224+ def dump_dict (self ) -> DumpDict :
206225 return {
207226 'attributes' : deepcopy (self ._attributes ),
208227 'field' : self .field ,
@@ -218,22 +237,23 @@ def __setattr__(self, key, value):
218237 for att in self ._attributes :
219238 if key == att .name :
220239 att .value = value
221- return None
240+ return None
222241 raise AttributeError (f'{ self .class_name } has no attribute { key } .' )
223242
224243 def __setitem__ (self , key , value ):
225244 return setattr (self , key , value )
226245
227- def __delattr__ (self , key ):
228- if key .upper () in self ._data :
229- del self ._data [key .upper ()]
246+ @override
247+ def __delattr__ (self , key : str ):
248+ if key .upper () in self .attributes :
249+ self ._attributes = [att for att in self ._attributes if att .name != key .upper ()]
230250 else :
231- raise AttributeError ("{ } has no attribute {}" . format ( self . class_name , key ) )
251+ raise AttributeError (f" { self . class_name } has no attribute { key } " )
232252
233- def __delitem__ (self , key ):
253+ def __delitem__ (self , key : str ):
234254 return delattr (self , key )
235255
236- def __contains__ (self , x ):
256+ def __contains__ (self , x : str ):
237257 return x .upper () in self .attributes
238258
239259 def copy (self ):
@@ -332,40 +352,41 @@ def _get_fmt_loader(self, fmt):
332352 return self ._load_hdf5
333353 raise NotImplementedError ('File format .%s is not supported.' % fmt .upper ())
334354
335- def load (self , path_or_buffer , ** kwargs ):
336- """Load data from a file or buffer.
337-
338- Parameters
339- ----------
340- path_or_buffer : str of string buffer
341- Source to read data from.
342- **kwargs : dict, optional
343- Any kwargs to be passed to load method.
344-
345- Returns
346- -------
347- comp : BaseComponent
348- BaseComponent with loaded attributes.
349- """
350- __import__ ('ipdb' ).set_trace ()
351- if isinstance (path_or_buffer , str ):
352- if os .path .isdir (path_or_buffer ):
353- return self ._load_ecl_binary (path_or_buffer , ** kwargs )
354- name = os .path .basename (path_or_buffer )
355- fmt = os .path .splitext (name )[1 ].strip ('.' )
356- return self ._get_fmt_loader (fmt )(path_or_buffer , ** kwargs )
357- return self ._read_buffer (path_or_buffer , ** kwargs )
355+ # def load(self, path_or_buffer, **kwargs):
356+ # """Load data from a file or buffer.
357+ #
358+ # Parameters
359+ # ----------
360+ # path_or_buffer : str of string buffer
361+ # Source to read data from.
362+ # **kwargs : dict, optional
363+ # Any kwargs to be passed to load method.
364+ #
365+ # Returns
366+ # -------
367+ # comp : BaseComponent
368+ # BaseComponent with loaded attributes.
369+ # """
370+ # __import__('ipdb').set_trace()
371+ # if isinstance(path_or_buffer, str):
372+ # if os.path.isdir(path_or_buffer):
373+ # return self._load_ecl_binary(path_or_buffer, **kwargs)
374+ # name = os.path.basename(path_or_buffer)
375+ # fmt = os.path.splitext(name)[1].strip('.')
376+ # return self._get_fmt_loader(fmt)(path_or_buffer, **kwargs)
377+ # return self._read_buffer(path_or_buffer, **kwargs)
358378
359379 def load (self , data , binary_data , logger ):
360380 """Load data."""
361381 self ._attributes = deepcopy (self ._attributes_to_load )
362382 for attr in self ._attributes :
383+ attr .component = self
363384 attr .load (data , binary_data , logger )
364385
365386
366- def _load_ecl_binary (self , path_to_results , ** kwargs ):
367- """Load data from RESULTS derictory."""
368- raise NotImplementedError ('Load from binary files is not implemented.' )
387+ # def _load_ecl_binary(self, path_to_results, **kwargs):
388+ # """Load data from RESULTS derictory."""
389+ # raise NotImplementedError('Load from binary files is not implemented.')
369390
370391 def _load_hdf5 (self , path , attrs = None , raise_errors = False , logger = None , subset = None , ** kwargs ):
371392 """Load data from a HDF5 file.
@@ -592,48 +613,3 @@ def _dump_ascii(self, path, attrs=None, mode='w', fmt='%f', compressed=True, **k
592613 self .dump_array_ascii (f , data , header = attr .upper (),
593614 fmt = fmt , compressed = compressed )
594615 return self
595-
596- @staticmethod
597- def dump_array_ascii (buffer , array , header = None , fmt = '%f' , compressed = True ):
598- """Writes array-like data into an ASCII buffer.
599-
600- Parameters
601- ----------
602- buffer : buffer-like
603- array : 1d, array-like
604- Array to be saved
605- header : str, optional
606- String to be written line before the array
607- fmt : str or sequence of strs, optional
608- Format to be passed into ``numpy.savetxt`` function. Default to '%f'.
609- compressed : bool
610- If True, uses compressed typing style
611- """
612- if header is not None :
613- buffer .write (header + '\n ' )
614-
615- if compressed :
616- i = 0
617- items_written = 0
618- while i < len (array ):
619- count = 1
620- while (i + count < len (array )) and (array [i + count ] == array [i ]):
621- count += 1
622- if count <= 4 :
623- buffer .write (' ' .join ([fmt % array [i ]] * count ))
624- items_written += count
625- else :
626- buffer .write (str (count ) + '*' + fmt % array [i ])
627- items_written += 1
628- i += count
629- if items_written > MAX_STRLEN :
630- buffer .write ('\n ' )
631- items_written = 0
632- else :
633- buffer .write (' ' )
634- buffer .write ('/\n ' )
635- else :
636- for i in range (0 , len (array ), MAX_STRLEN ):
637- buffer .write (' ' .join ([fmt % d for d in array [i :i + MAX_STRLEN ]]))
638- buffer .write ('\n ' )
639- buffer .write ('/\n ' )
0 commit comments