<commit_before>#
# Copyright (c), 2016-2020, SISSA (International School for Advanced Studies).
# All rights reserved.
# This file is distributed under the terms of the MIT License.
# See the file 'LICENSE' in the root directory of the present
# distribution, or http://opensource.org/licenses/MIT.
#
# @author <NAME> <<EMAIL>>
#
"""
This module contains classes for XML Schema wildcards.
"""
from typing import cast, Any, Callable, Dict, Iterable, Iterator, List, Optional, \
    Tuple, Union, Counter

from ..exceptions import XMLSchemaValueError
from ..names import XSI_NAMESPACE, XSD_ANY, XSD_ANY_ATTRIBUTE, \
    XSD_OPEN_CONTENT, XSD_DEFAULT_OPEN_CONTENT, XSI_TYPE
from ..aliases import ElementType, SchemaType, SchemaElementType, SchemaAttributeType, \
    ModelGroupType, ModelParticleType, AtomicValueType, IterDecodeType, IterEncodeType, \
    DecodedValueType, EncodedValueType
from ..translation import gettext as _
from ..helpers import get_namespace, raw_xml_encode
from ..xpath import XMLSchemaProtocol, ElementProtocol, XMLSchemaProxy, ElementPathMixin
from .xsdbase import ValidationMixin, XsdComponent
from .particles import ParticleMixin
from . import elements


OccursCounterType = Counter[Union[ModelParticleType, Tuple[ModelParticleType]]]


class XsdWildcard(XsdComponent):
    names = ()
    namespace: Union[Tuple[str], List[str]] = ('##any',)
    not_namespace: Union[Tuple[()], List[str]] = ()
    not_qname: Union[Tuple[()], List[str]] = ()
    process_contents = 'strict'

    # For compatibility with protocol of XSD elements/attributes
    type = None
    default = None
    fixed = None

    def __repr__(self) -> str:
        if self.not_namespace:
            return '%s(not_namespace=%r, process_contents=%r)' % (
                self.__class__.__name__, self.not_namespace, self.process_contents
            )
        else:
            return '%s(namespace=%r, process_contents=%r)' % (
                self.__class__.__name__, self.namespace, self.process_contents
            )

    def _parse(self) -> None:
        # Parse namespace and processContents
        namespace = self.elem.attrib.get('namespace', '##any').strip()
        if namespace == '##any':
            pass
        elif not namespace:
            self.namespace = []  # an empty value means no namespace allowed!
        elif namespace == '##other':
            self.namespace = [namespace]
        elif namespace == '##local':
            self.namespace = ['']
        elif namespace == '##targetNamespace':
            self.namespace = [self.target_namespace]
        else:
            self.namespace = []
            for ns in namespace.split():
                if ns == '##local':
                    self.namespace.append('')
                elif ns == '##targetNamespace':
                    self.namespace.append(self.target_namespace)
                elif ns.startswith('##'):
                    msg = _("wrong value %r in 'namespace' attribute")
                    self.parse_error(msg % ns)
                else:
                    self.namespace.append(ns)

        process_contents = self.elem.attrib.get('processContents', 'strict')
        if process_contents == 'strict':
            pass
        elif process_contents not in ('lax', 'skip'):
            msg = _("wrong value %r for 'processContents' attribute")
            self.parse_error(msg % self.process_contents)
        else:
            self.process_contents = process_contents

    def _parse_not_constraints(self) -> None:
        if 'notNamespace' not in self.elem.attrib:
            pass
        elif 'namespace' in self.elem.attrib:
            msg = _("'namespace' and 'notNamespace' attributes are mutually exclusive")
            self.parse_error(msg)
        else:
            self.namespace = []
            self.not_namespace = []
            for ns in self.elem.attrib['notNamespace'].strip().split():
                if ns == '##local':
                    self.not_namespace.append('')
                elif ns == '##targetNamespace':
                    self.not_namespace.append(self.target_namespace)
                elif ns.startswith('##'):
                    msg = _("wrong value %r in 'notNamespace' attribute")
                    self.parse_error(msg % ns)
                else:
                    self.not_namespace.append(ns)

        # Parse notQName attribute
        if 'notQName' not in self.elem.attrib:
            return

        not_qname = self.elem.attrib['notQName'].strip().split()

        if isinstance(self, XsdAnyAttribute) and \
                not all(not s.startswith('##') or s == '##defined'
                        for s in not_qname) or \
                not all(not s.startswith('##') or s in {'##defined', '##definedSibling'}
                        for s in not_qname):
            self.parse_error(_("wrong value for 'notQName' attribute"))
            return

        try:
            names = [x if x.startswith('##') else self.schema.resolve_qname(x, False)
                     for x in not_qname]
        except KeyError as err:
            msg = _("unmapped QName in 'notQName' attribute: %s")
            self.parse_error(msg % str(err))
            return
        except ValueError as err:
            msg = _("wrong QName format in 'notQName' attribute: %s")
            self.parse_error(msg % str(err))
            return

        if self.not_namespace:
            if any(not x.startswith('##') for x in names) and \
                    all(get_namespace(x) in self.not_namespace
                        for x in names if not x.startswith('##')):
                msg = _("the namespace of each QName in notQName is allowed by notNamespace")
                self.parse_error(msg)
        elif any(not self.is_namespace_allowed(get_namespace(x))
                 for x in names if not x.startswith('##')):
            msg = _("names in notQName must be in namespaces that are allowed")
            self.parse_error(msg)

        self.not_qname = names

    @property
    def built(self) -> bool:
        return True

    def is_matching(self, name: Optional[str],<commit_msg>Add value_constraint property to wildcards for compatibility<commit_after>#
# Copyright (c), 2016-2020, SISSA (International School for Advanced Studies).
# All rights reserved.
# This file is distributed under the terms of the MIT License.
# See the file 'LICENSE' in the root directory of the present
# distribution, or http://opensource.org/licenses/MIT.
#
# @author <NAME> <<EMAIL>>
#
"""
This module contains classes for XML Schema wildcards.
"""
from typing import cast, Any, Callable, Dict, Iterable, Iterator, List, Optional, \
    Tuple, Union, Counter

from ..exceptions import XMLSchemaValueError
from ..names import XSI_NAMESPACE, XSD_ANY, XSD_ANY_ATTRIBUTE, \
    XSD_OPEN_CONTENT, XSD_DEFAULT_OPEN_CONTENT, XSI_TYPE
from ..aliases import ElementType, SchemaType, SchemaElementType, SchemaAttributeType, \
    ModelGroupType, ModelParticleType, AtomicValueType, IterDecodeType, IterEncodeType, \
    DecodedValueType, EncodedValueType
from ..translation import gettext as _
from ..helpers import get_namespace, raw_xml_encode
from ..xpath import XMLSchemaProtocol, ElementProtocol, XMLSchemaProxy, ElementPathMixin
from .xsdbase import ValidationMixin, XsdComponent
from .particles import ParticleMixin
from . import elements


OccursCounterType = Counter[Union[ModelParticleType, Tuple[ModelParticleType]]]


class XsdWildcard(XsdComponent):
    names = ()
    namespace: Union[Tuple[str], List[str]] = ('##any',)
    not_namespace: Union[Tuple[()], List[str]] = ()
    not_qname: Union[Tuple[()], List[str]] = ()
    process_contents = 'strict'

    # For compatibility with protocol of XSD elements/attributes
    type = None
    default = None
    fixed = None

    def __repr__(self) -> str:
        if self.not_namespace:
            return '%s(not_namespace=%r, process_contents=%r)' % (
                self.__class__.__name__, self.not_namespace, self.process_contents
            )
        else:
            return '%s(namespace=%r, process_contents=%r)' % (
                self.__class__.__name__, self.namespace, self.process_contents
            )

    def _parse(self) -> None:
        # Parse namespace and processContents
        namespace = self.elem.attrib.get('namespace', '##any').strip()
        if namespace == '##any':
            pass
        elif not namespace:
            self.namespace = []  # an empty value means no namespace allowed!
        elif namespace == '##other':
            self.namespace = [namespace]
        elif namespace == '##local':
            self.namespace = ['']
        elif namespace == '##targetNamespace':
            self.namespace = [self.target_namespace]
        else:
            self.namespace = []
            for ns in namespace.split():
                if ns == '##local':
                    self.namespace.append('')
                elif ns == '##targetNamespace':
                    self.namespace.append(self.target_namespace)
                elif ns.startswith('##'):
                    msg = _("wrong value %r in 'namespace' attribute")
                    self.parse_error(msg % ns)
                else:
                    self.namespace.append(ns)

        process_contents = self.elem.attrib.get('processContents', 'strict')
        if process_contents == 'strict':
            pass
        elif process_contents not in ('lax', 'skip'):
            msg = _("wrong value %r for 'processContents' attribute")
            self.parse_error(msg % self.process_contents)
        else:
            self.process_contents = process_contents

    def _parse_not_constraints(self) -> None:
        if 'notNamespace' not in self.elem.attrib:
            pass
        elif 'namespace' in self.elem.attrib:
            msg = _("'namespace' and 'notNamespace' attributes are mutually exclusive")
            self.parse_error(msg)
        else:
            self.namespace = []
            self.not_namespace = []
            for ns in self.elem.attrib['notNamespace'].strip().split():
                if ns == '##local':
                    self.not_namespace.append('')
                elif ns == '##targetNamespace':
                    self.not_namespace.append(self.target_namespace)
                elif ns.startswith('##'):
                    msg = _("wrong value %r in 'notNamespace' attribute")
                    self.parse_error(msg % ns)
                else:
                    self.not_namespace.append(ns)

        # Parse notQName attribute
        if 'notQName' not in self.elem.attrib:
            return

        not_qname = self.elem.attrib['notQName'].strip().split()

        if isinstance(self, XsdAnyAttribute) and \
                not all(not s.startswith('##') or s == '##defined'
                        for s in not_qname) or \
                not all(not s.startswith('##') or s in {'##defined', '##definedSibling'}
                        for s in not_qname):
            self.parse_error(_("wrong value for 'notQName' attribute"))
            return

        try:
            names = [x if x.startswith('##') else self.schema.resolve_qname(x, False)
                     for x in not_qname]
        except KeyError as err:
            msg = _("unmapped QName in 'notQName' attribute: %s")
            self.parse_error(msg % str(err))
            return
        except ValueError as err:
            msg = _("wrong QName format in 'notQName' attribute: %s")
            self.parse_error(msg % str(err))
            return

        if self.not_namespace:
            if any(not x.startswith('##') for x in names) and \
                    all(get_namespace(x) in self.not_namespace
                        for x in names if not x.startswith('##')):
                msg = _("the namespace of each QName in notQName is allowed by notNamespace")
                self.parse_error(msg)
        elif any(not self.is_namespace_allowed(get_namespace(x))
                 for x in names if not x.startswith('##')):
            msg = _("names in notQName must be in namespaces that are allowed")
            self.parse_error(msg)

        self.not_qname = names

    @property
    def built(self) -> bool:
        return True

    @property
    def value_constraint(self) -> Optional[str]:
        return None

    def is_matching(self, name: Optional[str],
{'fraction_non_alphanumeric': 0.10761897067140665, 'fraction_numerical': 0.001292720368425305, 'mean_word_length': 2.1592649310872893, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 18, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, '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': '952987', 'n_tokens_mistral': 3431, 'n_tokens_neox': 3307, 'n_words': 933}