<commit_before>########################################################################
# amara/writers/_htmlprinters.py
"""
This module supports document serialization in HTML syntax.
"""

import re

from amara.writers import _xmlstream, htmlentities
from amara.writers._xmlprinter import xmlprinter

__all__ = ('htmlprinter', 'htmlprettyprinter')

class htmlprinter(xmlprinter):
    """
    An `htmlprinter` instance provides functions for serializing an XML
    or XML-like document to a stream, based on SAX-like event calls.

    The methods in this subclass of `xmlprinter` attempt to emit a
    document conformant to the HTML 4.01 syntax, with no extra
    whitespace added for visual formatting. The degree of correctness
    of the output depends on the data supplied in the event calls; no
    checks are done for conditions that would result in syntax errors,
    such as two attributes with the same name, "--" in a comment, etc.
    """

    _disable_ouput_escaping = 0

    def __init__(self, stream, encoding, byte_order_mark=None,
                 canonical_form=None):
        assert not canonical_form
        xmlprinter.__init__(self, stream, encoding, byte_order_mark, False)

    def start_document(self, version='4.0', standalone=None):
        """
        Handles a start-document event.

        Differs from the overridden method in that no XML declaration
        is written.
        """
        # Set the entity maps to the particular version of HTML being output.
        # If the version isn't one we know how to handle, fallback to 4.0.
        try:
            entities = self._versioned_entities[version]
        except KeyError:
            entities = self._versioned_entities['4.0']
        (self._text_entities,
         self._attr_entities_quot,
         self._attr_entities_apos) = entities
        return

    def doctype(self, name, publicid, systemid):
        """
        Handles a doctype event.

        Extends the overridden method by adding support for the case
        when there is a publicId and no systemId, which is allowed in
        HTML but not in XML.
        """
        if publicid and not systemid:
            self.write_ascii('<!DOCTYPE ')
            self.write_encode(name, 'document type name')
            self.write_ascii(' PUBLIC "')
            self.write_encode(publicId, 'document type public-id')
            self.write_ascii('">\n')
        else:
            xmlprinter.doctype(self, name, publicId, systemId)
        return

    def start_element(self, namespace, name, namespaces, attributes):
        """
        Handles a start-tag event.

        Extends the overridden method by disabling output escaping for
        the content of certain elements (SCRIPT and STYLE).
        """
        if namespace is not None:
            xmlprinter.start_element(self, namespace, name, namespaces,
                                     attributes)
            return

        if name.lower() in self._no_escape_elements:
            self._disable_ouput_escaping += 1

        xmlprinter.start_element(self, namespace, name, namespaces,
                                attributes)

        # HTML tags are never in minimized form ('<tag/>')
        self.write_ascii('>')
        self._element_name = None
        return

    def end_element(self, namespace, name):
        """
        Handles an end-tag event.

        Differs from the overridden method in that an end tag is not
        generated for certain elements.
        """
        if namespace is not None:
            xmlprinter.end_element(self, namespace, name)
            return

        element = name.lower()
        if element not in self._forbidden_end_elements:
            self.write_ascii('</')
            self.write_encode(name, 'element name')
            self.write_ascii('>')

        # Restore normal escaping if closing a no-escape element.
        if element in self._no_escape_elements:
            self._disable_ouput_escaping -= 1
        return

    def attribute(self, element_namespace, element_name, name, value):
        """
        Handles an attribute event.

        Extends the overridden method by writing boolean attributes in
        minimized form.
        """
        if element_namespace is not None:
            xmlprinter.attribute(self, element_namespace, element_name,
                                 name, value)
            return

        element = element_name.lower()
        attribute = name.lower()
        if (attribute in self._boolean_attributes
            and element in self._boolean_attributes[attribute]
            and attribute == value.lower()):
            # A boolean attribute, just write out the name
            self.write_ascii(' ')
            self.write_encode(name, 'attribute name')
        elif (attribute in self._uri_attributes
              and element in self._uri_attributes[attribute]):
            # From HTML 4.0 Section B.2.1
            # We recommend that user agents adopt the following convention for
            # handling non-ASCII characters:
            # 1. Represent each character in UTF-8 (see [RFC2279]) as one or
            #    more bytes.
            # 2. Escape these bytes with the URI escaping mechanism (i.e., by
            #    converting each byte to %HH, where HH is the hexadecimal
            #    notation of the byte value).
            # (Although this recommendation is for HTML user agents
            # that encounter HTML with improperly escaped URI refs,
            # we implement it in order to comply with XSLT's html
            # output method, and because there's no compelling reason
            # not to do it for non-XSLT serializations as well)
            #
            # FIXME:
            # "&" should not be escaped in an attribute value when it
            # it is followed by "{" (see Section B.7.1 of HTML 4.0).
            value = unicode(re.sub('[\x80-\xff]',
                                   lambda match: '%%%02X' % ord(match.group()),
                                   value.encode('UTF-8')))
            xmlprinter.attribute(self, element_namespace, element_name,
                                 name, value)
        else:
            xmlprinter.attribute(self, element_namespace, element_name,
                                 name, value)
        return

    def text(self, data, disable_escaping=False):
        """
        Handles a text event.

        Extends the overridden method by disabling output escaping if
        in the content of certain elements like SCRIPT or STYLE.
        """
        if self._element_name:
            self.write_ascii('>')<commit_msg>reverted changes to htmlprinter in revision 77<commit_after>########################################################################
# amara/writers/_htmlprinters.py
"""
This module supports document serialization in HTML syntax.
"""

import re

from amara.writers import _xmlstream, htmlentities
from amara.writers._xmlprinter import xmlprinter

__all__ = ('htmlprinter', 'htmlprettyprinter')

class htmlprinter(xmlprinter):
    """
    An `htmlprinter` instance provides functions for serializing an XML
    or XML-like document to a stream, based on SAX-like event calls.

    The methods in this subclass of `xmlprinter` attempt to emit a
    document conformant to the HTML 4.01 syntax, with no extra
    whitespace added for visual formatting. The degree of correctness
    of the output depends on the data supplied in the event calls; no
    checks are done for conditions that would result in syntax errors,
    such as two attributes with the same name, "--" in a comment, etc.
    """

    _disable_ouput_escaping = 0

    def __init__(self, stream, encoding, byte_order_mark=None,
                 canonical_form=None):
        assert not canonical_form
        xmlprinter.__init__(self, stream, encoding, byte_order_mark, False)

    def start_document(self, version='4.0', standalone=None):
        """
        Handles a start-document event.

        Differs from the overridden method in that no XML declaration
        is written.
        """
        # Set the entity maps to the particular version of HTML being output.
        # If the version isn't one we know how to handle, fallback to 4.0.
        try:
            entities = self._versioned_entities[version]
        except KeyError:
            entities = self._versioned_entities['4.0']
        (self._text_entities,
         self._attr_entities_quot,
         self._attr_entities_apos) = entities
        return

    def doctype(self, name, publicid, systemid):
        """
        Handles a doctype event.

        Extends the overridden method by adding support for the case
        when there is a publicId and no systemId, which is allowed in
        HTML but not in XML.
        """
        if publicid and not systemid:
            self.write_ascii('<!DOCTYPE ')
            self.write_encode(name, 'document type name')
            self.write_ascii(' PUBLIC "')
            self.write_encode(publicId, 'document type public-id')
            self.write_ascii('">\n')
        else:
            xmlprinter.doctype(self, name, publicId, systemId)
        return

    def _translate_attributes(self, element, attributes):
        bool_attrs, uri_attrs = self._boolean_attributes, self._uri_attributes
        for name, value in attributes:
            attr = name.lower()
            if attr in bool_attrs and element in bool_attrs[attr]:
                if attr == value.lower():
                    # A boolean attribute, just write out the name
                    value = None
            elif attr in uri_attrs and element in uri_attrs[attr]:
                # From HTML 4.0 Section B.2.1
                # We recommend that user agents adopt the following convention
                # for handling non-ASCII characters:
                # 1. Represent each character in UTF-8 (see [RFC2279]) as one
                #    or more bytes.
                # 2. Escape these bytes with the URI escaping mechanism
                #    (i.e., by converting each byte to %HH, where HH is the
                #     hexadecimal notation of the byte value).
                # (Although this recommendation is for HTML user agents
                # that encounter HTML with improperly escaped URI refs,
                # we implement it in order to comply with XSLT's html
                # output method, and because there's no compelling reason
                # not to do it for non-XSLT serializations as well)
                value = unicode(re.sub('[\x80-\xff]',
                                lambda match: '%%%02X' % ord(match.group()),
                                value.encode('UTF-8')))
            yield (name, value)
        return

    def start_element(self, namespace, name, namespaces, attributes):
        """
        Handles a start-tag event.

        Extends the overridden method by disabling output escaping for
        the content of certain elements (SCRIPT and STYLE).
        """
        if namespace is not None:
            xmlprinter.start_element(self, namespace, name, namespaces,
                                     attributes)
            return

        element = name.lower()
        if element in self._no_escape_elements:
            self._disable_ouput_escaping += 1

        # Translate attribute values as required
        if namespace is None:
            attributes = self._translate_attributes(element, attributes)

        xmlprinter.start_element(self, namespace, name, namespaces,
                                 attributes)

        # HTML tags are never in minimized form ('<tag/>')
        self.write_ascii('>')
        self._element_name = None
        return

    def end_element(self, namespace, name):
        """
        Handles an end-tag event.

        Differs from the overridden method in that an end tag is not
        generated for certain elements.
        """
        if namespace is not None:
            xmlprinter.end_element(self, namespace, name)
            return

        element = name.lower()
        if element not in self._forbidden_end_elements:
            self.write_ascii('</')
            self.write_encode(name, 'element name')
            self.write_ascii('>')

        # Restore normal escaping if closing a no-escape element.
        if element in self._no_escape_elements:
            self._disable_ouput_escaping -= 1
        return

    def text(self, data, disable_escaping=False):
        """
        Handles a text event.

        Extends the overridden method by disabling output escaping if
        in the content of certain elements like SCRIPT or STYLE.
        """
        if self._element_name:
            self.write_ascii('>')
{'fraction_non_alphanumeric': 0.08200580710978576, 'fraction_numerical': 0.004865416306992074, 'mean_word_length': 2.029236985975755, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 23}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2243329', 'n_tokens_mistral': 3320, 'n_tokens_neox': 3137, 'n_words': 1171}