Example #1
0
def webpack_settings_from_settings(registry_settings, prefixes=None):
    prefixes = prefixes or ['webpack.']
    settings = {}
    for k, v in registry_settings.items():
        for prefix in prefixes:
            slicelen = len(prefix)
            if k.startswith(prefix):
                setting_name = k[slicelen:]
                try:
                    default = DEFAULT_SETTINGS[setting_name]
                except KeyError:
                    toggle = prefix + 'errorOnInvalidSetting'
                    if toggle in registry_settings:
                        default = ''
                    else:
                        raise ConfigurationError('Invalid webpack setting %s' %
                                                 setting_name)
                # jinja2_webpack exposes a DEFAULT_SETTINGS dict which
                # contains the default value for all the settings.
                # Use the type of the default to process the setting from ini.
                if type(default) == bool:
                    v = asbool(v)
                elif type(default) == FunctionType:
                    v = resolve_dotted(v)
                elif setting_name == 'renderByExt':
                    v = parse_renderByExt(v)
                settings[setting_name] = v
    return settings
Example #2
0
def parse_renderByExt(val):
    # resolves dotted names
    result = parse_multiline(val)
    resolved_result = {}
    for k, v in result.items():
        resolved_result[k] = resolve_dotted(v)
    return resolved_result
Example #3
0
def fetch_inventory_cmd(store, config_file, force_overwrite, data_dir):
    """Build up list of wines available on a store's website.

    Arguments:
    STORE: Store from which to fetch inventory.

        Supported options: kenaston, lc

    Options documentation:

    -c, --config: Path to config file.

    -d, --data_dir: Location to save results to.

    -f, --force_overwrite: Overwrite file specified by --saved_urls. Useful if
        you want to refresh the list - new wines added, etc.
    """
    saved_urls = os.path.join(data_dir, 'inventory', store, 'urls.txt')
    config = ConfigParser()
    print(f'Reading config from {config_file}')
    config.read(config_file)

    all_wine_urls = []

    if os.path.exists(saved_urls) and not force_overwrite:
        print(f'URLs file {saved_urls} already exists and force overwrite '
              'was not specified. Use -f or --force-overwrite if you want to '
              'overwrite this file.\nExiting.')
        sys.exit(0)
    if os.path.exists(saved_urls) and force_overwrite:
        print(f'URLs file {saved_urls} exists but force_overwrite was '
              'specified. Beginning URL fetch.')
    elif not os.path.exists(saved_urls):
        print(f'Beginning URL fetch (this can take some time)...')

    # Setup for processing the first page
    next_page_url = config[store]["first_query_url"]

    # Initialize list parser defined for the given store
    list_parser = resolve_dotted(config[store]['list_parser'])()

    while next_page_url:
        # TODO: debug/verbose when logging set up.
        print(f'Processing {next_page_url}')
        req = requests.get(config[store]["base_url"] + next_page_url)
        wine_urls, next_page_url = list_parser(req)
        all_wine_urls.extend(wine_urls)
        time.sleep(0.1)

    print(f'Done fetching urls. Writing results to {saved_urls}')

    target_dir = os.path.dirname(saved_urls)
    if not os.path.exists(target_dir):
        os.makedirs(target_dir)

    with open(saved_urls, 'w') as f:
        for url in all_wine_urls:
            f.write(config[store]['base_url'] + url + '\n')
Example #4
0
    def dump(self, sql_type):
        log.info("Dumping schemas for SQL type%r" % sql_type)
        # SQL type names are prefixed with an underscore to distinguish
        # them from actual portal_types
        dottedname = sql_type.lstrip('_')
        main_klass = resolve_dotted(dottedname)

        schemas = []
        schema_dumper = SQLSchemaDumper()

        # Also consider columns from base classes (inheritance).
        # We only consider one level of inheritance though, we don't look
        # up base classes recursively.
        bases = list(filter(_is_mapped_class, main_klass.__bases__))
        mapper_args = getattr(main_klass, '__mapper_args__', {})

        if bases and 'polymorphic_identity' not in mapper_args:
            raise NotImplementedError(
                "Unexpected inheritance for %r: Mapped base classes, but "
                "no polymorphic_identity found!" % main_klass)

        for base_class in bases:
            if list(filter(_is_mapped_class, base_class.__bases__)) != []:
                raise NotImplementedError(
                    "More than one level of inheritance currently not"
                    "supported when dumping SQL schemas.")

        for cls in [main_klass] + bases:
            schema = schema_dumper.dump(cls)
            schemas.append(schema)

        type_dump = OrderedDict((
            ('portal_type', sql_type),
            ('title', main_klass.__name__),
            ('schemas', schemas),
        ))

        return type_dump
Example #5
0
    def dump(self, sql_type):
            log.info("Dumping schemas for SQL type%r" % sql_type)
            # SQL type names are prefixed with an underscore to distinguish
            # them from actual portal_types
            dottedname = sql_type.lstrip('_')
            main_klass = resolve_dotted(dottedname)

            schemas = []
            schema_dumper = SQLSchemaDumper()

            # Also consider columns from base classes (inheritance).
            # We only consider one level of inheritance though, we don't look
            # up base classes recursively.
            bases = list(filter(_is_mapped_class, main_klass.__bases__))
            mapper_args = getattr(main_klass, '__mapper_args__', {})

            if bases and 'polymorphic_identity' not in mapper_args:
                raise NotImplementedError(
                    "Unexpected inheritance for %r: Mapped base classes, but "
                    "no polymorphic_identity found!" % main_klass)

            for base_class in bases:
                if list(filter(_is_mapped_class, base_class.__bases__)) != []:
                    raise NotImplementedError(
                        "More than one level of inheritance currently not"
                        "supported when dumping SQL schemas.")

            for cls in [main_klass] + bases:
                schema = schema_dumper.dump(cls)
                schemas.append(schema)

            type_dump = OrderedDict((
                ('portal_type', sql_type),
                ('title', main_klass.__name__),
                ('schemas', schemas),
            ))

            return type_dump
Example #6
0
def update_models_cmd(store, config_file, data_dir):
    saved_urls = os.path.join(data_dir, 'inventory', store, 'urls.txt')

    if not os.path.exists(saved_urls):
        print(f'Inventory list {saved_urls} does not exist. Please run the '
              f'fetch_inventory command for store {store} and then try again.')
        sys.exit(1)

    config = ConfigParser()
    print(f'Reading config from {config_file}')
    config.read(config_file)
    parser = resolve_dotted(config[store]['parser'])()
    db = setup_db(config['default']['db'])

    with open(saved_urls) as f:
        for url in f:
            url = url.strip()
            print(f'Fetching and scraping {url}')
            req = requests.get(url)
            data = parser(req)
            return
            print(f'Adding {data.name} to DB')
            # TODO: replace with tinydb update
            db.insert(data.to_native())
    def install(self):
        """
        Recipe install function.
        """

        # Helper functions

        def split(s):
            """
            Template filter splitting on any whitespace.
            """

            return re.split("\s+", s.strip())

        def as_bool(s):
            """
            Template filter which translates the given string into a boolean.
            """

            return s.lower() in ("yes", "true", "1", "on")

        def strip_dict(d):
            """
            Strips the values of a dictionary in place. All values are assumed
            to be strings. The same dictionary object is returned.
            """

            for k, v in d.iteritems():
                d[k] = v.strip()
            return d

        # Validate template and target lists
        template_file_option = self.options.get(
                "template-file",
                self.options.get("input")
                )
        target_file_option = self.options.get(
                "target-file",
                self.options.get("output")
                )
        template_files = split(template_file_option)
        target_files = split(target_file_option)
        if len(template_files) != len(target_files):
            raise zc.buildout.UserError(
                    "The number of template and target files must match")

        # Validate and normalise target executable option
        target_executables = split(self.options.get("target-executable",
                                                    "false"))
        target_executables = [as_bool(v) for v in target_executables]
        if len(target_executables) == 1:
            value = target_executables[0]
            target_executables = (value for i in xrange(len(template_files)))
        else:
            if len(target_executables) != len(template_files):
                raise zc.buildout.UserError("The number of target executables"
                        "must 0, 1 or match the number of template files")

        # Assemble lists
        files = zip(template_files, target_files, target_executables)

        # Assemble template context
        context = strip_dict(dict(self.options))

        # Handle eggs specially
        if "eggs" in context:
            log.info("Making working set out of the eggs")
            eggs = Eggs(self.buildout, self.options["recipe"], self.options)
            names, eggs = eggs.working_set()
            context["eggs"] = eggs

        # Make recursive dict to be enable access dashed values.
        context['context'] = context

        # Make options from other parts available.
        part_options = dict(self.buildout)
        if 'parts' not in context.keys():
            context.update({'parts': part_options})
        else:
            log.error("You should not use parts as a name of a variable,"
                      " since it is used internally by this receipe")
            raise zc.buildout.UserError("parts used as a variable in %s"
                                        % self.name)

        filters = self.options.get('jinja2_filters')
        if filters:
            jinja2_filters = {}
            filters = filters.split()
            for filter_ in filters:
                try:
                    jinja2_filters[filter_.split('.')[-1]] = resolve_dotted(filter_)
                except ImportError, e:
                    raise zc.buildout.UserError("Filter '%s' not found.\n%s"
                                                % (filter_, e))
Example #8
0
    def load_environment(self):
        """Load an :class:`Environment` instance defined in the YAML file.

        Expects the following format:

        .. code-block:: yaml

            directory: ../static
            url: /media
            debug: True
            updater: timestamp
            filters:
                - my_custom_package.my_filter
            config:
                compass_bin: /opt/compass
                another_custom_config_value: foo

            bundles:
                # ...

        All values, including ``directory`` and ``url`` are optional. The
        syntax for defining bundles is the same as for
        :meth:`~.YAMLLoader.load_bundles`.

        Sample usage::

            from webassets.loaders import YAMLLoader
            loader = YAMLLoader('asset.yml')
            env = loader.load_environment()

            env['some-bundle'].urls()
        """
        f, filename = self._open()
        try:
            obj = self.yaml.load(f) or {}

            env = Environment()

            # Load environment settings
            for setting in ('debug', 'cache', 'versions', 'url_expire',
                            'auto_build', 'url', 'directory', 'manifest', 'load_path',
                            'cache_file_mode',
                            # TODO: The deprecated values; remove at some point
                            'expire', 'updater'):
                if setting in obj:
                    setattr(env, setting, obj[setting])

            # Treat the 'directory' option special, make it relative to the
            # path of the YAML file, if we know it.
            if filename and 'directory' in env.config:
                env.directory = path.normpath(
                    path.join(path.dirname(filename),
                              env.config['directory']))

            # Treat the 'filters' option special, it should resolve the
            # entries as classes and register them to the environment
            if 'filters' in obj:
                try:
                    resolve_dotted = self._get_import_resolver()
                except ImportError:
                    raise EnvironmentError(
                        "In order to use custom filters in the YAMLLoader "
                        "you must install the zope.dottedname package")
                for filter_class in obj['filters']:
                    try:
                        cls = resolve_dotted(filter_class)
                    except ImportError:
                        raise LoaderError("Unable to resolve class %s" % filter_class)
                    if inspect.isclass(cls):
                        register_filter(cls)
                    else:
                        raise LoaderError("Custom filters must be classes "
                            "not modules or functions")

            # Load custom config options
            if 'config' in obj:
                env.config.update(obj['config'])

            # Load bundles
            bundles = self._get_bundles(obj.get('bundles', {}))
            for name, bundle in six.iteritems(bundles):
                env.register(name, bundle)

            return env
        finally:
            f.close()
Example #9
0
    def load_environment(self):
        """Load an :class:`Environment` instance defined in the YAML file.

        Expects the following format:

        .. code-block:: yaml

            directory: ../static
            url: /media
            debug: True
            updater: timestamp
            filters:
                - my_custom_package.my_filter
            config:
                compass_bin: /opt/compass
                another_custom_config_value: foo

            bundles:
                # ...

        All values, including ``directory`` and ``url`` are optional. The
        syntax for defining bundles is the same as for
        :meth:`~.YAMLLoader.load_bundles`.

        Sample usage::

            from webassets.loaders import YAMLLoader
            loader = YAMLLoader('asset.yml')
            env = loader.load_environment()

            env['some-bundle'].urls()
        """
        f, filename = self._open()
        try:
            obj = self.yaml.load(f) or {}

            env = Environment()

            # Load environment settings
            for setting in (
                    'debug',
                    'cache',
                    'versions',
                    'url_expire',
                    'auto_build',
                    'url',
                    'directory',
                    'manifest',
                    'load_path',
                    'cache_file_mode',
                    # TODO: The deprecated values; remove at some point
                    'expire',
                    'updater'):
                if setting in obj:
                    setattr(env, setting, obj[setting])

            # Treat the 'directory' option special, make it relative to the
            # path of the YAML file, if we know it.
            if filename and 'directory' in env.config:
                env.directory = path.normpath(
                    path.join(path.dirname(filename), env.config['directory']))

            # Treat the 'filters' option special, it should resolve the
            # entries as classes and register them to the environment
            if 'filters' in obj:
                try:
                    resolve_dotted = self._get_import_resolver()
                except ImportError:
                    raise EnvironmentError(
                        "In order to use custom filters in the YAMLLoader "
                        "you must install the zope.dottedname package")
                for filter_class in obj['filters']:
                    try:
                        cls = resolve_dotted(filter_class)
                    except ImportError:
                        raise LoaderError("Unable to resolve class %s" %
                                          filter_class)
                    if inspect.isclass(cls):
                        register_filter(cls)
                    else:
                        raise LoaderError("Custom filters must be classes "
                                          "not modules or functions")

            # Load custom config options
            if 'config' in obj:
                env.config.update(obj['config'])

            # Load bundles
            bundles = self._get_bundles(obj.get('bundles', {}))
            for name, bundle in six.iteritems(bundles):
                env.register(name, bundle)

            return env
        finally:
            f.close()
Example #10
0
    def install(self):
        """
        Recipe install function.
        """

        # Helper functions

        def split(s):
            """
            Template filter splitting on any whitespace.
            """

            return re.split(r'\s+', s.strip())

        def as_bool(s):
            """
            Template filter which translates the given string into a boolean.
            """

            return s.lower() in ("yes", "true", "1", "on")

        def strip_dict(d):
            """
            Strips the values of a dictionary in place. All values are assumed
            to be strings. The same dictionary object is returned.
            """

            for k, v in d.items():
                d[k] = v.strip()
            return d

        # Validate template and target lists
        template_file_option = self.options.get(
            "template-file",
            self.options.get("input"),
        )
        target_file_option = self.options.get(
            "target-file",
            self.options.get("output"),
        )
        template_files = split(template_file_option)
        target_files = split(target_file_option)
        if len(template_files) != len(target_files):
            raise zc.buildout.UserError(
                "The number of template and target files must match")

        # Validate and normalise target executable option
        target_executables = split(
            self.options.get("target-executable", "false"))
        target_executables = [as_bool(v) for v in target_executables]
        if len(target_executables) == 1:
            value = target_executables[0]
            target_executables = (value for i in range(len(template_files)))
        else:
            if len(target_executables) != len(template_files):
                raise zc.buildout.UserError(
                    "The number of target executables"
                    "must 0, 1 or match the number of template files")

        # Assemble lists
        files = zip(template_files, target_files, target_executables)

        # Assemble template context
        context = strip_dict(dict(self.options))

        # Handle eggs specially
        if "eggs" in context:
            log.info("Making working set out of the eggs")
            eggs = Eggs(self.buildout, self.options["recipe"], self.options)
            names, eggs = eggs.working_set()
            context["eggs"] = eggs

        # Make recursive dict to be enable access dashed values.
        context['context'] = context

        # Make options from other parts available.
        part_options = SafeBuildout(self.buildout)
        if 'parts' not in context.keys():
            context.update({'parts': part_options})
        else:
            log.error("You should not use parts as a name of a variable,"
                      " since it is used internally by this recipe")
            raise zc.buildout.UserError("parts used as a variable in %s" %
                                        self.name)

        filters = self.options.get('jinja2_filters')
        if filters:
            jinja2_filters = {}
            filters = filters.split()
            for filter_ in filters:
                try:
                    jinja2_filters[filter_.split('.')[-1]] = resolve_dotted(
                        filter_)
                except ImportError as e:
                    raise zc.buildout.UserError("Filter '%s' not found.\n%s" %
                                                (filter_, e))
        else:
            jinja2_filters = {}

        filters = {
            "split": split,
            "as_bool": as_bool,
            "type": type,
            "eval": eval,
            "re_escape": re.escape,
        }
        filters.update(jinja2_filters)

        # Set up jinja2 environment
        jinja2_env = self._jinja2_env(filters=filters)

        # Load, render, and save files
        for template_file, target_file, executable in files:
            template = self._load_template(jinja2_env, template_file)
            output = template.render(**context)

            # Make target file
            target_file = os.path.abspath(target_file)
            self._ensure_dir(os.path.dirname(target_file))

            fp = open(target_file, "wt")
            fp.write(output)
            fp.close()

            # Chmod target file
            if executable:
                os.chmod(target_file, 0o755)

            self.options.created(target_file)

        return self.options.created()