コード例 #1
0
ファイル: test_parser.py プロジェクト: ArcTanSusan/django
 def test_token_smart_split(self):
     """
     #7027 -- _() syntax should work with spaces
     """
     token = Token(TokenType.BLOCK, 'sometag _("Page not found") value|yesno:_("yes,no")')
     split = token.split_contents()
     self.assertEqual(split, ["sometag", '_("Page not found")', 'value|yesno:_("yes,no")'])
コード例 #2
0
ファイル: otree_forms.py プロジェクト: yatsky/otree-core
    def parse(cls, parser, token: Token):

        # here is how split_contents() works:

        # {% formfield player.f1 label="f1 label" %}
        # ...yields:
        # ['formfield', 'player.f1', 'label="f1 label"']

        # {% formfield player.f2 "f2 label with no kwarg" %}
        # ...yields:
        # ['formfield', 'player.f2', '"f2 label with no kwarg"']

        # handle where the user did {% formfield player.f label = "foo" %}
        token.contents = token.contents.replace('label = ', 'label=')
        bits = token.split_contents()
        tagname = bits.pop(0)
        if len(bits) < 1:
            raise TemplateSyntaxError(f"{tagname} requires the name of the field.")
        field_name = bits.pop(0)
        if bits[:1] == ['with']:
            bits.pop(0)
        arg_dict = token_kwargs(bits, parser, support_legacy=False)
        if bits:
            raise TemplateSyntaxError(f'Unused parameter to formfield tag: {bits[0]}')
        return cls(field_name, **arg_dict)
コード例 #3
0
 def test_token_smart_split(self):
     """
     #7027 -- _() syntax should work with spaces
     """
     token = Token(TokenType.BLOCK, 'sometag _("Page not found") value|yesno:_("yes,no")')
     split = token.split_contents()
     self.assertEqual(split, ["sometag", '_("Page not found")', 'value|yesno:_("yes,no")'])
コード例 #4
0
def choose_from_list(parser: Parser, token: Token):
    try:
        tag_name, first, last, how_many = token.split_contents()
    except ValueError:
        msg = "lotto first:int last:int how_many:int"
        raise template.TemplateSyntaxError(msg)
    return ChooseNode(first, last, how_many)
コード例 #5
0
ファイル: minified_js.py プロジェクト: gnprice/zulip
def minified_js(parser: Parser, token: Token) -> MinifiedJSNode:
    try:
        tag_name, sourcefile = token.split_contents()
    except ValueError:
        raise TemplateSyntaxError("%s token requires an argument" % (token,))
    if not (sourcefile[0] == sourcefile[-1] and sourcefile[0] in ('"', "'")):
        raise TemplateSyntaxError("%s tag should be quoted" % (tag_name,))

    sourcefile = sourcefile[1:-1]
    if sourcefile not in settings.JS_SPECS:
        raise TemplateSyntaxError("%s tag invalid argument: no JS file %s"
                                  % (tag_name, sourcefile))
    return MinifiedJSNode(sourcefile)
コード例 #6
0
ファイル: sitecats.py プロジェクト: idlesign/django-sitecats
def sitecats_categories(parser: Parser, token: Token):

    tokens = token.split_contents()
    use_template = detect_clause(parser, 'template', tokens)
    target_obj = detect_clause(parser, 'from', tokens)

    if target_obj is None:
        raise template.TemplateSyntaxError(
            '`sitecats_categories` tag expects the following notation: '
            '{% sitecats_categories from my_categories_list template "sitecats/my_categories.html" %}.'
        )

    return sitecats_categoriesNode(target_obj, use_template)
コード例 #7
0
def minified_js(parser: Parser, token: Token) -> MinifiedJSNode:
    try:
        tag_name, sourcefile = token.split_contents()
    except ValueError:
        raise TemplateSyntaxError("%s token requires an argument" % (token, ))
    if not (sourcefile[0] == sourcefile[-1] and sourcefile[0] in ('"', "'")):
        raise TemplateSyntaxError("%s tag should be quoted" % (tag_name, ))

    sourcefile = sourcefile[1:-1]
    if sourcefile not in settings.JS_SPECS:
        raise TemplateSyntaxError("%s tag invalid argument: no JS file %s" %
                                  (tag_name, sourcefile))
    return MinifiedJSNode(sourcefile)
コード例 #8
0
ファイル: sitecats.py プロジェクト: idlesign/django-sitecats
def sitecats_url(parser: Parser, token: Token):

    tokens = token.split_contents()
    as_clause = detect_clause(parser, 'as', tokens, as_filter_expr=False)
    target_list = detect_clause(parser, 'using', tokens)
    category = detect_clause(parser, 'for', tokens)

    if category is None or target_list is None:
        raise template.TemplateSyntaxError(
            '`sitecats_url` tag expects the following notation: '
            '{% sitecats_url for my_category using my_categories_list as someurl %}.'
        )

    return sitecats_urlNode(category, target_list, as_clause)
コード例 #9
0
    def parse(cls, parser, token: Token):

        # here is how split_contents() works:

        # {% formfield player.f1 label="f1 label" %}
        # ...yields:
        # ['formfield', 'player.f1', 'label="f1 label"']

        # {% formfield player.f2 "f2 label with no kwarg" %}
        # ...yields:
        # ['formfield', 'player.f2', '"f2 label with no kwarg"']

        # handle where the user did {% formfield player.f label = "foo" %}
        token.contents = token.contents.replace('label = ', 'label=')
        bits = token.split_contents()
        tagname = bits.pop(0)
        if len(bits) < 1:
            raise TemplateSyntaxError(
                "{tagname!r} requires at least one argument.".format(
                    tagname=tagname))
        field = bits.pop(0)
        if bits:
            if bits[0] == 'with':
                bits.pop(0)
            arg_dict = token_kwargs(bits, parser, support_legacy=False)
            label_arg = arg_dict.pop('label', None)
            for key in arg_dict:
                msg = '{} tag received unknown argument "{}"'.format(tagname, key)
                raise TemplateSyntaxError(msg)
        else:
            label_arg = None
        if bits:
            raise TemplateSyntaxError(
                'Unknown argument for {tagname} tag: {bits!r}'.format(
                    tagname=tagname,
                    bits=bits))
        return cls(field, label_arg=label_arg)
コード例 #10
0
def decode_token(
        token: Token, positional_args: Iterable[Mapping[str, Any]],
        named_args: Mapping[str,
                            Mapping[str,
                                    Any]], allow_unknown_positional_args: bool,
        allow_unknown_named_args: bool) -> Tuple[List[Any], Dict[str, Any]]:
    """Splits the token and returns its name and positional as well as named arguments.

    positional_args is a sequence of option sets specifying expected positional args.
    named_args assigns each argument name a set of options specifying expected named args.

    options:
    quotes [str]: option to control quote handling: "disallowed", "optional", "required", "ignore" (all besides "ignore" cut off quotes if they match) [default: "optional"]
    converter [Callable]: Callable used to convert the string argument into another type; if None, converter will not be called [default: None]
    optional [bool]: option specifying whether the argument is optional [default: False]
    default [Any]: default value to return if argument is not given explicitly (if Callable: return value of Callable will be used) [default: None]
    check_identifier [bool]: if True check whether the argument value is a valid python identifier with str.isidentifier() [default: False]
    is_boolean_arg [bool]: if True the argument is treated as Boolean-Argument -> see Boolean-Args below (named_args only) [default: False]

    Boolean-Args:
    Boolean-Args are named arguments which can look like positional ones. But their presence is treated like True and absence like False.
    However assignments (normal named argument notation) are always possible too (-> converted will be utils.to_bool()).
    Example:
        {% my_tag silent=True %} is the same as {% my_tag silent %}
        {% my_tag silent=False %} is the same as {% my_tag %}
    """
    # default values for options
    DEFAULT_QUOTES = "optional"
    DEFAULT_CONVERTER = None
    DEFAULT_OPTIONAL = False
    DEFAULT_DEFAULT = None
    DEFAULT_CHECK_IDENTIFIER = False
    DEFAULT_IS_BOOLEAN_ARG = False

    # sort positional and named args
    tag_name, *contents = token.split_contents()
    positional = []
    named = {}
    positional_res = []
    named_res = {}
    for i, content in enumerate(contents):
        arg = split_named_argument(content)
        if len(arg) == 1:
            if len(named) > 0:
                raise TemplateSyntaxError(
                    f"Named argument ({list(named.keys())[-1]}) must not be followed by positional argument."
                )
            positional.append(arg[0])
        else:
            named[arg[0]] = arg[1]

    # do positional args
    positional_iter = iter(positional)
    i = 0
    for options in positional_args:
        try:
            arg = next(positional_iter)
        except StopIteration:
            if options.get("optional", DEFAULT_OPTIONAL):
                positional_res.append(options["default"]() if isinstance(
                    options.get("default", DEFAULT_DEFAULT), Callable
                ) else options.get("default", DEFAULT_DEFAULT))
            else:
                raise TemplateSyntaxError(
                    f"Positional argument {i} is not optional.")
        else:
            if arg[0] == arg[-1] and arg[0] in ("'", '"'):
                if options.get("quotes", DEFAULT_QUOTES) == "disallowed":
                    raise TemplateSyntaxError(
                        f"Positional argument {i} must not be inside quotes.")
                elif options.get("quotes", DEFAULT_QUOTES) == "optional":
                    arg = arg[1:-1]
                elif options.get("quotes", DEFAULT_QUOTES) == "required":
                    arg = arg[1:-1]
            else:
                if options.get("quotes", DEFAULT_QUOTES) == "required":
                    raise TemplateSyntaxError(
                        f"Positional argument {i} must be inside quotes.")
            if options.get(
                    "check_identifier",
                    DEFAULT_CHECK_IDENTIFIER) and not arg.isidentifier():
                raise TemplateSyntaxError(
                    f"Positional argument {i} must be a valid python identifier."
                )
            positional_res.append(
                arg if options.get("quotes", DEFAULT_CONVERTER) is None else
                options["converter"](arg))
        i += 1
    remaining = list(positional_iter)
    for arg in remaining:
        if not allow_unknown_positional_args and len(remaining) > 0:
            if arg in named_args and named_args[arg].get(
                    "is_boolean_arg", DEFAULT_IS_BOOLEAN_ARG
            ):  # handle Boolean-Arg (positional notation)
                named_res[arg] = True
            else:
                raise TemplateSyntaxError(
                    f"Positional argument {i} is not allowed.")
        else:
            if arg in named_args and named_args[arg].get(
                    "is_boolean_arg", DEFAULT_IS_BOOLEAN_ARG
            ):  # handle Boolean-Arg (positional notation)
                named_res[arg] = True
            else:
                positional_res.append(arg)

    # do named args
    for argname, options in named_args.items():
        arg: Any
        if argname in named_res and not options["is_boolean_arg"]:
            raise TemplateSyntaxError(
                f"Named argument {argname} can only be given once.")
        elif options.get("is_boolean_arg", DEFAULT_IS_BOOLEAN_ARG
                         ):  # handle Boolean-Arg (assignment notation)
            if argname in named:
                arg = named[argname]
                if arg[0] == arg[-1] and arg[0] in ("'", '"'):
                    arg = arg[1:-1]
                named_res[argname] = to_boolean(arg)
            elif not argname in named_res:
                named_res[argname] = False
        elif argname in named:
            arg = named[argname]
            if arg[0] == arg[-1] and arg[0] in ("'", '"'):
                if options.get("quotes", DEFAULT_QUOTES) == "disallowed":
                    raise TemplateSyntaxError(
                        f"Named argument {argname} must not be inside quotes.")
                elif options.get("quotes", DEFAULT_QUOTES) == "optional":
                    arg = arg[1:-1]
                elif options.get("quotes", DEFAULT_QUOTES) == "required":
                    arg = arg[1:-1]
            else:
                if options.get("quotes", DEFAULT_QUOTES) == "required":
                    raise TemplateSyntaxError(
                        f"Named argument {argname} must be inside quotes.")
            if options.get(
                    "check_identifier",
                    DEFAULT_CHECK_IDENTIFIER) and not arg.isidentifier():
                raise TemplateSyntaxError(
                    f"Positional argument {i} must be a valid python identifier."
                )
            named_res[argname] = arg if options.get(
                "converter",
                DEFAULT_CONVERTER) is None else options["converter"](arg)
        elif options.get("optional", DEFAULT_OPTIONAL):
            named_res[argname] = options["default"]() if isinstance(
                options.get("default", DEFAULT_DEFAULT),
                Callable) else options.get("default", DEFAULT_DEFAULT)
        else:
            raise TemplateSyntaxError(
                f"Named argument {argname} is not optional.")
        if argname in named:
            del named[argname]
    if not allow_unknown_named_args and len(named) > 0:
        raise TemplateSyntaxError(
            f"Named argument {next(iter(named.keys()))} is not allowed.")
    else:
        named_res.update(named)

    # return result
    return tag_name, positional_res, named_res