You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 33 Next »


Introduced changes should work in parallel with existing API (unless it proves impossible)

'Old' methods and classes will be marked as deprecated  


1.  DB_ENTRY

1.1. Class structure:

Class keeps information about one, particular  database entry (eg. pulse-file, HDC container, SQL-database, etc etc)

Class structure siagram


  • db_entry class represents data accessible through Access Layer 
  • hdc_entry , sql_entry  are examples of classes that represents IMAS data entry accessible via other mechanisms than AL (if they will be implemented in future)
  • imas_entry a parent class for all ??_entry classes. It will be implemented in future if any other mechanism of accessing data than AL will be used. Could be empty...  

THIS PAGE FOCUSES ON DESIGN OF DB_ENTRY AND IDS CLASSES ONLY!

1.2. Definition (constructor)

DB Entry  is defined by:

  • backend_id - MDSPLUS_BACKEND, MEMORY_BACKEND, ASCII_BACKEND - mandatory -   
  • db name - eg. test   - mandatory 
  • shot - mandatory
  • run - mandatory
  • user name - eg. g2bpalak  -  optional - if None → $USER
  • data version - e.g. 3 - optional - currently not used,  we should keep it as it will point us to a proper dir in imasdb structure, when we develop versions 4,5, etc  - if None → 3
db_entry constructor
def __init__(self, backend_id, db_name, shot, run, user_name = None, data_version = 3)
	if userName is None:
		user = $USER


Additional "URI-based" constructor will be added in future...

1.3. Create/open/close

All parameters that defines db_entry  are set in constructor, so create, open, close will have no arguments

db_entry create/open/close
def create(self, options = None)
def open(self, options = None)
def close(self, options = None)

options - additional options (possibly backend specific)

1.4. IDS storing /reading

1.4.1. IDS get

IDS GET
def get(self, idsName, occurrence = 0) # idsName (e.g. 'equilibrium') ENUM ?
	wallObj = initialize_ids_obj('wall') 
	wallObj.put(self(db_entry))
	return wallObj

1.4.2. IDS put

IDS PUT
def put(self, ids, occurrence = 0)

1.4.3. IDS putSlice

IDS PUT
def put_slice(self, ids, occurrence = 0)

1.4.4. IDS getSlice

IDS GET
def get_slice(self, ids_name, time_requested, interpolation_method, occurrence=0): # idsName (e.g. 'equilibrium')
	return ids

1.5. Any other method is needed to ba added to db_entry class?

def delete(self, ids_name, occurrence=0):

2. IDS superclass

Parent class for all classes representing particular IDSes. 

2.1. Class  methods (aka "static")

def get_ids(cls, ids_name):

3. IDS class

To be backward compatible or not to be backward compatible, that is the question!

Backward compatibility, understood as possibility of using 'old' and 'new' approach at the same time:

(plus) Can be achieved without big effort, as content of IDS class will not change (a lot)

(plus) All 'old' scripts will work - no modifications needed →  users are happy (smile)

(minus) Currently all methods use context kept in IDS that was a reason of many problems. New API is designed to overcome this issue. Keeping compatibility means that methods still have to be able to use context stored in IDS that is error prone.

(minus) All unwanted, messy methods operating on context stored (setCtx, etc)  must be kept 


Compatibility can be also ensured by introducing new names of methods - putSlice  vs put_slice 

3.1. Class  methods (aka "static")

def get_max_occurrences(cls):

def read_time_mode(self, ctx):

def read_time(self, ctx):

3.2. IDS storing / reading

db_entry  is used to provide explicitly context to methods. This parameter should be mandatory, but is optional to keep compatibility....


def put(self, occurrence=0, db_entry=None):

def get(self, occurrence=0, db_entry=None):

def putSlice(self, occurrence=0, db_entry=None):

def getSlice(self, time_requested, interpolation_method, occurrence=0, db_entry=None):

3.3. Additional methods

def copy_values(self, ids):

def delete_data(self, occurrence=0, db_entry=None ):

def partial_get(self, dataPath, occurrence=0, db_entry=None):

def get_field(self, dataPath, occurrence=0, db_entry=None):


3.4. "Messy" methods

... that are not in line with proposed design but they must be kept to ensure backward compatibility.

def setPulseCtx(self, ctx):
def getPulseCtx(self):


4. Examples

4.1. Backward compatibility

PUTGET
  imasEnv = imas.ids(1111, 1111)
  imasEnv.create_env(user, db_name, dd_version)  
    
  # Mandatory property
  imasEnv.pf_active.ids_properties.homogeneous_time = 2

  imasEnv.pf_active.put()
        
  imasEnv.close()
imasEnv = imas.ids(1111, 1111)
imasEnv.open_env(user, db_name, dd_version)  




imasEnv.pf_active.get()
  
imasEnv.close()



4.2. Storing/reading data via db_entry methods

PUTGET
dbEntry = imas.db_entry(imasdef.MDSPLUS_BACKEND, db_name, 2222, 2222)
dbEntry.create()  
    
ids = pf_active()
# Mandatory property
ids.ids_properties.homogeneous_time = 2

dbEntry.put(ids)

dbEntry.close()
dbEntry = imas.db_entry(imasdef.MDSPLUS_BACKEND, db_name, 2222, 2222)
dbEntry.open()  





ids = dbEntry.get('pf_active')

dbEntry.close()

4.3. Storing/reading data via ids methods

PUTGET
dbEntry = imas.db_entry(imasdef.MDSPLUS_BACKEND, db_name, 3333, 3333)
dbEntry.create()  
    
ids = pf_active()
ids.ids_properties.homogeneous_time = 2

ids.put(db_entry = dbEntry)
dbEntry.close()
dbEntry = imas.db_entry(imasdef.MDSPLUS_BACKEND, db_name, 3333, 3333)
dbEntry.create()  

ids = pf_active()


ids.get(db_entry = dbEntry)
dbEntry.close()

5. TO DO / Open points

5.1. IDS superclass

"Ids" will be a natural name for superclass but "ids" defined in ids.py already exists (the class that contains all IDSes as its attributes).

Will using "Ids" and "ids" be confusing ( "I" vs "i") ? "Ids" superclass will be defined for internal purposes only....

5.2. IDS names

ids = dbEntry.get('pf_active')

To avoid any mistakes, db_entry.get method argument describing IDS should not be a string (ida name - 'equilibrium', 'wall' etc) but a constant value.

It can be implemented using enum or class attribute

5.2.1. Enum

class IDSNames(enum):  #any better name?

     EQUILIBRIUM = 'equilibrium'

     WALL = 'wall' 

etc etc

ids = dbEntry.get(IDSNames.WALL)


e.g. IDSNames.WALL

5.2.2. Given IDS class attribute

e.g. Wall.__name__

ids = dbEntry.get(Wall.__name__)



5.3. Importing IDS classes

  • IDSes are defined in modules (files) corresponding to their names (e.g.  class wall defined in wall.py)
  • A correct usage is
    • from imas import wall;   ids_wall = wall.wall()
    • from imas.wall import wal; ids_wall = wall()
  • lt could be make easier for user adding import in imas __init__.py  (from wall import wall)
    • __init__.py has to be generated based on IDSDef.xml to add from <ids> import <ids>
    • user can use simpler form: "ids_wall = wall()" without doing any explicit imports



Suggestion from Olivier:

could all specific IDS type modules be imported to a front end 'ids' module? so users would do:
wall = ids.wall()
instead of proposed
wall = wall.wall()also this would allow for 'exploring' the available IDS types, while is users need to import module per IDS type user need to know the exact list of types available for a given version


Answer: Requested schema cannot be implemented without breaking backward compatibility due to name clash

Explanation:

  • existing imas.ids is a class (container keeping all IDSes as attributes)
    • it will be not used in new 'scenario' but
    • it should be kept for backward compatibility
    • BTW the issue results from bad decisions took at design time
      • ids class is container for IDSes so its name doesn't correspond to its role
      • according to Py naming convention ids class should be named using capital letters - so IDS 
  • proposed - imas/ids is a package (module/directory) keeping all IDS classes ( <ids>.py)
  • once initialised ids object cannot be both: class and module at the same time


Proposed solution - to change ids package/directory to other name (idses?)






  • No labels