From aac598d64fc0fa50cc068fc50173068e5d89b3fd Mon Sep 17 00:00:00 2001 From: Robert Smallshire Date: Tue, 24 Feb 2015 17:27:37 +0100 Subject: [PATCH 1/8] Update numpy dtypes extension for correct type codes. --- segpy/ext/numpyext.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/segpy/ext/numpyext.py b/segpy/ext/numpyext.py index 1fff0dc..2583caf 100644 --- a/segpy/ext/numpyext.py +++ b/segpy/ext/numpyext.py @@ -2,11 +2,11 @@ import numpy -NUMPY_DTYPES = {'ibm': numpy.dtype('f4'), - 'l': numpy.dtype('i4'), - 'h': numpy.dtype('i2'), - 'f': numpy.dtype('f4'), - 'b': numpy.dtype('i1')} +NUMPY_DTYPES = {'ibm': numpy.dtype('f4'), + 'int32': numpy.dtype('i4'), + 'int16': numpy.dtype('i2'), + 'float32': numpy.dtype('f4'), + 'int8': numpy.dtype('i1')} def make_dtype(data_sample_format): From 7d2079de833a1616e40ef12a7fa09c9ccffbfa91 Mon Sep 17 00:00:00 2001 From: Robert Smallshire Date: Tue, 24 Feb 2015 17:28:41 +0100 Subject: [PATCH 2/8] Time slice extraction example program. --- examples/timeslice.py | 139 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 examples/timeslice.py diff --git a/examples/timeslice.py b/examples/timeslice.py new file mode 100644 index 0000000..06f6763 --- /dev/null +++ b/examples/timeslice.py @@ -0,0 +1,139 @@ +"""Extract a timeslice from a 3D seismic volume to a Numpy array. + +Usage: timeslice.py [-h] [--dtype DTYPE] [--null NULL] + segy-file npy-file slice-index + +Positional arguments: + segy-file Path to an existing SEG Y file of 3D seismic data + npy-file Path to the Numpy array file to be created for the timeslice + slice-index Zero based index of the time slice to be extracted + +Optional arguments: + -h, --help show this help message and exit + --dtype DTYPE Numpy data type. If not provided a dtype compatible with the + SEG Y data will be used. + --null NULL Sample value to use for missing or short traces. + +Example: + + timeslice.py stack_final_int8.sgy slice_800.npy 800 --null=42.0 --dtype=f +""" +from __future__ import print_function + +import argparse + +import os + +import sys +import traceback + +from segpy.reader import create_reader +from segpy.ext.numpyext import make_dtype + +import numpy as np + + +class DimensionalityError(Exception): + pass + + +def extract_timeslice(segy_filename, out_filename, slice_index, dtype=None, null=0): + """Extract a timeslice from a 3D SEG Y file to a Numpy NPY file. + + Args: + segy_filename: Filename of a SEG Y file. + + out_filename: Filename of the NPY file. + + slice_index: The zero-based index (increasing with depth) of the slice to be extracted. + + dtype: Optional Numpy dtype for the result array. If not provided a dtype compatible with + the SEG Y data will be used. + + null: Optional sample value to use for missing or short traces. Defaults to zero. + """ + with open(segy_filename, 'rb') as segy_file: + + segy_reader = create_reader(segy_file) + + if dtype is None: + dtype = make_dtype(segy_reader.data_sample_format) + + if segy_reader.dimensionality != 3: + raise DimensionalityError("Cannot slice {n} dimensional seismic.".format(segy_reader.dimensionality)) + + i_line_range = segy_reader.inline_range() + x_line_range = segy_reader.xline_range() + + i_size = len(i_line_range) + x_size = len(x_line_range) + t_size = segy_reader.max_num_trace_samples() + + if not (0 <= slice_index < t_size): + raise ValueError("Time slice index {0} out of range {} to {}".format(slice_index, 0, t_size)) + + timeslice = np.full((x_size, i_size), null, dtype) + + for inline_num, xline_num in segy_reader.inline_xline_numbers(): + trace_index = segy_reader.trace_index((inline_num, xline_num)) + trace = segy_reader.trace_samples(trace_index) + + try: + sample = trace[slice_index] + except IndexError: + sample = null + + i_index = inline_num - i_line_range.start + x_index = xline_num - x_line_range.start + timeslice[x_index, i_index] = sample + + np.save(out_filename, timeslice) + + +def nullable_dtype(s): + return None if s == "" else np.dtype(s) + + +def main(argv=None): + parser = argparse.ArgumentParser() + parser.add_argument("segy_file", metavar="segy-file", + help="Path to an existing SEG Y file of 3D seismic data") + + parser.add_argument("npy_file", metavar="npy-file", + help="Path to the Numpy array file to be created for the timeslice") + + parser.add_argument("slice_index", metavar="slice-index", type=int, + help="Zero based index of the time slice to be extracted", ) + + parser.add_argument("--dtype", type=nullable_dtype, default="", + help="Numpy data type. If not provided a dtype compatible with the SEG Y data will be used.") + + parser.add_argument("--null", type=float, default=0.0, + help="Sample value to use for missing or short traces.") + + if argv is None: + argv = sys.argv[1:] + + args = parser.parse_args(argv) + + try: + extract_timeslice(args.segy_file, + args.npy_file, + args.slice_index, + args.dtype, + args.null) + except (FileNotFoundError, IsADirectoryError) as e: + print(e, file=sys.stderr) + return os.EX_NOINPUT + except PermissionError as e: + print(e, file=sys.stderr) + return os.EX_NOPERM + except Exception as e: + traceback.print_exception(type(e), e, e.__traceback__, file=sys.stderr) + return os.EX_SOFTWARE + return os.EX_OK + + +if __name__ == '__main__': + sys.exit(main()) + From b1782b9c812884e808b41e272b76db57426216b3 Mon Sep 17 00:00:00 2001 From: Robert Smallshire Date: Tue, 24 Feb 2015 21:13:16 +0100 Subject: [PATCH 3/8] Packaging work and explicit __version__ --- DESCRIPTION.rst | 32 +++++++++++++ README.rst | 15 ++++-- segpy/__init__.py | 2 +- setup.cfg | 5 ++ setup.py | 118 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 167 insertions(+), 5 deletions(-) create mode 100644 DESCRIPTION.rst create mode 100644 setup.cfg create mode 100644 setup.py diff --git a/DESCRIPTION.rst b/DESCRIPTION.rst new file mode 100644 index 0000000..898081a --- /dev/null +++ b/DESCRIPTION.rst @@ -0,0 +1,32 @@ +The SEG Y file format is one of several standards developed by the Society of Exploration Geophysicists for storing +geophysical seismic data. It is an open standard, and is controlled by the SEG Technical Standards Committee, a +non-profit organization. + +This project aims to implement an open SEG Y module in Python for transporting seismic data between SEG Y files and +Python data structures in pure Python. + + +Status +====== + +*Segpy 2* is currently in alpha, so expect rough edges. That said, it seems to broadly work and is largely feature +complete. + + +What It Does +============ + +How To Get It +============= + +*Segpy* is available on the Python Package index and can be installed with ``pip``:: + + $ pip install segpy + + +Requirements +============ + +*Segpy 2* work with Python 3.2 and higher (and 2.7 for now). For the majority of use *Segpy 2* has no external +dependencies. Optional modules with further dependencies such as *Numpy* are included in the ``segpy.ext`` package of +extras. diff --git a/README.rst b/README.rst index 908cb45..14c276d 100644 --- a/README.rst +++ b/README.rst @@ -1,6 +1,6 @@ -===== -Segpy -===== +======= +Segpy 2 +======= Status ====== @@ -18,4 +18,11 @@ geophysical seismic data. It is an open standard, and is controlled by the SEG T non-profit organization. This project aims to implement an open SEG Y module in Python for transporting seismic data between SEG Y files and -Numpy arrays. Segpy is a package for reading, writing and manipulating SEG Y data in pure Python. +Python data structures in pure Python. + +Segpy Versions +============== + +Segpy 2.0 is a complete re-imagining of a SEG Y reader in Python and represents a complete break from Segpy 1.0 in terms +of the interface it presents to clients and the implementation behind those interfaces. Segpy 1.0 should be considered +unmaintained legacy software. The present and future of Segpy is Segpy 2. \ No newline at end of file diff --git a/segpy/__init__.py b/segpy/__init__.py index 8b13789..a790050 100644 --- a/segpy/__init__.py +++ b/segpy/__init__.py @@ -1 +1 @@ - +__version__ = '2.0.0a1' diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..79bc678 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,5 @@ +[bdist_wheel] +# This flag says that the code is written to work on both Python 2 and Python +# 3. If at all possible, it is good practice to do this. If you cannot, you +# will need to generate wheels for each Python version that you support. +universal=1 diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..efcb951 --- /dev/null +++ b/setup.py @@ -0,0 +1,118 @@ +import io +import os +import re +from setuptools import setup, find_packages # Always prefer setuptools over distutils +from codecs import open # To use a consistent encoding +from os import path + + +def read(*names, **kwargs): + with io.open( + os.path.join(os.path.dirname(__file__), *names), + encoding=kwargs.get("encoding", "utf8") + ) as fp: + return fp.read() + + +def find_version(*file_paths): + version_file = read(*file_paths) + version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", + version_file, re.M) + if version_match: + return version_match.group(1) + raise RuntimeError("Unable to find version string.") + + +here = path.abspath(path.dirname(__file__)) + +# Get the long description from the relevant file +with open(path.join(here, 'DESCRIPTION.rst'), encoding='utf-8') as f: + long_description = f.read() + +setup( + name='Segpy', + + # Versions should comply with PEP440. For a discussion on single-sourcing + # the version across setup.py and the project code, see + # https://packaging.python.org/en/latest/single_source_version.html + version=find_version("segpy/__init__.py"), + + description='Transfer of seismic data to and from SEG Y files', + long_description=long_description, + + # The project's main homepage. + url='https://github.com/rob-smallshire/segpy', + + # Author details + author='Robert Smallshire', + author_email='robert@smallshire.org.uk', + + # Choose your license + license='GPL', + + # See https://pypi.python.org/pypi?%3Aaction=list_classifiers + classifiers=[ + # How mature is this project? Common values are + # 3 - Alpha + # 4 - Beta + # 5 - Production/Stable + 'Development Status :: 3 - Alpha', + + # Indicate who your project is intended for + 'Intended Audience :: Developers', + 'Topic :: Software Development :: Build Tools', + + # Pick your license as you wish (should match "license" above) + 'License :: OSI Approved :: MIT License', + + # Specify the Python versions you support here. In particular, ensure + # that you indicate whether you support Python 2, Python 3 or both. + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.3', + 'Programming Language :: Python :: 3.4', + ], + + # What does your project relate to? + keywords='seismic geocomputing geophysics', + + # You can just specify the packages manually here if your project is + # simple. Or you can use find_packages(). + packages=find_packages(exclude=['contrib', 'docs', 'test*']), + + # List run-time dependencies here. These will be installed by pip when your + # project is installed. For an analysis of "install_requires" vs pip's + # requirements files see: + # https://packaging.python.org/en/latest/requirements.html + install_requires=[], + + # List additional groups of dependencies here (e.g. development dependencies). + # You can install these using the following syntax, for example: + # $ pip install -e .[dev,test] + extras_require = { + 'dev': ['check-manifest', 'wheel'], + 'doc': ['sphinx', 'cartouche'], + 'test': ['coverage', 'hypothesis'], + }, + + # If there are data files included in your packages that need to be + # installed, specify them here. If using Python 2.6 or less, then these + # have to be included in MANIFEST.in as well. + package_data={ + }, + + # Although 'package_data' is the preferred approach, in some case you may + # need to place data files outside of your packages. + # see http://docs.python.org/3.4/distutils/setupscript.html#installing-additional-files + # In this case, 'data_file' will be installed into '/my_data' + data_files=[], + + # To provide executable scripts, use entry points in preference to the + # "scripts" keyword. Entry points provide cross-platform support and allow + # pip to create the appropriate form of executable for the target platform. + entry_points={ + 'console_scripts': [ + ], + }, +) + From 17a6475e5bcad8b9103d9954454c170da895259a Mon Sep 17 00:00:00 2001 From: Robert Smallshire Date: Wed, 25 Feb 2015 10:57:29 +0100 Subject: [PATCH 4/8] Lower case Segpy->segpy in setup.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index efcb951..1e12102 100644 --- a/setup.py +++ b/setup.py @@ -30,7 +30,7 @@ with open(path.join(here, 'DESCRIPTION.rst'), encoding='utf-8') as f: long_description = f.read() setup( - name='Segpy', + name='segpy', # Versions should comply with PEP440. For a discussion on single-sourcing # the version across setup.py and the project code, see From 46ddafb37ce0c5177475a2ae7c20ed2938b9aeb1 Mon Sep 17 00:00:00 2001 From: Robert Smallshire Date: Thu, 26 Feb 2015 20:23:01 +0100 Subject: [PATCH 5/8] Layout --- test/test_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_util.py b/test/test_util.py index 40f0c3d..1b71b94 100644 --- a/test/test_util.py +++ b/test/test_util.py @@ -15,7 +15,7 @@ class TestBatched(unittest.TestCase): self.assertTrue(all(len(batch) == batch_size for batch in batches[:-1])) @given([int], - integers_in_range(1, 1000)) + integers_in_range(1, 1000)) def test_final_batch_sizes(self, items, batch_size): assume(len(items) > 0) assume(batch_size > 0) From e938be8507b7d83d3711c92345ad367cf3dcee0b Mon Sep 17 00:00:00 2001 From: Robert Smallshire Date: Thu, 26 Feb 2015 20:23:31 +0100 Subject: [PATCH 6/8] Fix trove classifier --- setup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 1e12102..cb1e41d 100644 --- a/setup.py +++ b/setup.py @@ -60,7 +60,8 @@ setup( # Indicate who your project is intended for 'Intended Audience :: Developers', - 'Topic :: Software Development :: Build Tools', + 'Topic :: Scientific/Engineering', + 'Topic :: Software Development :: Libraries', # Pick your license as you wish (should match "license" above) 'License :: OSI Approved :: MIT License', From e6ed86dc8d4a8ddabe8d5f91c55d87c41419adcc Mon Sep 17 00:00:00 2001 From: Robert Smallshire Date: Thu, 26 Feb 2015 20:25:42 +0100 Subject: [PATCH 7/8] Relocate segpy.ext.numpyext to a separately deployable package segpy-numpy which using pkg_resources entry points to deploy itself into segpy.ext at runtime. --- examples/timeslice.py | 8 +- segpy-ext/segpy-numpy/DESCRIPTION.rst | 20 +++ segpy-ext/segpy-numpy/__init__.py | 1 + segpy-ext/segpy-numpy/segpy_numpy/__init__.py | 10 ++ .../segpy-numpy/segpy_numpy/numpy/__init__.py | 1 + .../segpy-numpy/segpy_numpy/numpy/dtypes.py | 0 segpy-ext/segpy-numpy/setup.cfg | 5 + segpy-ext/segpy-numpy/setup.py | 127 ++++++++++++++++++ segpy/ext/__init__.py | 14 ++ 9 files changed, 181 insertions(+), 5 deletions(-) create mode 100644 segpy-ext/segpy-numpy/DESCRIPTION.rst create mode 100644 segpy-ext/segpy-numpy/__init__.py create mode 100644 segpy-ext/segpy-numpy/segpy_numpy/__init__.py create mode 100644 segpy-ext/segpy-numpy/segpy_numpy/numpy/__init__.py rename segpy/ext/numpyext.py => segpy-ext/segpy-numpy/segpy_numpy/numpy/dtypes.py (100%) create mode 100644 segpy-ext/segpy-numpy/setup.cfg create mode 100644 segpy-ext/segpy-numpy/setup.py diff --git a/examples/timeslice.py b/examples/timeslice.py index 06f6763..7755c4f 100644 --- a/examples/timeslice.py +++ b/examples/timeslice.py @@ -21,17 +21,15 @@ Example: from __future__ import print_function import argparse - import os - import sys import traceback -from segpy.reader import create_reader -from segpy.ext.numpyext import make_dtype - import numpy as np +from segpy.reader import create_reader +from segpy_numpy.numpy.dtypes import make_dtype + class DimensionalityError(Exception): pass diff --git a/segpy-ext/segpy-numpy/DESCRIPTION.rst b/segpy-ext/segpy-numpy/DESCRIPTION.rst new file mode 100644 index 0000000..4b735c4 --- /dev/null +++ b/segpy-ext/segpy-numpy/DESCRIPTION.rst @@ -0,0 +1,20 @@ +Segpy-Numpy offers tools for working with both *Segpy* and *Numpy*. See the *Segpy* documentation for further details. + + +What It Does +============ + +How To Get It +============= + +*Segpy-Numpy* is available on the Python Package index and can be installed with ``pip``:: + + $ pip install segpy-numpy + + +Requirements +============ + +*Segpy-Numpy* should work with Python 3.2 and higher (and 2.7 for now). For the majority of use *Segpy 2* has no +externaldependencies. Optional modules with further dependencies such as *Numpy* are included in the ``segpy.ext`` +package of extras. diff --git a/segpy-ext/segpy-numpy/__init__.py b/segpy-ext/segpy-numpy/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/segpy-ext/segpy-numpy/__init__.py @@ -0,0 +1 @@ + diff --git a/segpy-ext/segpy-numpy/segpy_numpy/__init__.py b/segpy-ext/segpy-numpy/segpy_numpy/__init__.py new file mode 100644 index 0000000..420f4ca --- /dev/null +++ b/segpy-ext/segpy-numpy/segpy_numpy/__init__.py @@ -0,0 +1,10 @@ +print("segpy_numpy.__init__ imported") + +from pkgutil import extend_path + +#__path__ = extend_path(__path__, __name__) +__version__ = '2.0.0a1' + + +def load(): + pass diff --git a/segpy-ext/segpy-numpy/segpy_numpy/numpy/__init__.py b/segpy-ext/segpy-numpy/segpy_numpy/numpy/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/segpy-ext/segpy-numpy/segpy_numpy/numpy/__init__.py @@ -0,0 +1 @@ + diff --git a/segpy/ext/numpyext.py b/segpy-ext/segpy-numpy/segpy_numpy/numpy/dtypes.py similarity index 100% rename from segpy/ext/numpyext.py rename to segpy-ext/segpy-numpy/segpy_numpy/numpy/dtypes.py diff --git a/segpy-ext/segpy-numpy/setup.cfg b/segpy-ext/segpy-numpy/setup.cfg new file mode 100644 index 0000000..79bc678 --- /dev/null +++ b/segpy-ext/segpy-numpy/setup.cfg @@ -0,0 +1,5 @@ +[bdist_wheel] +# This flag says that the code is written to work on both Python 2 and Python +# 3. If at all possible, it is good practice to do this. If you cannot, you +# will need to generate wheels for each Python version that you support. +universal=1 diff --git a/segpy-ext/segpy-numpy/setup.py b/segpy-ext/segpy-numpy/setup.py new file mode 100644 index 0000000..c604eaf --- /dev/null +++ b/segpy-ext/segpy-numpy/setup.py @@ -0,0 +1,127 @@ +import io +import os +import re +from setuptools import setup, find_packages # Always prefer setuptools over distutils +from codecs import open # To use a consistent encoding +from os import path + + +def read(*names, **kwargs): + with io.open( + os.path.join(os.path.dirname(__file__), *names), + encoding=kwargs.get("encoding", "utf8") + ) as fp: + return fp.read() + + +def find_version(*file_paths): + version_file = read(*file_paths) + version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", + version_file, re.M) + if version_match: + return version_match.group(1) + raise RuntimeError("Unable to find version string.") + + +here = path.abspath(path.dirname(__file__)) + + +def local_file(name): + return os.path.join(here, name) + + + +# Get the long description from the relevant file +with open(local_file('DESCRIPTION.rst'), encoding='utf-8') as f: + long_description = f.read() + +setup( + name='segpy-numpy', + + # Versions should comply with PEP440. For a discussion on single-sourcing + # the version across setup.py and the project code, see + # https://packaging.python.org/en/latest/single_source_version.html + version=find_version("segpy_numpy/__init__.py"), + + description='Interoperability between Numpy with Segpy.', + long_description=long_description, + + # The project's main homepage. + url='https://github.com/rob-smallshire/segpy', + + # Author details + author='Robert Smallshire', + author_email='robert@smallshire.org.uk', + + # Choose your license + license='GPL', + + # See https://pypi.python.org/pypi?%3Aaction=list_classifiers + classifiers=[ + # How mature is this project? Common values are + # 3 - Alpha + # 4 - Beta + # 5 - Production/Stable + 'Development Status :: 3 - Alpha', + + # Indicate who your project is intended for + 'Intended Audience :: Developers', + 'Topic :: Scientific/Engineering', + 'Topic :: Software Development :: Libraries', + + # Pick your license as you wish (should match "license" above) + 'License :: OSI Approved :: MIT License', + + # Specify the Python versions you support here. In particular, ensure + # that you indicate whether you support Python 2, Python 3 or both. + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.3', + 'Programming Language :: Python :: 3.4', + ], + + # What does your project relate to? + keywords='seismic geocomputing geophysics numpy', + + # You can just specify the packages manually here if your project is + # simple. Or you can use find_packages(). + packages=find_packages(here, exclude=['segpy', 'contrib', 'docs', 'test*']), + + # List run-time dependencies here. These will be installed by pip when your + # project is installed. For an analysis of "install_requires" vs pip's + # requirements files see: + # https://packaging.python.org/en/latest/requirements.html + install_requires=['numpy'], + + # List additional groups of dependencies here (e.g. development dependencies). + # You can install these using the following syntax, for example: + # $ pip install -e .[dev,test] + extras_require = { + 'dev': ['check-manifest', 'wheel'], + 'doc': ['sphinx', 'cartouche'], + 'test': ['coverage', 'hypothesis'], + }, + + # If there are data files included in your packages that need to be + # installed, specify them here. If using Python 2.6 or less, then these + # have to be included in MANIFEST.in as well. + package_data={ + }, + + # Although 'package_data' is the preferred approach, in some case you may + # need to place data files outside of your packages. + # see http://docs.python.org/3.4/distutils/setupscript.html#installing-additional-files + # In this case, 'data_file' will be installed into '/my_data' + data_files=[], + + # To provide executable scripts, use entry points in preference to the + # "scripts" keyword. Entry points provide cross-platform support and allow + # pip to create the appropriate form of executable for the target platform. + + # Declare entry-points to modules. + entry_points={ + 'segpy.ext': 'segpy-numpy = segpy_numpy' + }, +) + + diff --git a/segpy/ext/__init__.py b/segpy/ext/__init__.py index 8b13789..61ad851 100644 --- a/segpy/ext/__init__.py +++ b/segpy/ext/__init__.py @@ -1 +1,15 @@ +import pkg_resources +loaded = set() + + +def load_entry_points(name=None): + for entry_point in pkg_resources.iter_entry_points(group='segpy.ext', name=name): + package = entry_point.load() + if package not in loaded: + loaded.add(package) + __path__.extend(package.__path__) + package.load() + + +load_entry_points() From 9751fa6300874a2e740f59af4deb557382710878 Mon Sep 17 00:00:00 2001 From: Robert Smallshire Date: Fri, 27 Feb 2015 10:55:24 +0100 Subject: [PATCH 8/8] Docstring for segpy.ext.load_packages() --- segpy/ext/__init__.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/segpy/ext/__init__.py b/segpy/ext/__init__.py index 61ad851..ba891c3 100644 --- a/segpy/ext/__init__.py +++ b/segpy/ext/__init__.py @@ -4,6 +4,11 @@ loaded = set() def load_entry_points(name=None): + """Load extension packages into the segpy.ext namespace. + + Any packages registered against the 'segpy.ext' entry-point group will be + installed dynamically into the segpy.ext namespace. + """ for entry_point in pkg_resources.iter_entry_points(group='segpy.ext', name=name): package = entry_point.load() if package not in loaded: