Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 30 additions & 4 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,19 @@ on: [push, pull_request]

jobs:
tests:
name: python ${{ matrix.python-version }}
runs-on: ubuntu-20.04

strategy:
matrix:
python-version: [3.6, 3.7, 3.8, 3.9, "3.10", "3.11", "3.12", "3.13.0-beta.2", pypy2, pypy3]
python-version: [3.6, 3.7, 3.8, 3.9, "3.10", "3.11", "3.12", pypy3]
pytest-extra-options: ["--strict-config -W \"ignore:pkg_resources is deprecated\""]
include:
- python-version: pypy2
pytest-extra-options: ""
- python-version: "3.13.0-beta.2"
pytest-extra-options: "--strict-config -W \"ignore:pkg_resources is deprecated\" -W ignore::DeprecationWarning"
fail-fast: false

steps:
- uses: actions/checkout@v2
Expand All @@ -16,10 +25,27 @@ jobs:
with:
python-version: ${{ matrix.python-version }}

- name: Install setuptools
- name: Install genshi
run: |
pip install -e .

- name: Install testing requirements
run: |
pip install setuptools
pip install setuptools pytest

- name: Run test suite
run: |
python setup.py test
pytest -Werror --strict-markers --verbosity=1 --color=yes ${{ matrix.pytest-extra-options }} genshi
# Above flags are:
# -Werror
# treat warnings as errors
# --strict-config
# error out if the configuration file is not parseable
# --strict-markers
# error out if a marker is used but not defined in the
# configuration file
# --verbosity=1
# turn the verbosity up so pytest prints the names of the tests
# it's currently working on
# --color=yes
# force coloured output in the terminal
2 changes: 1 addition & 1 deletion genshi/filters/i18n.py
Original file line number Diff line number Diff line change
Expand Up @@ -536,7 +536,7 @@ class DomainDirective(I18NDirective):
"""Implementation of the ``i18n:domain`` directive which allows choosing
another i18n domain(catalog) to translate from.

>>> from genshi.filters.tests.i18n import DummyTranslations
>>> from genshi.filters.tests.test_i18n import DummyTranslations
>>> tmpl = MarkupTemplate('''<html xmlns:i18n="http://genshi.edgewall.org/i18n">
... <p i18n:msg="">Bar</p>
... <div i18n:domain="foo">
Expand Down
6 changes: 3 additions & 3 deletions genshi/filters/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@
import unittest

def suite():
from genshi.filters.tests import test_html, i18n, transform
from genshi.filters.tests import test_html, test_i18n, test_transform
suite = unittest.TestSuite()
suite.addTest(test_html.suite())
suite.addTest(i18n.suite())
suite.addTest(test_i18n.suite())
if hasattr(doctest, 'NORMALIZE_WHITESPACE'):
suite.addTest(transform.suite())
suite.addTest(test_transform.suite())
return suite

if __name__ == '__main__':
Expand Down
2 changes: 1 addition & 1 deletion genshi/filters/tests/test_html.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from genshi.input import HTML, ParseError
from genshi.filters.html import HTMLFormFiller, HTMLSanitizer
from genshi.template import MarkupTemplate
from genshi.tests.test_utils import doctest_suite
from genshi.tests.utils import doctest_suite

class HTMLFormFillerTestCase(unittest.TestCase):

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from genshi.filters.i18n import Translator, extract
from genshi.input import HTML
from genshi.compat import IS_PYTHON2, StringIO
from genshi.tests.test_utils import doctest_suite
from genshi.tests.utils import doctest_suite


class DummyTranslations(NullTranslations):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from genshi.filters.transform import Transformer, StreamBuffer, ENTER, EXIT, \
OUTSIDE, INSIDE, ATTR, BREAK
import genshi.filters.transform
from genshi.tests.test_utils import doctest_suite
from genshi.tests.utils import doctest_suite


FOO = '<root>ROOT<foo name="foo">FOO</foo></root>'
Expand Down
47 changes: 33 additions & 14 deletions genshi/filters/transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,21 @@
the ``<head>`` of the input document:

>>> from genshi.builder import tag
>>> from genshi.input import HTML
>>> html = HTML('''<html>
... <head><title>Some Title</title></head>
... <body>
... Some <em>body</em> text.
... </body>
... <head><title>Some Title</title></head>
... <body>
... Some <em>body</em> text.
... </body>
... </html>''',
... encoding='utf-8')
>>> print(html | Transformer('body/em').map(six.text_type.upper, TEXT)
... .unwrap().wrap(tag.u))
<html>
<head><title>Some Title</title></head>
<body>
Some <u>BODY</u> text.
</body>
<head><title>Some Title</title></head>
<body>
Some <u>BODY</u> text.
</body>
</html>

The ``Transformer`` support a large number of useful transformations out of the
Expand Down Expand Up @@ -138,6 +139,7 @@ class Transformer(object):
outside a `START`/`END` container (e.g. ``text()``) will yield an `OUTSIDE`
mark.

>>> from genshi.input import HTML
>>> html = HTML('<html><head><title>Some Title</title></head>'
... '<body>Some <em>body</em> text.</body></html>',
... encoding='utf-8')
Expand Down Expand Up @@ -213,6 +215,7 @@ def apply(self, function):

As an example, here is a simple `TEXT` event upper-casing transform:

>>> from genshi.input import HTML
>>> def upper(stream):
... for mark, (kind, data, pos) in stream:
... if mark and kind is TEXT:
Expand All @@ -238,6 +241,7 @@ def select(self, path):
"""Mark events matching the given XPath expression, within the current
selection.

>>> from genshi.input import HTML
>>> html = HTML('<body>Some <em>test</em> text</body>', encoding='utf-8')
>>> print(html | Transformer().select('.//em').trace())
(None, ('START', (QName('body'), Attrs()), (None, 1, 0)))
Expand All @@ -262,6 +266,7 @@ def invert(self):
Specificaly, all marks are converted to null marks, and all null marks
are converted to OUTSIDE marks.

>>> from genshi.input import HTML
>>> html = HTML('<body>Some <em>test</em> text</body>', encoding='utf-8')
>>> print(html | Transformer('//em').invert().trace())
('OUTSIDE', ('START', (QName('body'), Attrs()), (None, 1, 0)))
Expand All @@ -282,6 +287,7 @@ def end(self):

Example:

>>> from genshi.input import HTML
>>> html = HTML('<body>Some <em>test</em> text</body>', encoding='utf-8')
>>> print(html | Transformer('//em').end().trace())
('OUTSIDE', ('START', (QName('body'), Attrs()), (None, 1, 0)))
Expand All @@ -305,6 +311,7 @@ def empty(self):

Example:

>>> from genshi.input import HTML
>>> html = HTML('<html><head><title>Some Title</title></head>'
... '<body>Some <em>body</em> text.</body></html>',
... encoding='utf-8')
Expand All @@ -321,6 +328,7 @@ def remove(self):

Example:

>>> from genshi.input import HTML
>>> html = HTML('<html><head><title>Some Title</title></head>'
... '<body>Some <em>body</em> text.</body></html>',
... encoding='utf-8')
Expand All @@ -339,6 +347,7 @@ def unwrap(self):

Example:

>>> from genshi.input import HTML
>>> html = HTML('<html><head><title>Some Title</title></head>'
... '<body>Some <em>body</em> text.</body></html>',
... encoding='utf-8')
Expand All @@ -353,6 +362,7 @@ def unwrap(self):
def wrap(self, element):
"""Wrap selection in an element.

>>> from genshi.input import HTML
>>> html = HTML('<html><head><title>Some Title</title></head>'
... '<body>Some <em>body</em> text.</body></html>',
... encoding='utf-8')
Expand All @@ -370,6 +380,7 @@ def wrap(self, element):
def replace(self, content):
"""Replace selection with content.

>>> from genshi.input import HTML
>>> html = HTML('<html><head><title>Some Title</title></head>'
... '<body>Some <em>body</em> text.</body></html>',
... encoding='utf-8')
Expand All @@ -389,6 +400,7 @@ def before(self, content):
In this example we insert the word 'emphasised' before the <em> opening
tag:

>>> from genshi.input import HTML
>>> html = HTML('<html><head><title>Some Title</title></head>'
... '<body>Some <em>body</em> text.</body></html>',
... encoding='utf-8')
Expand All @@ -407,6 +419,7 @@ def after(self, content):

Here, we insert some text after the </em> closing tag:

>>> from genshi.input import HTML
>>> html = HTML('<html><head><title>Some Title</title></head>'
... '<body>Some <em>body</em> text.</body></html>',
... encoding='utf-8')
Expand All @@ -425,6 +438,7 @@ def prepend(self, content):

Inserting some new text at the start of the <body>:

>>> from genshi.input import HTML
>>> html = HTML('<html><head><title>Some Title</title></head>'
... '<body>Some <em>body</em> text.</body></html>',
... encoding='utf-8')
Expand All @@ -441,6 +455,7 @@ def prepend(self, content):
def append(self, content):
"""Insert content before the END event of the selection.

>>> from genshi.input import HTML
>>> html = HTML('<html><head><title>Some Title</title></head>'
... '<body>Some <em>body</em> text.</body></html>',
... encoding='utf-8')
Expand All @@ -462,6 +477,7 @@ def attr(self, name, value):
If `value` evaulates to `None` the attribute will be deleted from the
element:

>>> from genshi.input import HTML
>>> html = HTML('<html><head><title>Some Title</title></head>'
... '<body>Some <em class="before">body</em> <em>text</em>.</body>'
... '</html>', encoding='utf-8')
Expand Down Expand Up @@ -505,6 +521,7 @@ def copy(self, buffer, accumulate=False):
be appended to the buffer rather than replacing it.

>>> from genshi.builder import tag
>>> from genshi.input import HTML
>>> buffer = StreamBuffer()
>>> html = HTML('<html><head><title>Some Title</title></head>'
... '<body>Some <em>body</em> text.</body></html>',
Expand Down Expand Up @@ -560,6 +577,7 @@ def cut(self, buffer, accumulate=False):
"""Copy selection into buffer and remove the selection from the stream.

>>> from genshi.builder import tag
>>> from genshi.input import HTML
>>> buffer = StreamBuffer()
>>> html = HTML('<html><head><title>Some Title</title></head>'
... '<body>Some <em>body</em> text.</body></html>',
Expand Down Expand Up @@ -593,6 +611,7 @@ def buffer(self):
For example, to move all <note> elements inside a <notes> tag at the
top of the document:

>>> from genshi.input import HTML
>>> doc = HTML('<doc><notes></notes><body>Some <note>one</note> '
... 'text <note>two</note>.</body></doc>',
... encoding='utf-8')
Expand All @@ -612,6 +631,7 @@ def filter(self, filter):
once for each contiguous block of marked events.

>>> from genshi.filters.html import HTMLSanitizer
>>> from genshi.input import HTML
>>> html = HTML('<html><body>Some text<script>alert(document.cookie)'
... '</script> and some more text</body></html>',
... encoding='utf-8')
Expand All @@ -628,6 +648,7 @@ def map(self, function, kind):
the selection.

>>> import six
>>> from genshi.input import HTML
>>> html = HTML('<html><head><title>Some Title</title></head>'
... '<body>Some <em>body</em> text.</body></html>',
... encoding='utf-8')
Expand All @@ -646,19 +667,14 @@ def substitute(self, pattern, replace, count=1):

Refer to the documentation for ``re.sub()`` for details.

>>> from genshi.input import HTML
>>> html = HTML('<html><body>Some text, some more text and '
... '<b>some bold text</b>\\n'
... '<i>some italicised text</i></body></html>',
... encoding='utf-8')
>>> print(html | Transformer('body/b').substitute('(?i)some', 'SOME'))
<html><body>Some text, some more text and <b>SOME bold text</b>
<i>some italicised text</i></body></html>
>>> tags = tag.html(tag.body('Some text, some more text and\\n',
... Markup('<b>some bold text</b>')))
>>> print(tags.generate() | Transformer('body').substitute(
... '(?i)some', 'SOME'))
<html><body>SOME text, some more text and
<b>SOME bold text</b></body></html>

:param pattern: A regular expression object or string.
:param replace: Replacement pattern.
Expand All @@ -670,6 +686,7 @@ def substitute(self, pattern, replace, count=1):
def rename(self, name):
"""Rename matching elements.

>>> from genshi.input import HTML
>>> html = HTML('<html><body>Some text, some more text and '
... '<b>some bold text</b></body></html>',
... encoding='utf-8')
Expand All @@ -681,6 +698,7 @@ def rename(self, name):
def trace(self, prefix='', fileobj=None):
"""Print events as they pass through the transform.

>>> from genshi.input import HTML
>>> html = HTML('<body>Some <em>test</em> text</body>', encoding='utf-8')
>>> print(html | Transformer('em').trace())
(None, ('START', (QName('body'), Attrs()), (None, 1, 0)))
Expand Down Expand Up @@ -1047,6 +1065,7 @@ class InjectorTransformation(object):
... yield event
... for event in stream:
... yield event
>>> from genshi.input import HTML
>>> html = HTML('<body>Some <em>test</em> text</body>', encoding='utf-8')
>>> print(html | Transformer('.//em').apply(Top('Prefix ')))
Prefix <body>Some <em>test</em> text</body>
Expand Down
20 changes: 10 additions & 10 deletions genshi/template/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,17 @@
import unittest

def suite():
from genshi.template.tests import base, directives, eval, interpolation, \
loader, markup, plugin, text
from genshi.template.tests import test_base, test_directives, test_eval, test_interpolation, \
test_loader, test_markup, test_plugin, test_text
suite = unittest.TestSuite()
suite.addTest(base.suite())
suite.addTest(directives.suite())
suite.addTest(eval.suite())
suite.addTest(interpolation.suite())
suite.addTest(loader.suite())
suite.addTest(markup.suite())
suite.addTest(plugin.suite())
suite.addTest(text.suite())
suite.addTest(test_base.suite())
suite.addTest(test_directives.suite())
suite.addTest(test_eval.suite())
suite.addTest(test_interpolation.suite())
suite.addTest(test_loader.suite())
suite.addTest(test_markup.suite())
suite.addTest(test_plugin.suite())
suite.addTest(test_text.suite())
return suite

if __name__ == '__main__':
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -178,18 +178,18 @@ def test_binop_not_contains(self):
'y': (1, 2, 3)}))

def test_binop_is(self):
self.assertEqual(True, Expression("1 is 1").evaluate({}))
self.assertEqual(True, Expression("x is y").evaluate({'x': 1, 'y': 1}))
self.assertEqual(False, Expression("1 is 2").evaluate({}))
self.assertEqual(False, Expression("x is y").evaluate({'x': 1, 'y': 2}))
self.assertEqual(True, Expression("True is True").evaluate({}))
self.assertEqual(True, Expression("x is y").evaluate({'x': True, 'y': True}))
self.assertEqual(False, Expression("True is False").evaluate({}))
self.assertEqual(False, Expression("x is y").evaluate({'x': True, 'y': False}))

def test_binop_is_not(self):
self.assertEqual(True, Expression("1 is not 2").evaluate({}))
self.assertEqual(True, Expression("x is not y").evaluate({'x': 1,
'y': 2}))
self.assertEqual(False, Expression("1 is not 1").evaluate({}))
self.assertEqual(False, Expression("x is not y").evaluate({'x': 1,
'y': 1}))
self.assertEqual(True, Expression("True is not False").evaluate({}))
self.assertEqual(True, Expression("x is not y").evaluate({'x': True,
'y': False}))
self.assertEqual(False, Expression("True is not True").evaluate({}))
self.assertEqual(False, Expression("x is not y").evaluate({'x': True,
'y': True}))

def test_boolop_and(self):
self.assertEqual(False, Expression("True and False").evaluate({}))
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading