lookups

DCI lookups in Python (inspired by Netbeans Platform Lookups API)


Keywords
lookup, lookups, dci
License
MPL-2.0
Install
pip install lookups==0.3.0

Documentation

PyPI version shields.io PyPI download shields.io PyPI Python version shields.io GitHub license shields.io

GitHub commits since shields.io GitHub build shields.io Codecov shields.io

lookups - Find object instances

DCI lookups for Python (inspired by Netbeans Platform Lookups API)

Principle

A lookup is like a dict where you can store object instances as values. And the search keys are their type classes.

Simply.

But lookups implements a bit more than that:

  • You can also lookup by parent class and not just the most subclasses of an instance.
  • You can get hold of a lookups.Result, which allows you to register a listener for a given class search. You will be notified when an instance of that class is added/removed from the lookup.
  • Deferred instanciation with lookups.Convertor. That is, an 'instance' can appear in a lookup but not be instanciated until it is actually used (ie. looked up). Useful for heavy objects or plugins.
  • lookups.Item can provide you with additional info on an instance: display string, persistence ID string, type, and instance itself.

lookups.GenericLookup

This is the most basic but versatile and dynamic lookup. (HINT: For Java folks, it corresponds to your AbstractLookup ;-) ).

It comes in two main parts:

  • lookups.InstanceContent provide write-access to the lookup: add/set/remove instances.
  • lookups.GenericLookup provide read-access to search in the lookup.
from lookups import InstanceContent, GenericLookup

my_content = InstanceContent()
my_lookup = GenericLookup(my_content)

# Adds some objects
class ParentClass:
    pass

class ChildClass(ParentClass):
    pass

parent = ParentClass()
my_content.add(parent)
child1 = ChildClass()
my_content.add(child1)
child2 = ChildClass()
my_content.add(child2)

...

# lookup(cls): get first matching instance
# a_match will be any of parent, child1 or child2
a_parent_match = my_lookup.lookup(ParentClass)

# lookup_all(cls): get all matching instances
# all_parent_matches is an immutable sequence
#     of parent, child1 and child2
all_parent_matches = my_lookup.lookup_all(ParentClass)
# all_children_matches is an immutable sequence
#     of child1 and child2
all_children_matches = my_lookup.lookup_all(ChildClass)

# lookup_result(cls): get a Result object for the searched class
parent_result = my_lookup.lookup_result(ParentClass)
# all_instances(): all instances corresponding to the searched
#     class (ie. similar to plain lookup_all())
parent_result.all_instances()
# all_classes(): Immutable set of all types in the result.
#     Here it would be set(ParentClass, ChildClass)
parent_result.all_classes()

# Lookup result listener
def call_me_back(result):
    print('Result changed. Instances are now', result.all_instances())

parent_result.add_lookup_listener(call_me_back)

...

my_content.remove(child1)
# -> This will invoke call_me_back()
# You can also provide a `concurrent.futures.Executor` when
# creating the content to control how the listeners are called:
#     InstanceContent(notify_in: Executor = None).

Other lookups

  • lookups.Lookup.get_default(): The default lookup in a system.
  • lookups.ProxyLookup: A lookup that merge results from several lookups.
  • lookups.DelegatedLookup: A lookup that redirects to another (dynamic) lookup, through a LookupProvider.
  • lookups.EntryPointLookup: A lookup loading its instances from a setuptools entry point group (ie. provided by any installed package).
  • lookups.fixed: Simple unmodifiable lookup. Content is set at creation time. Will be one of:
    • lookup.SimpleLookup: A basic lookup with a static content.
    • lookups.singleton: Unmodifiable lookup that contains just one fixed object.
    • lookups.EmptyLookup: A lookup containing nothing.