# Copyright (c) 2015 Mirantis, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import os.path import pkg_resources from yaql.language import contexts from yaql.language import conventions from yaql.language import factory from yaql.language import specs from yaql.language import utils from yaql.language import yaqltypes from yaql.standard_library import boolean as std_boolean from yaql.standard_library import branching as std_branching from yaql.standard_library import collections as std_collections from yaql.standard_library import common as std_common from yaql.standard_library import date_time as std_datetime from yaql.standard_library import math as std_math from yaql.standard_library import queries as std_queries from yaql.standard_library import regex as std_regex from yaql.standard_library import strings as std_strings from yaql.standard_library import system as std_system from yaql.standard_library import yaqlized as std_yaqlized _cached_expressions = {} _cached_engine = None _default_context = None def detect_version(): try: dist = pkg_resources.get_distribution('yaql') location = os.path.normcase(dist.location) this_location = os.path.normcase(__file__) if not this_location.startswith(os.path.join(location, 'yaql')): raise pkg_resources.DistributionNotFound() return dist.version except pkg_resources.DistributionNotFound: return 'Undefined (package was not installed with setuptools)' __version__ = detect_version() def _setup_context(data, context, finalizer, convention): if context is None: context = contexts.Context( convention=convention or conventions.CamelCaseConvention()) if finalizer is None: @specs.parameter('iterator', yaqltypes.Iterable()) @specs.name('#iter') def limit(iterator): return iterator @specs.inject('limiter', yaqltypes.Delegate('#iter')) @specs.inject('engine', yaqltypes.Engine()) @specs.name('#finalize') def finalize(obj, limiter, engine): if engine.options.get('yaql.convertOutputData', True): return utils.convert_output_data(obj, limiter, engine) return obj context.register_function(limit) context.register_function(finalize) else: context.register_function(finalizer) if data is not utils.NO_VALUE: context['$'] = utils.convert_input_data(data) return context def create_context(data=utils.NO_VALUE, context=None, system=True, common=True, boolean=True, strings=True, math=True, collections=True, queries=True, regex=True, branching=True, no_sets=False, finalizer=None, delegates=False, convention=None, datetime=True, yaqlized=True, group_by_agg_fallback=True): context = _setup_context(data, context, finalizer, convention) if system: std_system.register_fallbacks(context) context = context.create_child_context() std_system.register(context, delegates) if common: std_common.register(context) if boolean: std_boolean.register(context) if strings: std_strings.register(context) if math: std_math.register(context) if collections: std_collections.register(context, no_sets) if queries: std_queries.register(context, group_by_agg_fallback) if regex: std_regex.register(context) if branching: std_branching.register(context) if datetime: std_datetime.register(context) if yaqlized: context = std_yaqlized.register(context) return context YaqlFactory = factory.YaqlFactory def eval(expression, data=None): global _cached_engine, _cached_expressions, _default_context if _cached_engine is None: _cached_engine = YaqlFactory().create() parsed_expression = _cached_expressions.get(expression) if parsed_expression is None: parsed_expression = _cached_engine(expression) _cached_expressions[expression] = parsed_expression if _default_context is None: _default_context = create_context() return parsed_expression.evaluate( data=data, context=_default_context.create_child_context())