<commit_before># -*- coding: utf-8 -*-

"""Utilities for loading definitions from reusable Django apps."""

import copy

from django.core.exceptions import ImproperlyConfigured
from django.utils.importlib import import_module

from djanjinja import get_env
from djanjinja.environment import Environment


class Bundle(object):
    
    """
    Store a bunch of tests, filters and functions from a single app.
    
    Instances of the ``Bundle`` class store tests, filters and functions in an
    internal register that can then be lazily merged with the Jinja2
    environment later on. It is used when apps want to define a number of
    utilities for lazy loading from template code, typically using the
    ``{% load %}`` template tag defined in djanjinja.extensions.bundles.
    
    Essentially, a bundle is just an environment without the templating and
    loading parts. They can be pushed onto another environment, which will
    return a new environment with a new set of filters, globals and tests but
    all the other attributes from the original environment.
    """
    
    TYPES = (
        'test',
        'filter', 'ctxfilter', 'envfilter',
        'function', 'ctxfunction', 'envfunction'
    )
    
    # Set these attributes now, to prevent pylint from flagging errors later.
    test = None
    filter = None
    ctxfilter = None
    envfilter = None
    function = None
    ctxfunction = None
    envfunction = None
    
    def __init__(self):
        self.filters = {}
        self.globals = {}
        self.tests = {}
    
    def merge_into(self, environment=None):
        """Push this bundle onto the environment, returning a new env."""
        
        if environment is None:
            environment = get_env()
        
        for attr in ['globals', 'filters', 'tests']:
            getattr(environment, attr).update(getattr(self, attr))
        
        return environment
    
    
    # Dynamically create decorators for each type.
    for type in TYPES:
        # We get the attribute from the `Environment` class itself because it
        # will be an unbound method at this point.
        # `im_func` is the underlying function definition. Within this
        # definition, `self` has no special meaning, so by copying it here
        # we can essentially repurpose the same method for this class. It's
        # actually similar to a mixin.
        vars()[type] = copy.copy(getattr(Environment, type).im_func)
        
        # Clean up ``type`` from the namespace.
        del type


def get_bundle(app_label, bundle_name):
    
    """
    Loads the bundle with a given name for a specific app.
    
    First, we import the app. Then, we look in the ``bundles`` sub-module for
    the specified bundle name. If the given name is a top-level attribute of
    ``bundles``, we use that. Otherwise, we try to import a submodule of
    ``bundles`` with that name and look for a ``bundle`` attribute in that
    submodule.
    
    Note that this function only retrieves the bundle; it does not insert it
    into the environment. To do this in one step, use the ``load()`` function
    in this module.
    """
    
    from django.conf import settings
    
    # Load the app (this is a plain Python module).
    app, app_name = None, ''
    for full_app_name in settings.INSTALLED_APPS:
        if app_label in (full_app_name, full_app_name.split('.')[-1]):
            app = import_module(full_app_name)
            app_name = full_app_name
            break
    if not (app and app_name):
        raise ImproperlyConfigured(
            'App with label %r not found' % (app_label,))
    
    # Try to find the bundles sub-module. Having this separate allows us to
    # provide a more detailed exception message.
    try:
        bundles = import_module('.bundles', package=app_name)
    except ImportError:
        raise ImproperlyConfigured(
            'App %r has no `bundles` module' % (app_name,))
    
    # Now load the specified bundle name. First we look to see if it is a top-
    # level attribute of the bundles module:
    if hasattr(bundles, bundle_name):
        bundle = getattr(bundles, bundle_name)
        if isinstance(bundle, Bundle):
            return bundle
    <commit_msg>If importing a bundle fails it now gives the original error. Previously, this behaviour was masking the cause of a bundle failing to be imported by assuming it meant that the bundle itself didn't exist. In truth, this error was typically triggered by an import error from the bundle's dependencies.<commit_after># -*- coding: utf-8 -*-

"""Utilities for loading definitions from reusable Django apps."""

import copy

from django.core.exceptions import ImproperlyConfigured
from django.utils.importlib import import_module

from djanjinja import get_env
from djanjinja.environment import Environment


class Bundle(object):
    
    """
    Store a bunch of tests, filters and functions from a single app.
    
    Instances of the ``Bundle`` class store tests, filters and functions in an
    internal register that can then be lazily merged with the Jinja2
    environment later on. It is used when apps want to define a number of
    utilities for lazy loading from template code, typically using the
    ``{% load %}`` template tag defined in djanjinja.extensions.bundles.
    
    Essentially, a bundle is just an environment without the templating and
    loading parts. They can be pushed onto another environment, which will
    return a new environment with a new set of filters, globals and tests but
    all the other attributes from the original environment.
    """
    
    TYPES = (
        'test',
        'filter', 'ctxfilter', 'envfilter',
        'function', 'ctxfunction', 'envfunction'
    )
    
    # Set these attributes now, to prevent pylint from flagging errors later.
    test = None
    filter = None
    ctxfilter = None
    envfilter = None
    function = None
    ctxfunction = None
    envfunction = None
    
    def __init__(self):
        self.filters = {}
        self.globals = {}
        self.tests = {}
    
    def merge_into(self, environment=None):
        """Push this bundle onto the environment, returning a new env."""
        
        if environment is None:
            environment = get_env()
        
        for attr in ['globals', 'filters', 'tests']:
            getattr(environment, attr).update(getattr(self, attr))
        
        return environment
    
    
    # Dynamically create decorators for each type.
    for type in TYPES:
        # We get the attribute from the `Environment` class itself because it
        # will be an unbound method at this point.
        # `im_func` is the underlying function definition. Within this
        # definition, `self` has no special meaning, so by copying it here
        # we can essentially repurpose the same method for this class. It's
        # actually similar to a mixin.
        vars()[type] = copy.copy(getattr(Environment, type).im_func)
        
        # Clean up ``type`` from the namespace.
        del type


def get_bundle(app_label, bundle_name):
    
    """
    Loads the bundle with a given name for a specific app.
    
    First, we import the app. Then, we look in the ``bundles`` sub-module for
    the specified bundle name. If the given name is a top-level attribute of
    ``bundles``, we use that. Otherwise, we try to import a submodule of
    ``bundles`` with that name and look for a ``bundle`` attribute in that
    submodule.
    
    Note that this function only retrieves the bundle; it does not insert it
    into the environment. To do this in one step, use the ``load()`` function
    in this module.
    """
    
    from django.conf import settings
    
    # Load the app (this is a plain Python module).
    app, app_name = None, ''
    for full_app_name in settings.INSTALLED_APPS:
        if app_label in (full_app_name, full_app_name.split('.')[-1]):
            app = import_module(full_app_name)
            app_name = full_app_name
            break
    if not (app and app_name):
        raise ImproperlyConfigured(
            'App with label %r not found' % (app_label,))
    
    # Try to find the bundles sub-module. Having this separate allows us to
    # provide a more detailed exception message.
    try:
        bundles = import_module('.bundles', package=app_name)
    except ImportError as msg:
        raise ImproperlyConfigured(
            'App %r has no `bundles` module or an error occured while importing it (error was `%s`)'\
                % (app_name, msg))
    
    # Now load the specified bundle name. First we look to see if it is a top-
    # level attribute of the bundles module:
    if hasattr(bundles, bundle_name):
        bundle = getattr(bundles, bundle_name)
        if isinstance(bundle, Bundle):
            return bundle
    
{'fraction_non_alphanumeric': 0.07235579636527825, 'fraction_numerical': 0.0006772773450728074, 'mean_word_length': 2.5454181672669067, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7616621', 'n_tokens_mistral': 2361, 'n_tokens_neox': 2325, 'n_words': 1036}