# Custom resolvers

The resolver is a pluggable object that webassets uses to find the contents of a `Bundle` on the filesystem, as well as to generate the correct urls to these files.

For example, the default resolver searches the `Environment.load_path`, or looks within `Environment.directory`. The webassets Django integration will use Django’s staticfile finders to look for files.

For normal usage, you will not need to write your own resolver, or indeed need to know how they work. However, if you want to integrate `webassets` with another framework, or if your application is complex enough that it requires custom file referencing, read on.

## The API as webassets sees it

`webassets` expects to find the resolver via the `Environment.resolver` property, and expects this object to provide the following methods:

Resolver.resolve_source(ctx, item)

  Given `item` from a Bundle’s contents, this has to return the final value to use, usually an absolute filesystem path.

  Note

  It is also allowed to return urls and bundle instances (or generally anything else the calling `Bundle` instance may be able to handle). Indeed this is the reason why the name of this method does not imply a return type.

  The incoming item is usually a relative path, but may also be an absolute path, or a url. These you will commonly want to return unmodified.

  This method is also allowed to resolve `item` to multiple values, in which case a list should be returned. This is commonly used if `item` includes glob instructions (wildcards).

  Note

  Instead of this, subclasses should consider implementing `search_for_source()` instead.

Resolver.resolve_output_to_path(ctx, target, bundle)

  Given `target`, this has to return the absolute filesystem path to which the output file of `bundle` should be written.

  `target` may be a relative or absolute path, and is usually taking from the `Bundle.output` property.

  If a version-placeholder is used (`%(version)s`, it is still unresolved at this point.

Resolver.resolve_source_to_url(ctx, filepath, item)

  Given the absolute filesystem path in `filepath`, as well as the original value from `Bundle.contents` which resolved to this path, this must return the absolute url through which the file is to be referenced.

  Depending on the use case, either the `filepath` or the `item` argument will be more helpful in generating the url.

  This method should raise a `ValueError` if the url cannot be determined.

Resolver.resolve_output_to_url(ctx, target)

  Given `target`, this has to return the url through which the output file can be referenced.

  `target` may be a relative or absolute path, and is usually taking from the `Bundle.output` property.

  This is different from `resolve_source_to_url()` in that you do not passed along the result of `resolve_output_to_path()`. This is because in many use cases, the filesystem is not available at the point where the output url is needed (the media server may on a different machine).

## Methods to overwrite

However, in practice, you will usually want to override the builtin `Resolver`, and customize it’s behaviour where necessary. The default resolver already splits what is is doing into multiple methods; so that you can either override them, or refer to them in your own implementation, as makes sense.

Instead of the official entrypoints above, you may instead prefer to override the following methods of the default resolver class:

Resolver.search_for_source(ctx, item)

  Called by `resolve_source()` after determining that `item` is a relative filesystem path.

  You should always overwrite this method, and let `resolve_source()` deal with absolute paths, urls and other types of items that a bundle may contain.

Resolver.search_load_path(ctx, item)

  This is called by `search_for_source()` when a `Environment.load_path` is set.

  If you want to change how the load path is processed, overwrite this method.

## Helpers to use

The following methods of the default resolver class you may find useful as helpers while implementing your subclass:

Resolver.consider_single_directory(directory, item)

  Searches for `item` within `directory`. Is able to resolve glob instructions.

  Subclasses can call this when they have narrowed done the location of a bundle item to a single directory.

Resolver.glob(basedir, expr)

  Evaluates a glob expression. Yields a sorted list of absolute filenames.

Resolver.query_url_mapping(ctx, filepath)

  Searches the environment-wide url mapping (based on the urls assigned to each directory in the load path). Returns the correct url for `filepath`.

  Subclasses should be sure that they really want to call this method, instead of simply falling back to `super()`.

### Example: A prefix resolver

The following is a simple resolver implementation that searches for files in a different directory depending on the first directory part.

    from webassets.env import Resolver

    class PrefixResolver(Resolver):

        def __init__(self, prefixmap):
            self.map = prefixmap

        def search_for_source(self, ctx, item):
            parts = item.split('/', 1)
            if len(parts) < 2:
                raise ValueError(
                    '"%s" not valid; a static path requires a prefix.' % item)

            prefix, name = parts
            if not prefix in self.map:
                raise ValueError(('Prefix "%s" of static path "%s" is not '
                                  'registered') % (prefix, item))

            # For the rest, defer to base class method, which provides
            # support for things like globbing.
            return self.consider_single_directory(self.map[prefix], name)

Using it:

    env = webassets.Environment(path, url)
    env.resolver = PrefixResolver({
        'app1': '/var/www/app1/static',
        'app2': '/srv/deploy/media/app2',
    })
    bundle = Bundle(
       'app2/scripts/jquery.js',
       'app1/*.js',
    )

### Other implementations

- django-assets Resolver (search for `class DjangoResolver`).

- Flask-Assets Resolver (search for `class FlaskResolver`).

- pyramid_webassets Resolver (search for `class PyramidResolver`).