From a3b26275561d72a9062abe85757aa5381d079748 Mon Sep 17 00:00:00 2001 From: brettlangdon Date: Fri, 24 Aug 2018 08:36:37 -0400 Subject: [PATCH] Update documentation and get ready for v1.0.1 --- CHANGELOG | 17 +++++++- README.md | 86 ++++++++++++++++++++++++++++++++++++++++ README.rst | 29 -------------- importhook/meta_paths.py | 5 --- setup.py | 8 ++-- 5 files changed, 105 insertions(+), 40 deletions(-) create mode 100644 README.md delete mode 100644 README.rst diff --git a/CHANGELOG b/CHANGELOG index 909e81c..5f21ec5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,10 +1,23 @@ Importhook Changelog =================== +Version 1.0.1 +------------- + +:Released: 09-24-2018 + +:Changes: + Expand on documentation. + + Fix `setup.py` long description content type. + + Cleanup code for finder and meta paths. + + Version 1.0.0 ------------- -:Released: 09-22-2018 +:Released: 09-24-2018 :Changes: - Initial release + Initial release diff --git a/README.md b/README.md new file mode 100644 index 0000000..71c8d15 --- /dev/null +++ b/README.md @@ -0,0 +1,86 @@ +Importhook +========= + +[![PyPI version](https://badge.fury.io/py/importhook.svg)](https://badge.fury.io/py/importhook) + +`importhook` is a Python package that lets you configure functions to call whenever a specific module is imported. + + +## Installation + +```bash +pip install importhook +``` + +## Usage +Configure a hook to be called when `socket` module is imported. + +```python +import importhook + +# Setup hook to be called any time the `socket` module is imported and loaded into module cache +@importhook.on_import('socket') +def on_socket_import(socket): + print('"socket" module has been imported') + +# Import module +import socket +``` + + +You can also use `importhook` to intercept and modify a module on import by returning a Python module from your hook function. + +```python +import importhook + +# Setup hook to be called any time the `socket` module is imported and loaded into module cache +@importhook.on_import('socket') +def on_socket_import(socket): + new_socket = importhook.copy_module(socket) + setattr(new_socket, 'gethostname', lambda: 'patched-hostname') + return new_socket + +# Import module +import socket + +# Prints: 'patched-hostname' +print(socket.gethostname()) +``` + + +`importhook` also comes with helpers to reload modules that have already been imported. + +```python +import socket +import importhook + + +# Setup hook to be called any time the `socket` module is imported and loaded into module cache +@ DEV: `on_socket_import` will be called immediately because the `socket` module is already loaded +@importhook.on_import('socket') +def on_socket_import(socket): + print('"socket" module has been imported') + + +# Reload the socket module +# DEV: Reassign to `socket` in case one of our hooks modifies the module +socket = importhook.reload_module(socket) +``` +## Design decisions +### Overwriting sys.meta_paths +If a Python developer wants to modify the import behavior they can do so by adding a new `importlib.abc.Finder` +class into `sys.meta_path`. + +```python +import sys + +# Add our custom `importlib.abc.Finder` to `sys.meta_path` +sys.meta_path.append(MyCustomFinder) +``` + +One of the major design decisions we have taken with `importhook` is to wrap/overwrite `sys.meta_path`. +What it means is that `importhook` will continue to work as expected regardless of any other modifications of `sys.meta_path`. + +There is however one caveat, if you were to do `sys.meta_path = [MyCustomFinder] + sys.meta_path` then `sys.meta_path` will get +converted back into a `list`. Existing modifications to the finders in `sys.meta_path` will still work as expected, but any +new finders added will not get hooked. diff --git a/README.rst b/README.rst deleted file mode 100644 index f977c4a..0000000 --- a/README.rst +++ /dev/null @@ -1,29 +0,0 @@ -Importhook -========= - -.. image:: https://badge.fury.io/py/importhook.svg - :target: https://badge.fury.io/py/importhook - - -Installation -~~~~~~~~~~~~ - -.. code:: bash - - pip install importhook - - -Usage -~~~~~ - -.. code:: python - - import importhook - - # Setup hook to be called any time the `socket` module is imported and loaded into module cache - @importhook.on_import('socket') - def on_socket_import(socket): - print('"socket" module has been imported') - - # Import module - import socket diff --git a/importhook/meta_paths.py b/importhook/meta_paths.py index 6fb35fc..484dc4c 100644 --- a/importhook/meta_paths.py +++ b/importhook/meta_paths.py @@ -13,8 +13,3 @@ class HookMetaPaths(list): def __setitem__(self, key, val): super(HookMetaPaths, self).__setitem__(hook_finder(val)) - - def __add__(self, other): - if not isinstance(other, HookMetaPaths): - other = HookMetaPaths(other) - super(HookMetaPaths, self).__add__(other) diff --git a/setup.py b/setup.py index 9fcdd00..46c0ca8 100644 --- a/setup.py +++ b/setup.py @@ -1,25 +1,26 @@ """ importhook -============== +========== """ from setuptools import find_packages, setup def get_long_description(): - with open('README.rst') as f: + with open('README.md') as f: rv = f.read() return rv setup( name='importhook', - version='1.0.0', + version='1.0.1', url='https://github.com/brettlangdon/importhook', license='MIT', author='Brett Langdon', author_email='me@brett.is', description='Execute code when certain modules are imported', long_description=get_long_description(), + long_description_content_type='text/markdown', py_modules=find_packages(), zip_safe=False, include_package_data=True, @@ -30,7 +31,6 @@ setup( 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Operating System :: OS Independent', - 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 3', 'Programming Language :: Python', ]