ISCE_INSAR/components/iscesys/Parsers/rdf/data/files.py

266 lines
8.3 KiB
Python
Raw Normal View History

2019-01-16 19:40:08 +00:00
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Copyright 2014 California Institute of Technology. ALL RIGHTS RESERVED.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# United States Government Sponsorship acknowledged. This software is subject to
# U.S. export control laws and regulations and has been classified as 'EAR99 NLR'
# (No [Export] License Required except when exporting to an embargoed country,
# end user, or in support of a prohibited end use). By downloading this software,
# the user agrees to comply with all applicable U.S. export laws and regulations.
# The user has the responsibility to obtain export licenses, or other export
# authority as may be required before exporting this software to any 'EAR99'
# embargoed foreign country or citizen of those countries.
#
# Author: Eric Belz
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"""data-->RDF is THE RDF OBJECT"""
##\namespace rdf.data.files Usable data object for files.
import sys
import collections
#pylint:disable=E1101
try:
DICT = collections.OrderedDict
except AttributeError:
print >> sys.stderr, "Not 2.7: using (UnOrdered) dict for rdf mapping"
DICT = dict
## An RDF Mothership: A fully interpresed RDF File.
class RDF(object):
"""RDF object is made from the read_rdf helper function:
>>>data = rdf_reader('rdf.txt')
It is an associate array, so like a dict:
>>>data[key]
returns a value- as a float or string-or whatever "eval" returns.
All the standard OrderDict methods can be used, and will return the
full RDFField object that represent the value, units, dimension....
comments.
You may __setitem__:
>>>rdf[key] = value #equivalent to
>>>rdf[key] = RDFField(value)
That is, it transforms assignee into an RDFField for you.
"""
## Make an instance from DICT argument
## \param dict_ is an rdf-enough dictionary
## \return RDF instance
@classmethod
def fromdict(cls, dict_):
"""instantiate from a DICT"""
result = cls()
for key, value in dict_.items():
result[key.strip()] = value
return result
## Make it from keyword arguments
## \param *args is an rdf-enough arguments (like dict)
## \param **dict_ is an rdf-enough dictionary
## \return RDF instance
@classmethod
def fromstar(cls, *args, **dict_):
"""instantiate from *args **dict_)"""
# todo: (dict(*args) + dict_)
rdf_ = cls()
for pair in args:
key, value = pair
rdf_[str(key)] = value
pass
return rdf_ + cls.fromdict(dict_)
## Instaniate from a file
## \param src RDF file name
## \retval RDF an rdf instance
@staticmethod
def fromfile(src):
"""src -> RDF"""
from iscesys.Parsers.rdf import rdfparse
return rdfparse(src)
## \verb{ rdf << src } Sucks up an new rdf file.
## \param src RDF file name
## \returns src + RDF
def __lshift__(self, src):
return self + self.__class__.fromfile(src)
def __ilshift__(self, src):
return self<<src
## Don't use init-- it's internal.
## \param *args Internal constructor takes *args
def __init__(self, *args):
"""RDF(*args)
"""
## The data are an associative array-or the rdf spec is worthless.
self.data = DICT(args)
## Get attr from ::DICT If needed
## \param attr Attritubute
## \retval self.attr OR
## \retval self.data.attr If needed
def __getattr__(self, attr):
try:
result = object.__getattribute__(self, attr)
except AttributeError:
result = getattr(self.data, attr)
return result
@property
def rdf(self):
return self
## Return value, vs "get" returns RDFField
def __getitem__(self, key):
return self.data[key].value
## Set the item to an RDFField
## \param key an RDF key
## \param value any kind of value
## \par Side Effects:
## assigns key in RDF.data with RDFField value
## \returns None
def __setitem__(self, key, value):
from rdf.data.entries import RDFField
# Service If: convert to RDFField so you don't have to
if not isinstance(value, RDFField):
value = RDFField(value)
self.data[key] = value
## Delete key, field
## \param key an RDF key
## \par Side Effects:
## deletes key from RDF.data
## \returns None
def __delitem__(self, key):
self.data.__delitem__(key)
## iteritems()
def __iter__(self):
return iter(self.data.iteritems())
## Access as method or property (this is really for clients)
def __call__(self):
"""self()->self so that x.rdf()()-->x.rdf()->x.rdf"""
return self
def record(self, key):
"""convery self[key] to an RDFRecord"""
from iscesys.Parsers.rdf.data.entries import RDFRecord
field = self.get(key)
return RDFRecord(key, field)
def records(self):
"""Get all records from record()"""
return map(self.record, self.keys())
## Get maximum index (column) of OPERATOR in file's strings
def _max_index(self):
return max(map(int, self.records()))
def __str__(self):
from iscesys.Parsers.rdf.data.entries import RDFRecord
max_index = self._max_index()
## now insert space...
final_result = []
for record in self.records():
line = record.__str__(index=max_index)
final_result.append(line + '\n')
return "".join(final_result)
## rep the data attribute
def __repr__(self):
return repr(self.data)
def __len__(self):
return len(self.data)
## rdf >> dst \\n
## see tofile().
def __rshift__(self, dst):
return self.tofile(dst)
## Add is concatenation, and is not communative
## \param other An RDF instance
## \retval result Is another RDF instance
def __add__(self, other):
result = RDF()
for key, field in self.items():
result[key] = field
for key, field in other.items():
if result.has_key(key): #Guard
print ("WARNING: overwritting:", key)
result[key] = field
return result
## Incremental add an RDFRecord - very non polymorphic implementation...
## This is not pythonic and need fixing-the desibn flaw lies in
## either parse.py or the RDF spc itself
## \param other Could be RDF, tuple, list, other...
def __iadd__(self, other):
"""You can increment with:
Another RDF:
OR RecursiveRecord or RDF
this is in development
"""
if other:
if isinstance(other, self.__class__):
self = self + other
elif isinstance(other, tuple):
self[other[0]] = other[1]
elif isinstance(other, list):
for item in other:
self += item
else:
try:
self = self + other.rdf()
except AttributeError:
raise TypeError(
"Can't add type:" + other.__class__.__name__
)
return self
## Write to file, with some formatting
## \param dst file name (writable)
## \par Side Effects:
## writes dst
## \returns
def tofile(self, dst):
"""write data to a file"""
with open(dst, 'w') as fdst:
fdst.write(str(self))
## return dst to make idempotent
return dst
## Convert to a standard (key, value) ::DICT
def todict(self):
"""Convert to a normal dict()"""
result = {}
for key, field in self.iteritems():
result.update( {key : field()} )
return result