{ "info": { "author": "Zach Ennenga", "author_email": "astrozees@gmail.com", "bugtrack_url": null, "classifiers": [], "description": "# Module Discovery Utils\n\n## Motivation\n\nA simple library to make it easier to dynamically find and discover objects from a predefined set of packages.\n\nThere is often a pattern used in python where subclasses of an object are defined, and by virtua of being a subclass, those objects are either directly or indirectly added to a registry.\n\nExamples of this are Flask routes, and Sqlalchemy tables.\n\nThis is all well and good, but the problem is, you need to import those modules to register them. A common solution is to create a registry file of sorts, sometimes in the __init__.py file.\n\nOften, you have a significant number of classes, and are frequently adding new ones, or removing old ones. However, maintaining a single file that imports all of them can be cumbersome, and falls afoul of python style rules and formatting tools, as the imports are technically not used in the registry file.\n\nThus, using python's importlib, pkgutils, and introspection tools, there are a number of ways to dynamically scan a package, load all submodules, and parse out objects of interest.\n\nI have implemented and reimplemented this sort of code many, many times, and I hope I can prevent others from doing the same in the future.\n\n## Usage\n\n\nTo recursively import all modules in a group of packages:\n```python\nfrom module_discovery_utils import load_all_modules_in_packages\nfrom blah import package, package2\n\nload_all_modules_in_packages(package)\nload_all_modules_in_packages(package2)\n```\nOR\n```python\nfrom module_discovery_utils import load_all_modules_in_packages\nfrom blah import package, package2\n\nload_all_modules_in_packages([package, package2])\n\n```\n\nTo find all subclasses in a package:\n```python\nfrom module_discovery_utils import find_subclasses_in_packages\nfrom blah import package, package2, BaseClass1, BaseClass2\n\nfind_subclasses_in_packages([package, package2], [BaseClass1, BaseClass2])\n```\n\nYou can also technically do:\n```python\nfrom module_discovery_utils import load_all_modules_in_packages\nfrom blah import package, package2, BaseClass\n\nload_all_modules_in_packages([package, package2])\nsubclasses = BaseClass.__subclasses__()\n```\nHowever, the problem I have with that solution is there are cases (such as testing) where you may not want to retrieve all defined subclasses.\n\nIt's pratically impossible to control what gets imported when in a python program, and you don't want to potentially rely on import order, or imports from other parts of the program to determine which subclasses are \"visible\" at any given time.\n\nTo find all instances of a given base class in a given set of packages:\n```python\nfrom module_discovery_utils import find_instances_in_packages\nfrom blah import package, package2, BaseClass1, BaseClass2\n\nfind_instances_in_packages([package, package2], [BaseClass1, BaseClass2])\n```", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/zsennenga/module-discovery-utils", "keywords": "", "license": "Apache License 2.0", "maintainer": "", "maintainer_email": "", "name": "module-discovery-utils", "package_url": "https://pypi.org/project/module-discovery-utils/", "platform": "", "project_url": "https://pypi.org/project/module-discovery-utils/", "project_urls": { "Homepage": "https://github.com/zsennenga/module-discovery-utils" }, "release_url": "https://pypi.org/project/module-discovery-utils/1.1.1/", "requires_dist": null, "requires_python": "", "summary": "A simple library to allow easy package/module level introspection", "version": "1.1.1" }, "last_serial": 4553320, "releases": { "1.0.1": [ { "comment_text": "", "digests": { "md5": "3a47fafb24f9385a55c44ce29c685919", "sha256": "350dcb6dd65a182391b557918099ddd48df3de24189beaa41f4a07a1ae8b1765" }, "downloads": -1, "filename": "module-discovery-utils-1.0.1.tar.gz", "has_sig": false, "md5_digest": "3a47fafb24f9385a55c44ce29c685919", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 3826, "upload_time": "2018-12-02T08:52:58", "url": "https://files.pythonhosted.org/packages/92/ce/dc5ea49f934f61ddf974f0c4423d651f730193aa9961e6643f46cd54eefe/module-discovery-utils-1.0.1.tar.gz" } ], "1.1.1": [ { "comment_text": "", "digests": { "md5": "68e1212bd6dd3adb4cd469302f2815d4", "sha256": "e02a9873a1aa105e893934d4365cd2606996a64c56a45e9c6e6f4faf955f5e7b" }, "downloads": -1, "filename": "module-discovery-utils-1.1.1.tar.gz", "has_sig": false, "md5_digest": "68e1212bd6dd3adb4cd469302f2815d4", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 3964, "upload_time": "2018-12-02T21:17:11", "url": "https://files.pythonhosted.org/packages/c1/17/c0e2a407f736e349962f18ac2ac797b7160ac14e99a9a6272f60f76be988/module-discovery-utils-1.1.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "68e1212bd6dd3adb4cd469302f2815d4", "sha256": "e02a9873a1aa105e893934d4365cd2606996a64c56a45e9c6e6f4faf955f5e7b" }, "downloads": -1, "filename": "module-discovery-utils-1.1.1.tar.gz", "has_sig": false, "md5_digest": "68e1212bd6dd3adb4cd469302f2815d4", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 3964, "upload_time": "2018-12-02T21:17:11", "url": "https://files.pythonhosted.org/packages/c1/17/c0e2a407f736e349962f18ac2ac797b7160ac14e99a9a6272f60f76be988/module-discovery-utils-1.1.1.tar.gz" } ] }