Skip to content

Commit

Permalink
Add SectionItems.get method - fixes #322 (#510)
Browse files Browse the repository at this point in the history
* Add tests for #322

* Add SectionsItems.get method (#322)

* Update docstring for SectionItems.get

* Update docs for #322

* Add additional test for #322

* Add SectionItems.get(..., add=True) to docs
  • Loading branch information
kinverarity1 authored May 13, 2022
1 parent 357cec6 commit 8aafe04
Show file tree
Hide file tree
Showing 7 changed files with 210 additions and 4 deletions.
52 changes: 51 additions & 1 deletion docs/source/changelog.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,55 @@
List of changes
===============================

Unreleased changes (Available on GitHub)
----------------------------------------
- Fix `#322`_ - provide a way to consistently retrieve header items which may
or may not be present in the header:

If you try ordinary item-style access,
as is normal in Python, a KeyError exception will be raised if it is missing:

.. code-block:: python
>>> permit = las.well['PRMT']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "c:\devapps\kinverarity\projects\lasio\lasio\las_items.py", line 313, in __getitem__
raise KeyError("%s not in %s" % (key, self.keys()))
KeyError: "PRMT not in ['STRT', 'STOP', 'STEP', 'NULL', 'COMP', 'WELL', 'FLD', 'LOC', 'PROV', 'SRVC', 'DATE', 'UWI']"
A better pattern is to use the :meth:`lasio.SectionItems.get` method, which
allows you to specify a default value in the case of it missing:

.. code-block:: python
>>> permit = las.well.get('PRMT', 'unknown')
>>> permit
HeaderItem(mnemonic="PRMT", unit="", value="unknown", descr="")
You can use the ``add=True`` keyword argument if you would like this
header item to be added, as well as returned:

.. code-block:: python
>>> permit = las.well.get('PRMT', 'unknown', add=True)
>>> las.well
[HeaderItem(mnemonic="STRT", unit="M", value="0.05", descr="FIRST INDEX VALUE"),
HeaderItem(mnemonic="STOP", unit="M", value="136.6", descr="LAST INDEX VALUE"),
HeaderItem(mnemonic="STEP", unit="M", value="0.05", descr="STEP"),
HeaderItem(mnemonic="NULL", unit="", value="-99999", descr="NULL VALUE"),
HeaderItem(mnemonic="COMP", unit="", value="", descr="COMP"),
HeaderItem(mnemonic="WELL", unit="", value="Scorpio E1", descr="WELL"),
HeaderItem(mnemonic="FLD", unit="", value="", descr=""),
HeaderItem(mnemonic="LOC", unit="", value="Mt Eba", descr="LOC"),
HeaderItem(mnemonic="SRVC", unit="", value="", descr=""),
HeaderItem(mnemonic="CTRY", unit="", value="", descr=""),
HeaderItem(mnemonic="STAT", unit="", value="SA", descr="STAT"),
HeaderItem(mnemonic="CNTY", unit="", value="", descr=""),
HeaderItem(mnemonic="DATE", unit="", value="15/03/2015", descr="DATE"),
HeaderItem(mnemonic="UWI", unit="", value="6038-187", descr="WUNT"),
HeaderItem(mnemonic="PRMT", unit="", value="unknown", descr="")]
Version 0.30 (12 May 2022)
--------------------------
- Fixes for `#446`_ (Implement a numpy-based reader for the data section; `#452`_) and
Expand Down Expand Up @@ -308,6 +357,7 @@ Version 0.2 (2015-07-08)
.. _#318: https://github.com/kinverarity1/lasio/issues/318
.. _#319: https://github.com/kinverarity1/lasio/issues/319
.. _#321: https://github.com/kinverarity1/lasio/issues/321
.. _#322: https://github.com/kinverarity1/lasio/issues/322
.. _#325: https://github.com/kinverarity1/lasio/issues/325
.. _#326: https://github.com/kinverarity1/lasio/issues/326
.. _#327: https://github.com/kinverarity1/lasio/issues/327
Expand Down Expand Up @@ -387,7 +437,7 @@ Version 0.2 (2015-07-08)
.. _#268: https://github.com/kinverarity1/lasio/issues/268
.. _#451: https://github.com/kinverarity1/lasio/issues/451
.. _#453: https://github.com/kinverarity1/lasio/issues/453
.. _#455: https://github.com/kinverarity1/lasio/issues/455.. _#83: https://github.com/kinverarity1/lasio/issues/83
.. _#455: https://github.com/kinverarity1/lasio/issues/455
.. _#265: https://github.com/kinverarity1/lasio/issues/265
.. _#332: https://github.com/kinverarity1/lasio/issues/332
.. _#375: https://github.com/kinverarity1/lasio/issues/375
Expand Down
2 changes: 1 addition & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
master_doc = "index"

project = u"lasio"
copyright = u"2013-2021, lasio contributors"
copyright = u"2013-2022, lasio contributors"
author = u"lasio contributors"

from pkg_resources import get_distribution
Expand Down
45 changes: 45 additions & 0 deletions docs/source/header-section.rst
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,51 @@ There are methods intended for removing curves. Say you want to remove the PR cu
CurveItem(mnemonic="DFAR", unit="G/CM3", value="", descr="DFAR", original_mnemonic="DFAR", data.shape=(121,)),
CurveItem(mnemonic="DNEAR", unit="G/CM3", value="", descr="DNEAR", original_mnemonic="DNEAR", data.shape=(121,))]
Another common task is to retrieve a header item that may or may not be in the
file. If you try ordinary item-style access,
as is normal in Python, a KeyError exception will be raised if it is missing:

.. code-block:: python
>>> permit = las.well['PRMT']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "c:\devapps\kinverarity\projects\lasio\lasio\las_items.py", line 313, in __getitem__
raise KeyError("%s not in %s" % (key, self.keys()))
KeyError: "PRMT not in ['STRT', 'STOP', 'STEP', 'NULL', 'COMP', 'WELL', 'FLD', 'LOC', 'PROV', 'SRVC', 'DATE', 'UWI']"
A better pattern is to use the :meth:`lasio.SectionItems.get` method, which
allows you to specify a default value in the case of it missing:

.. code-block:: python
>>> permit = las.well.get('PRMT', 'unknown')
>>> permit
HeaderItem(mnemonic="PRMT", unit="", value="unknown", descr="")
You can use the ``add=True`` keyword argument if you would like this
header item to be added, as well as returned:

.. code-block:: python
>>> permit = las.well.get('PRMT', 'unknown', add=True)
>>> las.well
[HeaderItem(mnemonic="STRT", unit="M", value="0.05", descr="FIRST INDEX VALUE"),
HeaderItem(mnemonic="STOP", unit="M", value="136.6", descr="LAST INDEX VALUE"),
HeaderItem(mnemonic="STEP", unit="M", value="0.05", descr="STEP"),
HeaderItem(mnemonic="NULL", unit="", value="-99999", descr="NULL VALUE"),
HeaderItem(mnemonic="COMP", unit="", value="", descr="COMP"),
HeaderItem(mnemonic="WELL", unit="", value="Scorpio E1", descr="WELL"),
HeaderItem(mnemonic="FLD", unit="", value="", descr=""),
HeaderItem(mnemonic="LOC", unit="", value="Mt Eba", descr="LOC"),
HeaderItem(mnemonic="SRVC", unit="", value="", descr=""),
HeaderItem(mnemonic="CTRY", unit="", value="", descr=""),
HeaderItem(mnemonic="STAT", unit="", value="SA", descr="STAT"),
HeaderItem(mnemonic="CNTY", unit="", value="", descr=""),
HeaderItem(mnemonic="DATE", unit="", value="15/03/2015", descr="DATE"),
HeaderItem(mnemonic="UWI", unit="", value="6038-187", descr="WUNT"),
HeaderItem(mnemonic="PRMT", unit="", value="unknown", descr="")]
Handling special cases of header lines
--------------------------------------

Expand Down
3 changes: 1 addition & 2 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@ The final version of lasio with Python 2.7 support is v0.26.
encodings
lasio
contributing

.. include:: changelog.rst
changelog

* :ref:`genindex`
* :ref:`search`
5 changes: 5 additions & 0 deletions docs/source/lasio.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ Reading data
.. autoattribute:: lasio.LASFile.data
.. automethod:: lasio.LASFile.stack_curves

Reading and modifying header data
---------------------------------
.. autoclass:: lasio.SectionItems
:members:

Modifying data
--------------
.. automethod:: lasio.LASFile.set_data
Expand Down
66 changes: 66 additions & 0 deletions lasio/las_items.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,72 @@ def __getitem__(self, key):
else:
raise KeyError("%s not in %s" % (key, self.keys()))

def get(self, mnemonic, default="", add=False):
"""Get an item, with a default value for the situation when it is missing.
Arguments:
mnemonic (str): mnemonic of item to retrieve
default (str, HeaderItem, or CurveItem): default to provide
if *mnemonic* is missing from the section. If a string is
provided, it will be used as the ``value`` attribute of a new
HeaderItem or the ``descr`` attribute of a new CurveItem.
add (bool): if True, the returned HeaderItem/CurveItem will also
be appended to the SectionItems. By default this is not done.
Returns:
:class:`lasio.HeaderItem`/:class:`lasio.CurveItem`: item from
the section, if it is in there, or
a new item, if it is not. If a CurveItem is returned, the
``data`` attribute will contain ``numpy.nan`` values.
"""
if mnemonic in self:
return self[mnemonic]
else:
if not (
isinstance(default, HeaderItem)
or isinstance(default, CurveItem)
):
default = str(default)
# Determine appropriate type of item to create (HeaderItem
# or CurveItem).

if len(self):
first_item = self[0]
item_type = type(first_item)
else:
item_type = HeaderItem

if item_type is CurveItem:
new_data = np.asarray(first_item.data)
new_data = new_data * np.nan

item = CurveItem(
mnemonic=mnemonic,
descr=default,
data=new_data
)
else:
item = HeaderItem(
mnemonic=mnemonic,
value=default
)
else:
assert type(default) in (HeaderItem, CurveItem)

item = type(default)(
mnemonic=mnemonic,
unit=default.unit,
value=default.value,
descr=default.descr
)
if type(item) is CurveItem:
item.data = np.array(default.data)

if add:
self.append(item)
return item

def __delitem__(self, key):
"""Delete item by either mnemonic or index.
Expand Down
41 changes: 41 additions & 0 deletions tests/test_sectionitems.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,3 +154,44 @@ def test_mnemonic_rename_1():
las = lasio.read(egfn("sample.las"))
las.curves[-1].mnemonic = ""
assert las.curves[-1].mnemonic == "UNKNOWN"


def test_get_exists():
sitems = lasio.SectionItems()
sitems.append(
lasio.HeaderItem('WELL', value='1')
)
item = sitems.get('WELL', default='2')
assert item.value == '1'

def test_get_missing_default_str():
sitems = lasio.SectionItems()
item = sitems.get('WELL', default='2')
assert item.value == '2'

def test_get_missing_default_int():
sitems = lasio.SectionItems()
item = sitems.get('WELL', default=2)
assert item.value == '2'

def test_get_missing_default_item():
sitems = lasio.SectionItems()
item = sitems.get('WELL', default=lasio.HeaderItem(mnemonic='XXX', value='3'))
assert item.mnemonic == 'WELL'
assert item.value == '3'

def test_get_missing_curveitem():
sitems = lasio.SectionItems()
sitems.append(
lasio.CurveItem('DEPT', data=[1, 2, 3])
)
item = sitems.get('GAMMA')
assert type(item) is lasio.CurveItem
assert np.isnan(item.data).all()

def test_get_missing_add():
sitems = lasio.SectionItems()
item = sitems.get('WELL', default='3', add=True)
existing_item = sitems[0]
assert existing_item.mnemonic == 'WELL'
assert existing_item.value == '3'

0 comments on commit 8aafe04

Please sign in to comment.