API Details¶
The first thing to know about Ways is that it is not a tool, it is a toolkit. Ways is not immediately useful. You, the user, make Ways useful for your pipeline.
If you haven’t already, please read the API Summary page on each of the main ideas that Ways uses. This document will expand on ideas written there.
Contexts¶
If you go to ways.base.situation.Context
, you can read more about the class.
Context objects have
- a hierarchy
- a data property which is similar to a ChainMap
- an actions property which can be used to extend a Context’s interface
The Context object is the most important class in Ways because it encompasses two critical functions.
- The Context is basically a “hierarchy interface”. Everything that Ways builds is based on hierarchies that the user has full control over. Hierarchies each have their own actions, data, and order of importance and the Context lets us write functions around them.
- The data that a Context uses is loaded exactly when it is queried. This means that we can load some plugins, create a Context object, add another plugin, and the Context picks up that new data without you doing anything.
Once you’ve read through the Context object, read ways.api.get_context()
.
You should become familiar with the Flyweight design pattern
(http://sourcemaking.com/design_patterns/flyweight) because that’s also an
important part about how Ways creates Context objects.
Plugins¶
In the ways.base.plugin
file, you’ll find a couple very basic classes.
Context objects are built out of plugins. There’s not much to say about plugins other than that they wrap around a dict that the user loads.
Two documents that cover all the different Plugin Sheet keyes are Plugin Basics and Advanced Plugin Topics.
At this point, it’s a good idea to re-read each of Context object’s methods and how those relate to the different plugin keys.
Ways Cache¶
Now that you understand Context objects, it’s important to know how they are
loaded. In the ways.base.cache
file, you’ll find the functions that are
used to register Contexts and plugins, which we’ve talked about already, and also
register Descriptors and Actions, which we haven’t been explained yet.
When Ways first is imported and used, it gathers plugins that it can see in the WAYS_PLUGINS and WAYS_DESCRIPTOR environment variables. Once you’re actually in Python, it’s best to just use Python functions to add additional objects.
If you absolutely need to add paths to those environment variables, first ask
yourself why you think you need to. If you still think its necessary, add the
paths with os.environ and the run ways.api.init_plugins()
.
Warning
This function will remove any objects that were added using Python so it’s not recommended to use. But you can do it.
Descriptors¶
Read through Descriptors to get the jist about how Descriptor objects are built as a user. There’s not much to say about them other than they’re classes used to load Plugin Sheets. That way, you can load plugins into Ways from disk, a database, or whatever other method you’d like.
Other than that, they are not special in any way. Everything related to
Descriptors is found in the ways.base.descriptor
file. To see how
they’re loaded, revisit ways.base.cache
.
In particular, two things in cache.py are interesting to maintainers.
- add_search_path is just an alias to add_descriptor. The user can add plugins just by giving a filepath or folder and the Descriptor object needed will be built for them. Most of the time, that’s all anyone need while using Ways.
- add_descriptor and add_plugin both try their best to catch errors before they happen so the user can review any Descriptor or plugins that didn’t load. For more information on that, check out Troubleshooting Ways.
Actions¶
Many pages talk about Actions. It’s mentioned in API Summary, Why use Ways, Common Patterns And Best Practices and even has its own section in Troubleshooting Ways. There’s not much point in repeating what has already been said so lets talk just about how Ways actually exposes Actions to the user.
When an Action is registered to Ways (using ways.base.cache.add_action()
),
the user specifies a hierarchy for the Action and a name to call it.
This is kept in a dictionary in ways.ACTION_CACHE
.
When the user calls an action using ways.api.Context.actions
,
the following happens:
- Ways looks up to see if that Action/Context has a definition for that Action. If there’s no definition, look for a default value. If neither, raise an AttributeError.
- If an Action is found, the function is wrapped using funtools.partial. The partial function adds the Context/Asset that called it as the first arg.
context = ways.api.get_context('something')
context.actions.some_action_name()
So by using functools.partial, we eliminate the need for the user to write
context.actions.some_action_name(context)
Any class that inherits from ways.api.Action
is automatically registered to
Ways, because the ways.parsing.resource.ActionRegistry
metaclass registers
the class once it’s defined.
Assets¶
The Asset object is a simple wrapper around a Context object. Nearly all of its methods are used for getting data that the user has provided.
All classes and functions are located in the ways.parsing.resource
file.
There are a couple functions in particular that are interesting to developers.
The first is ways.parsing.resource._get_value()
. If a user queries a part
of an Asset that exists, the value is returned. But if the value doesn’t exist,
Ways is still able to “build” the value based on surrounding information. For the
sake of making it easier to search for, the two methods are called
“Parent-Search” and “Child-Search”. All of the functions related to those
search methods are either scoped functions in ways.parsing.resource._get_value()
or somewhere within ways.parsing.resource
.
The other function that’s very important is
ways.parsing.resource._find_context_using_info()
.
Basically, if a user tries to run ways.api.get_asset()
without giving a context,
this function will try to “find” a matching Context to use instead. At the risk
of reiterating the same information twice, read through
ways.parsing.resource._find_context_using_info()
and func:ways.api.get_asset
docstrings. Both functions go in detail about the common pitfalls of auto-finding Contexts.
api.py¶
This module is where almost every function or class meant to be used by developers is put. There’s nothing really special about it, just know that it’s there and exists for the user’s convenience.