las-read-rs 0.1.1__cp310-cp310-manylinux_2_34_x86_64.whl

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.
@@ -0,0 +1,79 @@
1
+ Metadata-Version: 2.4
2
+ Name: las_read_rs
3
+ Version: 0.1.1
4
+ Summary: A high-performance LAS (Log ASCII Standard) file reader written in Rust
5
+ Author-email: Emiliano Flores <jemilianofl@github.com>
6
+ Requires-Python: >=3.7
7
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
8
+
9
+ # LAS_read_rs
10
+
11
+ **LAS_read_rs** is a high-performance Python library for reading **LAS (Log ASCII Standard)** files, written in **Rust** using `pyo3` and `nom`. It is designed to be a faster alternative to pure Python implementations, capable of parsing large geophysical log files efficiently.
12
+
13
+ ## Features
14
+
15
+ - ๐Ÿš€ **High Performance**: Built with Rust's `nom` parser combinators and parallelized with `rayon` for maximum speed.
16
+ - ๐Ÿงต **Multi-threaded**: parses the data section (`~ASCII`) in parallel chunks.
17
+ - ๐Ÿ“ฆ **Easy Installation**: Distributed as a standard Python wheel via PyPI.
18
+ - ๐Ÿ **Pythonic Interface**: Simple `read()` function returning a `LASFile` object.
19
+ - โœ… **Standard Compliant**: Supports LAS 2.0 (and 1.2 compatible structure).
20
+
21
+ ## Benchmarks
22
+
23
+ Parsed a LAS file with **100,000 lines** of data:
24
+ - **LAS_read_rs**: ~0.8s (Pure parsing time) / ~3.8s (Including CLI overhead benchmarks)
25
+ - **Pure Python**: Significantly slower (typically 10x-50x slower depending on implementation).
26
+
27
+ ## Installation
28
+
29
+ ```bash
30
+ pip install LAS_read_rs
31
+ ```
32
+
33
+ ## Usage
34
+
35
+ ```python
36
+ import lasio_rs
37
+
38
+ # Read a LAS file
39
+ las = lasio_rs.read("path/to/well_log.las")
40
+
41
+ # Access Version Information
42
+ print(las.version)
43
+ # Output (JSON representation):
44
+ # {
45
+ # "VERS": {"mnemonic": "VERS", "value": "2.0", "descr": "CWLS LOG ASCII STANDARD - VERSION 2.0"},
46
+ # "WRAP": {"mnemonic": "WRAP", "value": "NO", "descr": "One line per depth step"}
47
+ # }
48
+
49
+ # Access Well Metadata (e.g., STRT, STOP, NULL)
50
+ # Note: Currently exposed mainly via debug getters or verifying structure
51
+ # Future versions will expose a full dictionary-like interface.
52
+
53
+ print(f"Well Name: {las.well_name}")
54
+ ```
55
+
56
+ ## Structure
57
+
58
+ The library maps LAS sections to Rust structs:
59
+ - `~Version` -> `las.version`
60
+ - `~Well` -> `las.well`
61
+ - `~Curves` -> `las.curves` (Metadata)
62
+ - `~ASCII` -> Data columns (Stored internally as efficient vectors)
63
+
64
+ ## Building from Source
65
+
66
+ Requirements:
67
+ - Python 3.7+
68
+ - Rust (cargo, rustc)
69
+ - `maturin`
70
+
71
+ ```bash
72
+ pip install maturin
73
+ maturin develop --release
74
+ ```
75
+
76
+ ## License
77
+
78
+ MIT
79
+
@@ -0,0 +1,7 @@
1
+ las_read_rs-0.1.1.dist-info/METADATA,sha256=VOYbTSMyNgWnAxv6vHvFTg3TR8oAA_eu3q4KJxbg4Q0,2333
2
+ las_read_rs-0.1.1.dist-info/WHEEL,sha256=wWeP6JRxAL_oJlqLsckA512CC09LPG7OAdt_mycafo4,109
3
+ lasio_rs/__init__.py,sha256=EgGxrSR3njk8PPL7ev0prizObOipRyfBui-QVI7dkjQ,31
4
+ lasio_rs/_lasio_rs.cp313-win_amd64.pyd,sha256=sE_eS52Q2ayVUdKwPSgzQQxzUy2WN1NnVtaVASjKc_8,1380352
5
+ lasio_rs/_lasio_rs.cpython-310-x86_64-linux-gnu.so,sha256=yvH5W_qywWqcrNws3lnjEuCTnr8fGZRVLoZqJz8gQbw,928496
6
+ lasio_rs/las.py,sha256=EKQzfFfnXo_RyY3Ip6h0eQQvkjjyh5_y6yEizaE6Hys,4382
7
+ las_read_rs-0.1.1.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: maturin (1.11.5)
3
+ Root-Is-Purelib: false
4
+ Tag: cp310-cp310-manylinux_2_34_x86_64
lasio_rs/__init__.py ADDED
@@ -0,0 +1 @@
1
+ from .las import read, LASFile
Binary file
lasio_rs/las.py ADDED
@@ -0,0 +1,147 @@
1
+ from ._lasio_rs import read as _rust_read
2
+ import json
3
+
4
+
5
+ class SectionItems:
6
+ def __init__(self, data_dict):
7
+ # Allow init from dict of HeaderItems or dict of dicts (from json)
8
+ self._data = {}
9
+ for k, v in data_dict.items():
10
+ if isinstance(v, dict):
11
+ # Check if it is a Curve dict or Header dict
12
+ self._data[k] = HeaderItem(v)
13
+ else:
14
+ self._data[k] = v
15
+
16
+ def __getitem__(self, key):
17
+ item = self._data.get(key)
18
+ if item:
19
+ return item
20
+ raise KeyError(f"{key} not found")
21
+
22
+ def keys(self):
23
+ return self._data.keys()
24
+
25
+ def values(self):
26
+ return self._data.values()
27
+
28
+ def items(self):
29
+ return self._data.items()
30
+
31
+ def get(self, key, default=None):
32
+ return self._data.get(key, default)
33
+
34
+ def __repr__(self):
35
+ return f"SectionItems({list(self.keys())})"
36
+
37
+
38
+ class HeaderItem:
39
+ def __init__(self, item_dict):
40
+ self.mnemonic = item_dict.get("mnemonic")
41
+ self.unit = item_dict.get("unit")
42
+ self.value = item_dict.get("value")
43
+ self.descr = item_dict.get("descr")
44
+ self.original_mnemonic = self.mnemonic # Compatibility
45
+
46
+ def __repr__(self):
47
+ return f'HeaderItem(mnemonic="{self.mnemonic}", unit="{self.unit}", value="{self.value}", descr="{self.descr}")'
48
+
49
+
50
+ class CurveItem(HeaderItem):
51
+ def __init__(self, item_dict, las_file_ref):
52
+ super().__init__(item_dict)
53
+ self._las = las_file_ref
54
+ self._data = None
55
+
56
+ @property
57
+ def data(self):
58
+ if self._data is None:
59
+ # Lazy load from Rust
60
+ self._data = self._las._rust.get_curve_data(self.mnemonic)
61
+ if self._data is None:
62
+ self._data = []
63
+ return self._data
64
+
65
+ def __getitem__(self, index):
66
+ return self.data[index]
67
+
68
+ def __len__(self):
69
+ return len(self.data)
70
+
71
+ def __repr__(self):
72
+ return f'CurveItem(mnemonic="{self.mnemonic}", unit="{self.unit}", value="{self.value}", descr="{self.descr}", data.shape=({len(self)},))'
73
+
74
+
75
+ class LASFile:
76
+ def __init__(self, rust_las):
77
+ self._rust = rust_las
78
+
79
+ # Hydrate metadata from JSON
80
+ header_json = rust_las.json_headers
81
+ header_data = json.loads(header_json)
82
+
83
+ self.version = SectionItems(header_data.get("version", {}))
84
+ self.well = SectionItems(header_data.get("well", {}))
85
+ self.params = SectionItems(header_data.get("params", {}))
86
+
87
+ # Curves needs special handling to link back to Rust for data
88
+ raw_curves = header_data.get("curves", {})
89
+ self.curves = SectionItems({})
90
+ # Overwrite with CurveItems
91
+ curve_dict = {}
92
+ for k, v in raw_curves.items():
93
+ curve_dict[k] = CurveItem(v, self)
94
+ self.curves = SectionItems(curve_dict)
95
+
96
+ def __getitem__(self, key):
97
+ # Access curve data directly by mnemonic
98
+ if isinstance(key, str):
99
+ if key in self.curves.keys():
100
+ return self.curves[key].data
101
+ raise KeyError(f"Curve {key} not found")
102
+
103
+ def keys(self):
104
+ return self.curves.keys()
105
+
106
+ def to_df(self):
107
+ """Convert LAS data to a pandas DataFrame.
108
+
109
+ Returns:
110
+ pandas.DataFrame: DataFrame with curve mnemonics as columns.
111
+ """
112
+ try:
113
+ import pandas as pd
114
+ except ImportError:
115
+ raise ImportError(
116
+ "pandas is required for to_df(). Install with: pip install pandas"
117
+ )
118
+
119
+ data = {}
120
+ for mnemonic in self.curves.keys():
121
+ curve = self.curves[mnemonic]
122
+ data[mnemonic] = curve.data
123
+ return pd.DataFrame(data)
124
+
125
+ def to_polars(self):
126
+ """Convert LAS data to a polars DataFrame.
127
+
128
+ Returns:
129
+ polars.DataFrame: DataFrame with curve mnemonics as columns.
130
+ """
131
+ try:
132
+ import polars as pl
133
+ except ImportError:
134
+ raise ImportError(
135
+ "polars is required for to_polars(). Install with: pip install polars"
136
+ )
137
+
138
+ data = {}
139
+ for mnemonic in self.curves.keys():
140
+ curve = self.curves[mnemonic]
141
+ data[mnemonic] = curve.data
142
+ return pl.DataFrame(data)
143
+
144
+
145
+ def read(file_path):
146
+ rust_obj = _rust_read(str(file_path))
147
+ return LASFile(rust_obj)