log2frame 0.2.1__tar.gz → 0.2.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (24) hide show
  1. {log2frame-0.2.1/src/log2frame.egg-info → log2frame-0.2.2}/PKG-INFO +3 -3
  2. {log2frame-0.2.1 → log2frame-0.2.2}/README.md +2 -2
  3. {log2frame-0.2.1 → log2frame-0.2.2}/pyproject.toml +1 -1
  4. {log2frame-0.2.1 → log2frame-0.2.2}/src/log2frame/__init__.py +22 -2
  5. {log2frame-0.2.1 → log2frame-0.2.2}/src/log2frame/dictionaries/units.py +11 -2
  6. {log2frame-0.2.1 → log2frame-0.2.2}/src/log2frame/dlis.py +27 -2
  7. {log2frame-0.2.1 → log2frame-0.2.2}/src/log2frame/las.py +35 -2
  8. {log2frame-0.2.1 → log2frame-0.2.2}/src/log2frame/lis.py +27 -2
  9. {log2frame-0.2.1 → log2frame-0.2.2}/src/log2frame/log.py +84 -4
  10. {log2frame-0.2.1 → log2frame-0.2.2}/src/log2frame/pack.py +2 -2
  11. {log2frame-0.2.1 → log2frame-0.2.2}/src/log2frame/rft.py +2 -2
  12. {log2frame-0.2.1 → log2frame-0.2.2/src/log2frame.egg-info}/PKG-INFO +3 -3
  13. {log2frame-0.2.1 → log2frame-0.2.2}/LICENSE +0 -0
  14. {log2frame-0.2.1 → log2frame-0.2.2}/setup.cfg +0 -0
  15. {log2frame-0.2.1 → log2frame-0.2.2}/src/log2frame/debug.py +0 -0
  16. {log2frame-0.2.1 → log2frame-0.2.2}/src/log2frame/dictionaries/__init__.py +0 -0
  17. {log2frame-0.2.1 → log2frame-0.2.2}/src/log2frame/dictionaries/units_dictionary.json +0 -0
  18. {log2frame-0.2.1 → log2frame-0.2.2}/src/log2frame.egg-info/SOURCES.txt +0 -0
  19. {log2frame-0.2.1 → log2frame-0.2.2}/src/log2frame.egg-info/dependency_links.txt +0 -0
  20. {log2frame-0.2.1 → log2frame-0.2.2}/src/log2frame.egg-info/requires.txt +0 -0
  21. {log2frame-0.2.1 → log2frame-0.2.2}/src/log2frame.egg-info/top_level.txt +0 -0
  22. {log2frame-0.2.1 → log2frame-0.2.2}/test/test_log.py +0 -0
  23. {log2frame-0.2.1 → log2frame-0.2.2}/test/test_pack.py +0 -0
  24. {log2frame-0.2.1 → log2frame-0.2.2}/test/test_readers.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: log2frame
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Summary: A function to facilitate loading well log data, in las or dlis format, as dataframe.
5
5
  Author-email: Martin Carlos Araya <martinaraya@gmail.com>
6
6
  License: MIT License
@@ -51,8 +51,8 @@ Dynamic: license-file
51
51
 
52
52
  A function to read well log data in LAS, LIS and DLIS formats and extract curves data as DataFrame.
53
53
 
54
- The curves and header data are stored in an instance of `Log` class, designed to hold this data and operate with it.
55
- If multiple log files are read together, the __Log__ instances are packed in a `Pack` instance, designed to hold `Log` instances and operate with them.
54
+ The curves and header data are stored in an instance of ``Log`` class, designed to hold this data and operate with it. It provides convenient access to metadata like well name, UWI, and curve units (via ``.units`` or the safer ``.units_dict()``).
55
+ If multiple log files are read together, the __Log__ instances are packed in a ``Pack`` instance, designed to hold ``Log`` instances and operate with them.
56
56
 
57
57
  # unit-aware mode
58
58
  When `simpandas` is installed, `log2frame` can preserve curve units and index units through the `use_simpandas` option.
@@ -4,8 +4,8 @@
4
4
 
5
5
  A function to read well log data in LAS, LIS and DLIS formats and extract curves data as DataFrame.
6
6
 
7
- The curves and header data are stored in an instance of `Log` class, designed to hold this data and operate with it.
8
- If multiple log files are read together, the __Log__ instances are packed in a `Pack` instance, designed to hold `Log` instances and operate with them.
7
+ The curves and header data are stored in an instance of ``Log`` class, designed to hold this data and operate with it. It provides convenient access to metadata like well name, UWI, and curve units (via ``.units`` or the safer ``.units_dict()``).
8
+ If multiple log files are read together, the __Log__ instances are packed in a ``Pack`` instance, designed to hold ``Log`` instances and operate with them.
9
9
 
10
10
  # unit-aware mode
11
11
  When `simpandas` is installed, `log2frame` can preserve curve units and index units through the `use_simpandas` option.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "log2frame"
7
- version = "0.2.1"
7
+ version = "0.2.2"
8
8
  authors = [
9
9
  { name="Martin Carlos Araya", email="martinaraya@gmail.com" },
10
10
  ]
@@ -14,8 +14,11 @@ import os.path
14
14
  import logging
15
15
  from .rft import *
16
16
 
17
- __version__ = '0.2.1'
18
- __release__ = 20260426
17
+ for name in ("lasio", "lasio.reader", "lasio.las", "unyts"):
18
+ logging.getLogger(name).setLevel(logging.WARNING)
19
+
20
+ __version__ = '0.2.2'
21
+ __release__ = 20260427
19
22
  __all__ = ['read', 'concat']
20
23
 
21
24
 
@@ -55,6 +58,23 @@ def _read_one(path: str, raise_error=True, use_simpandas=None, correct_units=Tru
55
58
 
56
59
 
57
60
  def read(path: str, recursive=True, raise_error=False, squeeze=True, use_simpandas=None, correct_units=True):
61
+ """Read a well-log file (LAS, DLIS, LIS) into a units-aware :class:`Log` container.
62
+
63
+ Accepts individual file paths or a list of paths/globs. If multiple files are
64
+ read, they are returned grouped in a :class:`Pack` container.
65
+
66
+ Parameters
67
+ ----------
68
+ path : str | list[str]
69
+ Path to the ``.las``, ``.dlis``, or ``.lis`` file(s). Glob expressions and directory paths are supported.
70
+ recursive : bool, default True
71
+ If reading a path pattern with globs, controls whether directories are searched recursively.
72
+ squeeze : bool, default True
73
+ If True and only one log is inside a resulting pack, return that single Log object instead of the Pack.
74
+ use_simpandas : bool | None, default None
75
+ raise_error : bool, default False
76
+ correct_units : bool, default True
77
+ """
58
78
  if use_simpandas is not None and use_simpandas is True and not _params_.simpandas_:
59
79
  raise ModuleNotFoundError("SimPandas is not installed, please install it or set parameter `use_simpandas` to False.")
60
80
  use_simpandas = _params_.simpandas_ if use_simpandas is None else bool(use_simpandas)
@@ -12,8 +12,17 @@ from pathlib import Path
12
12
  this_path_ = Path(__file__).with_name('units_dictionary.json').absolute()
13
13
  this_path_ = dirname(this_path_) + '/'
14
14
 
15
- with open(this_path_ + 'units_dictionary.json', 'r') as f:
16
- units_correction_dict_ = json.load(f)
15
+ try:
16
+ with open(this_path_ + 'units_dictionary.json', 'r') as f:
17
+ units_correction_dict_ = json.load(f)
18
+ except (FileNotFoundError, json.JSONDecodeError) as e:
19
+ import warnings
20
+ warnings.warn(
21
+ f"log2frame: units-correction dictionary not found "
22
+ f"({type(e).__name__}: {e}); proceeding with unit-correction disabled.",
23
+ UserWarning,
24
+ )
25
+ units_correction_dict_ = {}
17
26
 
18
27
 
19
28
  def correct_units(units):
@@ -19,8 +19,8 @@ try:
19
19
  except ModuleNotFoundError:
20
20
  pass
21
21
 
22
- __version__ = '0.2.1'
23
- __release__ = 20260426
22
+ __version__ = '0.2.2'
23
+ __release__ = 20260427
24
24
 
25
25
  logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.INFO)
26
26
 
@@ -34,6 +34,31 @@ class DLISIOError(Exception):
34
34
 
35
35
 
36
36
  def dlis2frame(path: str, use_simpandas=None, raise_error=True, correct_units=True):
37
+ """Read a DLIS file into a :class:`Log` container.
38
+
39
+ Parameters
40
+ ----------
41
+ path : str
42
+ Path to the ``.dlis`` file.
43
+ use_simpandas : bool | None, default None
44
+ If True, the returned :class:`Log` wraps a
45
+ :class:`simpandas.SimDataFrame` and units propagate through
46
+ operations. If False, plain :class:`pandas.DataFrame` is used.
47
+ ``None`` falls back to True when SimPandas is installed.
48
+ raise_error : bool, default True
49
+ If False, parse errors are caught and ``None`` is returned
50
+ instead of raising.
51
+ correct_units : bool, default True
52
+ Apply the LAS-mnemonic-to-canonical-unit corrections (GR's
53
+ ``GAPI`` ↔ ``gAPI`` etc.) defined in
54
+ :data:`dictionaries.units_correction_dict_`.
55
+
56
+ Returns
57
+ -------
58
+ Log | Pack | None
59
+ The parsed log; or a ``Pack`` of logs if multiple frames are present;
60
+ ``None`` if parsing failed and ``raise_error=False``.
61
+ """
37
62
  if not os.path.isfile(path):
38
63
  raise FileNotFoundError("The provided path can't be found:\n" + str(path))
39
64
  if type(path) is str:
@@ -18,8 +18,8 @@ try:
18
18
  except ModuleNotFoundError:
19
19
  pass
20
20
 
21
- __version__ = '0.2.1'
22
- __release__ = 20260426
21
+ __version__ = '0.2.2'
22
+ __release__ = 20260427
23
23
 
24
24
  logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.INFO)
25
25
 
@@ -33,6 +33,39 @@ class LASIOError(Exception):
33
33
 
34
34
 
35
35
  def las2frame(path: str, use_simpandas=None, raise_error=True, correct_units=True):
36
+ """Read a LAS file (1.2 / 2.0 / 3.0) into a :class:`Log` container.
37
+
38
+ Parameters
39
+ ----------
40
+ path : str
41
+ Path to the ``.las`` file.
42
+ use_simpandas : bool | None, default None
43
+ If True, the returned :class:`Log` wraps a
44
+ :class:`simpandas.SimDataFrame` and units propagate through
45
+ operations. If False, plain :class:`pandas.DataFrame` is used.
46
+ ``None`` falls back to True when SimPandas is installed.
47
+ raise_error : bool, default True
48
+ If False, parse errors are caught and ``None`` is returned
49
+ instead of raising.
50
+ correct_units : bool, default True
51
+ Apply the LAS-mnemonic-to-canonical-unit corrections (GR's
52
+ ``GAPI`` ↔ ``gAPI`` etc.) defined in
53
+ :data:`dictionaries.units_correction_dict_`.
54
+
55
+ Returns
56
+ -------
57
+ Log | None
58
+ The parsed log; ``None`` if parsing failed and
59
+ ``raise_error=False``.
60
+
61
+ Examples
62
+ --------
63
+ >>> log = log2frame.las2frame("well.las")
64
+ >>> log.curves
65
+ ['GR', 'NPHI', 'RHOB', 'DT']
66
+ >>> log.units_dict()['GR']
67
+ 'gAPI'
68
+ """
36
69
  if not os.path.isfile(path):
37
70
  raise FileNotFoundError("The provided path can't be found:\n" + str(path))
38
71
  if type(path) is str:
@@ -18,8 +18,8 @@ try:
18
18
  except ModuleNotFoundError:
19
19
  pass
20
20
 
21
- __version__ = '0.2.1'
22
- __release__ = 20260426
21
+ __version__ = '0.2.2'
22
+ __release__ = 20260427
23
23
 
24
24
  logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.INFO)
25
25
 
@@ -32,6 +32,31 @@ class DLISIOError(Exception):
32
32
  self.message = 'ERROR: reading LIS file ' + message
33
33
 
34
34
  def lis2frame(path: str, use_simpandas=None, raise_error=True, correct_units=True):
35
+ """Read a LIS file into a :class:`Log` container.
36
+
37
+ Parameters
38
+ ----------
39
+ path : str
40
+ Path to the ``.lis`` or ``.lti`` file.
41
+ use_simpandas : bool | None, default None
42
+ If True, the returned :class:`Log` wraps a
43
+ :class:`simpandas.SimDataFrame` and units propagate through
44
+ operations. If False, plain :class:`pandas.DataFrame` is used.
45
+ ``None`` falls back to True when SimPandas is installed.
46
+ raise_error : bool, default True
47
+ If False, parse errors are caught and ``None`` is returned
48
+ instead of raising.
49
+ correct_units : bool, default True
50
+ Apply the LAS-mnemonic-to-canonical-unit corrections (GR's
51
+ ``GAPI`` ↔ ``gAPI`` etc.) defined in
52
+ :data:`dictionaries.units_correction_dict_`.
53
+
54
+ Returns
55
+ -------
56
+ Log | Pack | None
57
+ The parsed log; or a ``Pack`` of logs if multiple frames are present;
58
+ ``None`` if parsing failed and ``raise_error=False``.
59
+ """
35
60
  if not os.path.isfile(path):
36
61
  raise FileNotFoundError("The provided path can't be found:\n" + str(path))
37
62
  if type(path) is str:
@@ -9,8 +9,8 @@ import pandas as pd
9
9
  import unyts
10
10
 
11
11
 
12
- __version__ = '0.2.1'
13
- __release__ = 20260426
12
+ __version__ = '0.2.2'
13
+ __release__ = 20260427
14
14
  __all__ = ['Log']
15
15
 
16
16
  logging.basicConfig(level=logging.INFO)
@@ -22,6 +22,43 @@ class Log2FrameType(type):
22
22
 
23
23
 
24
24
  class Log(object, metaclass=Log2FrameType):
25
+ """A single well-log file represented as a units-aware container.
26
+
27
+ Public attributes
28
+ -----------------
29
+ name : str
30
+ Well name (from the ``WELL`` mnemonic).
31
+ uwi : str | None
32
+ Unique Well Identifier (from ``UWI`` / ``API``); ``None`` if absent.
33
+ path : str
34
+ Path to the source file.
35
+ source : str
36
+ Format identifier — ``"LAS"`` / ``"DLIS"`` / ``"LIS"``.
37
+ data : SimDataFrame | DataFrame
38
+ Curves, indexed by depth.
39
+ columns : list[str]
40
+ Curve mnemonics.
41
+ index_units : str
42
+ Unit of the depth index (``"M"`` / ``"FT"`` / …).
43
+ units : pandas.Series
44
+ Per-mnemonic units. **Multi-element Series**; do not test for
45
+ truthiness directly — see :meth:`units_dict`.
46
+ well : object
47
+ WELL-section attribute access (``log.well.STRT`` etc.).
48
+ header, meta, curves : ...
49
+ Free-form access to the LAS / DLIS sections.
50
+
51
+ Methods
52
+ -------
53
+ index_to(unit) → Log
54
+ Return a copy with the depth index converted to *unit*.
55
+ to(unit) → Log
56
+ Convert *all* curves to *unit* where the conversion is defined.
57
+ set_index(curve), set_index_name(name), set_index_units(unit)
58
+ Mutators on the depth index.
59
+ rename, copy, sort, keys
60
+ DataFrame-style helpers.
61
+ """
25
62
 
26
63
  def __init__(self, data=None, header=None, units=None, source=None, well=None):
27
64
  self.data = data
@@ -122,17 +159,60 @@ class Log(object, metaclass=Log2FrameType):
122
159
 
123
160
  @property
124
161
  def index_units(self):
162
+ units_str = None
125
163
  if hasattr(self.data, 'index_units'):
126
- return self.data.index_units
164
+ units_str = self.data.index_units
127
165
  elif self.data.index.name in self.units:
128
- return self.units[self.data.index.name]
166
+ units_str = self.units[self.data.index.name]
129
167
  else:
130
168
  logging.warning("index units are not defined.")
169
+
170
+ if isinstance(units_str, str):
171
+ _DEPTH_UNIT_CANONICAL = {
172
+ "m": "m", "metre": "m", "meter": "m", "meters": "m", "metres": "m",
173
+ "ft": "ft", "foot": "ft", "feet": "ft",
174
+ }
175
+ return _DEPTH_UNIT_CANONICAL.get(units_str.strip().lower(), units_str)
176
+ return units_str
131
177
 
132
178
  @index_units.setter
133
179
  def index_units(self, units: str):
134
180
  self.set_index_units(units)
135
181
 
182
+ @property
183
+ def units(self) -> pd.Series:
184
+ """Per-mnemonic units as a pandas ``Series`` (not a dict).
185
+
186
+ .. note::
187
+ ``Log.units`` is a multi-element ``Series``, **not** a dict.
188
+ The conventional ``dict(log.units or {})`` pattern silently
189
+ evaluates to ``{}`` because of pandas' truthiness behaviour.
190
+ Use :meth:`units_dict` or ``dict(log.units)`` explicitly.
191
+ """
192
+ return self._units
193
+
194
+ @units.setter
195
+ def units(self, value):
196
+ self._units = value
197
+
198
+ def units_dict(self) -> dict:
199
+ """Return the curve→unit mapping as a plain ``dict``.
200
+
201
+ Use this instead of ``dict(log.units)`` if you want to support both
202
+ the (unusual) zero-curve case and the normal multi-curve case in a
203
+ single line.
204
+
205
+ >>> units = log.units_dict()
206
+ >>> units.get('GR', 'unknown')
207
+ 'gAPI'
208
+ """
209
+ if self._units is None:
210
+ return {}
211
+ s = self._units
212
+ if hasattr(s, "empty") and s.empty:
213
+ return {}
214
+ return dict(s)
215
+
136
216
  def keys(self):
137
217
  return self.data.columns
138
218
 
@@ -9,8 +9,8 @@ import numpy as np
9
9
  import pandas as pd
10
10
  from .log import Log, Log2FrameType
11
11
 
12
- __version__ = '0.2.1'
13
- __release__ = 20260426
12
+ __version__ = '0.2.2'
13
+ __release__ = 20260427
14
14
  __all__ = ['Pack', 'concat']
15
15
 
16
16
  logging.basicConfig(level=logging.INFO)
@@ -8,8 +8,8 @@ import pandas as pd
8
8
  import glob
9
9
  import os
10
10
 
11
- __version__ = '0.2.1'
12
- __release__ = 20260426
11
+ __version__ = '0.2.2'
12
+ __release__ = 20260427
13
13
  __all__ = ['rft_summaries_from_folders', 'rft_summary']
14
14
 
15
15
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: log2frame
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Summary: A function to facilitate loading well log data, in las or dlis format, as dataframe.
5
5
  Author-email: Martin Carlos Araya <martinaraya@gmail.com>
6
6
  License: MIT License
@@ -51,8 +51,8 @@ Dynamic: license-file
51
51
 
52
52
  A function to read well log data in LAS, LIS and DLIS formats and extract curves data as DataFrame.
53
53
 
54
- The curves and header data are stored in an instance of `Log` class, designed to hold this data and operate with it.
55
- If multiple log files are read together, the __Log__ instances are packed in a `Pack` instance, designed to hold `Log` instances and operate with them.
54
+ The curves and header data are stored in an instance of ``Log`` class, designed to hold this data and operate with it. It provides convenient access to metadata like well name, UWI, and curve units (via ``.units`` or the safer ``.units_dict()``).
55
+ If multiple log files are read together, the __Log__ instances are packed in a ``Pack`` instance, designed to hold ``Log`` instances and operate with them.
56
56
 
57
57
  # unit-aware mode
58
58
  When `simpandas` is installed, `log2frame` can preserve curve units and index units through the `use_simpandas` option.
File without changes
File without changes
File without changes
File without changes