Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 15 Apr 2021 21:01:06 GMT
From:      Sofian Brabez <sbz@FreeBSD.org>
To:        ports-committers@FreeBSD.org, dev-commits-ports-all@FreeBSD.org, dev-commits-ports-main@FreeBSD.org
Subject:   git: a08dcbae9bc9 - main - textproc/py-feedparser: use new devel/py-sgmllib3k as run dependency
Message-ID:  <202104152101.13FL16ZK073514@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by sbz:

URL: https://cgit.FreeBSD.org/ports/commit/?id=a08dcbae9bc945ad6e78a4e5362fd760dc0220c0

commit a08dcbae9bc945ad6e78a4e5362fd760dc0220c0
Author:     Sofian Brabez <sbz@FreeBSD.org>
AuthorDate: 2021-04-15 19:54:43 +0000
Commit:     Sofian Brabez <sbz@FreeBSD.org>
CommitDate: 2021-04-15 21:00:24 +0000

    textproc/py-feedparser: use new devel/py-sgmllib3k as run dependency
    
    Do not ship sgmllib via ${FILESDIR} because it breaks the egg
    registration of the feedparser module when installed via distutil,
    instead add new created port devel/py-sgmllib3k as run dependency. This
    seems the right approach of solving this issue.
    
    PR:             250380
---
 textproc/py-feedparser/Makefile         |  21 +-
 textproc/py-feedparser/files/sgmllib.py | 547 --------------------------------
 2 files changed, 5 insertions(+), 563 deletions(-)

diff --git a/textproc/py-feedparser/Makefile b/textproc/py-feedparser/Makefile
index 692d5a3c458a..ddcdeaad2d82 100644
--- a/textproc/py-feedparser/Makefile
+++ b/textproc/py-feedparser/Makefile
@@ -2,17 +2,18 @@
 
 PORTNAME=	feedparser
 PORTVERSION=	6.0.2
-PORTREVISION=	1
+PORTREVISION=	2
 CATEGORIES=	textproc python
 PKGNAMEPREFIX=	${PYTHON_PKGNAMEPREFIX}
 
 MAINTAINER=	sbz@FreeBSD.org
 COMMENT=	Universal feed parser written in Python
 
-LICENSE=	BSD2CLAUSE PSFL
-LICENSE_COMB=	multi
+LICENSE=	BSD2CLAUSE
 LICENSE_FILE=	${WRKSRC}/LICENSE
 
+RUN_DEPENDS=	${PYTHON_PKGNAMEPREFIX}sgmllib3k>=0:devel/py-sgmllib3k@${PY_FLAVOR}
+
 USES=		python:3.6+ tar:bzip2
 USE_PYTHON=	autoplist distutils
 USE_GITHUB=	yes
@@ -25,18 +26,6 @@ PORTDOCS=	NEWS README.rst
 
 OPTIONS_DEFINE=	DOCS
 
-.include <bsd.port.pre.mk>
-
-.if ${PYTHON_REL} > 3700
-PLIST_FILES+=	${PYTHON_SITELIBDIR}/sgmllib.py
-
-post-install:
-	${INSTALL_DATA} ${FILESDIR}/sgmllib.py ${STAGEDIR}/${PYTHON_SITELIBDIR}/sgmllib.py
-.endif
-
-post-patch:
-	@${REINPLACE_CMD} '/sgmllib3k/d' ${WRKSRC}/setup.py
-
 post-install-DOCS-on:
 	@${MKDIR} ${STAGEDIR}${DOCSDIR}
 	${INSTALL_DATA} ${PORTDOCS:S,^,${WRKSRC}/,} ${STAGEDIR}${DOCSDIR}
@@ -44,4 +33,4 @@ post-install-DOCS-on:
 do-test:
 	@(cd ${WRKSRC}; ${PYTHON_CMD} tests/runtests.py)
 
-.include <bsd.port.post.mk>
+.include <bsd.port.mk>
diff --git a/textproc/py-feedparser/files/sgmllib.py b/textproc/py-feedparser/files/sgmllib.py
deleted file mode 100644
index 88a02a307f40..000000000000
--- a/textproc/py-feedparser/files/sgmllib.py
+++ /dev/null
@@ -1,547 +0,0 @@
-"""A parser for SGML, using the derived class as a static DTD."""
-
-# XXX This only supports those SGML features used by HTML.
-
-# XXX There should be a way to distinguish between PCDATA (parsed
-# character data -- the normal case), RCDATA (replaceable character
-# data -- only char and entity references and end tags are special)
-# and CDATA (character data -- only end tags are special).  RCDATA is
-# not supported at all.
-
-import _markupbase
-import re
-
-__all__ = ["SGMLParser", "SGMLParseError"]
-
-# Regular expressions used for parsing
-
-interesting = re.compile('[&<]')
-incomplete = re.compile('&([a-zA-Z][a-zA-Z0-9]*|#[0-9]*)?|'
-                           '<([a-zA-Z][^<>]*|'
-                              '/([a-zA-Z][^<>]*)?|'
-                              '![^<>]*)?')
-
-entityref = re.compile('&([a-zA-Z][-.a-zA-Z0-9]*)[^a-zA-Z0-9]')
-charref = re.compile('&#([0-9]+)[^0-9]')
-
-starttagopen = re.compile('<[>a-zA-Z]')
-shorttagopen = re.compile('<[a-zA-Z][-.a-zA-Z0-9]*/')
-shorttag = re.compile('<([a-zA-Z][-.a-zA-Z0-9]*)/([^/]*)/')
-piclose = re.compile('>')
-endbracket = re.compile('[<>]')
-tagfind = re.compile('[a-zA-Z][-_.a-zA-Z0-9]*')
-attrfind = re.compile(
-    r'\s*([a-zA-Z_][-:.a-zA-Z_0-9]*)(\s*=\s*'
-    r'(\'[^\']*\'|"[^"]*"|[][\-a-zA-Z0-9./,:;+*%?!&$\(\)_#=~\'"@]*))?')
-
-
-class SGMLParseError(RuntimeError):
-    """Exception raised for all parse errors."""
-    pass
-
-
-# SGML parser base class -- find tags and call handler functions.
-# Usage: p = SGMLParser(); p.feed(data); ...; p.close().
-# The dtd is defined by deriving a class which defines methods
-# with special names to handle tags: start_foo and end_foo to handle
-# <foo> and </foo>, respectively, or do_foo to handle <foo> by itself.
-# (Tags are converted to lower case for this purpose.)  The data
-# between tags is passed to the parser by calling self.handle_data()
-# with some data as argument (the data may be split up in arbitrary
-# chunks).  Entity references are passed by calling
-# self.handle_entityref() with the entity reference as argument.
-
-class SGMLParser(_markupbase.ParserBase):
-    # Definition of entities -- derived classes may override
-    entity_or_charref = re.compile('&(?:'
-      '([a-zA-Z][-.a-zA-Z0-9]*)|#([0-9]+)'
-      ')(;?)')
-
-    def __init__(self, verbose=0):
-        """Initialize and reset this instance."""
-        self.verbose = verbose
-        self.reset()
-
-    def reset(self):
-        """Reset this instance. Loses all unprocessed data."""
-        self.__starttag_text = None
-        self.rawdata = ''
-        self.stack = []
-        self.lasttag = '???'
-        self.nomoretags = 0
-        self.literal = 0
-        _markupbase.ParserBase.reset(self)
-
-    def setnomoretags(self):
-        """Enter literal mode (CDATA) till EOF.
-
-        Intended for derived classes only.
-        """
-        self.nomoretags = self.literal = 1
-
-    def setliteral(self, *args):
-        """Enter literal mode (CDATA).
-
-        Intended for derived classes only.
-        """
-        self.literal = 1
-
-    def feed(self, data):
-        """Feed some data to the parser.
-
-        Call this as often as you want, with as little or as much text
-        as you want (may include '\n').  (This just saves the text,
-        all the processing is done by goahead().)
-        """
-
-        self.rawdata = self.rawdata + data
-        self.goahead(0)
-
-    def close(self):
-        """Handle the remaining data."""
-        self.goahead(1)
-
-    def error(self, message):
-        raise SGMLParseError(message)
-
-    # Internal -- handle data as far as reasonable.  May leave state
-    # and data to be processed by a subsequent call.  If 'end' is
-    # true, force handling all data as if followed by EOF marker.
-    def goahead(self, end):
-        rawdata = self.rawdata
-        i = 0
-        n = len(rawdata)
-        while i < n:
-            if self.nomoretags:
-                self.handle_data(rawdata[i:n])
-                i = n
-                break
-            match = interesting.search(rawdata, i)
-            if match: j = match.start()
-            else: j = n
-            if i < j:
-                self.handle_data(rawdata[i:j])
-            i = j
-            if i == n: break
-            if rawdata[i] == '<':
-                if starttagopen.match(rawdata, i):
-                    if self.literal:
-                        self.handle_data(rawdata[i])
-                        i = i+1
-                        continue
-                    k = self.parse_starttag(i)
-                    if k < 0: break
-                    i = k
-                    continue
-                if rawdata.startswith("</", i):
-                    k = self.parse_endtag(i)
-                    if k < 0: break
-                    i = k
-                    self.literal = 0
-                    continue
-                if self.literal:
-                    if n > (i + 1):
-                        self.handle_data("<")
-                        i = i+1
-                    else:
-                        # incomplete
-                        break
-                    continue
-                if rawdata.startswith("<!--", i):
-                        # Strictly speaking, a comment is --.*--
-                        # within a declaration tag <!...>.
-                        # This should be removed,
-                        # and comments handled only in parse_declaration.
-                    k = self.parse_comment(i)
-                    if k < 0: break
-                    i = k
-                    continue
-                if rawdata.startswith("<?", i):
-                    k = self.parse_pi(i)
-                    if k < 0: break
-                    i = i+k
-                    continue
-                if rawdata.startswith("<!", i):
-                    # This is some sort of declaration; in "HTML as
-                    # deployed," this should only be the document type
-                    # declaration ("<!DOCTYPE html...>").
-                    k = self.parse_declaration(i)
-                    if k < 0: break
-                    i = k
-                    continue
-            elif rawdata[i] == '&':
-                if self.literal:
-                    self.handle_data(rawdata[i])
-                    i = i+1
-                    continue
-                match = charref.match(rawdata, i)
-                if match:
-                    name = match.group(1)
-                    self.handle_charref(name)
-                    i = match.end(0)
-                    if rawdata[i-1] != ';': i = i-1
-                    continue
-                match = entityref.match(rawdata, i)
-                if match:
-                    name = match.group(1)
-                    self.handle_entityref(name)
-                    i = match.end(0)
-                    if rawdata[i-1] != ';': i = i-1
-                    continue
-            else:
-                self.error('neither < nor & ??')
-            # We get here only if incomplete matches but
-            # nothing else
-            match = incomplete.match(rawdata, i)
-            if not match:
-                self.handle_data(rawdata[i])
-                i = i+1
-                continue
-            j = match.end(0)
-            if j == n:
-                break # Really incomplete
-            self.handle_data(rawdata[i:j])
-            i = j
-        # end while
-        if end and i < n:
-            self.handle_data(rawdata[i:n])
-            i = n
-        self.rawdata = rawdata[i:]
-        # XXX if end: check for empty stack
-
-    # Extensions for the DOCTYPE scanner:
-    _decl_otherchars = '='
-
-    # Internal -- parse processing instr, return length or -1 if not terminated
-    def parse_pi(self, i):
-        rawdata = self.rawdata
-        if rawdata[i:i+2] != '<?':
-            self.error('unexpected call to parse_pi()')
-        match = piclose.search(rawdata, i+2)
-        if not match:
-            return -1
-        j = match.start(0)
-        self.handle_pi(rawdata[i+2: j])
-        j = match.end(0)
-        return j-i
-
-    def get_starttag_text(self):
-        return self.__starttag_text
-
-    # Internal -- handle starttag, return length or -1 if not terminated
-    def parse_starttag(self, i):
-        self.__starttag_text = None
-        start_pos = i
-        rawdata = self.rawdata
-        if shorttagopen.match(rawdata, i):
-            # SGML shorthand: <tag/data/ == <tag>data</tag>
-            # XXX Can data contain &... (entity or char refs)?
-            # XXX Can data contain < or > (tag characters)?
-            # XXX Can there be whitespace before the first /?
-            match = shorttag.match(rawdata, i)
-            if not match:
-                return -1
-            tag, data = match.group(1, 2)
-            self.__starttag_text = '<%s/' % tag
-            tag = tag.lower()
-            k = match.end(0)
-            self.finish_shorttag(tag, data)
-            self.__starttag_text = rawdata[start_pos:match.end(1) + 1]
-            return k
-        # XXX The following should skip matching quotes (' or ")
-        # As a shortcut way to exit, this isn't so bad, but shouldn't
-        # be used to locate the actual end of the start tag since the
-        # < or > characters may be embedded in an attribute value.
-        match = endbracket.search(rawdata, i+1)
-        if not match:
-            return -1
-        j = match.start(0)
-        # Now parse the data between i+1 and j into a tag and attrs
-        attrs = []
-        if rawdata[i:i+2] == '<>':
-            # SGML shorthand: <> == <last open tag seen>
-            k = j
-            tag = self.lasttag
-        else:
-            match = tagfind.match(rawdata, i+1)
-            if not match:
-                self.error('unexpected call to parse_starttag')
-            k = match.end(0)
-            tag = rawdata[i+1:k].lower()
-            self.lasttag = tag
-        while k < j:
-            match = attrfind.match(rawdata, k)
-            if not match: break
-            attrname, rest, attrvalue = match.group(1, 2, 3)
-            if not rest:
-                attrvalue = attrname
-            else:
-                if (attrvalue[:1] == "'" == attrvalue[-1:] or
-                    attrvalue[:1] == '"' == attrvalue[-1:]):
-                    # strip quotes
-                    attrvalue = attrvalue[1:-1]
-                attrvalue = self.entity_or_charref.sub(
-                    self._convert_ref, attrvalue)
-            attrs.append((attrname.lower(), attrvalue))
-            k = match.end(0)
-        if rawdata[j] == '>':
-            j = j+1
-        self.__starttag_text = rawdata[start_pos:j]
-        self.finish_starttag(tag, attrs)
-        return j
-
-    # Internal -- convert entity or character reference
-    def _convert_ref(self, match):
-        if match.group(2):
-            return self.convert_charref(match.group(2)) or \
-                '&#%s%s' % match.groups()[1:]
-        elif match.group(3):
-            return self.convert_entityref(match.group(1)) or \
-                '&%s;' % match.group(1)
-        else:
-            return '&%s' % match.group(1)
-
-    # Internal -- parse endtag
-    def parse_endtag(self, i):
-        rawdata = self.rawdata
-        match = endbracket.search(rawdata, i+1)
-        if not match:
-            return -1
-        j = match.start(0)
-        tag = rawdata[i+2:j].strip().lower()
-        if rawdata[j] == '>':
-            j = j+1
-        self.finish_endtag(tag)
-        return j
-
-    # Internal -- finish parsing of <tag/data/ (same as <tag>data</tag>)
-    def finish_shorttag(self, tag, data):
-        self.finish_starttag(tag, [])
-        self.handle_data(data)
-        self.finish_endtag(tag)
-
-    # Internal -- finish processing of start tag
-    # Return -1 for unknown tag, 0 for open-only tag, 1 for balanced tag
-    def finish_starttag(self, tag, attrs):
-        try:
-            method = getattr(self, 'start_' + tag)
-        except AttributeError:
-            try:
-                method = getattr(self, 'do_' + tag)
-            except AttributeError:
-                self.unknown_starttag(tag, attrs)
-                return -1
-            else:
-                self.handle_starttag(tag, method, attrs)
-                return 0
-        else:
-            self.stack.append(tag)
-            self.handle_starttag(tag, method, attrs)
-            return 1
-
-    # Internal -- finish processing of end tag
-    def finish_endtag(self, tag):
-        if not tag:
-            found = len(self.stack) - 1
-            if found < 0:
-                self.unknown_endtag(tag)
-                return
-        else:
-            if tag not in self.stack:
-                try:
-                    method = getattr(self, 'end_' + tag)
-                except AttributeError:
-                    self.unknown_endtag(tag)
-                else:
-                    self.report_unbalanced(tag)
-                return
-            found = len(self.stack)
-            for i in range(found):
-                if self.stack[i] == tag: found = i
-        while len(self.stack) > found:
-            tag = self.stack[-1]
-            try:
-                method = getattr(self, 'end_' + tag)
-            except AttributeError:
-                method = None
-            if method:
-                self.handle_endtag(tag, method)
-            else:
-                self.unknown_endtag(tag)
-            del self.stack[-1]
-
-    # Overridable -- handle start tag
-    def handle_starttag(self, tag, method, attrs):
-        method(attrs)
-
-    # Overridable -- handle end tag
-    def handle_endtag(self, tag, method):
-        method()
-
-    # Example -- report an unbalanced </...> tag.
-    def report_unbalanced(self, tag):
-        if self.verbose:
-            print('*** Unbalanced </' + tag + '>')
-            print('*** Stack:', self.stack)
-
-    def convert_charref(self, name):
-        """Convert character reference, may be overridden."""
-        try:
-            n = int(name)
-        except ValueError:
-            return
-        if not 0 <= n <= 127:
-            return
-        return self.convert_codepoint(n)
-
-    def convert_codepoint(self, codepoint):
-        return chr(codepoint)
-
-    def handle_charref(self, name):
-        """Handle character reference, no need to override."""
-        replacement = self.convert_charref(name)
-        if replacement is None:
-            self.unknown_charref(name)
-        else:
-            self.handle_data(replacement)
-
-    # Definition of entities -- derived classes may override
-    entitydefs = \
-            {'lt': '<', 'gt': '>', 'amp': '&', 'quot': '"', 'apos': '\''}
-
-    def convert_entityref(self, name):
-        """Convert entity references.
-
-        As an alternative to overriding this method; one can tailor the
-        results by setting up the self.entitydefs mapping appropriately.
-        """
-        table = self.entitydefs
-        if name in table:
-            return table[name]
-        else:
-            return
-
-    def handle_entityref(self, name):
-        """Handle entity references, no need to override."""
-        replacement = self.convert_entityref(name)
-        if replacement is None:
-            self.unknown_entityref(name)
-        else:
-            self.handle_data(replacement)
-
-    # Example -- handle data, should be overridden
-    def handle_data(self, data):
-        pass
-
-    # Example -- handle comment, could be overridden
-    def handle_comment(self, data):
-        pass
-
-    # Example -- handle declaration, could be overridden
-    def handle_decl(self, decl):
-        pass
-
-    # Example -- handle processing instruction, could be overridden
-    def handle_pi(self, data):
-        pass
-
-    # To be overridden -- handlers for unknown objects
-    def unknown_starttag(self, tag, attrs): pass
-    def unknown_endtag(self, tag): pass
-    def unknown_charref(self, ref): pass
-    def unknown_entityref(self, ref): pass
-
-
-class TestSGMLParser(SGMLParser):
-
-    def __init__(self, verbose=0):
-        self.testdata = ""
-        SGMLParser.__init__(self, verbose)
-
-    def handle_data(self, data):
-        self.testdata = self.testdata + data
-        if len(repr(self.testdata)) >= 70:
-            self.flush()
-
-    def flush(self):
-        data = self.testdata
-        if data:
-            self.testdata = ""
-            print('data:', repr(data))
-
-    def handle_comment(self, data):
-        self.flush()
-        r = repr(data)
-        if len(r) > 68:
-            r = r[:32] + '...' + r[-32:]
-        print('comment:', r)
-
-    def unknown_starttag(self, tag, attrs):
-        self.flush()
-        if not attrs:
-            print('start tag: <' + tag + '>')
-        else:
-            print('start tag: <' + tag, end=' ')
-            for name, value in attrs:
-                print(name + '=' + '"' + value + '"', end=' ')
-            print('>')
-
-    def unknown_endtag(self, tag):
-        self.flush()
-        print('end tag: </' + tag + '>')
-
-    def unknown_entityref(self, ref):
-        self.flush()
-        print('*** unknown entity ref: &' + ref + ';')
-
-    def unknown_charref(self, ref):
-        self.flush()
-        print('*** unknown char ref: &#' + ref + ';')
-
-    def unknown_decl(self, data):
-        self.flush()
-        print('*** unknown decl: [' + data + ']')
-
-    def close(self):
-        SGMLParser.close(self)
-        self.flush()
-
-
-def test(args = None):
-    import sys
-
-    if args is None:
-        args = sys.argv[1:]
-
-    if args and args[0] == '-s':
-        args = args[1:]
-        klass = SGMLParser
-    else:
-        klass = TestSGMLParser
-
-    if args:
-        file = args[0]
-    else:
-        file = 'test.html'
-
-    if file == '-':
-        f = sys.stdin
-    else:
-        try:
-            f = open(file, 'r')
-        except IOError as msg:
-            print(file, ":", msg)
-            sys.exit(1)
-
-    data = f.read()
-    if f is not sys.stdin:
-        f.close()
-
-    x = klass()
-    for c in data:
-        x.feed(c)
-    x.close()
-
-
-if __name__ == '__main__':
-    test()



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202104152101.13FL16ZK073514>