{"id":19741203,"url":"https://github.com/marrow/package","last_synced_at":"2025-04-30T06:30:23.652Z","repository":{"id":24569771,"uuid":"27977265","full_name":"marrow/package","owner":"marrow","description":"Plugin discovery and management, dependency graphing, and object import path canonicalization.","archived":false,"fork":false,"pushed_at":"2025-01-18T02:00:15.000Z","size":132,"stargazers_count":9,"open_issues_count":2,"forks_count":1,"subscribers_count":2,"default_branch":"develop","last_synced_at":"2025-04-14T06:50:02.140Z","etag":null,"topics":["canonicalization","cpython","plugin-manager","plugin-system","pypi","pypy","python","reference-parsing"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/marrow.png","metadata":{"files":{"readme":"README.rst","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2014-12-13T23:34:07.000Z","updated_at":"2025-01-18T02:00:14.000Z","dependencies_parsed_at":"2024-11-12T01:26:59.402Z","dependency_job_id":"50a07398-bb9b-4f19-b072-a88f73ebe6f1","html_url":"https://github.com/marrow/package","commit_stats":{"total_commits":95,"total_committers":3,"mean_commits":"31.666666666666668","dds":0.04210526315789476,"last_synced_commit":"c6d874afe735538abcf84a7b259ffaa7515376ad"},"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marrow%2Fpackage","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marrow%2Fpackage/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marrow%2Fpackage/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marrow%2Fpackage/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/marrow","download_url":"https://codeload.github.com/marrow/package/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251653883,"owners_count":21622210,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["canonicalization","cpython","plugin-manager","plugin-system","pypi","pypy","python","reference-parsing"],"created_at":"2024-11-12T01:25:12.505Z","updated_at":"2025-04-30T06:30:23.368Z","avatar_url":"https://github.com/marrow.png","language":"Python","readme":"==============\nMarrow Package\n==============\n\n    © 2014-2023 Alice Bevan-McGregor and contributors.\n\n..\n\n    https://github.com/marrow/package\n\n..\n\n    |latestversion| |masterstatus| |mastercover| |issuecount|\n\n1. What is Marrow Package?\n==========================\n\nThis package is a combination of utilities for handling object lookup, resolving object names, and managing simple to\ncomplex plugin architectures.  Notably it includes a dependency graph system for extensions and helper for looking up\nqualified object names.\n\nThis library is fully unit tested where possible.\n\n\n2. Installation\n===============\n\nInstalling ``marrow.package`` is easy, just execute the following in a terminal::\n\n    pip install marrow.package\n\n**Note:** We *strongly* recommend always using a container, virtualization, or sandboxing environment of some kind when\ndeveloping using Python; installing things system-wide is yucky (for a variety of reasons) nine times out of ten.  We\nprefer light-weight `virtualenv \u003chttps://virtualenv.pypa.io/en/latest/virtualenv.html\u003e`_, others prefer solutions as\nrobust as `Vagrant \u003chttp://www.vagrantup.com\u003e`_.\n\nIf you add ``marrow.package`` to the ``install_requires`` argument of the call to ``setup()`` in your application's\n``setup.py`` file, Marrow Package will be automatically installed and made available when your own application or\nlibrary is installed.  We recommend using \"less than\" version numbers to ensure there are no unintentional\nside-effects when updating.  Use ``marrow.package\u003c2.2`` to get all bugfixes for the current release, and\n``marrow.package\u003c3.0`` to get bugfixes and feature updates while ensuring that large breaking changes are not installed.\n\n\n2.1. Development Version\n------------------------\n\n    |developstatus| |developcover|\n\nDevelopment takes place on `GitHub \u003chttps://github.com/\u003e`_ in the\n`marrow.package \u003chttps://github.com/marrow/package/\u003e`_ project.  Issue tracking, documentation, and downloads\nare provided there.\n\nInstalling the current development version requires `Git \u003chttp://git-scm.com/\u003e`_, a distributed source code management\nsystem.  If you have Git you can run the following to download and *link* the development version into your Python\nruntime::\n\n    git clone https://github.com/marrow/package.git\n    (cd package; python setup.py develop)\n\nYou can then upgrade to the latest version at any time::\n\n    (cd package; git pull; python setup.py develop)\n\nIf you would like to make changes and contribute them back to the project, fork the GitHub project, make your changes,\nand submit a pull request.  This process is beyond the scope of this documentation; for more information see\n`GitHub's documentation \u003chttp://help.github.com/\u003e`_.\n\n\n3. Getting Object References\n============================\n\nObject references describe the module and attribute path needed to resolve the object.  For example, ``foo:bar`` is a\nreference that describes importing \"foo\" prior to retrieving an object named \"bar\" from the module.  On Python 3.3+ a\nuseful shortcut is provided, ``__qualname__`` which speeds up this lookup.\n\nFor example, let's define a class and get a reference to it::\n\n    from marrow.package.canonical import name\n    \n    class Example(object):\n        pass\n    \n    assert name(Example) == '__main__:Example'\n\nYou can, depending on platform, retrieve a reference to any of the following types of objects:\n\n* Module level:\n\t* class\n\t* class instance\n\t* class method\n\t* class staticmethod\n\t* function\n\t* instance classmethod\n\t* instance method\n\t* instance staticmethod\n* nested classes and methods\n* closures\n\n\n3.1. Resolving Plugin References\n================================\n\nThe ``load`` utility can optionally be provided a plugin namespace to search. If the target object is found within the\nnamespace, the name of the plugin entry will be returned. By default, if a named plugin can **not** be found, a\n``LookupError`` will be raised. If a direct reference is acceptable, the boolean ``direct`` argument (third positional)\ncan be made truthy to permit direct references.\n\n    from marrow.package.canonical import name\n\n    assert name(name, 'marrow.package.sample') == 'name'\n\n\n\n4. Resolving Object References\n==============================\n\nTwo utilities are provided which allow you resolve string path references to objects.  The first is quite simple::\n\n    from marrow.package.loader import traverse\n    \n    assert traverse({'foo': {'bar': 27}}, 'foo.bar') == 27\n\nThis will search the dictionary described for a \"foo\" element, then \"bar\" element.\n\nThe ``traverse`` function takes some additional optional arguments.  If ``executable`` is ``True`` any executable\nfunction encountered will be executed without arguments. Traversal will continue on the result of that call.  You can\nchange the separator as desired, i.e. to a '/' using the ``separator`` argument.\n\nBy default attributes (but not array elements) prefixed with an underscore are taboo.  They will not resolve, raising\na LookupError.  You can allow these by setting ``protect`` to ``False``.\n\nCertain allowances are made: if a 'path segment' is numerical, it's treated as an array index. If attribute lookup\nfails, it will re-try on that object using array notation and continue from there.  This makes lookup very flexible.\n\n\n4.1. Resolving Import References\n--------------------------------\n\nThe more complete API for name resolution uses the ``load`` function, which takes the same optional keyword arguments\nas ``traverse``.  Additionally, this function accepts an optional ``namespace`` to search for plugins within.  For\nexample::\n\n    from marrow.package.loader import load\n    from pip import main\n    \n    # Load class Foo from example.objects\n    load('example.objects:Foo')\n        \n    # Load the result of the class method ``new`` of the Foo object\n    load('example.objects:Foo.new', executable=True)\n    \n    # Load the \"pip\" command-line interface.\n    assert load('pip', 'console_scripts') is main\n\nProviding a namespace does not prevent explicit object lookup (dot-colon notation) from working.\n\n\n\n4.2. Caching Import References\n------------------------------\n\nAn attribute-access dictionary is provided that acts as an import cache::\n\n    from marrow.package.cache import PackageCache\n    from pip import main\n    \n    cache = PackageCache('console_scripts')\n    \n    assert cache.pip is main\n    assert cache['pip'] is main\n    assert len(cache) == 1\n    assert 'pip' in cache\n\n\n4.3. Lazy Import Reference Attributes\n-------------------------------------\n\nYou can lazily load and cache an object reference upon dereferencing from an instance using the ``lazyload`` utility\nfrom the ``marrow.package.lazy`` module.  Assign the result of calling this function with either an object reference\npassed in positionally::\n\n    class MyClass:\n        debug = lazyload('logging:debug')\n\nOr the attribute path to traverse (using ``marrow.package.loader:traverse``) prefixed by a period::\n\n    class AnotherClass:\n        target = 'logging:info'\n        log = lazyload('.target')\n\nAny additional arguments are passed to the eventual call to `load()`.  This utility builds on a simpler one that is\nalso offered for fully-tested re-use, ``lazy``, a decorator like ``@property`` which will cache the result, with\nthread-safe locking to ensure only one call will ever be made to the decorated function, per instance.\n\n\n5. Managing Plugins\n===================\n\nThis package provides two main methods of dealing with plugins and extensions, the first is simple, the second\nprovides full dependency graphing of the extensions.\n\n5.1. Plugin Manager\n-------------------\n\nThe ``PluginManager`` class takes two arguments: the first is the entry point ``namespace`` to search, the second is\nan optional iterable of folders to add to the Python search path for installed packages, allowing your application to\nhave a dedicated plugins folder.\n\nIt provides a ``register`` method which take a name and the object to use as the plugin and registers it internally,\nsupporting both attribute and array-like notation for retrieval, as well as iteration of plugins (includes all entry\npoint plugins found and any custom registered ones).\n\n5.2. Extension Manager\n----------------------\n\nAt a higher level is a ``PluginManager`` subclass called ``ExtensionManager`` which additionally exposes a ``sort``\nmethod capable of resolving dependency order for extensions which follow a simple protocol: have an attribute or array\nelement matching the following, all optional:\n\n* ``provides`` — declare tags describing the features offered by the plugin\n* ``needs`` — declare the tags that must be present for this extension to function\n* ``uses`` — declare the tags that must be evaluated prior to this extension, but aren't hard requirements\n* ``first`` — declare that this extension is a dependency of all other non-first extensions\n* ``last`` — declare that this extension depends on all other non-last extensions\n* ``excludes`` — declare tags that must not be present in other plugins for this one to be usable\n\n\n6. Version History\n==================\n\nVersion 1.0\n-----------\n\n* **Initial release.**  Combination of utilities from other Marrow projects.\n\nVersion 1.0.1\n-------------\n\n* **Extended decorator support.**  New code paths and tests added to cover canonicalization of decorated functions.\n\nVersion 1.0.2\n-------------\n\n* **Diagnostic information.**  Removed extraneous diagnostic information.\n\nVersion 1.1\n-----------\n\n* **Added lazy evaluation.**  There are two new helpers for caching of ``@property``-style attributes and lazy lookup\n  of object references.\n\nVersion 1.2\n-----------\n\n* **Deprecated Python 2.6 and 3.3.** While no particular backwards incompatible change was made; as setuptools no\n  longer supports these versions, these versions are now hard/impossible to test.\n* **Allow extensions to declare exclusions.** Flags that must not be defined for the extension to be usable.\n\nVersion 2.0\n-----------\n\n* **Updated minimum Python version.** Marrow Package now requires Python 3.5 or later.\n* **Removed Python 2 support and version specific code.** The project has been updated to modern Python packaging\n  standards, including modern namespace use. Modern namespaces are wholly incompatible with the previous namespacing\n  mechanism; this project can not be simultaneously installed with any Marrow project that is Python 2 compatible.\n* **Extensive type annotation and in-development validation.** When run without optimizations (`-O` argument to Python\n  or `PYTHONOPTIMIZE` environment variable) type annotations will be validated.\n* **Reduced test fragility.** Previously the tests utilized the `console_scripts` namespace, this was fragile to the\n  presence of other installed libraries, e.g. `numpy` broke the tests on Travis.\n\nVersion 2.1\n-----------\n\n* **Migrated from Travis-CI to GitHub Actions for test automation.**\n* **Implement package-relative path lookup.** The `load` utility function can now resolve the path to a file relative\n  to a package. This is particularly useful for looking up the path to template files or on-disk static assets.\n* **Protected attribute access now fails.** Underscore-prefixed attributes are assumed to be \"protected\", with the\n  technical note that Python adds new internal \"double underscore\" attributes which must not spontaneously exist, or\n  generate errors other than `AttributeError`.\n* **Tests are now independent of third-party plugin registration.**\n\nVersion 2.1.1\n-------------\n\n* **Update type hinting validation.** The ``typeguard`` package has removed a functional utility; decoration now used.\n* **Canonical plugin name resolution.** The ``name()`` utility can now resolve the plugin name if given a plugin\n  namespace to check.\n\n\n7. License\n==========\n\nMarrow Package has been released under the MIT Open Source license.\n\n7.1. The MIT License\n--------------------\n\nCopyright © 2014-2023 Alice Bevan-McGregor and contributors.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\ndocumentation files (the “Software”), to deal in the Software without restriction, including without limitation the\nrights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit\npersons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the\nSoftware.\n\nTHE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\nWARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\nOTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n.. |masterstatus| image:: http://img.shields.io/travis/marrow/package/master.svg?style=flat\n    :target: https://travis-ci.org/marrow/package\n    :alt: Release Build Status\n\n.. |developstatus| image:: http://img.shields.io/travis/marrow/package/develop.svg?style=flat\n    :target: https://travis-ci.org/marrow/package\n    :alt: Development Build Status\n\n.. |latestversion| image:: http://img.shields.io/pypi/v/marrow.package.svg?style=flat\n    :target: https://pypi.python.org/pypi/marrow.package\n    :alt: Latest Version\n\n.. |mastercover| image:: http://img.shields.io/codecov/c/github/marrow/package/master.svg?style=flat\n    :target: https://codecov.io/github/marrow/package?branch=master\n    :alt: Release Test Coverage\n\n.. |developcover| image:: http://img.shields.io/codecov/c/github/marrow/package/develop.svg?style=flat\n    :target: https://codecov.io/github/marrow/package?branch=develop\n    :alt: Development Test Coverage\n\n.. |issuecount| image:: http://img.shields.io/github/issues/marrow/package.svg?style=flat\n    :target: https://github.com/marrow/package/issues\n    :alt: Github Issues\n\n.. |cake| image:: http://img.shields.io/badge/cake-lie-1b87fb.svg?style=flat\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarrow%2Fpackage","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarrow%2Fpackage","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarrow%2Fpackage/lists"}