<commit_before>#!/usr/bin/env python
"""
A `Property Lists`_ is a data representation used in Apple's Mac OS X as
a convenient way to store standard object types, such as string, number,
boolean, and container object.

This file contains a class ``XmlPropertyListParser`` for parse
a property list file and get back a python native data structure.

    :copyright: 2008 by <NAME> <<EMAIL>>
    :license: MIT (See LICENSE file for more details)

.. _Property Lists: http://developer.apple.com/documentation/Cocoa/Conceptual/PropertyLists/
"""
from xml.sax import make_parser, handler, xmlreader


class XmlPropertyListParser(handler.ContentHandler):
    """
    The ``XmlPropertyListParser`` class provides methods that
    convert `Property Lists`_ objects from xml format.
    Property list objects include ``string``, ``unicode``,
    ``list``, ``dict``, ``datetime``, and ``int`` or ``float``.

        :copyright: 2008 by <NAME> <<EMAIL>>
        :license: MIT License

    .. _Property List: http://developer.apple.com/documentation/Cocoa/Conceptual/PropertyLists/
    """

    class ParseError(Exception):
        """Raised when parsing is failed."""
        pass

    def _assert(self, test, message):
        if not test:
            raise XmlPropertyListParser.ParseError(message)

    # ------------------------------------------------
    # SAX2: ContentHandler
    # ------------------------------------------------
    def startDocument(self):
        self.__stack = []
        self.__plist = None
        self.__key = None
        self.__characters = None

    def endDocument(self):
        self._assert(self.__plist is not None, "A top level element must be <plist>.")        

    def startElement(self, name, attributes):
        if name in XmlPropertyListParser.START_CALLBACKS:
            XmlPropertyListParser.START_CALLBACKS[name](self, name, attributes)
        if name in XmlPropertyListParser.PARSE_CALLBACKS:
            self.__characters = []

    def endElement(self, name):
        if name in XmlPropertyListParser.END_CALLBACKS:
            XmlPropertyListParser.END_CALLBACKS[name](self, name)
        if name in XmlPropertyListParser.PARSE_CALLBACKS:
            # Creates character string from buffered characters.
            content = ''.join(self.__characters)
            XmlPropertyListParser.PARSE_CALLBACKS[name](self, name, content)
            self.__characters = None

    def characters(self, content):
        if self.__characters is not None:
            self.__characters.append(content)

    # ------------------------------------------------
    # XmlPropertyListParser private
    # ------------------------------------------------
    def _push_value(self, value):
        values = self.__stack
        if not values:
            self.__plist = value
        else:
            top = values[-1]
            if isinstance(top, dict):
                self._assert(self.__key is not None, "Missing key for dictionary.")
                top[self.__key] = value
                self.__key = None
            elif isinstance(top, list):
                top.append(value)
            else:
                raise XmlPropertyListParser.ParseError(
                    "multiple objects at top level")

        if isinstance(value, (dict, list)):
            values.append(value)

    def _pop_value(self):
        self.__stack.pop()

    def _start_plist(self, name, attrs):
        self._assert(not self.__stack and self.__plist is None, "<plist> more than once.")
        self._assert(attrs.get('version', '1.0') == '1.0',
            "version 1.0 is only supported, but was '%s'." % attrs.get('version'))

    def _start_array(self, name, attrs):
        self._push_value(list())

    def _start_dict(self, name, attrs):
        self._push_value(dict())

    def _end_array(self, name):
        self._pop_value()

    def _end_dict(self, name):
        self._pop_value()

    def _start_true(self, name, attrs):
        self._push_value(True)

    def _start_false(self, name, attrs):
        self._push_value(False)

    def _parse_key(self, name, content):
        self.__key = content

    def _parse_string(self, name, content):
        self._push_value(content)

    def _parse_data(self, name, content):
        import base64
        self._push_value(base64.b64decode(content))

    def _parse_date(self, name, content):
        import time, datetime
        self._push_value(datetime.datetime(
            *(time.strptime(content, "%Y-%m-%dT%H:%M:%SZ")[0:6])))

    def _parse_real(self, name, content):
        self._push_value(float(content))

    def _parse_integer(self, name, content):
        self._push_value(int(content))

    START_CALLBACKS = {
        'plist': _start_plist,
        'array': _start_array,<commit_msg>Replaced time.strptime with regex pattern matching<commit_after>#!/usr/bin/env python
"""
A `Property Lists`_ is a data representation used in Apple's Mac OS X as
a convenient way to store standard object types, such as string, number,
boolean, and container object.

This file contains a class ``XmlPropertyListParser`` for parse
a property list file and get back a python native data structure.

    :copyright: 2008 by <NAME> <<EMAIL>>
    :license: MIT (See LICENSE file for more details)

.. _Property Lists: http://developer.apple.com/documentation/Cocoa/Conceptual/PropertyLists/
"""
from xml.sax import make_parser, handler, xmlreader


class XmlPropertyListParser(handler.ContentHandler):
    """
    The ``XmlPropertyListParser`` class provides methods that
    convert `Property Lists`_ objects from xml format.
    Property list objects include ``string``, ``unicode``,
    ``list``, ``dict``, ``datetime``, and ``int`` or ``float``.

        :copyright: 2008 by <NAME> <<EMAIL>>
        :license: MIT License

    .. _Property List: http://developer.apple.com/documentation/Cocoa/Conceptual/PropertyLists/
    """

    class ParseError(Exception):
        """Raised when parsing is failed."""
        pass

    def _assert(self, test, message):
        if not test:
            raise XmlPropertyListParser.ParseError(message)

    # ------------------------------------------------
    # SAX2: ContentHandler
    # ------------------------------------------------
    def startDocument(self):
        self.__stack = []
        self.__plist = None
        self.__key = None
        self.__characters = None

    def endDocument(self):
        self._assert(self.__plist is not None, "A top level element must be <plist>.")        

    def startElement(self, name, attributes):
        if name in XmlPropertyListParser.START_CALLBACKS:
            XmlPropertyListParser.START_CALLBACKS[name](self, name, attributes)
        if name in XmlPropertyListParser.PARSE_CALLBACKS:
            self.__characters = []

    def endElement(self, name):
        if name in XmlPropertyListParser.END_CALLBACKS:
            XmlPropertyListParser.END_CALLBACKS[name](self, name)
        if name in XmlPropertyListParser.PARSE_CALLBACKS:
            # Creates character string from buffered characters.
            content = ''.join(self.__characters)
            XmlPropertyListParser.PARSE_CALLBACKS[name](self, name, content)
            self.__characters = None

    def characters(self, content):
        if self.__characters is not None:
            self.__characters.append(content)

    # ------------------------------------------------
    # XmlPropertyListParser private
    # ------------------------------------------------
    def _push_value(self, value):
        values = self.__stack
        if not values:
            self.__plist = value
        else:
            top = values[-1]
            if isinstance(top, dict):
                self._assert(self.__key is not None, "Missing key for dictionary.")
                top[self.__key] = value
                self.__key = None
            elif isinstance(top, list):
                top.append(value)
            else:
                raise XmlPropertyListParser.ParseError(
                    "multiple objects at top level")

        if isinstance(value, (dict, list)):
            values.append(value)

    def _pop_value(self):
        self.__stack.pop()

    def _start_plist(self, name, attrs):
        self._assert(not self.__stack and self.__plist is None, "<plist> more than once.")
        self._assert(attrs.get('version', '1.0') == '1.0',
            "version 1.0 is only supported, but was '%s'." % attrs.get('version'))

    def _start_array(self, name, attrs):
        self._push_value(list())

    def _start_dict(self, name, attrs):
        self._push_value(dict())

    def _end_array(self, name):
        self._pop_value()

    def _end_dict(self, name):
        self._pop_value()

    def _start_true(self, name, attrs):
        self._push_value(True)

    def _start_false(self, name, attrs):
        self._push_value(False)

    def _parse_key(self, name, content):
        self.__key = content

    def _parse_string(self, name, content):
        self._push_value(content)

    def _parse_data(self, name, content):
        import base64
        self._push_value(base64.b64decode(content))

    def _parse_date(self, name, content):
        #import time, datetime
        #self._push_value(datetime.datetime(
        #    *(time.strptime(content, "%Y-%m-%dT%H:%M:%SZ")[0:6])))
        import re, datetime
        pat = re.compile(r'(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})Z')
        m = pat.match(content)
        if not m:
            raise XmlPropertyListParser.ParseError("Failed to parse datetime '%s'" % content)
        d = datetime.datetime(*([int(m.group(i)) for i in xrange(1, 7)]))
        self._push_value(d)

    def _parse_real(self, name, content):
        self._push_value(float(content))

    def _parse_integer(self, name, content):
        self._push_value(int(content))

    START_CALLBACKS = {
        'plist': _start_plist,
        'array': _start_array,
{'fraction_non_alphanumeric': 0.14561350618028338, 'fraction_numerical': 0.005627575118078585, 'mean_word_length': 2.2544146500981035, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 6}, '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': '2305943', 'n_tokens_mistral': 2876, 'n_tokens_neox': 2716, 'n_words': 733}