def webassets_init(): global env static_path = get_webassets_path() public = config.get(u'ckan.base_public_folder') public_folder = os.path.abspath( os.path.join(os.path.dirname(__file__), u'..', public)) base_path = os.path.join(public_folder, u'base') env = Environment() env.directory = static_path env.debug = config.get(u'debug', False) env.url = u'/webassets/' env.append_path(base_path, u'/base/') logger.debug(u'Base path {0}'.format(base_path)) create_library(u'vendor', os.path.join(base_path, u'vendor')) create_library(u'base', os.path.join(base_path, u'javascript')) create_library(u'datapreview', os.path.join(base_path, u'datapreview')) create_library(u'css', os.path.join(base_path, u'css'))
def webassets_init(): global env static_path = get_webassets_path() public = config.get(u'ckan.base_public_folder') public_folder = os.path.abspath(os.path.join( os.path.dirname(__file__), u'..', public)) base_path = os.path.join(public_folder, u'base') env = Environment() env.directory = static_path env.debug = config.get(u'debug', False) env.url = u'/webassets/' env.append_path(base_path, u'/base/') logger.debug(u'Base path {0}'.format(base_path)) create_library(u'vendor', os.path.join( base_path, u'vendor')) create_library(u'base', os.path.join(base_path, u'javascript')) create_library(u'datapreview', os.path.join(base_path, u'datapreview')) create_library(u'css', os.path.join(base_path, u'css'))
def test_append_load_path(self): env = Environment() assert env.load_path == [] env.append_path('foo', '/foo') assert env.load_path == ['foo'] assert env.url_mapping == {'foo': '/foo'} # Works without path env.append_path('bar') assert env.load_path == ['foo', 'bar'] assert env.url_mapping == {'foo': '/foo'}
def test_append_load_path(self): env = Environment() assert env.load_path == [] env.append_path("foo", "/foo") assert env.load_path == ["foo"] assert env.url_mapping == {"foo": "/foo"} # Works without path env.append_path("bar") assert env.load_path == ["foo", "bar"] assert env.url_mapping == {"foo": "/foo"}
class IndicoPlugin(Plugin): """Base class for an Indico plugin All your plugins need to inherit from this class. It extends the `Plugin` class from Flask-PluginEngine with useful indico-specific functionality that makes it easier to write custom plugins. When creating your plugin, the class-level docstring is used to generate the friendly name and description of a plugin. Its first line becomes the name while everything else goes into the description. This class provides methods for some of the more common hooks Indico provides. Additional signals are defined in :mod:`~indico.core.signals` and can be connected to custom functions using :meth:`connect`. """ #: WTForm for the plugin's settings (requires `configurable=True`). #: All fields must return JSON-serializable types. settings_form = None #: A dictionary which can contain the kwargs for a specific field in the `settings_form`. settings_form_field_opts = {} #: A dictionary containing default values for settings default_settings = {} #: A dictionary containing default values for event-specific settings default_event_settings = {} #: A dictionary containing default values for user-specific settings default_user_settings = {} #: A set containing the names of settings which store ACLs acl_settings = frozenset() #: A set containing the names of event-specific settings which store ACLs acl_event_settings = frozenset() #: A dict containing custom converters for settings settings_converters = {} #: A dict containing custom converters for event-specific settings event_settings_converters = {} #: A dict containing custom converters for user-specific settings user_settings_converters = {} #: If the plugin should link to a details/config page in the admin interface configurable = False #: The group category that the plugin belongs to category = None #: If `settings`, `event_settings` and `user_settings` should use strict #: mode, i.e. only allow keys in `default_settings`, `default_event_settings` #: or `default_user_settings` (or the related `acl_settings` sets) strict_settings = False def init(self): """Called when the plugin is being loaded/initialized. If you want to run custom initialization code, this is the method to override. Make sure to call the base method or the other overridable methods in this class will not be called anymore. """ assert self.configurable or not self.settings_form, 'Non-configurable plugin cannot have a settings form' self.alembic_versions_path = os.path.join(self.root_path, 'migrations') self.connect(signals.plugin.cli, self.add_cli_command) self.connect(signals.plugin.get_blueprints, lambda app: self.get_blueprints()) self.template_hook('vars-js', self.inject_vars_js) self._setup_assets() self._import_models() def _setup_assets(self): config = Config.getInstance() url_base_path = urlparse(config.getBaseURL()).path output_dir = os.path.join(config.getHtdocsDir(), 'static', 'assets', 'plugins', self.name) output_url = '{}/static/assets/plugins/{}'.format(url_base_path, self.name) static_dir = os.path.join(self.root_path, 'static') static_url = '{}/static/plugins/{}'.format(url_base_path, self.name) self.assets = Environment(output_dir, output_url, debug=config.getDebug()) self.assets.append_path(output_dir, output_url) self.assets.append_path(static_dir, static_url) configure_pyscss(self.assets) self.register_assets() def _import_models(self): old_models = set(db.Model._decl_class_registry.items()) import_all_models(self.package_name) added_models = set(db.Model._decl_class_registry.items()) - old_models # Ensure that only plugin schemas have been touched. It would be nice if we could actually # restrict a plugin to plugin_PLUGNNAME but since we load all models from the plugin's package # which could contain more than one plugin this is not easily possible. for name, model in added_models: schema = model.__table__.schema if not schema.startswith('plugin_'): raise Exception("Plugin '{}' added a model which is not in a plugin schema ('{}' in '{}')" .format(self.name, name, schema)) def connect(self, signal, receiver, **connect_kwargs): connect_kwargs['weak'] = False func = wrap_in_plugin_context(self, receiver) func.indico_plugin = self signal.connect(func, **connect_kwargs) def get_blueprints(self): """Return blueprints to be registered on the application A single blueprint can be returned directly, for multiple blueprint you need to yield them or return an iterable. """ pass def get_vars_js(self): """Return a dictionary with variables to be added to vars.js file""" return None @cached_property def translation_path(self): """ Return translation files to be used by the plugin. By default, get <root_path>/translations, unless it does not exist """ translations_path = os.path.join(self.root_path, 'translations') return translations_path if os.path.exists(translations_path) else None @cached_property def translation_domain(self): """Return the domain for this plugin's translation_path""" path = self.translation_path return Domain(path) if path else NullDomain() def add_cli_command(self, manager): """Add custom commands/submanagers to the manager of the `indico` cli tool.""" pass def register_assets(self): """Add assets to the plugin's webassets environment. In most cases the whole method can consist of calls to :meth:`register_js_bundle` and :meth:`register_css_bundle`. """ pass def register_js_bundle(self, name, *files): """Registers a JS bundle in the plugin's webassets environment""" pretty_name = re.sub(r'_js$', '', name) bundle = Bundle(*files, filters='rjsmin', output='js/{}_%(version)s.min.js'.format(pretty_name)) self.assets.register(name, bundle) def register_css_bundle(self, name, *files): """Registers an SCSS bundle in the plugin's webassets environment""" pretty_name = re.sub(r'_css$', '', name) bundle = Bundle(*files, filters=('pyscss', 'cssrewrite', 'cssmin'), output='css/{}_%(version)s.min.css'.format(pretty_name), depends=SASS_BASE_MODULES) self.assets.register(name, bundle) def inject_css(self, name, view_class=None, subclasses=True, condition=None): """Injects a CSS bundle into Indico's pages :param name: Name of the bundle :param view_class: If a WP class is specified, only inject it into pages using that class :param subclasses: also inject into subclasses of `view_class` :param condition: a callable to determine whether to inject or not. only called, when the view_class criterion matches """ self._inject_asset(signals.plugin.inject_css, name, view_class, subclasses, condition) def inject_js(self, name, view_class=None, subclasses=True, condition=None): """Injects a JS bundle into Indico's pages :param name: Name of the bundle :param view_class: If a WP class is specified, only inject it into pages using that class :param subclasses: also inject into subclasses of `view_class` :param condition: a callable to determine whether to inject or not. only called, when the view_class criterion matches """ self._inject_asset(signals.plugin.inject_js, name, view_class, subclasses, condition) def _inject_asset(self, signal, name, view_class=None, subclasses=True, condition=None): """Injects an asset bundle into Indico's pages :param signal: the signal to use for injection :param name: Name of the bundle :param view_class: If a WP class is specified, only inject it into pages using that class :param subclasses: also inject into subclasses of `view_class` :param condition: a callable to determine whether to inject or not. only called, when the view_class criterion matches """ def _do_inject(sender): if condition is None or condition(): return self.assets[name].urls() if view_class is None: self.connect(signal, _do_inject) elif not subclasses: self.connect(signal, _do_inject, sender=view_class) else: def _func(sender): if issubclass(sender, view_class): return _do_inject(sender) self.connect(signal, _func) def inject_vars_js(self): """Returns a string that will define variables for the plugin in the vars.js file""" vars_js = self.get_vars_js() if vars_js: return 'var {}Plugin = {};'.format(self.name.title(), json.dumps(vars_js)) def template_hook(self, name, receiver, priority=50, markup=True): """Registers a function to be called when a template hook is invoked. For details see :func:~`indico.web.flask.templating.register_template_hook` """ register_template_hook(name, receiver, priority, markup, self) @classproperty @classmethod def logger(cls): return Logger.get('plugin.{}'.format(cls.name)) @cached_classproperty @classmethod def settings(cls): """:class:`SettingsProxy` for the plugin's settings""" if cls.name is None: raise RuntimeError('Plugin has not been loaded yet') instance = cls.instance with instance.plugin_context(): # in case the default settings come from a property return SettingsProxy('plugin_{}'.format(cls.name), instance.default_settings, cls.strict_settings, acls=cls.acl_settings, converters=cls.settings_converters) @cached_classproperty @classmethod def event_settings(cls): """:class:`EventSettingsProxy` for the plugin's event-specific settings""" if cls.name is None: raise RuntimeError('Plugin has not been loaded yet') instance = cls.instance with instance.plugin_context(): # in case the default settings come from a property return EventSettingsProxy('plugin_{}'.format(cls.name), instance.default_event_settings, cls.strict_settings, acls=cls.acl_event_settings, converters=cls.event_settings_converters) @cached_classproperty @classmethod def user_settings(cls): """:class:`UserSettingsProxy` for the plugin's user-specific settings""" if cls.name is None: raise RuntimeError('Plugin has not been loaded yet') instance = cls.instance with instance.plugin_context(): # in case the default settings come from a property return UserSettingsProxy('plugin_{}'.format(cls.name), instance.default_user_settings, cls.strict_settings, converters=cls.user_settings_converters)
from clldutils.path import Path import clld def skip(_in, out, **kw): """filter to skip content of assets which are fetched from CDN in production.""" out.write('') # pragma: no cover _static_path = Path(clld.__file__).parent.joinpath('web', 'static').as_posix() environment = Environment(_static_path, '/clld:web/static/', manifest='json:', auto_build=False) environment.append_path(_static_path, url='/clld:web/static/') bundles = { 'js': [ Bundle('js/jquery.js', 'js/leaflet-src.js', filters=(skip, )), 'js/bootstrap.min.js', 'js/jquery.dataTables.min.js', 'js/oms.min.js', Bundle('js/bootstrapx-clickover.js', 'js/tree.jquery.js', 'js/leaflet-providers.js', 'js/leaflet.label.js', 'js/Control.FullScreen.js', 'js/leaflet-hash.js', 'js/clld.js', 'project.js',
class WPBase(OldObservable): """ """ _title = "Indico" # required user-specific "data packages" _userData = [] def __init__( self, rh ): config = Config.getInstance() db_connected = DBMgr.getInstance().isConnected() self._rh = rh self._locTZ = "" self._asset_env = Environment(os.path.join(config.getHtdocsDir(), "static", "assets"), '/static/assets/') self._asset_env.config['PYSCSS_LOAD_PATHS'] = [os.path.join(config.getHtdocsDir(), 'sass', 'lib', 'compass')] self._asset_env.append_path(config.getHtdocsDir(), '/') if db_connected: debug = HelperMaKaCInfo.getMaKaCInfoInstance().isDebugActive() else: debug = False # This is done in order to avoid the problem sending the error report because the DB is not connected. if db_connected: info = HelperMaKaCInfo.getMaKaCInfoInstance() self._asset_env.debug = info.isDebugActive() self._dir = config.getTPLDir() self._asset_env.debug = debug if db_connected: css_file = config.getCssStylesheetName() else: css_file = 'Default.css' # register existing assets assets.register_all_js(self._asset_env) assets.register_all_css(self._asset_env, css_file) #store page specific CSS and JS self._extraCSS = [] self._extraJS = [] def _getBaseURL( self ): if self._rh._req.is_https() and Config.getInstance().getBaseSecureURL(): baseurl = Config.getInstance().getBaseSecureURL() else: baseurl = Config.getInstance().getBaseURL() return baseurl def _getTitle( self ): return self._title def _setTitle( self, newTitle ): self._title = newTitle.strip() def getCSSFiles(self): return self._asset_env['base_css'].urls() + \ self._asset_env['base_sass'].urls() def _getJavaScriptInclude(self, scriptPath): return '<script src="'+ scriptPath +'" type="text/javascript"></script>\n' def getJSFiles(self): return self._asset_env['base_js'].urls() def _includeJSPackage(self, pkg_names): if not isinstance(pkg_names, list): pkg_names = [pkg_names] urls = [] for pkg_name in pkg_names: urls += self._asset_env['indico_' + pkg_name.lower()].urls() return urls def _getJavaScriptUserData(self): """ Returns structured data that should be passed on to the client side but depends on user data (can't be in vars.js.tpl) """ user = self._getAW().getUser(); from MaKaC.webinterface.asyndico import UserDataFactory userData = dict((packageName, UserDataFactory(user).build(packageName)) for packageName in self._userData) return userData def _getHeadContent( self ): """ Returns _additional_ content between <head></head> tags. Please note that <title>, <meta> and standard CSS are always included. Override this method to add your own, page-specific loading of JavaScript, CSS and other legal content for HTML <head> tag. """ return "" def _getWarningMessage(self): return "" def _getHTMLHeader( self ): from MaKaC.webinterface.pages.conferences import WPConfSignIn from MaKaC.webinterface.pages.signIn import WPSignIn from MaKaC.webinterface.pages.registrationForm import WPRegistrationFormSignIn from MaKaC.webinterface.rh.base import RHModificationBaseProtected from MaKaC.webinterface.rh.admins import RHAdminBase area="" if isinstance(self._rh, RHModificationBaseProtected): area=i18nformat(""" - _("Management area")""") elif isinstance(self._rh, RHAdminBase): area=i18nformat(""" - _("Administrator area")""") info = HelperMaKaCInfo().getMaKaCInfoInstance() websession = self._getAW().getSession() if websession: language = websession.getLang() else: language = info.getLang() return wcomponents.WHTMLHeader().getHTML({ "area": area, "baseurl": self._getBaseURL(), "conf": Config.getInstance(), "page": self, "extraCSS": self.getCSSFiles(), "extraJSFiles": self.getJSFiles(), "extraJS": self._extraJS, "language": language, "social": info.getSocialAppConfig(), "assets": self._asset_env }) def _getHTMLFooter( self ): return """ </body> </html> """ def _display( self, params ): """ """ return _("no content") def _getAW( self ): return self._rh.getAW() def display( self, **params ): """ """ return "%s%s%s"%( self._getHTMLHeader(), \ self._display( params ), \ self._getHTMLFooter() ) def addExtraJSFile(self, filename): self._extraJSFiles.append(filename) def addExtraJS(self, jsCode): self._extraJS.append(jsCode) # auxiliar functions def _escapeChars(self, text): # Not doing anything right now - it used to convert % to %% for old-style templates return text
class IndicoPlugin(Plugin): """Base class for an Indico plugin All your plugins need to inherit from this class. It extends the `Plugin` class from Flask-PluginEngine with useful indico-specific functionality that makes it easier to write custom plugins. When creating your plugin, the class-level docstring is used to generate the friendly name and description of a plugin. Its first line becomes the name while everything else goes into the description. This class provides methods for some of the more common hooks Indico provides. Additional signals are defined in :mod:`~indico.core.signals` and can be connected to custom functions using :meth:`connect`. """ #: WTForm for the plugin's settings (requires `configurable=True`). #: All fields must return JSON-serializable types. settings_form = None #: A dictionary which can contain the kwargs for a specific field in the `settings_form`. settings_form_field_opts = {} #: A dictionary containing default values for settings default_settings = {} #: A dictionary containing default values for event-specific settings default_event_settings = {} #: A dictionary containing default values for user-specific settings default_user_settings = {} #: A set containing the names of settings which store ACLs acl_settings = frozenset() #: A set containing the names of event-specific settings which store ACLs acl_event_settings = frozenset() #: If the plugin should link to a details/config page in the admin interface configurable = False #: The group category that the plugin belongs to category = None #: If `settings`, `event_settings` and `user_settings` should use strict #: mode, i.e. only allow keys in `default_settings`, `default_event_settings` #: or `default_user_settings` (or the related `acl_settings` sets) strict_settings = False def init(self): """Called when the plugin is being loaded/initialized. If you want to run custom initialization code, this is the method to override. Make sure to call the base method or the other overridable methods in this class will not be called anymore. """ assert self.configurable or not self.settings_form, 'Non-configurable plugin cannot have a settings form' self.alembic_versions_path = os.path.join(self.root_path, 'migrations') self.connect(signals.plugin.cli, self.add_cli_command) self.connect(signals.plugin.get_blueprints, lambda app: self.get_blueprints()) self.template_hook('vars-js', self.inject_vars_js) self._setup_assets() self._import_models() def _setup_assets(self): config = Config.getInstance() url_base_path = urlparse(config.getBaseURL()).path output_dir = os.path.join(config.getHtdocsDir(), 'static', 'assets', 'plugins', self.name) output_url = '{}/static/assets/plugins/{}'.format( url_base_path, self.name) static_dir = os.path.join(self.root_path, 'static') static_url = '{}/static/plugins/{}'.format(url_base_path, self.name) self.assets = Environment(output_dir, output_url, debug=config.getDebug()) self.assets.append_path(output_dir, output_url) self.assets.append_path(static_dir, static_url) configure_pyscss(self.assets) self.register_assets() def _import_models(self): old_models = set(db.Model._decl_class_registry.items()) import_all_models(self.package_name) added_models = set(db.Model._decl_class_registry.items()) - old_models # Ensure that only plugin schemas have been touched. It would be nice if we could actually # restrict a plugin to plugin_PLUGNNAME but since we load all models from the plugin's package # which could contain more than one plugin this is not easily possible. for name, model in added_models: schema = model.__table__.schema if not schema.startswith('plugin_'): raise Exception( "Plugin '{}' added a model which is not in a plugin schema ('{}' in '{}')" .format(self.name, name, schema)) def connect(self, signal, receiver, **connect_kwargs): connect_kwargs['weak'] = False func = wrap_in_plugin_context(self, receiver) func.indico_plugin = self signal.connect(func, **connect_kwargs) def get_blueprints(self): """Return blueprints to be registered on the application A single blueprint can be returned directly, for multiple blueprint you need to yield them or return an iterable. """ pass def get_vars_js(self): """Return a dictionary with variables to be added to vars.js file""" return None @cached_property def translation_path(self): """ Return translation files to be used by the plugin. By default, get <root_path>/translations, unless it does not exist """ translations_path = os.path.join(self.root_path, 'translations') return translations_path if os.path.exists(translations_path) else None @cached_property def translation_domain(self): """Return the domain for this plugin's translation_path""" path = self.translation_path return Domain(path) if path else NullDomain() def add_cli_command(self, manager): """Add custom commands/submanagers to the manager of the `indico` cli tool.""" pass def register_assets(self): """Add assets to the plugin's webassets environment. In most cases the whole method can consist of calls to :meth:`register_js_bundle` and :meth:`register_css_bundle`. """ pass def register_js_bundle(self, name, *files): """Registers a JS bundle in the plugin's webassets environment""" pretty_name = re.sub(r'_js$', '', name) bundle = Bundle(*files, filters='rjsmin', output='js/{}_%(version)s.min.js'.format(pretty_name)) self.assets.register(name, bundle) def register_css_bundle(self, name, *files): """Registers an SCSS bundle in the plugin's webassets environment""" pretty_name = re.sub(r'_css$', '', name) bundle = Bundle( *files, filters=('pyscss', 'cssrewrite', 'cssmin'), output='css/{}_%(version)s.min.css'.format(pretty_name), depends=SASS_BASE_MODULES) self.assets.register(name, bundle) def inject_css(self, name, view_class=None, subclasses=True, condition=None): """Injects a CSS bundle into Indico's pages :param name: Name of the bundle :param view_class: If a WP class is specified, only inject it into pages using that class :param subclasses: also inject into subclasses of `view_class` :param condition: a callable to determine whether to inject or not. only called, when the view_class criterion matches """ self._inject_asset(signals.plugin.inject_css, name, view_class, subclasses, condition) def inject_js(self, name, view_class=None, subclasses=True, condition=None): """Injects a JS bundle into Indico's pages :param name: Name of the bundle :param view_class: If a WP class is specified, only inject it into pages using that class :param subclasses: also inject into subclasses of `view_class` :param condition: a callable to determine whether to inject or not. only called, when the view_class criterion matches """ self._inject_asset(signals.plugin.inject_js, name, view_class, subclasses, condition) def _inject_asset(self, signal, name, view_class=None, subclasses=True, condition=None): """Injects an asset bundle into Indico's pages :param signal: the signal to use for injection :param name: Name of the bundle :param view_class: If a WP class is specified, only inject it into pages using that class :param subclasses: also inject into subclasses of `view_class` :param condition: a callable to determine whether to inject or not. only called, when the view_class criterion matches """ def _do_inject(sender): if condition is None or condition(): return self.assets[name].urls() if view_class is None: self.connect(signal, _do_inject) elif not subclasses: self.connect(signal, _do_inject, sender=view_class) else: def _func(sender): if issubclass(sender, view_class): return _do_inject(sender) self.connect(signal, _func) def inject_vars_js(self): """Returns a string that will define variables for the plugin in the vars.js file""" vars_js = self.get_vars_js() if vars_js: return 'var {}Plugin = {};'.format(self.name.title(), json.dumps(vars_js)) def template_hook(self, name, receiver, priority=50, markup=True): """Registers a function to be called when a template hook is invoked. For details see :func:~`indico.web.flask.templating.register_template_hook` """ register_template_hook(name, receiver, priority, markup, self) @classproperty @classmethod def logger(cls): return Logger.get('plugin.{}'.format(cls.name)) @cached_classproperty @classmethod def settings(cls): """:class:`SettingsProxy` for the plugin's settings""" if cls.name is None: raise RuntimeError('Plugin has not been loaded yet') instance = cls.instance with instance.plugin_context( ): # in case the default settings come from a property return SettingsProxy('plugin_{}'.format(cls.name), instance.default_settings, cls.strict_settings, acls=cls.acl_settings) @cached_classproperty @classmethod def event_settings(cls): """:class:`EventSettingsProxy` for the plugin's event-specific settings""" if cls.name is None: raise RuntimeError('Plugin has not been loaded yet') instance = cls.instance with instance.plugin_context( ): # in case the default settings come from a property return EventSettingsProxy('plugin_{}'.format(cls.name), instance.default_event_settings, cls.strict_settings, acls=cls.acl_event_settings) @cached_classproperty @classmethod def user_settings(cls): """:class:`UserSettingsProxy` for the plugin's user-specific settings""" if cls.name is None: raise RuntimeError('Plugin has not been loaded yet') instance = cls.instance with instance.plugin_context( ): # in case the default settings come from a property return UserSettingsProxy('plugin_{}'.format(cls.name), instance.default_user_settings, cls.strict_settings)
from __future__ import unicode_literals, print_function, division, absolute_import from webassets import Environment, Bundle from clldutils.path import Path import clld def skip(_in, out, **kw): """filter to skip content of assets which are fetched from CDN in production.""" out.write('') # pragma: no cover _static_path = Path(clld.__file__).parent.joinpath('web', 'static').as_posix() environment = Environment( _static_path, '/clld:web/static/', manifest='json:', auto_build=False) environment.append_path(_static_path, url='/clld:web/static/') bundles = { 'js': [ Bundle( 'js/jquery.js', 'js/leaflet-src.js', filters=(skip,)), 'js/bootstrap.min.js', 'js/jquery.dataTables.min.js', 'js/oms.min.js', Bundle( 'js/bootstrapx-clickover.js', 'js/tree.jquery.js', 'js/leaflet-providers.js', 'js/leaflet.label.js',
class TestCompilation(unittest.TestCase): def setUp(self): res = dirname(__file__)+'/resources/' self.env = Environment(dirname(__file__)+"/out", '/media-prefix') self.env.cache = False self.env.manifest = False self.env.append_path(res+"assets", "/") self.env.append_path(res+"vendor", "/vendors") self.env.append_path(res, None) self.env.config["compass_bin"] = "/home/arkus/.gem/ruby/1.9.1/bin/compass" self.env.config["vendor_path"] = "vendor" #logging.basicConfig(level=logging.DEBUG) def get_bundle_output(self, test_name): f = StringIO() js = Bundle('scss/%s.scss' % test_name, filters=CompassConnectorFilter, output='%s.css' % test_name) self.env.register(test_name, js) js.build(output=f) return f.getvalue() def test_simple(self): o = self.get_bundle_output("test_simple") self.assertIn("color: red;", o) def test_simple_import(self): o = self.get_bundle_output("test_simple_imports") self.assertIn("color: red;", o) self.assertIn("(style.css)", o) self.assertIn("(/style.css)", o) def test_fonts(self): o = self.get_bundle_output("test_fonts") self.assertIn("vendor-inline-font: url('data:font/truetype;base64,AAE", o) self.assertIn("app-inline-font: url('data:font/truetype;base64,AAE", o) self.assertIn("url('/this.eot?#iefix')", o) self.assertIn("src: url('/fonts/empty.ttf');", o) self.assertIn("src: url('/vendors/fonts/vendor_empty.ttf');", o) def test_images(self): o = self.get_bundle_output("test_images") self.assertIn("vendor-image-url: url('/vendors/images/vendor_1x1.png?", o) self.assertIn("app-image-url: url('/images/image.png?", o) self.assertIn("width-app: 10px;", o) self.assertIn("width-vendor: 10px;", o) self.assertIn("image-inline: url('data:image/png;base64,iVB", o) self.assertIn("vendor-generated-image-busted: url('/media-prefix/generated-images/1x1.png?", o) self.assertIn("vendor-generated-image: url('/media-prefix/generated-images/1x1.png');", o) self.assertIn("generated-image-busted: url('/media-prefix/generated-images/1x1.png?", o) self.assertIn("generated-image: url('/media-prefix/generated-images/1x1.png');", o) def test_sprites(self): o = self.get_bundle_output("test_sprites") self.assertIn("background: url('/media-prefix/generated-images/sprites/something-", o) self.assertIn("background: url('/media-prefix/generated-images/vendor-something-", o) def test_zurb(self): self.env.config["compass_plugins"] = {"zurb-foundation":"<99"} o = self.get_bundle_output("test_zurb") self.assertIn("body", o)
import clld def skip(_in, out, **kw): """filter to skip content of assets which are fetched from CDN in production. """ out.write('') # pragma: no cover environment = Environment( path(clld.__file__).dirname().joinpath('web', 'static'), '/clld:web/static/', manifest='json:', auto_build=False) environment.append_path( path(clld.__file__).dirname().joinpath('web', 'static'), url='/clld:web/static/') bundles = { 'js': [ Bundle( 'js/jquery-1.8.2.js', 'js/leaflet-src.js', filters=(skip,)), 'js/bootstrap.min.js', 'js/jquery.dataTables.min.js', 'js/oms.min.js', Bundle( 'js/bootstrapx-clickover.js', 'js/tree.jquery.js', 'js/leaflet-providers.js', 'js/leaflet.label.js',
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 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', # TODO: The deprecated values; remove at some point 'expire', 'updater'): if setting in obj: setattr(env, setting, obj[setting]) if 'load_path' in obj: load_path = obj['load_path'] if load_path: if isinstance(load_path, list): env.load_path.extend(load_path) else: env.append_path(load_path) # 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'])) # 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 bundles.iteritems(): env.register(name, bundle) return env finally: f.close()
def skip(_in, out, **kw): """filter to skip content of assets which are fetched from CDN in production. """ out.write('') # pragma: no cover environment = Environment(path(clld.__file__).dirname().joinpath( 'web', 'static'), '/clld:web/static/', manifest='json:', auto_build=False) environment.append_path(path(clld.__file__).dirname().joinpath( 'web', 'static'), url='/clld:web/static/') bundles = { 'js': [ Bundle('js/jquery-1.8.2.js', 'js/leaflet-src.js', filters=(skip, )), 'js/bootstrap.min.js', 'js/jquery.dataTables.min.js', 'js/oms.min.js', Bundle('js/bootstrapx-clickover.js', 'js/tree.jquery.js', 'js/leaflet-providers.js', 'js/leaflet.label.js', 'js/Control.FullScreen.js', 'js/leaflet-hash.js', 'js/clld.js',