import json
import logging
# The standard library OrderedDict was introduced in Python 2.7 so
# we have a third-party option to support Python 2.6
try:
from collections import OrderedDict
except ImportError:
from ordereddict import OrderedDict
import numpy as np
logger = logging.getLogger(__name__)
[docs]class CurveItem(HeaderItem):
'''Dictionary/namedtuple-style object for a LAS curve.
See :class:`lasio.las_items.HeaderItem`` for the (keyword) arguments.
Keyword Arguments:
data (array-like, 1-D): the curve's data.
'''
[docs] def __init__(self, mnemonic='', unit='', value='', descr='', data=None):
if data is None:
data = []
super(CurveItem, self).__init__(mnemonic, unit, value, descr)
self.data = np.asarray(data)
@property
def API_code(self):
'''Equivalent to the ``value`` attribute.'''
return self.value
[docs] def __repr__(self):
return (
'%s(mnemonic=%s, unit=%s, value=%s, '
'descr=%s, original_mnemonic=%s, data.shape=%s)' % (
self.__class__.__name__, self.mnemonic, self.unit, self.value,
self.descr, self.original_mnemonic, self.data.shape))
@property
def json(self):
return json.dumps({
'_type': self.__class__.__name__,
'mnemonic': self.original_mnemonic,
'unit': self.unit,
'value': self.value,
'descr': self.descr,
'data': list(self.data),
})
@json.setter
def json(self, value):
raise Exception('Cannot set objects from JSON')
[docs]class SectionItems(list):
'''Variant of a ``list`` which is used to represent a LAS section.
'''
[docs] def __init__(self, *args, **kwargs):
super(SectionItems, self).__init__(*args, **kwargs)
super(SectionItems, self).__setattr__('mnemonic_transforms', False)
[docs] def __str__(self):
rstr_lines = []
data = [['Mnemonic', 'Unit', 'Value', 'Description'],
['--------', '----', '-----', '-----------']]
data += [[str(x) for x in [item.mnemonic, item.unit, item.value,
item.descr]] for item in self]
col_widths = []
for i in range(len(data[0])):
col_widths.append(max([len(row[i]) for row in data]))
for row in data:
line_items = []
for i, item in enumerate(row):
line_items.append(item.ljust(col_widths[i] + 2))
rstr_lines.append(''.join(line_items))
return '\n'.join(rstr_lines)
def mnemonic_compare(self, one, two):
if self.mnemonic_transforms:
try:
if one.upper() == two.upper():
return True
except AttributeError:
pass
else:
if one == two:
return True
return False
[docs] def __contains__(self, testitem):
'''Check whether a header item or mnemonic is in the section.
Arguments:
testitem (HeaderItem, CurveItem, str): either an item or a mnemonic
Returns:
bool
'''
for item in self:
if self.mnemonic_compare(testitem, item.mnemonic):
return True
elif hasattr(testitem, 'mnemonic'):
if self.mnemonic_compare(testitem.mnemonic, item.mnemonic):
return True
elif testitem is item:
return True
else:
return False
[docs] def keys(self):
'''Return mnemonics of all the HeaderItems in the section.'''
return [item.mnemonic for item in self]
[docs] def values(self):
'''Return HeaderItems in the section.'''
return self
[docs] def items(self):
'''Return pairs of (mnemonic, HeaderItem) from the section.'''
return [(item.mnemonic, item) for item in self]
def iterkeys(self):
return iter(self.keys())
def itervalues(self):
return iter(self)
def iteritems(self):
return iter(self.items())
[docs] def __getslice__(self, i0, i1):
'''For Python 2.7 compatibility.'''
return self.__getitem__(slice(i0, i1))
[docs] def __getitem__(self, key):
'''Item-style access by either mnemonic or index.
Arguments:
key (str, int, slice): either a mnemonic or the index to the list.
Returns:
item from the list (either HeaderItem or CurveItem)
'''
if isinstance(key, slice):
return SectionItems(super(SectionItems, self).__getitem__(key))
for item in self:
if self.mnemonic_compare(item.mnemonic, key):
return item
if isinstance(key, int):
return super(SectionItems, self).__getitem__(key)
else:
raise KeyError('%s not in %s' % (key, self.keys()))
[docs] def __delitem__(self, key):
'''Delete item by either mnemonic or index.
Arguments:
key (str, int): either a mnemonic or the index to the list.
'''
for ix, item in enumerate(self):
if self.mnemonic_compare(item.mnemonic, key):
super(SectionItems, self).__delitem__(ix)
return
if isinstance(key, int):
super(SectionItems, self).__delitem__(key)
return
else:
raise KeyError('%s not in %s' % (key, self.keys()))
[docs] def __setitem__(self, key, newitem):
'''Either replace the item or its value.
Arguments:
key (int, str): either the mnemonic or the index.
newitem (HeaderItem or str/float/int): the thing to be set.
If ``newitem`` is a :class:`lasio.las_items.HeaderItem` then the
existing item will be replaced. Otherwise the existing item's ``value``
attribute will be replaced.
i.e. this allows us to do
>>> from lasio import SectionItems, HeaderItem
>>> section = SectionItems(
... [HeaderItem(mnemonic="OPERATOR", value="John")]
... )
>>> section.OPERATOR
HeaderItem(mnemonic=OPERATOR, unit=, value=John, descr=)
>>> section.OPERATOR = 'Kent'
>>> section.OPERATOR
HeaderItem(mnemonic=OPERATOR, unit=, value=Kent, descr=)
See :meth:`lasio.las_items.SectionItems.set_item` and
:meth:`lasio.las_items.SectionItems.set_item_value`.
'''
if isinstance(newitem, HeaderItem):
self.set_item(key, newitem)
else:
self.set_item_value(key, newitem)
[docs] def __getattr__(self, key):
'''Provide attribute access via __contains__ e.g.
>>> from lasio import SectionItems, HeaderItem
>>> section = SectionItems(
... [HeaderItem(mnemonic="VERS", value=1.2)]
... )
>>> section['VERS']
HeaderItem(mnemonic=VERS, unit=, value=1.2, descr=)
>>> 'VERS' in section
True
>>> section.VERS
HeaderItem(mnemonic=VERS, unit=, value=1.2, descr=)
'''
known_attrs = ['mnemonic_transforms', ]
if not key in known_attrs:
if key in self:
return self[key]
super(SectionItems, self).__getattr__(key)
[docs] def __setattr__(self, key, value):
'''Allow access to :meth:`lasio.las_items.SectionItems.__setitem__`
via attribute access.
'''
if key in self:
self[key] = value
else:
super(SectionItems, self).__setattr__(key, value)
[docs] def set_item(self, key, newitem):
'''Replace an item by comparison of session mnemonics.
Arguments:
key (str): the item mnemonic (or HeaderItem with mnemonic)
you want to replace.
newitem (HeaderItem): the new item
If **key** is not present, it appends **newitem**.
'''
for i, item in enumerate(self):
if self.mnemonic_compare(key, item.mnemonic):
# This is very important. We replace items where
# 'mnemonic' is equal - i.e. we do not check
# against useful_mnemonic or original_mnemonic.
return super(SectionItems, self).__setitem__(i, newitem)
else:
self.append(newitem)
[docs] def set_item_value(self, key, value):
'''Set the ``value`` attribute of an item.
Arguments:
key (str): the mnemonic of the item (or HeaderItem with the
mnemonic) you want to edit
value (str, int, float): the new value.
'''
self[key].value = value
[docs] def append(self, newitem):
'''Append a new HeaderItem to the object.'''
super(SectionItems, self).append(newitem)
self.assign_duplicate_suffixes(newitem.useful_mnemonic)
[docs] def insert(self, i, newitem):
'''Insert a new HeaderItem to the object.'''
super(SectionItems, self).insert(i, newitem)
self.assign_duplicate_suffixes(newitem.useful_mnemonic)
[docs] def assign_duplicate_suffixes(self, test_mnemonic=None):
'''Check and re-assign suffixes for duplicate mnemonics.
Arguments:
test_mnemonic (str, optional): check for duplicates of
this mnemonic. If it is None, check all mnemonics.
'''
if test_mnemonic is None:
for test_mnemonic in {i.useful_mnemonic for i in self}:
self.assign_duplicate_suffixes(test_mnemonic)
else:
existing = [item.useful_mnemonic for item in self]
locations = []
for i, item in enumerate(self):
if self.mnemonic_compare(item.useful_mnemonic, test_mnemonic):
locations.append(i)
if len(locations) > 1:
current_count = 1
for i, loc in enumerate(locations):
item = self[loc]
item.set_session_mnemonic_only(item.useful_mnemonic + ':%d'
% (i + 1))
[docs] def dictview(self):
'''View of mnemonics and values as a dict.
Returns:
dict - keys are the mnemonics and the values are the ``value``
attributes.
'''
return dict(zip(self.keys(), [i.value for i in self.values()]))
@property
def json(self):
return json.dumps(
[item.json for item in self.values()])
@json.setter
def json(self, value):
raise Exception('Cannot set objects from JSON')