mirror of
https://github.com/openembedded/meta-openembedded.git
synced 2025-07-19 15:29:08 +02:00

This helps compiling with latest setuptools 0.58+ Signed-off-by: Khem Raj <raj.khem@gmail.com> Signed-off-by: Trevor Gamblin <trevor.gamblin@windriver.com>
4151 lines
143 KiB
Diff
4151 lines
143 KiB
Diff
From 8bb1ac2d81f697598a766714f2c439d78c85d71e Mon Sep 17 00:00:00 2001
|
|
From: Stephen L Arnold <nerdboy@gentoo.org>
|
|
Date: Sat, 7 Nov 2020 12:38:33 -0800
|
|
Subject: [PATCH] Modernize python versions (remove py2x) and fix tests, update
|
|
spec
|
|
|
|
* migrate to github actions for CI, add conda recipe/workflow
|
|
* fix document processing, update pandoc args and history
|
|
* convert doctests and modules to py3
|
|
* convert packaging/setup.py to pep517, keep doc processing
|
|
* cleanup tox cfg, add coverage, readme status
|
|
* add pep8speaks cfg, cleanup warnings, use correct env
|
|
* update setup_description.rst for packaging
|
|
* set version for test release => 0.6.0 and deploy
|
|
|
|
Upstream-Status: Backport [https://github.com/defunkt/pystache/pull/214]
|
|
Signed-off-by: Stephen L Arnold <nerdboy@gentoo.org>
|
|
---
|
|
.coveragerc | 38 +++
|
|
.gitchangelog.rc | 295 +++++++++++++++++++++
|
|
.github/workflows/ci.yml | 73 ++++++
|
|
.github/workflows/conda.yml | 55 ++++
|
|
.github/workflows/release.yml | 94 +++++++
|
|
.github/workflows/wheels.yml | 82 ++++++
|
|
.pep8speaks.yml | 15 ++
|
|
HISTORY.md | 37 ++-
|
|
MANIFEST.in | 8 +-
|
|
README.md | 141 +++++-----
|
|
TODO.md | 5 +-
|
|
conda/meta.yaml | 50 ++++
|
|
pyproject.toml | 3 +
|
|
pystache/__init__.py | 2 +-
|
|
pystache/commands/render.py | 4 +-
|
|
pystache/common.py | 13 +-
|
|
pystache/defaults.py | 2 +-
|
|
pystache/loader.py | 14 +-
|
|
pystache/parsed.py | 6 +-
|
|
pystache/parser.py | 20 +-
|
|
pystache/renderengine.py | 2 +-
|
|
pystache/renderer.py | 22 +-
|
|
pystache/specloader.py | 2 +-
|
|
pystache/tests/benchmark.py | 15 +-
|
|
pystache/tests/common.py | 10 +-
|
|
pystache/tests/examples/unicode_output.py | 2 +-
|
|
pystache/tests/main.py | 28 +-
|
|
pystache/tests/spectesting.py | 16 +-
|
|
pystache/tests/test___init__.py | 4 +-
|
|
pystache/tests/test_commands.py | 2 +-
|
|
pystache/tests/test_defaults.py | 18 +-
|
|
pystache/tests/test_examples.py | 40 +--
|
|
pystache/tests/test_loader.py | 46 ++--
|
|
pystache/tests/test_pystache.py | 6 +-
|
|
pystache/tests/test_renderengine.py | 148 +++++------
|
|
pystache/tests/test_renderer.py | 86 +++----
|
|
pystache/tests/test_simple.py | 20 +-
|
|
pystache/tests/test_specloader.py | 60 ++---
|
|
setup.cfg | 74 +++++-
|
|
setup.py | 134 +---------
|
|
setup_description.rst | 297 +++++++++++++---------
|
|
tox.ini | 118 +++++++--
|
|
travis.yml_disabled | 52 ++++
|
|
43 files changed, 1487 insertions(+), 672 deletions(-)
|
|
create mode 100644 .coveragerc
|
|
create mode 100644 .gitchangelog.rc
|
|
create mode 100644 .github/workflows/ci.yml
|
|
create mode 100644 .github/workflows/conda.yml
|
|
create mode 100644 .github/workflows/release.yml
|
|
create mode 100644 .github/workflows/wheels.yml
|
|
create mode 100644 .pep8speaks.yml
|
|
create mode 100644 conda/meta.yaml
|
|
create mode 100644 pyproject.toml
|
|
create mode 100644 travis.yml_disabled
|
|
|
|
diff --git a/.coveragerc b/.coveragerc
|
|
new file mode 100644
|
|
index 0000000..9a336dd
|
|
--- /dev/null
|
|
+++ b/.coveragerc
|
|
@@ -0,0 +1,38 @@
|
|
+# .coveragerc to control coverage.py
|
|
+[run]
|
|
+branch = True
|
|
+
|
|
+source = pystache
|
|
+
|
|
+omit =
|
|
+ .tox/*
|
|
+ setup.py
|
|
+ pystache/tests/*
|
|
+
|
|
+#plugins =
|
|
+# coverage_python_version
|
|
+
|
|
+[report]
|
|
+# must set this to True to see missing
|
|
+#show_missing = True
|
|
+
|
|
+# Regexes for lines to exclude from consideration
|
|
+exclude_lines =
|
|
+ # Have to re-enable the standard pragma
|
|
+ pragma: no cover
|
|
+
|
|
+ # Don't complain about missing debug-only code:
|
|
+ def __repr__
|
|
+ if self\.debug
|
|
+
|
|
+ # Don't complain if tests don't hit defensive assertion code:
|
|
+ raise AssertionError
|
|
+ raise NotImplementedError
|
|
+
|
|
+ # Don't complain if non-runnable code isn't run:
|
|
+ if 0:
|
|
+
|
|
+ignore_errors = True
|
|
+
|
|
+[html]
|
|
+directory = cover
|
|
diff --git a/.gitchangelog.rc b/.gitchangelog.rc
|
|
new file mode 100644
|
|
index 0000000..5cf63a0
|
|
--- /dev/null
|
|
+++ b/.gitchangelog.rc
|
|
@@ -0,0 +1,295 @@
|
|
+# -*- coding: utf-8; mode: python -*-
|
|
+##
|
|
+## Format
|
|
+##
|
|
+## ACTION: [AUDIENCE:] COMMIT_MSG [!TAG ...]
|
|
+##
|
|
+## Description
|
|
+##
|
|
+## ACTION is one of 'chg', 'fix', 'new'
|
|
+##
|
|
+## Is WHAT the change is about.
|
|
+##
|
|
+## 'chg' is for refactor, small improvement, cosmetic changes...
|
|
+## 'fix' is for bug fixes
|
|
+## 'new' is for new features, big improvement
|
|
+##
|
|
+## AUDIENCE is optional and one of 'dev', 'usr', 'pkg', 'test', 'doc'
|
|
+##
|
|
+## Is WHO is concerned by the change.
|
|
+##
|
|
+## 'dev' is for developpers (API changes, refactors...)
|
|
+## 'usr' is for final users (UI changes)
|
|
+## 'pkg' is for packagers (packaging changes)
|
|
+## 'test' is for testers (test only related changes)
|
|
+## 'doc' is for doc guys (doc only changes)
|
|
+##
|
|
+## COMMIT_MSG is ... well ... the commit message itself.
|
|
+##
|
|
+## TAGs are additionnal adjective as 'refactor' 'minor' 'cosmetic'
|
|
+##
|
|
+## They are preceded with a '!' or a '@' (prefer the former, as the
|
|
+## latter is wrongly interpreted in github.) Commonly used tags are:
|
|
+##
|
|
+## 'refactor' is obviously for refactoring code only
|
|
+## 'minor' is for a very meaningless change (a typo, adding a comment)
|
|
+## 'cosmetic' is for cosmetic driven change (re-indentation, 80-col...)
|
|
+## 'wip' is for partial functionality but complete subfunctionality.
|
|
+##
|
|
+## Example:
|
|
+##
|
|
+## new: usr: support of bazaar implemented
|
|
+## chg: re-indentend some lines !cosmetic
|
|
+## new: dev: updated code to be compatible with last version of killer lib.
|
|
+## fix: pkg: updated year of licence coverage.
|
|
+## new: test: added a bunch of test around user usability of feature X.
|
|
+## fix: typo in spelling my name in comment. !minor
|
|
+##
|
|
+## Please note that multi-line commit message are supported, and only the
|
|
+## first line will be considered as the "summary" of the commit message. So
|
|
+## tags, and other rules only applies to the summary. The body of the commit
|
|
+## message will be displayed in the changelog without reformatting.
|
|
+
|
|
+
|
|
+##
|
|
+## ``ignore_regexps`` is a line of regexps
|
|
+##
|
|
+## Any commit having its full commit message matching any regexp listed here
|
|
+## will be ignored and won't be reported in the changelog.
|
|
+##
|
|
+ignore_regexps = [
|
|
+ r'@minor', r'!minor',
|
|
+ r'@cosmetic', r'!cosmetic',
|
|
+ r'@refactor', r'!refactor',
|
|
+ r'@wip', r'!wip',
|
|
+ r'^([cC]hg|[fF]ix|[nN]ew)\s*:\s*[p|P]kg:',
|
|
+ r'^([cC]hg|[fF]ix|[nN]ew)\s*:\s*[d|D]ev:',
|
|
+ r'^(.{3,3}\s*:)?\s*[fF]irst commit.?\s*$',
|
|
+ r'^$', ## ignore commits with empty messages
|
|
+]
|
|
+
|
|
+
|
|
+## ``section_regexps`` is a list of 2-tuples associating a string label and a
|
|
+## list of regexp
|
|
+##
|
|
+## Commit messages will be classified in sections thanks to this. Section
|
|
+## titles are the label, and a commit is classified under this section if any
|
|
+## of the regexps associated is matching.
|
|
+##
|
|
+## Please note that ``section_regexps`` will only classify commits and won't
|
|
+## make any changes to the contents. So you'll probably want to go check
|
|
+## ``subject_process`` (or ``body_process``) to do some changes to the subject,
|
|
+## whenever you are tweaking this variable.
|
|
+##
|
|
+section_regexps = [
|
|
+ ('New', [
|
|
+ r'^[nN]ew\s*:\s*((dev|use?r|pkg|test|doc)\s*:\s*)?([^\n]*)$',
|
|
+ ]),
|
|
+ ('Features', [
|
|
+ r'^([nN]ew|[fF]eat)\s*:\s*((dev|use?r|pkg|test|doc)\s*:\s*)?([^\n]*)$',
|
|
+ ]),
|
|
+ ('Changes', [
|
|
+ r'^[cC]hg\s*:\s*((dev|use?r|pkg|test|doc)\s*:\s*)?([^\n]*)$',
|
|
+ ]),
|
|
+ ('Fixes', [
|
|
+ r'^[fF]ix\s*:\s*((dev|use?r|pkg|test|doc)\s*:\s*)?([^\n]*)$',
|
|
+ ]),
|
|
+
|
|
+ ('Other', None ## Match all lines
|
|
+ ),
|
|
+]
|
|
+
|
|
+
|
|
+## ``body_process`` is a callable
|
|
+##
|
|
+## This callable will be given the original body and result will
|
|
+## be used in the changelog.
|
|
+##
|
|
+## Available constructs are:
|
|
+##
|
|
+## - any python callable that take one txt argument and return txt argument.
|
|
+##
|
|
+## - ReSub(pattern, replacement): will apply regexp substitution.
|
|
+##
|
|
+## - Indent(chars=" "): will indent the text with the prefix
|
|
+## Please remember that template engines gets also to modify the text and
|
|
+## will usually indent themselves the text if needed.
|
|
+##
|
|
+## - Wrap(regexp=r"\n\n"): re-wrap text in separate paragraph to fill 80-Columns
|
|
+##
|
|
+## - noop: do nothing
|
|
+##
|
|
+## - ucfirst: ensure the first letter is uppercase.
|
|
+## (usually used in the ``subject_process`` pipeline)
|
|
+##
|
|
+## - final_dot: ensure text finishes with a dot
|
|
+## (usually used in the ``subject_process`` pipeline)
|
|
+##
|
|
+## - strip: remove any spaces before or after the content of the string
|
|
+##
|
|
+## - SetIfEmpty(msg="No commit message."): will set the text to
|
|
+## whatever given ``msg`` if the current text is empty.
|
|
+##
|
|
+## Additionally, you can `pipe` the provided filters, for instance:
|
|
+#body_process = Wrap(regexp=r'\n(?=\w+\s*:)') | Indent(chars=" ")
|
|
+#body_process = Wrap(regexp=r'\n(?=\w+\s*:)')
|
|
+#body_process = noop
|
|
+body_process = ReSub(r'((^|\n)[A-Z]\w+(-\w+)*: .*(\n\s+.*)*)+$', r'') | strip
|
|
+
|
|
+
|
|
+## ``subject_process`` is a callable
|
|
+##
|
|
+## This callable will be given the original subject and result will
|
|
+## be used in the changelog.
|
|
+##
|
|
+## Available constructs are those listed in ``body_process`` doc.
|
|
+subject_process = (strip |
|
|
+ ReSub(r'^([cC]hg|[fF]ix|[nN]ew)\s*:\s*((dev|use?r|pkg|test|doc)\s*:\s*)?([^\n@]*)(@[a-z]+\s+)*$', r'\4') |
|
|
+ SetIfEmpty("No commit message.") | ucfirst | final_dot)
|
|
+
|
|
+
|
|
+## ``tag_filter_regexp`` is a regexp
|
|
+##
|
|
+## Tags that will be used for the changelog must match this regexp.
|
|
+##
|
|
+#tag_filter_regexp = r'^v?[0-9]+\.[0-9]+(\.[0-9]+)?$'
|
|
+tag_filter_regexp = r'^[0-9]+\.[0-9]+(\.[0-9]+)?$'
|
|
+
|
|
+
|
|
+## ``unreleased_version_label`` is a string or a callable that outputs a string
|
|
+##
|
|
+## This label will be used as the changelog Title of the last set of changes
|
|
+## between last valid tag and HEAD if any.
|
|
+unreleased_version_label = "(unreleased)"
|
|
+#unreleased_version_label = lambda: swrap(
|
|
+# ["git", "describe", "--tags"],
|
|
+#shell=False)
|
|
+
|
|
+
|
|
+## ``output_engine`` is a callable
|
|
+##
|
|
+## This will change the output format of the generated changelog file
|
|
+##
|
|
+## Available choices are:
|
|
+##
|
|
+## - rest_py
|
|
+##
|
|
+## Legacy pure python engine, outputs ReSTructured text.
|
|
+## This is the default.
|
|
+##
|
|
+## - mustache(<template_name>)
|
|
+##
|
|
+## Template name could be any of the available templates in
|
|
+## ``templates/mustache/*.tpl``.
|
|
+## Requires python package ``pystache``.
|
|
+## Examples:
|
|
+## - mustache("markdown")
|
|
+## - mustache("restructuredtext")
|
|
+##
|
|
+## - makotemplate(<template_name>)
|
|
+##
|
|
+## Template name could be any of the available templates in
|
|
+## ``templates/mako/*.tpl``.
|
|
+## Requires python package ``mako``.
|
|
+## Examples:
|
|
+## - makotemplate("restructuredtext")
|
|
+##
|
|
+#output_engine = rest_py
|
|
+#output_engine = mustache("restructuredtext")
|
|
+output_engine = mustache("markdown")
|
|
+#output_engine = makotemplate("restructuredtext")
|
|
+
|
|
+
|
|
+## ``include_merge`` is a boolean
|
|
+##
|
|
+## This option tells git-log whether to include merge commits in the log.
|
|
+## The default is to include them.
|
|
+include_merge = True
|
|
+
|
|
+
|
|
+## ``log_encoding`` is a string identifier
|
|
+##
|
|
+## This option tells gitchangelog what encoding is outputed by ``git log``.
|
|
+## The default is to be clever about it: it checks ``git config`` for
|
|
+## ``i18n.logOutputEncoding``, and if not found will default to git's own
|
|
+## default: ``utf-8``.
|
|
+#log_encoding = 'utf-8'
|
|
+
|
|
+
|
|
+## ``publish`` is a callable
|
|
+##
|
|
+## Sets what ``gitchangelog`` should do with the output generated by
|
|
+## the output engine. ``publish`` is a callable taking one argument
|
|
+## that is an interator on lines from the output engine.
|
|
+##
|
|
+## Some helper callable are provided:
|
|
+##
|
|
+## Available choices are:
|
|
+##
|
|
+## - stdout
|
|
+##
|
|
+## Outputs directly to standard output
|
|
+## (This is the default)
|
|
+##
|
|
+## - FileInsertAtFirstRegexMatch(file, pattern, idx=lamda m: m.start(), flags)
|
|
+##
|
|
+## Creates a callable that will parse given file for the given
|
|
+## regex pattern and will insert the output in the file.
|
|
+## ``idx`` is a callable that receive the matching object and
|
|
+## must return a integer index point where to insert the
|
|
+## the output in the file. Default is to return the position of
|
|
+## the start of the matched string.
|
|
+##
|
|
+## - FileRegexSubst(file, pattern, replace, flags)
|
|
+##
|
|
+## Apply a replace inplace in the given file. Your regex pattern must
|
|
+## take care of everything and might be more complex. Check the README
|
|
+## for a complete copy-pastable example.
|
|
+##
|
|
+# publish = FileInsertIntoFirstRegexMatch(
|
|
+# "CHANGELOG.rst",
|
|
+# r'/(?P<rev>[0-9]+\.[0-9]+(\.[0-9]+)?)\s+\([0-9]+-[0-9]{2}-[0-9]{2}\)\n--+\n/',
|
|
+# idx=lambda m: m.start(1)
|
|
+# )
|
|
+#publish = stdout
|
|
+
|
|
+
|
|
+## ``revs`` is a list of callable or a list of string
|
|
+##
|
|
+## callable will be called to resolve as strings and allow dynamical
|
|
+## computation of these. The result will be used as revisions for
|
|
+## gitchangelog (as if directly stated on the command line). This allows
|
|
+## to filter exaclty which commits will be read by gitchangelog.
|
|
+##
|
|
+## To get a full documentation on the format of these strings, please
|
|
+## refer to the ``git rev-list`` arguments. There are many examples.
|
|
+##
|
|
+## Using callables is especially useful, for instance, if you
|
|
+## are using gitchangelog to generate incrementally your changelog.
|
|
+##
|
|
+## Some helpers are provided, you can use them::
|
|
+##
|
|
+## - FileFirstRegexMatch(file, pattern): will return a callable that will
|
|
+## return the first string match for the given pattern in the given file.
|
|
+## If you use named sub-patterns in your regex pattern, it'll output only
|
|
+## the string matching the regex pattern named "rev".
|
|
+##
|
|
+## - Caret(rev): will return the rev prefixed by a "^", which is a
|
|
+## way to remove the given revision and all its ancestor.
|
|
+##
|
|
+## Please note that if you provide a rev-list on the command line, it'll
|
|
+## replace this value (which will then be ignored).
|
|
+##
|
|
+## If empty, then ``gitchangelog`` will act as it had to generate a full
|
|
+## changelog.
|
|
+##
|
|
+## The default is to use all commits to make the changelog.
|
|
+#revs = ["^1.0.3", ]
|
|
+#revs = [
|
|
+# Caret(
|
|
+# FileFirstRegexMatch(
|
|
+# "CHANGELOG.rst",
|
|
+# r"(?P<rev>[0-9]+\.[0-9]+(\.[0-9]+)?)\s+\([0-9]+-[0-9]{2}-[0-9]{2}\)\n--+\n")),
|
|
+# "HEAD"
|
|
+#]
|
|
+revs = []
|
|
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
|
|
new file mode 100644
|
|
index 0000000..356dd2c
|
|
--- /dev/null
|
|
+++ b/.github/workflows/ci.yml
|
|
@@ -0,0 +1,73 @@
|
|
+# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
|
|
+# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
|
|
+
|
|
+name: ci
|
|
+
|
|
+on:
|
|
+ push:
|
|
+ branches: [ master ]
|
|
+ pull_request:
|
|
+ branches: [ master ]
|
|
+
|
|
+jobs:
|
|
+ build:
|
|
+
|
|
+ runs-on: ${{ matrix.os }}
|
|
+ defaults:
|
|
+ run:
|
|
+ shell: bash
|
|
+ env:
|
|
+ OS: ${{ matrix.os }}
|
|
+ PYTHON: ${{ matrix.python-version }}
|
|
+ PYTHONIOENCODING: utf-8
|
|
+ PIP_DOWNLOAD_CACHE: ${{ github.workspace }}/../.pip_download_cache
|
|
+ strategy:
|
|
+ fail-fast: false
|
|
+ matrix:
|
|
+ os: [ubuntu-20.04, macos-latest, windows-latest]
|
|
+ python-version: [3.6, 3.7, 3.8, 3.9]
|
|
+ steps:
|
|
+ - name: Set git crlf/eol
|
|
+ run: |
|
|
+ git config --global core.autocrlf false
|
|
+ git config --global core.eol lf
|
|
+
|
|
+ - uses: actions/checkout@v2
|
|
+ with:
|
|
+ submodules: True
|
|
+
|
|
+ - name: Set up Python ${{ matrix.python-version }}
|
|
+ uses: actions/setup-python@v2
|
|
+ with:
|
|
+ python-version: ${{ matrix.python-version }}
|
|
+
|
|
+ - name: Install dependencies
|
|
+ run: |
|
|
+ python -m pip install --upgrade pip
|
|
+ pip install tox tox-gh-actions
|
|
+
|
|
+ - name: Run tests with coverage
|
|
+ run: |
|
|
+ tox
|
|
+ env:
|
|
+ PLATFORM: ${{ matrix.os }}
|
|
+
|
|
+ - name: Upload coverage to Codecov
|
|
+ uses: codecov/codecov-action@v1
|
|
+ with:
|
|
+ env_vars: OS,PYTHON
|
|
+
|
|
+ - name: Test with specs and pystache-test
|
|
+ run: |
|
|
+ tox -e setup . ext/spec/specs
|
|
+
|
|
+ - name: Check pkg builds
|
|
+ run: |
|
|
+ tox -e deploy
|
|
+
|
|
+ - name: Check docs
|
|
+ if: runner.os == 'Linux'
|
|
+ run: |
|
|
+ sudo apt-get -qq update
|
|
+ sudo apt-get install -y pandoc
|
|
+ tox -e docs
|
|
diff --git a/.github/workflows/conda.yml b/.github/workflows/conda.yml
|
|
new file mode 100644
|
|
index 0000000..261f9ad
|
|
--- /dev/null
|
|
+++ b/.github/workflows/conda.yml
|
|
@@ -0,0 +1,55 @@
|
|
+name: Conda
|
|
+
|
|
+on:
|
|
+ workflow_dispatch:
|
|
+ pull_request:
|
|
+ push:
|
|
+ branches:
|
|
+ - master
|
|
+
|
|
+jobs:
|
|
+ build:
|
|
+ strategy:
|
|
+ fail-fast: false
|
|
+ matrix:
|
|
+ platform: [ubuntu-18.04, windows-latest, macos-latest]
|
|
+ python-version: [3.6, 3.7, 3.8, 3.9]
|
|
+
|
|
+ runs-on: ${{ matrix.platform }}
|
|
+
|
|
+ # The setup-miniconda action needs this to activate miniconda
|
|
+ defaults:
|
|
+ run:
|
|
+ shell: "bash -l {0}"
|
|
+
|
|
+ steps:
|
|
+ - uses: actions/checkout@v2
|
|
+ with:
|
|
+ fetch-depth: 0
|
|
+
|
|
+ - name: Cache conda
|
|
+ uses: actions/cache@v1
|
|
+ with:
|
|
+ path: ~/conda_pkgs_dir
|
|
+ key: ${{matrix.os}}-conda-pkgs-${{hashFiles('**/conda/meta.yaml')}}
|
|
+
|
|
+ - name: Get conda
|
|
+ uses: conda-incubator/setup-miniconda@v2
|
|
+ with:
|
|
+ python-version: ${{ matrix.python-version }}
|
|
+ channels: conda-forge
|
|
+ channel-priority: strict
|
|
+ use-only-tar-bz2: true
|
|
+ auto-activate-base: true
|
|
+
|
|
+ - name: Prepare
|
|
+ run: conda install conda-build conda-verify
|
|
+
|
|
+ - name: Build
|
|
+ run: conda build conda
|
|
+
|
|
+ - name: Install
|
|
+ run: conda install -c ${CONDA_PREFIX}/conda-bld/ pystache
|
|
+
|
|
+ - name: Test
|
|
+ run: python test_pystache.py
|
|
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
|
|
new file mode 100644
|
|
index 0000000..f33c4b5
|
|
--- /dev/null
|
|
+++ b/.github/workflows/release.yml
|
|
@@ -0,0 +1,94 @@
|
|
+name: Release
|
|
+
|
|
+on:
|
|
+ push:
|
|
+ # release on tag push
|
|
+ tags:
|
|
+ - '*'
|
|
+
|
|
+jobs:
|
|
+ wheels:
|
|
+
|
|
+ runs-on: ${{ matrix.os }}
|
|
+ defaults:
|
|
+ run:
|
|
+ shell: bash
|
|
+ env:
|
|
+ PYTHONIOENCODING: utf-8
|
|
+ strategy:
|
|
+ fail-fast: false
|
|
+ matrix:
|
|
+ os: [ubuntu-18.04, macos-latest, windows-latest]
|
|
+ python-version: [3.6, 3.7, 3.8, 3.9]
|
|
+ exclude:
|
|
+ - os: windows-latest
|
|
+ python-version: 2.7
|
|
+
|
|
+ steps:
|
|
+ - name: Set git crlf/eol
|
|
+ run: |
|
|
+ git config --global core.autocrlf false
|
|
+ git config --global core.eol lf
|
|
+
|
|
+ - uses: actions/checkout@v2
|
|
+ with:
|
|
+ fetch-depth: 0
|
|
+
|
|
+ - name: Set up Python ${{ matrix.python-version }}
|
|
+ uses: actions/setup-python@v2
|
|
+ with:
|
|
+ python-version: ${{ matrix.python-version }}
|
|
+
|
|
+ - name: Install dependencies
|
|
+ run: |
|
|
+ python -m pip install --upgrade pip wheel
|
|
+ pip install tox tox-gh-actions
|
|
+
|
|
+ - name: Build dist pkgs
|
|
+ run: |
|
|
+ tox -e deploy
|
|
+
|
|
+ - name: Upload artifacts
|
|
+ if: matrix.python-version == 3.7 && runner.os == 'Linux'
|
|
+ uses: actions/upload-artifact@v2
|
|
+ with:
|
|
+ name: wheels
|
|
+ path: ./dist/*.whl
|
|
+
|
|
+ create_release:
|
|
+ name: Create Release
|
|
+ needs: [wheels]
|
|
+ runs-on: ubuntu-18.04
|
|
+
|
|
+ steps:
|
|
+ - name: Get version
|
|
+ id: get_version
|
|
+ run: |
|
|
+ echo "VERSION=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_ENV
|
|
+ echo ${{ env.VERSION }}
|
|
+
|
|
+ - uses: actions/checkout@v2
|
|
+ with:
|
|
+ fetch-depth: 0
|
|
+
|
|
+ # download all artifacts to project dir
|
|
+ - uses: actions/download-artifact@v2
|
|
+
|
|
+ - name: Generate changes file
|
|
+ uses: sarnold/gitchangelog-action@master
|
|
+ with:
|
|
+ github_token: ${{ secrets.GITHUB_TOKEN}}
|
|
+
|
|
+ - name: Create release
|
|
+ id: create_release
|
|
+ uses: softprops/action-gh-release@v1
|
|
+ env:
|
|
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
+ with:
|
|
+ tag_name: ${{ env.VERSION }}
|
|
+ name: Release v${{ env.VERSION }}
|
|
+ body_path: CHANGES.md
|
|
+ draft: false
|
|
+ prerelease: false
|
|
+ files: |
|
|
+ wheels/pystache*.whl
|
|
diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml
|
|
new file mode 100644
|
|
index 0000000..58f0c5e
|
|
--- /dev/null
|
|
+++ b/.github/workflows/wheels.yml
|
|
@@ -0,0 +1,82 @@
|
|
+name: Wheels
|
|
+
|
|
+on:
|
|
+ workflow_dispatch:
|
|
+ pull_request:
|
|
+ #push:
|
|
+ #branches: [ master ]
|
|
+
|
|
+jobs:
|
|
+ build:
|
|
+
|
|
+ runs-on: ${{ matrix.os }}
|
|
+ defaults:
|
|
+ run:
|
|
+ shell: bash
|
|
+ env:
|
|
+ PYTHONIOENCODING: utf-8
|
|
+ strategy:
|
|
+ fail-fast: false
|
|
+ matrix:
|
|
+ os: [ubuntu-18.04, macos-latest, windows-latest]
|
|
+ python-version: [3.6, 3.7, 3.8, 3.9]
|
|
+
|
|
+ steps:
|
|
+ - name: Set git crlf/eol
|
|
+ run: |
|
|
+ git config --global core.autocrlf false
|
|
+ git config --global core.eol lf
|
|
+
|
|
+ - uses: actions/checkout@v2
|
|
+ with:
|
|
+ fetch-depth: 0
|
|
+
|
|
+ - name: Set up Python ${{ matrix.python-version }}
|
|
+ uses: actions/setup-python@v2
|
|
+ with:
|
|
+ python-version: ${{ matrix.python-version }}
|
|
+
|
|
+ - name: Install dependencies
|
|
+ run: |
|
|
+ python -m pip install --upgrade pip wheel
|
|
+ pip install tox tox-gh-actions
|
|
+
|
|
+ - name: Build dist pkgs
|
|
+ run: |
|
|
+ tox -e deploy
|
|
+
|
|
+ - name: Upload artifacts
|
|
+ if: matrix.python-version == 3.7 && runner.os == 'Linux'
|
|
+ uses: actions/upload-artifact@v2
|
|
+ with:
|
|
+ name: wheels
|
|
+ path: ./dist/*.whl
|
|
+
|
|
+ check_artifact:
|
|
+ name: Check wheel artifact
|
|
+ needs: [build]
|
|
+ runs-on: ${{ matrix.os }}
|
|
+ defaults:
|
|
+ run:
|
|
+ shell: bash
|
|
+ env:
|
|
+ PYTHONIOENCODING: utf-8
|
|
+ strategy:
|
|
+ fail-fast: false
|
|
+ matrix:
|
|
+ os: [ubuntu-18.04, macos-latest, windows-latest]
|
|
+ python-version: [3.6, 3.8, 3.9]
|
|
+
|
|
+ steps:
|
|
+ - name: Set up Python ${{ matrix.python-version }}
|
|
+ uses: actions/setup-python@v2
|
|
+ with:
|
|
+ python-version: ${{ matrix.python-version }}
|
|
+
|
|
+ # download all artifacts to project dir
|
|
+ - uses: actions/download-artifact@v2
|
|
+
|
|
+ - name: Check wheel install
|
|
+ run: |
|
|
+ bash -c 'export WHL=$(ls wheels/*.whl); python -m pip install $WHL'
|
|
+ pystache-test
|
|
diff --git a/.pep8speaks.yml b/.pep8speaks.yml
|
|
new file mode 100644
|
|
index 0000000..e841b66
|
|
--- /dev/null
|
|
+++ b/.pep8speaks.yml
|
|
@@ -0,0 +1,15 @@
|
|
+scanner:
|
|
+ linter: flake8 # Other option is pycodestyle
|
|
+
|
|
+no_blank_comment: False # If True, no comment is made on PR without any errors.
|
|
+descending_issues_order: True # If True, PEP 8 issues in message will be displayed in descending order of line numbers in the file
|
|
+
|
|
+[flake8]
|
|
+exclude =
|
|
+ .git,
|
|
+ .github,
|
|
+ __pycache__,
|
|
+ build,
|
|
+ dist
|
|
+
|
|
+max-line-length = 110
|
|
diff --git a/HISTORY.md b/HISTORY.md
|
|
index e5b7638..60b6308 100644
|
|
--- a/HISTORY.md
|
|
+++ b/HISTORY.md
|
|
@@ -1,7 +1,42 @@
|
|
History
|
|
=======
|
|
|
|
-**Note:** Official support for Python 2.4 will end with Pystache version 0.6.0.
|
|
+**Note:** Official support for Python 2.7 will end with Pystache version 0.6.0.
|
|
+
|
|
+0.6.0 (2021-03-04)
|
|
+------------------
|
|
+
|
|
+- Bump spec versions to latest => v1.1.3
|
|
+- Modernize python and CI tools, update docs/doctests
|
|
+- Update unicode conversion test for py3-only
|
|
+- Add pep8speaks cfg, cleanup warnings
|
|
+- Remove superfluous setup test/unused imports
|
|
+- Add conda recipe/CI build
|
|
+
|
|
+0.5.6 (2021-02-28)
|
|
+------------------
|
|
+
|
|
+- Use correct wheel name in release workflow, limit wheels
|
|
+- Add install check/test of downloaded wheel
|
|
+- Update/add ci workflows and tox cfg, bump to next dev0 version
|
|
+
|
|
+0.5.5 (2020-12-16)
|
|
+------------------
|
|
+
|
|
+- fix document processing, update pandoc args and history
|
|
+- add release.yml to CI, test env settings
|
|
+- fix bogus commit message, update versions and tox cf
|
|
+- add post-test steps for building pkgs with/without doc updates
|
|
+- add CI build check, fix MANIFEST.in pruning
|
|
+
|
|
+0.5.4-2 (2020-11-09)
|
|
+--------------------
|
|
+
|
|
+- Merge pull request #1 from sarnold/rebase-up
|
|
+- Bugfix: test_specloader.py: fix test_find__with_directory on other OSs
|
|
+- Bugfix: pystache/loader.py: remove stray windows line-endings
|
|
+- fix crufty (and insecure) http urls
|
|
+- Bugfix: modernize python versions (keep py27) and fix spec_test load cmd
|
|
|
|
0.5.4 (2014-07-11)
|
|
------------------
|
|
diff --git a/MANIFEST.in b/MANIFEST.in
|
|
index bdc64bf..1593143 100644
|
|
--- a/MANIFEST.in
|
|
+++ b/MANIFEST.in
|
|
@@ -1,7 +1,4 @@
|
|
-include README.md
|
|
-include HISTORY.md
|
|
-include LICENSE
|
|
-include TODO.md
|
|
+include README.md HISTORY.md TODO.md LICENSE
|
|
include setup_description.rst
|
|
include tox.ini
|
|
include test_pystache.py
|
|
@@ -11,3 +8,6 @@ recursive-include pystache/tests *.mustache *.txt
|
|
# We deliberately exclude the gh/ directory because it contains copies
|
|
# of resources needed only for the web page hosted on GitHub (via the
|
|
# gh-pages branch).
|
|
+exclude *.ini *travis*
|
|
+prune gh
|
|
+prune .git*
|
|
diff --git a/README.md b/README.md
|
|
index 54a9608..1203b7a 100644
|
|
--- a/README.md
|
|
+++ b/README.md
|
|
@@ -10,11 +10,25 @@ Pystache
|
|
<!-- -->
|
|
<!-- We leave the leading brackets empty here. Otherwise, unwanted -->
|
|
<!-- caption text shows up in the reST version converted by pandoc. -->
|
|
-
|
|
+[](https://github.com/sarnold/pystache/actions/workflows/ci.yml)
|
|
+[](https://github.com/sarnold/pystache/actions/workflows/conda.yml)
|
|
+[](https://github.com/sarnold/pystache/actions/workflows/wheels.yml)
|
|
+[](https://github.com/sarnold/pystache/actions/workflows/release.yml)
|
|
+[](https://www.python.org/downloads/)
|
|
|
|
-
|
|
+[](https://github.com/sarnold/pystache/releases/latest)
|
|
+[](https://github.com/sarnold/pystache/blob/master/LICENSE)
|
|
+[](https://codeclimate.com/github/sarnold/pystache/maintainability)
|
|
+[](https://codecov.io/gh/sarnold/pystache)
|
|
|
|
-[Pystache](http://defunkt.github.com/pystache) is a Python
|
|
+
|
|
+
|
|
+This updated fork of Pystache is currently tested on Python 3.6+ and in
|
|
+Conda, on Linux, Macos, and Windows (Python 2.7 support has been removed).
|
|
+
|
|
+
|
|
+
|
|
+[Pystache](http://sarnold.github.com/pystache) is a Python
|
|
implementation of [Mustache](http://mustache.github.com/). Mustache is a
|
|
framework-agnostic, logic-free templating system inspired by
|
|
[ctemplate](http://code.google.com/p/google-ctemplate/) and
|
|
@@ -27,10 +41,10 @@ provides a good introduction to Mustache's syntax. For a more complete
|
|
(and more current) description of Mustache's behavior, see the official
|
|
[Mustache spec](https://github.com/mustache/spec).
|
|
|
|
-Pystache is [semantically versioned](http://semver.org) and can be found
|
|
-on [PyPI](http://pypi.python.org/pypi/pystache). This version of
|
|
-Pystache passes all tests in [version
|
|
-1.1.2](https://github.com/mustache/spec/tree/v1.1.2) of the spec.
|
|
+Pystache is [semantically versioned](http://semver.org) and older versions
|
|
+can still be found on [PyPI](http://pypi.python.org/pypi/pystache). This
|
|
+version of Pystache now passes all tests in [version
|
|
+1.1.3](https://github.com/mustache/spec/tree/v1.1.3) of the spec.
|
|
|
|
|
|
Requirements
|
|
@@ -38,41 +52,25 @@ Requirements
|
|
|
|
Pystache is tested with--
|
|
|
|
-- Python 2.4 (requires simplejson [version
|
|
- 2.0.9](http://pypi.python.org/pypi/simplejson/2.0.9) or earlier)
|
|
-- Python 2.5 (requires
|
|
- [simplejson](http://pypi.python.org/pypi/simplejson/))
|
|
-- Python 2.6
|
|
-- Python 2.7
|
|
-- Python 3.1
|
|
-- Python 3.2
|
|
-- Python 3.3
|
|
-- [PyPy](http://pypy.org/)
|
|
+- Python 3.6
|
|
+- Python 3.7
|
|
+- Python 3.8
|
|
+- Python 3.9
|
|
+- Conda (py36-py39)
|
|
|
|
[Distribute](http://packages.python.org/distribute/) (the setuptools fork)
|
|
-is recommended over [setuptools](http://pypi.python.org/pypi/setuptools),
|
|
-and is required in some cases (e.g. for Python 3 support).
|
|
-If you use [pip](http://www.pip-installer.org/), you probably already satisfy
|
|
-this requirement.
|
|
+is no longer required over [setuptools](http://pypi.python.org/pypi/setuptools),
|
|
+as the current packaging is now PEP517-compliant.
|
|
|
|
JSON support is needed only for the command-line interface and to run
|
|
-the spec tests. We require simplejson for earlier versions of Python
|
|
-since Python's [json](http://docs.python.org/library/json.html) module
|
|
-was added in Python 2.6.
|
|
-
|
|
-For Python 2.4 we require an earlier version of simplejson since
|
|
-simplejson stopped officially supporting Python 2.4 in simplejson
|
|
-version 2.1.0. Earlier versions of simplejson can be installed manually,
|
|
-as follows:
|
|
+the spec tests; PyYAML can still be used (see the Develop section).
|
|
|
|
- pip install 'simplejson<2.1.0'
|
|
-
|
|
-Official support for Python 2.4 will end with Pystache version 0.6.0.
|
|
+Official support for Python 2 will end with Pystache version 0.6.0.
|
|
|
|
Install It
|
|
----------
|
|
|
|
- pip install pystache
|
|
+ pip install -U pystache -f https://github.com/sarnold/pystache/releases/
|
|
|
|
And test it--
|
|
|
|
@@ -85,12 +83,12 @@ Use It
|
|
------
|
|
|
|
>>> import pystache
|
|
- >>> print pystache.render('Hi {{person}}!', {'person': 'Mom'})
|
|
+ >>> print(pystache.render('Hi {{person}}!', {'person': 'Mom'}))
|
|
Hi Mom!
|
|
|
|
You can also create dedicated view classes to hold your view logic.
|
|
|
|
-Here's your view class (in .../examples/readme.py):
|
|
+Here's your view class (in ../pystache/tests/examples/readme.py):
|
|
|
|
class SayHello(object):
|
|
def to(self):
|
|
@@ -109,7 +107,7 @@ directory as your class definition):
|
|
Pull it together:
|
|
|
|
>>> renderer = pystache.Renderer()
|
|
- >>> print renderer.render(hello)
|
|
+ >>> print(renderer.render(hello))
|
|
Hello, Pizza!
|
|
|
|
For greater control over rendering (e.g. to specify a custom template
|
|
@@ -117,22 +115,22 @@ directory), use the `Renderer` class like above. One can pass attributes
|
|
to the Renderer class constructor or set them on a Renderer instance. To
|
|
customize template loading on a per-view basis, subclass `TemplateSpec`.
|
|
See the docstrings of the
|
|
-[Renderer](https://github.com/defunkt/pystache/blob/master/pystache/renderer.py)
|
|
+[Renderer](https://github.com/sarnold/pystache/blob/master/pystache/renderer.py)
|
|
class and
|
|
-[TemplateSpec](https://github.com/defunkt/pystache/blob/master/pystache/template_spec.py)
|
|
+[TemplateSpec](https://github.com/sarnold/pystache/blob/master/pystache/template_spec.py)
|
|
class for more information.
|
|
|
|
You can also pre-parse a template:
|
|
|
|
>>> parsed = pystache.parse(u"Hey {{#who}}{{.}}!{{/who}}")
|
|
- >>> print parsed
|
|
- [u'Hey ', _SectionNode(key=u'who', index_begin=12, index_end=18, parsed=[_EscapeNode(key=u'.'), u'!'])]
|
|
+ >>> print(parsed)
|
|
+ ['Hey ', _SectionNode(key='who', index_begin=12, index_end=18, parsed=[_EscapeNode(key='.'), '!'])]
|
|
|
|
And then:
|
|
|
|
- >>> print renderer.render(parsed, {'who': 'Pops'})
|
|
+ >>> print(renderer.render(parsed, {'who': 'Pops'}))
|
|
Hey Pops!
|
|
- >>> print renderer.render(parsed, {'who': 'you'})
|
|
+ >>> print(renderer.render(parsed, {'who': 'you'}))
|
|
Hey you!
|
|
|
|
Python 3
|
|
@@ -194,15 +192,16 @@ To test from a source distribution (without installing)--
|
|
python test_pystache.py
|
|
|
|
To test Pystache with multiple versions of Python (with a single
|
|
-command!), you can use [tox](http://pypi.python.org/pypi/tox):
|
|
+command!) and different platforms, you can use [tox](http://pypi.python.org/pypi/tox):
|
|
+
|
|
+ pip install tox
|
|
+ tox -e setup
|
|
|
|
- pip install 'virtualenv<1.8' # Version 1.8 dropped support for Python 2.4.
|
|
- pip install 'tox<1.4' # Version 1.4 dropped support for Python 2.4.
|
|
- tox
|
|
+To run tests on multiple versions with coverage, run:
|
|
|
|
-If you do not have all Python versions listed in `tox.ini`--
|
|
+ tox -e py38-linux,py39-linux # for example
|
|
|
|
- tox -e py26,py32 # for example
|
|
+(substitute your platform above, eg, macos or windows)
|
|
|
|
The source distribution tests also include doctests and tests from the
|
|
Mustache spec. To include tests from the Mustache spec in your test
|
|
@@ -217,57 +216,33 @@ parses the json files. To install PyYAML--
|
|
|
|
pip install pyyaml
|
|
|
|
+Once the submodule is available, you can run the full test set with:
|
|
+
|
|
+ tox -e setup . ext/spec/specs
|
|
+
|
|
To run a subset of the tests, you can use
|
|
[nose](http://somethingaboutorange.com/mrl/projects/nose/0.11.1/testing.html):
|
|
|
|
pip install nose
|
|
nosetests --tests pystache/tests/test_context.py:GetValueTests.test_dictionary__key_present
|
|
|
|
-### Using Python 3 with Pystache from source
|
|
-
|
|
-Pystache is written in Python 2 and must be converted to Python 3 prior to
|
|
-using it with Python 3. The installation process (and tox) do this
|
|
-automatically.
|
|
|
|
-To convert the code to Python 3 manually (while using Python 3)--
|
|
+Mailing List (old)
|
|
+------------------
|
|
|
|
- python setup.py build
|
|
-
|
|
-This writes the converted code to a subdirectory called `build`.
|
|
-By design, Python 3 builds
|
|
-[cannot](https://bitbucket.org/tarek/distribute/issue/292/allow-use_2to3-with-python-2)
|
|
-be created from Python 2.
|
|
-
|
|
-To convert the code without using setup.py, you can use
|
|
-[2to3](http://docs.python.org/library/2to3.html) as follows (two steps)--
|
|
-
|
|
- 2to3 --write --nobackups --no-diffs --doctests_only pystache
|
|
- 2to3 --write --nobackups --no-diffs pystache
|
|
-
|
|
-This converts the code (and doctests) in place.
|
|
-
|
|
-To `import pystache` from a source distribution while using Python 3, be
|
|
-sure that you are importing from a directory containing a converted
|
|
-version of the code (e.g. from the `build` directory after converting),
|
|
-and not from the original (unconverted) source directory. Otherwise, you will
|
|
-get a syntax error. You can help prevent this by not running the Python
|
|
-IDE from the project directory when importing Pystache while using Python 3.
|
|
-
|
|
-
|
|
-Mailing List
|
|
-------------
|
|
-
|
|
-There is a [mailing list](http://librelist.com/browser/pystache/). Note
|
|
+There is(was) a [mailing list](http://librelist.com/browser/pystache/). Note
|
|
that there is a bit of a delay between posting a message and seeing it
|
|
appear in the mailing list archive.
|
|
|
|
Credits
|
|
-------
|
|
|
|
- >>> context = { 'author': 'Chris Wanstrath', 'maintainer': 'Chris Jerdonek' }
|
|
- >>> print pystache.render("Author: {{author}}\nMaintainer: {{maintainer}}", context)
|
|
+ >>> import pystache
|
|
+ >>> context = { 'author': 'Chris Wanstrath', 'maintainer': 'Chris Jerdonek','refurbisher': 'Steve Arnold' }
|
|
+ >>> print(pystache.render("Author: {{author}}\nMaintainer: {{maintainer}}\nRefurbisher: {{refurbisher}}", context))
|
|
Author: Chris Wanstrath
|
|
Maintainer: Chris Jerdonek
|
|
+ Refurbisher: Steve Arnold
|
|
|
|
Pystache logo by [David Phillips](http://davidphillips.us/) is licensed
|
|
under a [Creative Commons Attribution-ShareAlike 3.0 Unported
|
|
diff --git a/TODO.md b/TODO.md
|
|
index cd82417..76853a4 100644
|
|
--- a/TODO.md
|
|
+++ b/TODO.md
|
|
@@ -6,11 +6,10 @@ In development branch:
|
|
* Figure out a way to suppress center alignment of images in reST output.
|
|
* Add a unit test for the change made in 7ea8e7180c41. This is with regard
|
|
to not requiring spec tests when running tests from a downloaded sdist.
|
|
-* End support for Python 2.4.
|
|
-* Add Python 3.3 to tox file (after deprecating 2.4).
|
|
+* End support for Python 2.7 (done as of 03/03/21 - SA)
|
|
+* Release 0.6.0 on github, make a pypi account (SA)
|
|
* Turn the benchmarking script at pystache/tests/benchmark.py into a command
|
|
in pystache/commands, or make it a subcommand of one of the existing
|
|
commands (i.e. using a command argument).
|
|
* Provide support for logging in at least one of the commands.
|
|
-* Make sure command parsing to pystache-test doesn't break with Python 2.4 and earlier.
|
|
* Combine pystache-test with the main command.
|
|
diff --git a/conda/meta.yaml b/conda/meta.yaml
|
|
new file mode 100644
|
|
index 0000000..e7f4fd9
|
|
--- /dev/null
|
|
+++ b/conda/meta.yaml
|
|
@@ -0,0 +1,50 @@
|
|
+{% set name = "pystache" %}
|
|
+{% set version = "0.6.0.dev0" %}
|
|
+
|
|
+package:
|
|
+ name: {{ name|lower }}
|
|
+ version: {{ version }}
|
|
+
|
|
+source:
|
|
+ path: ..
|
|
+
|
|
+build:
|
|
+ number: 0
|
|
+ script: {{ PYTHON }} -m pip install . --no-deps --ignore-installed -vvv
|
|
+ noarch: python
|
|
+ entry_points:
|
|
+ - pystache = pystache.commands.render:main
|
|
+ - pystache-test = pystache.commands.test:main
|
|
+
|
|
+requirements:
|
|
+ build:
|
|
+ - python
|
|
+ - setuptools
|
|
+
|
|
+ run:
|
|
+ - python
|
|
+
|
|
+test:
|
|
+ imports:
|
|
+ - pystache
|
|
+ - pystache.commands
|
|
+ - pystache.tests
|
|
+ - pystache.tests.data
|
|
+ - pystache.tests.data.locator
|
|
+ - pystache.tests.examples
|
|
+
|
|
+ commands:
|
|
+ - pystache --help
|
|
+ - pystache-test
|
|
+
|
|
+
|
|
+about:
|
|
+ home: https://github.com/sarnold/pystache
|
|
+ license: MIT
|
|
+ license_family: MIT
|
|
+ license_file: LICENSE
|
|
+ summary: Mustache for Python
|
|
+
|
|
+extra:
|
|
+ recipe-maintainers:
|
|
+ - sarnold
|
|
diff --git a/pyproject.toml b/pyproject.toml
|
|
new file mode 100644
|
|
index 0000000..2f21011
|
|
--- /dev/null
|
|
+++ b/pyproject.toml
|
|
@@ -0,0 +1,3 @@
|
|
+[build-system]
|
|
+requires = ["setuptools>=40.8.0", "wheel"]
|
|
+build-backend = "setuptools.build_meta"
|
|
diff --git a/pystache/__init__.py b/pystache/__init__.py
|
|
index 4cf2434..5edc1c5 100644
|
|
--- a/pystache/__init__.py
|
|
+++ b/pystache/__init__.py
|
|
@@ -10,4 +10,4 @@ from pystache.init import parse, render, Renderer, TemplateSpec
|
|
|
|
__all__ = ['parse', 'render', 'Renderer', 'TemplateSpec']
|
|
|
|
-__version__ = '0.5.4' # Also change in setup.py.
|
|
+__version__ = '0.6.0'
|
|
diff --git a/pystache/commands/render.py b/pystache/commands/render.py
|
|
index 1a9c309..9c913e7 100644
|
|
--- a/pystache/commands/render.py
|
|
+++ b/pystache/commands/render.py
|
|
@@ -22,7 +22,7 @@ except:
|
|
from sys import exc_info
|
|
ex_type, ex_value, tb = exc_info()
|
|
new_ex = Exception("%s: %s" % (ex_type.__name__, ex_value))
|
|
- raise new_ex.__class__, new_ex, tb
|
|
+ raise new_ex.__class__(new_ex).with_traceback(tb)
|
|
|
|
# The optparse module is deprecated in Python 2.7 in favor of argparse.
|
|
# However, argparse is not available in Python 2.6 and earlier.
|
|
@@ -88,7 +88,7 @@ def main(sys_argv=sys.argv):
|
|
context = json.loads(context)
|
|
|
|
rendered = renderer.render(template, context)
|
|
- print rendered
|
|
+ print(rendered)
|
|
|
|
|
|
if __name__=='__main__':
|
|
diff --git a/pystache/common.py b/pystache/common.py
|
|
index fb266dd..0e9b091 100644
|
|
--- a/pystache/common.py
|
|
+++ b/pystache/common.py
|
|
@@ -5,17 +5,12 @@ Exposes functionality needed throughout the project.
|
|
|
|
"""
|
|
|
|
-from sys import version_info
|
|
|
|
def _get_string_types():
|
|
- # TODO: come up with a better solution for this. One of the issues here
|
|
- # is that in Python 3 there is no common base class for unicode strings
|
|
- # and byte strings, and 2to3 seems to convert all of "str", "unicode",
|
|
- # and "basestring" to Python 3's "str".
|
|
- if version_info < (3, ):
|
|
- return basestring
|
|
- # The latter evaluates to "bytes" in Python 3 -- even after conversion by 2to3.
|
|
- return (unicode, type(u"a".encode('utf-8')))
|
|
+ """
|
|
+ Return the Python3 string type (no more python2)
|
|
+ """
|
|
+ return (str, type("a".encode('utf-8')))
|
|
|
|
|
|
_STRING_TYPES = _get_string_types()
|
|
diff --git a/pystache/defaults.py b/pystache/defaults.py
|
|
index bcfdf4c..2fab0e0 100644
|
|
--- a/pystache/defaults.py
|
|
+++ b/pystache/defaults.py
|
|
@@ -39,7 +39,7 @@ STRING_ENCODING = sys.getdefaultencoding()
|
|
FILE_ENCODING = sys.getdefaultencoding()
|
|
|
|
# The delimiters to start with when parsing.
|
|
-DELIMITERS = (u'{{', u'}}')
|
|
+DELIMITERS = ('{{', '}}')
|
|
|
|
# How to handle missing tags when rendering a template.
|
|
MISSING_TAGS = MissingTags.ignore
|
|
diff --git a/pystache/loader.py b/pystache/loader.py
|
|
index d4a7e53..ea01d17 100644
|
|
--- a/pystache/loader.py
|
|
+++ b/pystache/loader.py
|
|
@@ -6,6 +6,7 @@ This module provides a Loader class for locating and reading templates.
|
|
"""
|
|
|
|
import os
|
|
+import platform
|
|
import sys
|
|
|
|
from pystache import common
|
|
@@ -24,7 +25,7 @@ def _make_to_unicode():
|
|
"""
|
|
if encoding is None:
|
|
encoding = defaults.STRING_ENCODING
|
|
- return unicode(s, encoding, defaults.DECODE_ERRORS)
|
|
+ return str(s, encoding, defaults.DECODE_ERRORS)
|
|
return to_unicode
|
|
|
|
|
|
@@ -86,7 +87,7 @@ class Loader(object):
|
|
def _make_locator(self):
|
|
return Locator(extension=self.extension)
|
|
|
|
- def unicode(self, s, encoding=None):
|
|
+ def str(self, s, encoding=None):
|
|
"""
|
|
Convert a string to unicode using the given encoding, and return it.
|
|
|
|
@@ -104,8 +105,8 @@ class Loader(object):
|
|
Defaults to None.
|
|
|
|
"""
|
|
- if isinstance(s, unicode):
|
|
- return unicode(s)
|
|
+ if isinstance(s, str):
|
|
+ return str(s)
|
|
|
|
return self.to_unicode(s, encoding)
|
|
|
|
@@ -118,8 +119,9 @@ class Loader(object):
|
|
|
|
if encoding is None:
|
|
encoding = self.file_encoding
|
|
-
|
|
- return self.unicode(b, encoding)
|
|
+ if platform.system() == "Windows":
|
|
+ return self.str(b, encoding).replace('\r', '')
|
|
+ return self.str(b, encoding)
|
|
|
|
def load_file(self, file_name):
|
|
"""
|
|
diff --git a/pystache/parsed.py b/pystache/parsed.py
|
|
index 372d96c..75d417d 100644
|
|
--- a/pystache/parsed.py
|
|
+++ b/pystache/parsed.py
|
|
@@ -41,10 +41,10 @@ class ParsedTemplate(object):
|
|
"""
|
|
# We avoid use of the ternary operator for Python 2.4 support.
|
|
def get_unicode(node):
|
|
- if type(node) is unicode:
|
|
+ if type(node) is str:
|
|
return node
|
|
return node.render(engine, context)
|
|
- parts = map(get_unicode, self._parse_tree)
|
|
+ parts = list(map(get_unicode, self._parse_tree))
|
|
s = ''.join(parts)
|
|
|
|
- return unicode(s)
|
|
+ return str(s)
|
|
diff --git a/pystache/parser.py b/pystache/parser.py
|
|
index c6a171f..1afd50a 100644
|
|
--- a/pystache/parser.py
|
|
+++ b/pystache/parser.py
|
|
@@ -11,8 +11,8 @@ from pystache import defaults
|
|
from pystache.parsed import ParsedTemplate
|
|
|
|
|
|
-END_OF_LINE_CHARACTERS = [u'\r', u'\n']
|
|
-NON_BLANK_RE = re.compile(ur'^(.)', re.M)
|
|
+END_OF_LINE_CHARACTERS = ['\r', '\n']
|
|
+NON_BLANK_RE = re.compile(r'^(.)', re.M)
|
|
|
|
|
|
# TODO: add some unit tests for this.
|
|
@@ -30,12 +30,12 @@ def parse(template, delimiters=None):
|
|
|
|
Examples:
|
|
|
|
- >>> parsed = parse(u"Hey {{#who}}{{name}}!{{/who}}")
|
|
- >>> print str(parsed).replace('u', '') # This is a hack to get the test to pass both in Python 2 and 3.
|
|
+ >>> parsed = parse("Hey {{#who}}{{name}}!{{/who}}")
|
|
+ >>> print(str(parsed).replace('u', '')) # This is an old hack.
|
|
['Hey ', _SectionNode(key='who', index_begin=12, index_end=21, parsed=[_EscapeNode(key='name'), '!'])]
|
|
|
|
"""
|
|
- if type(template) is not unicode:
|
|
+ if type(template) is not str:
|
|
raise Exception("Template is not unicode: %s" % type(template))
|
|
parser = _Parser(delimiters)
|
|
return parser.parse(template)
|
|
@@ -94,7 +94,7 @@ class _CommentNode(object):
|
|
return _format(self)
|
|
|
|
def render(self, engine, context):
|
|
- return u''
|
|
+ return ''
|
|
|
|
|
|
class _ChangeNode(object):
|
|
@@ -106,7 +106,7 @@ class _ChangeNode(object):
|
|
return _format(self)
|
|
|
|
def render(self, engine, context):
|
|
- return u''
|
|
+ return ''
|
|
|
|
|
|
class _EscapeNode(object):
|
|
@@ -147,7 +147,7 @@ class _PartialNode(object):
|
|
def render(self, engine, context):
|
|
template = engine.resolve_partial(self.key)
|
|
# Indent before rendering.
|
|
- template = re.sub(NON_BLANK_RE, self.indent + ur'\1', template)
|
|
+ template = re.sub(NON_BLANK_RE, self.indent + r'\1', template)
|
|
|
|
return engine.render(template, context)
|
|
|
|
@@ -168,7 +168,7 @@ class _InvertedNode(object):
|
|
# Note that lambdas are considered truthy for inverted sections
|
|
# per the spec.
|
|
if data:
|
|
- return u''
|
|
+ return ''
|
|
return self.parsed_section.render(engine, context)
|
|
|
|
|
|
@@ -218,7 +218,7 @@ class _SectionNode(object):
|
|
parts.append(self.parsed.render(engine, context))
|
|
context.pop()
|
|
|
|
- return unicode(''.join(parts))
|
|
+ return str(''.join(parts))
|
|
|
|
|
|
class _Parser(object):
|
|
diff --git a/pystache/renderengine.py b/pystache/renderengine.py
|
|
index c797b17..2f1e341 100644
|
|
--- a/pystache/renderengine.py
|
|
+++ b/pystache/renderengine.py
|
|
@@ -160,7 +160,7 @@ class RenderEngine(object):
|
|
if not is_string(val):
|
|
# In case the template is an integer, for example.
|
|
val = self.to_str(val)
|
|
- if type(val) is not unicode:
|
|
+ if type(val) is not str:
|
|
val = self.literal(val)
|
|
return self.render(val, context, delimiters)
|
|
|
|
diff --git a/pystache/renderer.py b/pystache/renderer.py
|
|
index ff6a90c..064f040 100644
|
|
--- a/pystache/renderer.py
|
|
+++ b/pystache/renderer.py
|
|
@@ -32,7 +32,7 @@ class Renderer(object):
|
|
>>> partials = {'partial': 'Hello, {{thing}}!'}
|
|
>>> renderer = Renderer(partials=partials)
|
|
>>> # We apply print to make the test work in Python 3 after 2to3.
|
|
- >>> print renderer.render('{{>partial}}', {'thing': 'world'})
|
|
+ >>> print(renderer.render('{{>partial}}', {'thing': 'world'}))
|
|
Hello, world!
|
|
|
|
To customize string coercion (e.g. to render False values as ''), one can
|
|
@@ -130,7 +130,7 @@ class Renderer(object):
|
|
if string_encoding is None:
|
|
string_encoding = defaults.STRING_ENCODING
|
|
|
|
- if isinstance(search_dirs, basestring):
|
|
+ if isinstance(search_dirs, str):
|
|
search_dirs = [search_dirs]
|
|
|
|
self._context = None
|
|
@@ -177,16 +177,16 @@ class Renderer(object):
|
|
"""
|
|
# We type-check to avoid "TypeError: decoding Unicode is not supported".
|
|
# We avoid the Python ternary operator for Python 2.4 support.
|
|
- if isinstance(s, unicode):
|
|
+ if isinstance(s, str):
|
|
return s
|
|
- return self.unicode(s)
|
|
+ return self.str(s)
|
|
|
|
def _to_unicode_hard(self, s):
|
|
"""
|
|
Convert a basestring to a string with type unicode (not subclass).
|
|
|
|
"""
|
|
- return unicode(self._to_unicode_soft(s))
|
|
+ return str(self._to_unicode_soft(s))
|
|
|
|
def _escape_to_unicode(self, s):
|
|
"""
|
|
@@ -195,9 +195,9 @@ class Renderer(object):
|
|
Returns a unicode string (not subclass).
|
|
|
|
"""
|
|
- return unicode(self.escape(self._to_unicode_soft(s)))
|
|
+ return str(self.escape(self._to_unicode_soft(s)))
|
|
|
|
- def unicode(self, b, encoding=None):
|
|
+ def str(self, b, encoding=None):
|
|
"""
|
|
Convert a byte string to unicode, using string_encoding and decode_errors.
|
|
|
|
@@ -222,7 +222,7 @@ class Renderer(object):
|
|
|
|
# TODO: Wrap UnicodeDecodeErrors with a message about setting
|
|
# the string_encoding and decode_errors attributes.
|
|
- return unicode(b, encoding, self.decode_errors)
|
|
+ return str(b, encoding, self.decode_errors)
|
|
|
|
def _make_loader(self):
|
|
"""
|
|
@@ -230,7 +230,7 @@ class Renderer(object):
|
|
|
|
"""
|
|
return Loader(file_encoding=self.file_encoding, extension=self.file_extension,
|
|
- to_unicode=self.unicode, search_dirs=self.search_dirs)
|
|
+ to_unicode=self.str, search_dirs=self.search_dirs)
|
|
|
|
def _make_load_template(self):
|
|
"""
|
|
@@ -299,7 +299,7 @@ class Renderer(object):
|
|
try:
|
|
return load_partial(name)
|
|
except TemplateNotFoundError:
|
|
- return u''
|
|
+ return ''
|
|
|
|
return resolve_partial
|
|
|
|
@@ -316,7 +316,7 @@ class Renderer(object):
|
|
try:
|
|
return context_get(stack, name)
|
|
except KeyNotFoundError:
|
|
- return u''
|
|
+ return ''
|
|
|
|
return resolve_context
|
|
|
|
diff --git a/pystache/specloader.py b/pystache/specloader.py
|
|
index 3a77d4c..a82d52a 100644
|
|
--- a/pystache/specloader.py
|
|
+++ b/pystache/specloader.py
|
|
@@ -83,7 +83,7 @@ class SpecLoader(object):
|
|
|
|
"""
|
|
if spec.template is not None:
|
|
- return self.loader.unicode(spec.template, spec.template_encoding)
|
|
+ return self.loader.str(spec.template, spec.template_encoding)
|
|
|
|
path = self._find(spec)
|
|
|
|
diff --git a/pystache/tests/benchmark.py b/pystache/tests/benchmark.py
|
|
index d46e973..6cb54f8 100755
|
|
--- a/pystache/tests/benchmark.py
|
|
+++ b/pystache/tests/benchmark.py
|
|
@@ -13,6 +13,13 @@ tests/benchmark.py 10000
|
|
import sys
|
|
from timeit import Timer
|
|
|
|
+try:
|
|
+ import chevron as pystache
|
|
+ print('Using module: chevron')
|
|
+except (ImportError):
|
|
+ import pystache
|
|
+ print('Using module: pystache')
|
|
+
|
|
import pystache
|
|
|
|
# TODO: make the example realistic.
|
|
@@ -76,17 +83,17 @@ def main(sys_argv):
|
|
args = sys_argv[1:]
|
|
count = int(args[0])
|
|
|
|
- print "Benchmarking: %sx" % count
|
|
- print
|
|
+ print("Benchmarking: %sx" % count)
|
|
+ print()
|
|
|
|
for example in examples:
|
|
|
|
test = make_test_function(example)
|
|
|
|
t = Timer(test,)
|
|
- print min(t.repeat(repeat=3, number=count))
|
|
+ print(min(t.repeat(repeat=3, number=count)))
|
|
|
|
- print "Done"
|
|
+ print("Done")
|
|
|
|
|
|
if __name__ == '__main__':
|
|
diff --git a/pystache/tests/common.py b/pystache/tests/common.py
|
|
index 222e14f..12b76b5 100644
|
|
--- a/pystache/tests/common.py
|
|
+++ b/pystache/tests/common.py
|
|
@@ -72,8 +72,8 @@ def _find_files(root_dir, should_include):
|
|
# http://docs.python.org/library/os.html#os.walk
|
|
for dir_path, dir_names, file_names in os.walk(root_dir):
|
|
new_paths = [os.path.join(dir_path, file_name) for file_name in file_names]
|
|
- new_paths = filter(is_module, new_paths)
|
|
- new_paths = filter(should_include, new_paths)
|
|
+ new_paths = list(filter(is_module, new_paths))
|
|
+ new_paths = list(filter(should_include, new_paths))
|
|
paths.extend(new_paths)
|
|
|
|
return paths
|
|
@@ -183,7 +183,7 @@ class AssertExceptionMixin:
|
|
try:
|
|
callable(*args, **kwds)
|
|
raise Exception("Expected exception: %s: %s" % (exception_type, repr(msg)))
|
|
- except exception_type, err:
|
|
+ except exception_type as err:
|
|
self.assertEqual(str(err), msg)
|
|
|
|
|
|
@@ -228,10 +228,10 @@ class Attachable(object):
|
|
"""
|
|
def __init__(self, **kwargs):
|
|
self.__args__ = kwargs
|
|
- for arg, value in kwargs.iteritems():
|
|
+ for arg, value in kwargs.items():
|
|
setattr(self, arg, value)
|
|
|
|
def __repr__(self):
|
|
return "%s(%s)" % (self.__class__.__name__,
|
|
", ".join("%s=%s" % (k, repr(v))
|
|
- for k, v in self.__args__.iteritems()))
|
|
+ for k, v in self.__args__.items()))
|
|
diff --git a/pystache/tests/examples/unicode_output.py b/pystache/tests/examples/unicode_output.py
|
|
index da0e1d2..7bdea36 100644
|
|
--- a/pystache/tests/examples/unicode_output.py
|
|
+++ b/pystache/tests/examples/unicode_output.py
|
|
@@ -8,4 +8,4 @@ TODO: add a docstring.
|
|
class UnicodeOutput(object):
|
|
|
|
def name(self):
|
|
- return u'Henri Poincaré'
|
|
+ return 'Henri Poincaré'
|
|
diff --git a/pystache/tests/main.py b/pystache/tests/main.py
|
|
index 8af6b2e..17f2fb2 100644
|
|
--- a/pystache/tests/main.py
|
|
+++ b/pystache/tests/main.py
|
|
@@ -88,7 +88,7 @@ def main(sys_argv):
|
|
|
|
"""
|
|
# TODO: use logging module
|
|
- print "pystache: running tests: argv: %s" % repr(sys_argv)
|
|
+ print("pystache: running tests: argv: %s" % repr(sys_argv))
|
|
|
|
should_source_exist = False
|
|
spec_test_dir = None
|
|
@@ -131,11 +131,9 @@ def main(sys_argv):
|
|
module_names = _discover_test_modules(PACKAGE_DIR)
|
|
sys_argv.extend(module_names)
|
|
if project_dir is not None:
|
|
- # Add the current module for unit tests contained here (e.g.
|
|
- # to include SetupTests).
|
|
+ # Add the current module for unit tests contained here
|
|
sys_argv.append(__name__)
|
|
|
|
- SetupTests.project_dir = project_dir
|
|
|
|
extra_tests = make_extra_tests(project_dir, spec_test_dir)
|
|
test_program_class = make_test_program_class(extra_tests)
|
|
@@ -166,25 +164,3 @@ def _discover_test_modules(package_dir):
|
|
raise Exception("No unit-test modules found--\n in %s" % package_dir)
|
|
|
|
return names
|
|
-
|
|
-
|
|
-class SetupTests(TestCase):
|
|
-
|
|
- """Tests about setup.py."""
|
|
-
|
|
- project_dir = None
|
|
-
|
|
- def test_version(self):
|
|
- """
|
|
- Test that setup.py's version matches the package's version.
|
|
-
|
|
- """
|
|
- original_path = list(sys.path)
|
|
-
|
|
- sys.path.insert(0, self.project_dir)
|
|
-
|
|
- try:
|
|
- from setup import VERSION
|
|
- self.assertEqual(VERSION, pystache.__version__)
|
|
- finally:
|
|
- sys.path = original_path
|
|
diff --git a/pystache/tests/spectesting.py b/pystache/tests/spectesting.py
|
|
index ec8a08d..2dd57e8 100644
|
|
--- a/pystache/tests/spectesting.py
|
|
+++ b/pystache/tests/spectesting.py
|
|
@@ -37,7 +37,7 @@ except ImportError:
|
|
from sys import exc_info
|
|
ex_type, ex_value, tb = exc_info()
|
|
new_ex = Exception("%s: %s" % (ex_type.__name__, ex_value))
|
|
- raise new_ex.__class__, new_ex, tb
|
|
+ raise new_ex.__class__(new_ex).with_traceback(tb)
|
|
file_extension = 'json'
|
|
parser = json
|
|
else:
|
|
@@ -62,7 +62,7 @@ def get_spec_tests(spec_test_dir):
|
|
|
|
"""
|
|
# TODO: use logging module instead.
|
|
- print "pystache: spec tests: using %s" % _get_parser_info()
|
|
+ print("pystache: spec tests: using %s" % _get_parser_info())
|
|
|
|
cases = []
|
|
|
|
@@ -103,7 +103,7 @@ def _read_spec_tests(path):
|
|
|
|
"""
|
|
b = common.read(path)
|
|
- u = unicode(b, encoding=FILE_ENCODING)
|
|
+ u = str(b, encoding=FILE_ENCODING)
|
|
spec_data = parse(u)
|
|
tests = spec_data['tests']
|
|
|
|
@@ -133,7 +133,7 @@ def _convert_children(node):
|
|
return
|
|
# Otherwise, node is a dict, so attempt the conversion.
|
|
|
|
- for key in node.keys():
|
|
+ for key in list(node.keys()):
|
|
val = node[key]
|
|
|
|
if not isinstance(val, dict) or val.get('__tag__') != 'code':
|
|
@@ -158,9 +158,9 @@ def _deserialize_spec_test(data, file_path):
|
|
context = data['data']
|
|
description = data['desc']
|
|
# PyYAML seems to leave ASCII strings as byte strings.
|
|
- expected = unicode(data['expected'])
|
|
+ expected = str(data['expected'])
|
|
# TODO: switch to using dict.get().
|
|
- partials = data.has_key('partials') and data['partials'] or {}
|
|
+ partials = 'partials' in data and data['partials'] or {}
|
|
template = data['template']
|
|
test_name = data['name']
|
|
|
|
@@ -237,8 +237,8 @@ def parse(u):
|
|
value = loader.construct_mapping(node)
|
|
return eval(value['python'], {})
|
|
|
|
- yaml.add_constructor(u'!code', code_constructor)
|
|
- return yaml.load(u)
|
|
+ yaml.add_constructor('!code', code_constructor)
|
|
+ return yaml.full_load(u)
|
|
|
|
|
|
class SpecTestBase(unittest.TestCase, AssertStringMixin):
|
|
diff --git a/pystache/tests/test___init__.py b/pystache/tests/test___init__.py
|
|
index eae42c1..63d2c3b 100644
|
|
--- a/pystache/tests/test___init__.py
|
|
+++ b/pystache/tests/test___init__.py
|
|
@@ -6,9 +6,9 @@ Tests of __init__.py.
|
|
"""
|
|
|
|
# Calling "import *" is allowed only at the module level.
|
|
-GLOBALS_INITIAL = globals().keys()
|
|
+GLOBALS_INITIAL = list(globals().keys())
|
|
from pystache import *
|
|
-GLOBALS_PYSTACHE_IMPORTED = globals().keys()
|
|
+GLOBALS_PYSTACHE_IMPORTED = list(globals().keys())
|
|
|
|
import unittest
|
|
|
|
diff --git a/pystache/tests/test_commands.py b/pystache/tests/test_commands.py
|
|
index 2529d25..34fe8ba 100644
|
|
--- a/pystache/tests/test_commands.py
|
|
+++ b/pystache/tests/test_commands.py
|
|
@@ -39,7 +39,7 @@ class CommandsTestCase(unittest.TestCase):
|
|
|
|
"""
|
|
actual = self.callScript("Hi {{thing}}", '{"thing": "world"}')
|
|
- self.assertEqual(actual, u"Hi world\n")
|
|
+ self.assertEqual(actual, "Hi world\n")
|
|
|
|
def tearDown(self):
|
|
sys.stdout = ORIGINAL_STDOUT
|
|
diff --git a/pystache/tests/test_defaults.py b/pystache/tests/test_defaults.py
|
|
index c78ea7c..5399bb0 100644
|
|
--- a/pystache/tests/test_defaults.py
|
|
+++ b/pystache/tests/test_defaults.py
|
|
@@ -31,37 +31,37 @@ class DefaultsConfigurableTestCase(unittest.TestCase, AssertStringMixin):
|
|
self.saved[e] = getattr(pystache.defaults, e)
|
|
|
|
def tearDown(self):
|
|
- for key, value in self.saved.items():
|
|
+ for key, value in list(self.saved.items()):
|
|
setattr(pystache.defaults, key, value)
|
|
|
|
def test_tag_escape(self):
|
|
"""Test that changes to defaults.TAG_ESCAPE take effect."""
|
|
- template = u"{{foo}}"
|
|
+ template = "{{foo}}"
|
|
context = {'foo': '<'}
|
|
actual = pystache.render(template, context)
|
|
- self.assertString(actual, u"<")
|
|
+ self.assertString(actual, "<")
|
|
|
|
pystache.defaults.TAG_ESCAPE = lambda u: u
|
|
actual = pystache.render(template, context)
|
|
- self.assertString(actual, u"<")
|
|
+ self.assertString(actual, "<")
|
|
|
|
def test_delimiters(self):
|
|
"""Test that changes to defaults.DELIMITERS take effect."""
|
|
- template = u"[[foo]]{{foo}}"
|
|
+ template = "[[foo]]{{foo}}"
|
|
context = {'foo': 'FOO'}
|
|
actual = pystache.render(template, context)
|
|
- self.assertString(actual, u"[[foo]]FOO")
|
|
+ self.assertString(actual, "[[foo]]FOO")
|
|
|
|
pystache.defaults.DELIMITERS = ('[[', ']]')
|
|
actual = pystache.render(template, context)
|
|
- self.assertString(actual, u"FOO{{foo}}")
|
|
+ self.assertString(actual, "FOO{{foo}}")
|
|
|
|
def test_missing_tags(self):
|
|
"""Test that changes to defaults.MISSING_TAGS take effect."""
|
|
- template = u"{{foo}}"
|
|
+ template = "{{foo}}"
|
|
context = {}
|
|
actual = pystache.render(template, context)
|
|
- self.assertString(actual, u"")
|
|
+ self.assertString(actual, "")
|
|
|
|
pystache.defaults.MISSING_TAGS = 'strict'
|
|
self.assertRaises(pystache.context.KeyNotFoundError,
|
|
diff --git a/pystache/tests/test_examples.py b/pystache/tests/test_examples.py
|
|
index 5c9f74d..9f93de3 100644
|
|
--- a/pystache/tests/test_examples.py
|
|
+++ b/pystache/tests/test_examples.py
|
|
@@ -7,15 +7,15 @@ TODO: add a docstring.
|
|
|
|
import unittest
|
|
|
|
-from examples.comments import Comments
|
|
-from examples.double_section import DoubleSection
|
|
-from examples.escaped import Escaped
|
|
-from examples.unescaped import Unescaped
|
|
-from examples.template_partial import TemplatePartial
|
|
-from examples.delimiters import Delimiters
|
|
-from examples.unicode_output import UnicodeOutput
|
|
-from examples.unicode_input import UnicodeInput
|
|
-from examples.nested_context import NestedContext
|
|
+from .examples.comments import Comments
|
|
+from .examples.double_section import DoubleSection
|
|
+from .examples.escaped import Escaped
|
|
+from .examples.unescaped import Unescaped
|
|
+from .examples.template_partial import TemplatePartial
|
|
+from .examples.delimiters import Delimiters
|
|
+from .examples.unicode_output import UnicodeOutput
|
|
+from .examples.unicode_input import UnicodeInput
|
|
+from .examples.nested_context import NestedContext
|
|
from pystache import Renderer
|
|
from pystache.tests.common import EXAMPLES_DIR
|
|
from pystache.tests.common import AssertStringMixin
|
|
@@ -29,34 +29,34 @@ class TestView(unittest.TestCase, AssertStringMixin):
|
|
self.assertString(actual, expected)
|
|
|
|
def test_comments(self):
|
|
- self._assert(Comments(), u"<h1>A Comedy of Errors</h1>")
|
|
+ self._assert(Comments(), "<h1>A Comedy of Errors</h1>")
|
|
|
|
def test_double_section(self):
|
|
- self._assert(DoubleSection(), u"* first\n* second\n* third")
|
|
+ self._assert(DoubleSection(), "* first\n* second\n* third")
|
|
|
|
def test_unicode_output(self):
|
|
renderer = Renderer()
|
|
actual = renderer.render(UnicodeOutput())
|
|
- self.assertString(actual, u'<p>Name: Henri Poincaré</p>')
|
|
+ self.assertString(actual, '<p>Name: Henri Poincaré</p>')
|
|
|
|
def test_unicode_input(self):
|
|
renderer = Renderer()
|
|
actual = renderer.render(UnicodeInput())
|
|
- self.assertString(actual, u'abcdé')
|
|
+ self.assertString(actual, 'abcdé')
|
|
|
|
def test_escaping(self):
|
|
- self._assert(Escaped(), u"<h1>Bear > Shark</h1>")
|
|
+ self._assert(Escaped(), "<h1>Bear > Shark</h1>")
|
|
|
|
def test_literal(self):
|
|
renderer = Renderer()
|
|
actual = renderer.render(Unescaped())
|
|
- self.assertString(actual, u"<h1>Bear > Shark</h1>")
|
|
+ self.assertString(actual, "<h1>Bear > Shark</h1>")
|
|
|
|
def test_template_partial(self):
|
|
renderer = Renderer(search_dirs=EXAMPLES_DIR)
|
|
actual = renderer.render(TemplatePartial(renderer=renderer))
|
|
|
|
- self.assertString(actual, u"""<h1>Welcome</h1>
|
|
+ self.assertString(actual, """<h1>Welcome</h1>
|
|
Again, Welcome!""")
|
|
|
|
def test_template_partial_extension(self):
|
|
@@ -65,7 +65,7 @@ Again, Welcome!""")
|
|
view = TemplatePartial(renderer=renderer)
|
|
|
|
actual = renderer.render(view)
|
|
- self.assertString(actual, u"""Welcome
|
|
+ self.assertString(actual, """Welcome
|
|
-------
|
|
|
|
## Again, Welcome! ##""")
|
|
@@ -73,7 +73,7 @@ Again, Welcome!""")
|
|
def test_delimiters(self):
|
|
renderer = Renderer()
|
|
actual = renderer.render(Delimiters())
|
|
- self.assertString(actual, u"""\
|
|
+ self.assertString(actual, """\
|
|
* It worked the first time.
|
|
* And it worked the second time.
|
|
* Then, surprisingly, it worked the third time.
|
|
@@ -82,7 +82,7 @@ Again, Welcome!""")
|
|
def test_nested_context(self):
|
|
renderer = Renderer()
|
|
actual = renderer.render(NestedContext(renderer))
|
|
- self.assertString(actual, u"one and foo and two")
|
|
+ self.assertString(actual, "one and foo and two")
|
|
|
|
def test_nested_context_is_available_in_view(self):
|
|
renderer = Renderer()
|
|
@@ -91,7 +91,7 @@ Again, Welcome!""")
|
|
view.template = '{{#herp}}{{#derp}}{{nested_context_in_view}}{{/derp}}{{/herp}}'
|
|
|
|
actual = renderer.render(view)
|
|
- self.assertString(actual, u'it works!')
|
|
+ self.assertString(actual, 'it works!')
|
|
|
|
def test_partial_in_partial_has_access_to_grand_parent_context(self):
|
|
renderer = Renderer(search_dirs=EXAMPLES_DIR)
|
|
diff --git a/pystache/tests/test_loader.py b/pystache/tests/test_loader.py
|
|
index f2c2187..315daff 100644
|
|
--- a/pystache/tests/test_loader.py
|
|
+++ b/pystache/tests/test_loader.py
|
|
@@ -55,23 +55,23 @@ class LoaderTests(unittest.TestCase, AssertStringMixin, SetupDefaults):
|
|
|
|
def test_init__to_unicode__default(self):
|
|
loader = Loader()
|
|
- self.assertRaises(TypeError, loader.to_unicode, u"abc")
|
|
+ self.assertRaises(TypeError, loader.to_unicode, "abc")
|
|
|
|
decode_errors = defaults.DECODE_ERRORS
|
|
string_encoding = defaults.STRING_ENCODING
|
|
|
|
- nonascii = u'abcdé'.encode('utf-8')
|
|
+ nonascii = 'abcdé'.encode('utf-8')
|
|
|
|
loader = Loader()
|
|
self.assertRaises(UnicodeDecodeError, loader.to_unicode, nonascii)
|
|
|
|
defaults.DECODE_ERRORS = 'ignore'
|
|
loader = Loader()
|
|
- self.assertString(loader.to_unicode(nonascii), u'abcd')
|
|
+ self.assertString(loader.to_unicode(nonascii), 'abcd')
|
|
|
|
defaults.STRING_ENCODING = 'utf-8'
|
|
loader = Loader()
|
|
- self.assertString(loader.to_unicode(nonascii), u'abcdé')
|
|
+ self.assertString(loader.to_unicode(nonascii), 'abcdé')
|
|
|
|
|
|
def _get_path(self, filename):
|
|
@@ -83,9 +83,9 @@ class LoaderTests(unittest.TestCase, AssertStringMixin, SetupDefaults):
|
|
|
|
"""
|
|
loader = Loader()
|
|
- actual = loader.unicode("foo")
|
|
+ actual = loader.str("foo")
|
|
|
|
- self.assertString(actual, u"foo")
|
|
+ self.assertString(actual, "foo")
|
|
|
|
def test_unicode__basic__input_unicode(self):
|
|
"""
|
|
@@ -93,24 +93,24 @@ class LoaderTests(unittest.TestCase, AssertStringMixin, SetupDefaults):
|
|
|
|
"""
|
|
loader = Loader()
|
|
- actual = loader.unicode(u"foo")
|
|
+ actual = loader.str("foo")
|
|
|
|
- self.assertString(actual, u"foo")
|
|
+ self.assertString(actual, "foo")
|
|
|
|
def test_unicode__basic__input_unicode_subclass(self):
|
|
"""
|
|
Test unicode(): default arguments with unicode-subclass input.
|
|
|
|
"""
|
|
- class UnicodeSubclass(unicode):
|
|
+ class UnicodeSubclass(str):
|
|
pass
|
|
|
|
- s = UnicodeSubclass(u"foo")
|
|
+ s = UnicodeSubclass("foo")
|
|
|
|
loader = Loader()
|
|
- actual = loader.unicode(s)
|
|
+ actual = loader.str(s)
|
|
|
|
- self.assertString(actual, u"foo")
|
|
+ self.assertString(actual, "foo")
|
|
|
|
def test_unicode__to_unicode__attribute(self):
|
|
"""
|
|
@@ -119,16 +119,16 @@ class LoaderTests(unittest.TestCase, AssertStringMixin, SetupDefaults):
|
|
"""
|
|
loader = Loader()
|
|
|
|
- non_ascii = u'abcdé'.encode('utf-8')
|
|
- self.assertRaises(UnicodeDecodeError, loader.unicode, non_ascii)
|
|
+ non_ascii = 'abcdé'.encode('utf-8')
|
|
+ self.assertRaises(UnicodeDecodeError, loader.str, non_ascii)
|
|
|
|
def to_unicode(s, encoding=None):
|
|
if encoding is None:
|
|
encoding = 'utf-8'
|
|
- return unicode(s, encoding)
|
|
+ return str(s, encoding)
|
|
|
|
loader.to_unicode = to_unicode
|
|
- self.assertString(loader.unicode(non_ascii), u"abcdé")
|
|
+ self.assertString(loader.str(non_ascii), "abcdé")
|
|
|
|
def test_unicode__encoding_argument(self):
|
|
"""
|
|
@@ -137,12 +137,12 @@ class LoaderTests(unittest.TestCase, AssertStringMixin, SetupDefaults):
|
|
"""
|
|
loader = Loader()
|
|
|
|
- non_ascii = u'abcdé'.encode('utf-8')
|
|
+ non_ascii = 'abcdé'.encode('utf-8')
|
|
|
|
- self.assertRaises(UnicodeDecodeError, loader.unicode, non_ascii)
|
|
+ self.assertRaises(UnicodeDecodeError, loader.str, non_ascii)
|
|
|
|
- actual = loader.unicode(non_ascii, encoding='utf-8')
|
|
- self.assertString(actual, u'abcdé')
|
|
+ actual = loader.str(non_ascii, encoding='utf-8')
|
|
+ self.assertString(actual, 'abcdé')
|
|
|
|
# TODO: check the read() unit tests.
|
|
def test_read(self):
|
|
@@ -153,7 +153,7 @@ class LoaderTests(unittest.TestCase, AssertStringMixin, SetupDefaults):
|
|
loader = Loader()
|
|
path = self._get_path('ascii.mustache')
|
|
actual = loader.read(path)
|
|
- self.assertString(actual, u'ascii: abc')
|
|
+ self.assertString(actual, 'ascii: abc')
|
|
|
|
def test_read__file_encoding__attribute(self):
|
|
"""
|
|
@@ -167,7 +167,7 @@ class LoaderTests(unittest.TestCase, AssertStringMixin, SetupDefaults):
|
|
|
|
loader.file_encoding = 'utf-8'
|
|
actual = loader.read(path)
|
|
- self.assertString(actual, u'non-ascii: é')
|
|
+ self.assertString(actual, 'non-ascii: é')
|
|
|
|
def test_read__encoding__argument(self):
|
|
"""
|
|
@@ -180,7 +180,7 @@ class LoaderTests(unittest.TestCase, AssertStringMixin, SetupDefaults):
|
|
self.assertRaises(UnicodeDecodeError, loader.read, path)
|
|
|
|
actual = loader.read(path, encoding='utf-8')
|
|
- self.assertString(actual, u'non-ascii: é')
|
|
+ self.assertString(actual, 'non-ascii: é')
|
|
|
|
def test_read__to_unicode__attribute(self):
|
|
"""
|
|
diff --git a/pystache/tests/test_pystache.py b/pystache/tests/test_pystache.py
|
|
index 5447f8d..cf5d6af 100644
|
|
--- a/pystache/tests/test_pystache.py
|
|
+++ b/pystache/tests/test_pystache.py
|
|
@@ -71,14 +71,14 @@ class PystacheTests(unittest.TestCase):
|
|
template = "{{#stats}}({{key}} & {{value}}){{/stats}}"
|
|
stats = []
|
|
stats.append({'key': 123, 'value': ['something']})
|
|
- stats.append({'key': u"chris", 'value': 0.900})
|
|
+ stats.append({'key': "chris", 'value': 0.900})
|
|
context = { 'stats': stats }
|
|
self._assert_rendered(self.non_strings_expected, template, context)
|
|
|
|
def test_unicode(self):
|
|
template = 'Name: {{name}}; Age: {{age}}'
|
|
- context = {'name': u'Henri Poincaré', 'age': 156 }
|
|
- self._assert_rendered(u'Name: Henri Poincaré; Age: 156', template, context)
|
|
+ context = {'name': 'Henri Poincaré', 'age': 156}
|
|
+ self._assert_rendered('Name: Henri Poincaré; Age: 156', template, context)
|
|
|
|
def test_sections(self):
|
|
template = """<ul>{{#users}}<li>{{name}}</li>{{/users}}</ul>"""
|
|
diff --git a/pystache/tests/test_renderengine.py b/pystache/tests/test_renderengine.py
|
|
index db916f7..ed604c5 100644
|
|
--- a/pystache/tests/test_renderengine.py
|
|
+++ b/pystache/tests/test_renderengine.py
|
|
@@ -33,11 +33,11 @@ def mock_literal(s):
|
|
s: a byte string or unicode string.
|
|
|
|
"""
|
|
- if isinstance(s, unicode):
|
|
+ if isinstance(s, str):
|
|
# Strip off unicode super classes, if present.
|
|
- u = unicode(s)
|
|
+ u = str(s)
|
|
else:
|
|
- u = unicode(s, encoding='ascii')
|
|
+ u = str(s, encoding='ascii')
|
|
|
|
# We apply upper() to make sure we are actually using our custom
|
|
# function in the tests
|
|
@@ -94,17 +94,17 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
engine = kwargs.get('engine', self._engine())
|
|
|
|
if partials is not None:
|
|
- engine.resolve_partial = lambda key: unicode(partials[key])
|
|
+ engine.resolve_partial = lambda key: str(partials[key])
|
|
|
|
context = ContextStack(*context)
|
|
|
|
# RenderEngine.render() only accepts unicode template strings.
|
|
- actual = engine.render(unicode(template), context)
|
|
+ actual = engine.render(str(template), context)
|
|
|
|
self.assertString(actual=actual, expected=expected)
|
|
|
|
def test_render(self):
|
|
- self._assert_render(u'Hi Mom', 'Hi {{person}}', {'person': 'Mom'})
|
|
+ self._assert_render('Hi Mom', 'Hi {{person}}', {'person': 'Mom'})
|
|
|
|
def test__resolve_partial(self):
|
|
"""
|
|
@@ -112,10 +112,10 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
|
|
"""
|
|
engine = self._engine()
|
|
- partials = {'partial': u"{{person}}"}
|
|
+ partials = {'partial': "{{person}}"}
|
|
engine.resolve_partial = lambda key: partials[key]
|
|
|
|
- self._assert_render(u'Hi Mom', 'Hi {{>partial}}', {'person': 'Mom'}, engine=engine)
|
|
+ self._assert_render('Hi Mom', 'Hi {{>partial}}', {'person': 'Mom'}, engine=engine)
|
|
|
|
def test__literal(self):
|
|
"""
|
|
@@ -125,13 +125,13 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
engine = self._engine()
|
|
engine.literal = lambda s: s.upper()
|
|
|
|
- self._assert_render(u'BAR', '{{{foo}}}', {'foo': 'bar'}, engine=engine)
|
|
+ self._assert_render('BAR', '{{{foo}}}', {'foo': 'bar'}, engine=engine)
|
|
|
|
def test_literal__sigil(self):
|
|
template = "<h1>{{& thing}}</h1>"
|
|
context = {'thing': 'Bear > Giraffe'}
|
|
|
|
- expected = u"<h1>Bear > Giraffe</h1>"
|
|
+ expected = "<h1>Bear > Giraffe</h1>"
|
|
|
|
self._assert_render(expected, template, context)
|
|
|
|
@@ -143,7 +143,7 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
engine = self._engine()
|
|
engine.escape = lambda s: "**" + s
|
|
|
|
- self._assert_render(u'**bar', '{{foo}}', {'foo': 'bar'}, engine=engine)
|
|
+ self._assert_render('**bar', '{{foo}}', {'foo': 'bar'}, engine=engine)
|
|
|
|
def test__escape_does_not_call_literal(self):
|
|
"""
|
|
@@ -157,7 +157,7 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
template = 'literal: {{{foo}}} escaped: {{foo}}'
|
|
context = {'foo': 'bar'}
|
|
|
|
- self._assert_render(u'literal: BAR escaped: **bar', template, context, engine=engine)
|
|
+ self._assert_render('literal: BAR escaped: **bar', template, context, engine=engine)
|
|
|
|
def test__escape_preserves_unicode_subclasses(self):
|
|
"""
|
|
@@ -167,7 +167,7 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
variable value is markupsafe.Markup when escaping.
|
|
|
|
"""
|
|
- class MyUnicode(unicode):
|
|
+ class MyUnicode(str):
|
|
pass
|
|
|
|
def escape(s):
|
|
@@ -182,7 +182,7 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
template = '{{foo1}} {{foo2}}'
|
|
context = {'foo1': MyUnicode('bar'), 'foo2': 'bar'}
|
|
|
|
- self._assert_render(u'**bar bar**', template, context, engine=engine)
|
|
+ self._assert_render('**bar bar**', template, context, engine=engine)
|
|
|
|
# Custom to_str for testing purposes.
|
|
def _to_str(self, val):
|
|
@@ -197,9 +197,9 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
template = '{{value}}'
|
|
context = {'value': None}
|
|
|
|
- self._assert_render(u'None', template, context, engine=engine)
|
|
+ self._assert_render('None', template, context, engine=engine)
|
|
engine.to_str = self._to_str
|
|
- self._assert_render(u'', template, context, engine=engine)
|
|
+ self._assert_render('', template, context, engine=engine)
|
|
|
|
def test_to_str__lambda(self):
|
|
"""Test the to_str attribute for a lambda."""
|
|
@@ -207,9 +207,9 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
template = '{{value}}'
|
|
context = {'value': lambda: None}
|
|
|
|
- self._assert_render(u'None', template, context, engine=engine)
|
|
+ self._assert_render('None', template, context, engine=engine)
|
|
engine.to_str = self._to_str
|
|
- self._assert_render(u'', template, context, engine=engine)
|
|
+ self._assert_render('', template, context, engine=engine)
|
|
|
|
def test_to_str__section_list(self):
|
|
"""Test the to_str attribute for a section list."""
|
|
@@ -217,9 +217,9 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
template = '{{#list}}{{.}}{{/list}}'
|
|
context = {'list': [None, None]}
|
|
|
|
- self._assert_render(u'NoneNone', template, context, engine=engine)
|
|
+ self._assert_render('NoneNone', template, context, engine=engine)
|
|
engine.to_str = self._to_str
|
|
- self._assert_render(u'', template, context, engine=engine)
|
|
+ self._assert_render('', template, context, engine=engine)
|
|
|
|
def test_to_str__section_lambda(self):
|
|
# TODO: add a test for a "method with an arity of 1".
|
|
@@ -239,7 +239,7 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
template = '{{text}} {{int}} {{{int}}}'
|
|
context = {'int': 100, 'text': 'foo'}
|
|
|
|
- self._assert_render(u'FOO 100 100', template, context, engine=engine)
|
|
+ self._assert_render('FOO 100 100', template, context, engine=engine)
|
|
|
|
def test_tag__output_not_interpolated(self):
|
|
"""
|
|
@@ -248,7 +248,7 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
"""
|
|
template = '{{template}}: {{planet}}'
|
|
context = {'template': '{{planet}}', 'planet': 'Earth'}
|
|
- self._assert_render(u'{{planet}}: Earth', template, context)
|
|
+ self._assert_render('{{planet}}: Earth', template, context)
|
|
|
|
def test_tag__output_not_interpolated__section(self):
|
|
"""
|
|
@@ -257,7 +257,7 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
"""
|
|
template = '{{test}}'
|
|
context = {'test': '{{#hello}}'}
|
|
- self._assert_render(u'{{#hello}}', template, context)
|
|
+ self._assert_render('{{#hello}}', template, context)
|
|
|
|
## Test interpolation with "falsey" values
|
|
#
|
|
@@ -268,17 +268,17 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
def test_interpolation__falsey__zero(self):
|
|
template = '{{.}}'
|
|
context = 0
|
|
- self._assert_render(u'0', template, context)
|
|
+ self._assert_render('0', template, context)
|
|
|
|
def test_interpolation__falsey__none(self):
|
|
template = '{{.}}'
|
|
context = None
|
|
- self._assert_render(u'None', template, context)
|
|
+ self._assert_render('None', template, context)
|
|
|
|
def test_interpolation__falsey__zero(self):
|
|
template = '{{.}}'
|
|
context = False
|
|
- self._assert_render(u'False', template, context)
|
|
+ self._assert_render('False', template, context)
|
|
|
|
# Built-in types:
|
|
#
|
|
@@ -310,7 +310,7 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
Check tag interpolation with a built-in type: string.
|
|
|
|
"""
|
|
- self._assert_builtin_type('abc', 'upper', 'ABC', u'xyz')
|
|
+ self._assert_builtin_type('abc', 'upper', 'ABC', 'xyz')
|
|
|
|
def test_interpolation__built_in_type__integer(self):
|
|
"""
|
|
@@ -324,7 +324,7 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
#
|
|
# we need to resort to built-in attributes (double-underscored) on
|
|
# the integer type.
|
|
- self._assert_builtin_type(15, '__neg__', -15, u'999')
|
|
+ self._assert_builtin_type(15, '__neg__', -15, '999')
|
|
|
|
def test_interpolation__built_in_type__list(self):
|
|
"""
|
|
@@ -338,7 +338,7 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
|
|
template = '{{#section}}{{%s}}{{/section}}' % attr_name
|
|
context = {'section': item, attr_name: 7}
|
|
- self._assert_render(u'7', template, context)
|
|
+ self._assert_render('7', template, context)
|
|
|
|
# This test is also important for testing 2to3.
|
|
def test_interpolation__nonascii_nonunicode(self):
|
|
@@ -347,8 +347,8 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
|
|
"""
|
|
template = '{{nonascii}}'
|
|
- context = {'nonascii': u'abcdé'.encode('utf-8')}
|
|
- self._assert_render(u'abcdé', template, context)
|
|
+ context = {'nonascii': 'abcdé'.encode('utf-8')}
|
|
+ self._assert_render('abcdé', template, context)
|
|
|
|
def test_implicit_iterator__literal(self):
|
|
"""
|
|
@@ -358,7 +358,7 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
template = """{{#test}}{{{.}}}{{/test}}"""
|
|
context = {'test': ['<', '>']}
|
|
|
|
- self._assert_render(u'<>', template, context)
|
|
+ self._assert_render('<>', template, context)
|
|
|
|
def test_implicit_iterator__escaped(self):
|
|
"""
|
|
@@ -368,7 +368,7 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
template = """{{#test}}{{.}}{{/test}}"""
|
|
context = {'test': ['<', '>']}
|
|
|
|
- self._assert_render(u'<>', template, context)
|
|
+ self._assert_render('<>', template, context)
|
|
|
|
def test_literal__in_section(self):
|
|
"""
|
|
@@ -378,7 +378,7 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
template = '{{#test}}1 {{{less_than}}} 2{{/test}}'
|
|
context = {'test': {'less_than': '<'}}
|
|
|
|
- self._assert_render(u'1 < 2', template, context)
|
|
+ self._assert_render('1 < 2', template, context)
|
|
|
|
def test_literal__in_partial(self):
|
|
"""
|
|
@@ -389,11 +389,11 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
partials = {'partial': '1 {{{less_than}}} 2'}
|
|
context = {'less_than': '<'}
|
|
|
|
- self._assert_render(u'1 < 2', template, context, partials=partials)
|
|
+ self._assert_render('1 < 2', template, context, partials=partials)
|
|
|
|
def test_partial(self):
|
|
partials = {'partial': "{{person}}"}
|
|
- self._assert_render(u'Hi Mom', 'Hi {{>partial}}', {'person': 'Mom'}, partials=partials)
|
|
+ self._assert_render('Hi Mom', 'Hi {{>partial}}', {'person': 'Mom'}, partials=partials)
|
|
|
|
def test_partial__context_values(self):
|
|
"""
|
|
@@ -406,7 +406,9 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
partials = {'partial': 'unescaped: {{{foo}}} escaped: {{foo}}'}
|
|
context = {'foo': '<'}
|
|
|
|
- self._assert_render(u'unescaped: < escaped: <', template, context, engine=engine, partials=partials)
|
|
+ self._assert_render(
|
|
+ 'unescaped: < escaped: <',
|
|
+ template, context, engine=engine, partials=partials)
|
|
|
|
## Test cases related specifically to lambdas.
|
|
|
|
@@ -417,8 +419,8 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
|
|
"""
|
|
template = '{{#nonascii}}{{.}}{{/nonascii}}'
|
|
- context = {'nonascii': u'abcdé'.encode('utf-8')}
|
|
- self._assert_render(u'abcdé', template, context)
|
|
+ context = {'nonascii': 'abcdé'.encode('utf-8')}
|
|
+ self._assert_render('abcdé', template, context)
|
|
|
|
# This test is also important for testing 2to3.
|
|
def test_lambda__returning_nonascii_nonunicode(self):
|
|
@@ -427,8 +429,8 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
|
|
"""
|
|
template = '{{lambda}}'
|
|
- context = {'lambda': lambda: u'abcdé'.encode('utf-8')}
|
|
- self._assert_render(u'abcdé', template, context)
|
|
+ context = {'lambda': lambda: 'abcdé'.encode('utf-8')}
|
|
+ self._assert_render('abcdé', template, context)
|
|
|
|
## Test cases related specifically to sections.
|
|
|
|
@@ -440,7 +442,7 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
template = '{{/section}}'
|
|
try:
|
|
self._assert_render(None, template)
|
|
- except ParsingError, err:
|
|
+ except ParsingError as err:
|
|
self.assertEqual(str(err), "Section end tag mismatch: section != None")
|
|
|
|
def test_section__end_tag_mismatch(self):
|
|
@@ -451,7 +453,7 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
template = '{{#section_start}}{{/section_end}}'
|
|
try:
|
|
self._assert_render(None, template)
|
|
- except ParsingError, err:
|
|
+ except ParsingError as err:
|
|
self.assertEqual(str(err), "Section end tag mismatch: section_end != section_start")
|
|
|
|
def test_section__context_values(self):
|
|
@@ -464,7 +466,7 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
template = '{{#test}}unescaped: {{{foo}}} escaped: {{foo}}{{/test}}'
|
|
context = {'test': {'foo': '<'}}
|
|
|
|
- self._assert_render(u'unescaped: < escaped: <', template, context, engine=engine)
|
|
+ self._assert_render('unescaped: < escaped: <', template, context, engine=engine)
|
|
|
|
def test_section__context_precedence(self):
|
|
"""
|
|
@@ -473,7 +475,7 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
"""
|
|
template = '{{entree}} : {{#vegetarian}}{{entree}}{{/vegetarian}}'
|
|
context = {'entree': 'chicken', 'vegetarian': {'entree': 'beans and rice'}}
|
|
- self._assert_render(u'chicken : beans and rice', template, context)
|
|
+ self._assert_render('chicken : beans and rice', template, context)
|
|
|
|
def test_section__list_referencing_outer_context(self):
|
|
"""
|
|
@@ -491,7 +493,7 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
|
|
template = "{{#list}}{{greeting}} {{name}}, {{/list}}"
|
|
|
|
- self._assert_render(u"Hi Al, Hi Bob, ", template, context)
|
|
+ self._assert_render("Hi Al, Hi Bob, ", template, context)
|
|
|
|
def test_section__output_not_interpolated(self):
|
|
"""
|
|
@@ -500,7 +502,7 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
"""
|
|
template = '{{#section}}{{template}}{{/section}}: {{planet}}'
|
|
context = {'section': True, 'template': '{{planet}}', 'planet': 'Earth'}
|
|
- self._assert_render(u'{{planet}}: Earth', template, context)
|
|
+ self._assert_render('{{planet}}: Earth', template, context)
|
|
|
|
# TODO: have this test case added to the spec.
|
|
def test_section__string_values_not_lists(self):
|
|
@@ -511,7 +513,7 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
template = '{{#section}}foo{{/section}}'
|
|
context = {'section': '123'}
|
|
# If strings were interpreted as lists, this would give "foofoofoo".
|
|
- self._assert_render(u'foo', template, context)
|
|
+ self._assert_render('foo', template, context)
|
|
|
|
def test_section__nested_truthy(self):
|
|
"""
|
|
@@ -525,7 +527,7 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
"""
|
|
template = '| A {{#bool}}B {{#bool}}C{{/bool}} D{{/bool}} E |'
|
|
context = {'bool': True}
|
|
- self._assert_render(u'| A B C D E |', template, context)
|
|
+ self._assert_render('| A B C D E |', template, context)
|
|
|
|
def test_section__nested_with_same_keys(self):
|
|
"""
|
|
@@ -537,16 +539,16 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
# Start with an easier, working case.
|
|
template = '{{#x}}{{#z}}{{y}}{{/z}}{{/x}}'
|
|
context = {'x': {'z': {'y': 1}}}
|
|
- self._assert_render(u'1', template, context)
|
|
+ self._assert_render('1', template, context)
|
|
|
|
template = '{{#x}}{{#x}}{{y}}{{/x}}{{/x}}'
|
|
context = {'x': {'x': {'y': 1}}}
|
|
- self._assert_render(u'1', template, context)
|
|
+ self._assert_render('1', template, context)
|
|
|
|
def test_section__lambda(self):
|
|
template = '{{#test}}Mom{{/test}}'
|
|
context = {'test': (lambda text: 'Hi %s' % text)}
|
|
- self._assert_render(u'Hi Mom', template, context)
|
|
+ self._assert_render('Hi Mom', template, context)
|
|
|
|
# This test is also important for testing 2to3.
|
|
def test_section__lambda__returning_nonascii_nonunicode(self):
|
|
@@ -555,8 +557,8 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
|
|
"""
|
|
template = '{{#lambda}}{{/lambda}}'
|
|
- context = {'lambda': lambda text: u'abcdé'.encode('utf-8')}
|
|
- self._assert_render(u'abcdé', template, context)
|
|
+ context = {'lambda': lambda text: 'abcdé'.encode('utf-8')}
|
|
+ self._assert_render('abcdé', template, context)
|
|
|
|
def test_section__lambda__returning_nonstring(self):
|
|
"""
|
|
@@ -565,7 +567,7 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
"""
|
|
template = '{{#lambda}}foo{{/lambda}}'
|
|
context = {'lambda': lambda text: len(text)}
|
|
- self._assert_render(u'3', template, context)
|
|
+ self._assert_render('3', template, context)
|
|
|
|
def test_section__iterable(self):
|
|
"""
|
|
@@ -575,10 +577,10 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
template = '{{#iterable}}{{.}}{{/iterable}}'
|
|
|
|
context = {'iterable': (i for i in range(3))} # type 'generator'
|
|
- self._assert_render(u'012', template, context)
|
|
+ self._assert_render('012', template, context)
|
|
|
|
- context = {'iterable': xrange(4)} # type 'xrange'
|
|
- self._assert_render(u'0123', template, context)
|
|
+ context = {'iterable': range(4)} # type 'xrange'
|
|
+ self._assert_render('0123', template, context)
|
|
|
|
d = {'foo': 0, 'bar': 0}
|
|
# We don't know what order of keys we'll be given, but from the
|
|
@@ -586,8 +588,8 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
# "If items(), keys(), values(), iteritems(), iterkeys(), and
|
|
# itervalues() are called with no intervening modifications to
|
|
# the dictionary, the lists will directly correspond."
|
|
- expected = u''.join(d.keys())
|
|
- context = {'iterable': d.iterkeys()} # type 'dictionary-keyiterator'
|
|
+ expected = ''.join(list(d.keys()))
|
|
+ context = {'iterable': iter(d.keys())} # type 'dictionary-keyiterator'
|
|
self._assert_render(expected, template, context)
|
|
|
|
def test_section__lambda__tag_in_output(self):
|
|
@@ -605,7 +607,7 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
"""
|
|
template = '{{#test}}Hi {{person}}{{/test}}'
|
|
context = {'person': 'Mom', 'test': (lambda text: text + " :)")}
|
|
- self._assert_render(u'Hi Mom :)', template, context)
|
|
+ self._assert_render('Hi Mom :)', template, context)
|
|
|
|
def test_section__lambda__list(self):
|
|
"""
|
|
@@ -621,7 +623,7 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
'lambdas': [lambda text: "~{{%s}}~" % text,
|
|
lambda text: "#{{%s}}#" % text]}
|
|
|
|
- self._assert_render(u'<~bar~#bar#>', template, context)
|
|
+ self._assert_render('<~bar~#bar#>', template, context)
|
|
|
|
def test_section__lambda__mixed_list(self):
|
|
"""
|
|
@@ -636,7 +638,7 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
context = {'foo': 'bar',
|
|
'lambdas': [lambda text: "~{{%s}}~" % text, 1]}
|
|
|
|
- self._assert_render(u'<~bar~foo>', template, context)
|
|
+ self._assert_render('<~bar~foo>', template, context)
|
|
|
|
def test_section__lambda__not_on_context_stack(self):
|
|
"""
|
|
@@ -653,7 +655,7 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
"""
|
|
context = {'foo': 'bar', 'lambda': (lambda text: "{{.}}")}
|
|
template = '{{#foo}}{{#lambda}}blah{{/lambda}}{{/foo}}'
|
|
- self._assert_render(u'bar', template, context)
|
|
+ self._assert_render('bar', template, context)
|
|
|
|
def test_section__lambda__no_reinterpolation(self):
|
|
"""
|
|
@@ -670,15 +672,15 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
"""
|
|
template = '{{#planet}}{{#lambda}}dot{{/lambda}}{{/planet}}'
|
|
context = {'planet': 'Earth', 'dot': '~{{.}}~', 'lambda': (lambda text: "#{{%s}}#" % text)}
|
|
- self._assert_render(u'#~{{.}}~#', template, context)
|
|
+ self._assert_render('#~{{.}}~#', template, context)
|
|
|
|
def test_comment__multiline(self):
|
|
"""
|
|
Check that multiline comments are permitted.
|
|
|
|
"""
|
|
- self._assert_render(u'foobar', 'foo{{! baz }}bar')
|
|
- self._assert_render(u'foobar', 'foo{{! \nbaz }}bar')
|
|
+ self._assert_render('foobar', 'foo{{! baz }}bar')
|
|
+ self._assert_render('foobar', 'foo{{! \nbaz }}bar')
|
|
|
|
def test_custom_delimiters__sections(self):
|
|
"""
|
|
@@ -689,7 +691,7 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
"""
|
|
template = '{{=[[ ]]=}}[[#foo]]bar[[/foo]]'
|
|
context = {'foo': True}
|
|
- self._assert_render(u'bar', template, context)
|
|
+ self._assert_render('bar', template, context)
|
|
|
|
def test_custom_delimiters__not_retroactive(self):
|
|
"""
|
|
@@ -698,7 +700,7 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
Test case for issue #35: https://github.com/defunkt/pystache/issues/35
|
|
|
|
"""
|
|
- expected = u' {{foo}} '
|
|
+ expected = ' {{foo}} '
|
|
self._assert_render(expected, '{{=$ $=}} {{foo}} ')
|
|
self._assert_render(expected, '{{=$ $=}} {{foo}} $={{ }}=$') # was yielding u' '.
|
|
|
|
@@ -713,7 +715,7 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
template = 'Hello, {{person.name}}. I see you are {{person.details.age}}.'
|
|
person = Attachable(name='Biggles', details={'age': 42})
|
|
context = {'person': person}
|
|
- self._assert_render(u'Hello, Biggles. I see you are 42.', template, context)
|
|
+ self._assert_render('Hello, Biggles. I see you are 42.', template, context)
|
|
|
|
def test_dot_notation__multiple_levels(self):
|
|
"""
|
|
@@ -722,7 +724,7 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
"""
|
|
template = """Hello, Mr. {{person.name.lastname}}.
|
|
I see you're back from {{person.travels.last.country.city}}."""
|
|
- expected = u"""Hello, Mr. Pither.
|
|
+ expected = """Hello, Mr. Pither.
|
|
I see you're back from Cornwall."""
|
|
context = {'person': {'name': {'firstname': 'unknown', 'lastname': 'Pither'},
|
|
'travels': {'last': {'country': {'city': 'Cornwall'}}},
|
|
@@ -758,10 +760,10 @@ class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
|
|
context = {'a': {'b': 'A.B'}, 'c': {'a': 'A'} }
|
|
|
|
template = '{{a.b}}'
|
|
- self._assert_render(u'A.B', template, context)
|
|
+ self._assert_render('A.B', template, context)
|
|
|
|
template = '{{#c}}{{a}}{{/c}}'
|
|
- self._assert_render(u'A', template, context)
|
|
+ self._assert_render('A', template, context)
|
|
|
|
template = '{{#c}}{{a.b}}{{/c}}'
|
|
self.assertException(KeyNotFoundError, "Key %(unicode)s'a.b' not found: missing %(unicode)s'b'" %
|
|
diff --git a/pystache/tests/test_renderer.py b/pystache/tests/test_renderer.py
|
|
index 0dbe0d9..e0d2448 100644
|
|
--- a/pystache/tests/test_renderer.py
|
|
+++ b/pystache/tests/test_renderer.py
|
|
@@ -10,7 +10,7 @@ import os
|
|
import sys
|
|
import unittest
|
|
|
|
-from examples.simple import Simple
|
|
+from .examples.simple import Simple
|
|
from pystache import Renderer
|
|
from pystache import TemplateSpec
|
|
from pystache.common import TemplateNotFoundError
|
|
@@ -33,7 +33,7 @@ def _make_renderer():
|
|
def mock_unicode(b, encoding=None):
|
|
if encoding is None:
|
|
encoding = 'ascii'
|
|
- u = unicode(b, encoding=encoding)
|
|
+ u = str(b, encoding=encoding)
|
|
return u.upper()
|
|
|
|
|
|
@@ -197,13 +197,13 @@ class RendererTests(unittest.TestCase, AssertStringMixin):
|
|
|
|
"""
|
|
renderer = self._renderer()
|
|
- b = u"é".encode('utf-8')
|
|
+ b = "é".encode('utf-8')
|
|
|
|
renderer.string_encoding = "ascii"
|
|
- self.assertRaises(UnicodeDecodeError, renderer.unicode, b)
|
|
+ self.assertRaises(UnicodeDecodeError, renderer.str, b)
|
|
|
|
renderer.string_encoding = "utf-8"
|
|
- self.assertEqual(renderer.unicode(b), u"é")
|
|
+ self.assertEqual(renderer.str(b), "é")
|
|
|
|
def test_unicode__decode_errors(self):
|
|
"""
|
|
@@ -212,14 +212,14 @@ class RendererTests(unittest.TestCase, AssertStringMixin):
|
|
"""
|
|
renderer = self._renderer()
|
|
renderer.string_encoding = "ascii"
|
|
- b = u"déf".encode('utf-8')
|
|
+ b = "déf".encode('utf-8')
|
|
|
|
renderer.decode_errors = "ignore"
|
|
- self.assertEqual(renderer.unicode(b), "df")
|
|
+ self.assertEqual(renderer.str(b), "df")
|
|
|
|
renderer.decode_errors = "replace"
|
|
# U+FFFD is the official Unicode replacement character.
|
|
- self.assertEqual(renderer.unicode(b), u'd\ufffd\ufffdf')
|
|
+ self.assertEqual(renderer.str(b), u'd\ufffd\ufffdf')
|
|
|
|
## Test the _make_loader() method.
|
|
|
|
@@ -243,7 +243,7 @@ class RendererTests(unittest.TestCase, AssertStringMixin):
|
|
renderer = self._renderer()
|
|
renderer.file_encoding = 'enc'
|
|
renderer.file_extension = 'ext'
|
|
- renderer.unicode = unicode_
|
|
+ renderer.str = unicode_
|
|
|
|
loader = renderer._make_loader()
|
|
|
|
@@ -260,12 +260,12 @@ class RendererTests(unittest.TestCase, AssertStringMixin):
|
|
"""
|
|
renderer = self._renderer()
|
|
rendered = renderer.render('foo')
|
|
- self.assertEqual(type(rendered), unicode)
|
|
+ self.assertEqual(type(rendered), str)
|
|
|
|
def test_render__unicode(self):
|
|
renderer = self._renderer()
|
|
- actual = renderer.render(u'foo')
|
|
- self.assertEqual(actual, u'foo')
|
|
+ actual = renderer.render('foo')
|
|
+ self.assertEqual(actual, 'foo')
|
|
|
|
def test_render__str(self):
|
|
renderer = self._renderer()
|
|
@@ -274,8 +274,8 @@ class RendererTests(unittest.TestCase, AssertStringMixin):
|
|
|
|
def test_render__non_ascii_character(self):
|
|
renderer = self._renderer()
|
|
- actual = renderer.render(u'Poincaré')
|
|
- self.assertEqual(actual, u'Poincaré')
|
|
+ actual = renderer.render('Poincaré')
|
|
+ self.assertEqual(actual, 'Poincaré')
|
|
|
|
def test_render__context(self):
|
|
"""
|
|
@@ -326,7 +326,7 @@ class RendererTests(unittest.TestCase, AssertStringMixin):
|
|
|
|
"""
|
|
renderer = _make_renderer()
|
|
- template = u"déf".encode("utf-8")
|
|
+ template = "déf".encode("utf-8")
|
|
|
|
# Check that decode_errors and string_encoding are both respected.
|
|
renderer.decode_errors = 'ignore'
|
|
@@ -334,7 +334,7 @@ class RendererTests(unittest.TestCase, AssertStringMixin):
|
|
self.assertEqual(renderer.render(template), "df")
|
|
|
|
renderer.string_encoding = 'utf_8'
|
|
- self.assertEqual(renderer.render(template), u"déf")
|
|
+ self.assertEqual(renderer.render(template), "déf")
|
|
|
|
def test_make_resolve_partial(self):
|
|
"""
|
|
@@ -347,7 +347,7 @@ class RendererTests(unittest.TestCase, AssertStringMixin):
|
|
|
|
actual = resolve_partial('foo')
|
|
self.assertEqual(actual, 'bar')
|
|
- self.assertEqual(type(actual), unicode, "RenderEngine requires that "
|
|
+ self.assertEqual(type(actual), str, "RenderEngine requires that "
|
|
"resolve_partial return unicode strings.")
|
|
|
|
def test_make_resolve_partial__unicode(self):
|
|
@@ -362,7 +362,7 @@ class RendererTests(unittest.TestCase, AssertStringMixin):
|
|
self.assertEqual(resolve_partial("partial"), "foo")
|
|
|
|
# Now with a value that is already unicode.
|
|
- renderer.partials = {'partial': u'foo'}
|
|
+ renderer.partials = {'partial': 'foo'}
|
|
resolve_partial = renderer._make_resolve_partial()
|
|
# If the next line failed, we would get the following error:
|
|
# TypeError: decoding Unicode is not supported
|
|
@@ -373,7 +373,7 @@ class RendererTests(unittest.TestCase, AssertStringMixin):
|
|
data_dir = get_data_path()
|
|
renderer = Renderer(search_dirs=data_dir)
|
|
actual = renderer.render_name("say_hello", to='foo')
|
|
- self.assertString(actual, u"Hello, foo")
|
|
+ self.assertString(actual, "Hello, foo")
|
|
|
|
def test_render_path(self):
|
|
"""
|
|
@@ -412,7 +412,7 @@ class RendererTests(unittest.TestCase, AssertStringMixin):
|
|
|
|
spec = Spec()
|
|
actual = renderer.render(spec)
|
|
- self.assertString(actual, u'hello, world')
|
|
+ self.assertString(actual, 'hello, world')
|
|
|
|
def test_render__view(self):
|
|
"""
|
|
@@ -484,7 +484,7 @@ class Renderer_MakeRenderEngineTests(unittest.TestCase, AssertStringMixin, Asser
|
|
Check that resolve_partial returns unicode (and not a subclass).
|
|
|
|
"""
|
|
- class MyUnicode(unicode):
|
|
+ class MyUnicode(str):
|
|
pass
|
|
|
|
renderer = Renderer()
|
|
@@ -495,12 +495,12 @@ class Renderer_MakeRenderEngineTests(unittest.TestCase, AssertStringMixin, Asser
|
|
|
|
actual = engine.resolve_partial('str')
|
|
self.assertEqual(actual, "foo")
|
|
- self.assertEqual(type(actual), unicode)
|
|
+ self.assertEqual(type(actual), str)
|
|
|
|
# Check that unicode subclasses are not preserved.
|
|
actual = engine.resolve_partial('subclass')
|
|
self.assertEqual(actual, "abc")
|
|
- self.assertEqual(type(actual), unicode)
|
|
+ self.assertEqual(type(actual), str)
|
|
|
|
def test__resolve_partial__not_found(self):
|
|
"""
|
|
@@ -512,7 +512,7 @@ class Renderer_MakeRenderEngineTests(unittest.TestCase, AssertStringMixin, Asser
|
|
engine = renderer._make_render_engine()
|
|
resolve_partial = engine.resolve_partial
|
|
|
|
- self.assertString(resolve_partial('foo'), u'')
|
|
+ self.assertString(resolve_partial('foo'), '')
|
|
|
|
def test__resolve_partial__not_found__missing_tags_strict(self):
|
|
"""
|
|
@@ -539,7 +539,7 @@ class Renderer_MakeRenderEngineTests(unittest.TestCase, AssertStringMixin, Asser
|
|
engine = renderer._make_render_engine()
|
|
resolve_partial = engine.resolve_partial
|
|
|
|
- self.assertString(resolve_partial('foo'), u'')
|
|
+ self.assertString(resolve_partial('foo'), '')
|
|
|
|
def test__resolve_partial__not_found__partials_dict__missing_tags_strict(self):
|
|
"""
|
|
@@ -566,12 +566,12 @@ class Renderer_MakeRenderEngineTests(unittest.TestCase, AssertStringMixin, Asser
|
|
|
|
"""
|
|
renderer = self._make_renderer()
|
|
- renderer.unicode = mock_unicode
|
|
+ renderer.str = mock_unicode
|
|
|
|
engine = renderer._make_render_engine()
|
|
literal = engine.literal
|
|
|
|
- b = u"foo".encode("ascii")
|
|
+ b = "foo".encode("ascii")
|
|
self.assertEqual(literal(b), "FOO")
|
|
|
|
def test__literal__handles_unicode(self):
|
|
@@ -585,7 +585,7 @@ class Renderer_MakeRenderEngineTests(unittest.TestCase, AssertStringMixin, Asser
|
|
engine = renderer._make_render_engine()
|
|
literal = engine.literal
|
|
|
|
- self.assertEqual(literal(u"foo"), "foo")
|
|
+ self.assertEqual(literal("foo"), "foo")
|
|
|
|
def test__literal__returns_unicode(self):
|
|
"""
|
|
@@ -598,16 +598,16 @@ class Renderer_MakeRenderEngineTests(unittest.TestCase, AssertStringMixin, Asser
|
|
engine = renderer._make_render_engine()
|
|
literal = engine.literal
|
|
|
|
- self.assertEqual(type(literal("foo")), unicode)
|
|
+ self.assertEqual(type(literal("foo")), str)
|
|
|
|
- class MyUnicode(unicode):
|
|
+ class MyUnicode(str):
|
|
pass
|
|
|
|
s = MyUnicode("abc")
|
|
|
|
self.assertEqual(type(s), MyUnicode)
|
|
- self.assertTrue(isinstance(s, unicode))
|
|
- self.assertEqual(type(literal(s)), unicode)
|
|
+ self.assertTrue(isinstance(s, str))
|
|
+ self.assertEqual(type(literal(s)), str)
|
|
|
|
## Test the engine's escape attribute.
|
|
|
|
@@ -630,12 +630,12 @@ class Renderer_MakeRenderEngineTests(unittest.TestCase, AssertStringMixin, Asser
|
|
|
|
"""
|
|
renderer = Renderer()
|
|
- renderer.unicode = mock_unicode
|
|
+ renderer.str = mock_unicode
|
|
|
|
engine = renderer._make_render_engine()
|
|
escape = engine.escape
|
|
|
|
- b = u"foo".encode('ascii')
|
|
+ b = "foo".encode('ascii')
|
|
self.assertEqual(escape(b), "FOO")
|
|
|
|
def test__escape__has_access_to_original_unicode_subclass(self):
|
|
@@ -644,16 +644,16 @@ class Renderer_MakeRenderEngineTests(unittest.TestCase, AssertStringMixin, Asser
|
|
|
|
"""
|
|
renderer = Renderer()
|
|
- renderer.escape = lambda s: unicode(type(s).__name__)
|
|
+ renderer.escape = lambda s: str(type(s).__name__)
|
|
|
|
engine = renderer._make_render_engine()
|
|
escape = engine.escape
|
|
|
|
- class MyUnicode(unicode):
|
|
+ class MyUnicode(str):
|
|
pass
|
|
|
|
- self.assertEqual(escape(u"foo".encode('ascii')), unicode.__name__)
|
|
- self.assertEqual(escape(u"foo"), unicode.__name__)
|
|
+ self.assertEqual(escape("foo".encode('ascii')), str.__name__)
|
|
+ self.assertEqual(escape("foo"), str.__name__)
|
|
self.assertEqual(escape(MyUnicode("foo")), MyUnicode.__name__)
|
|
|
|
def test__escape__returns_unicode(self):
|
|
@@ -667,17 +667,17 @@ class Renderer_MakeRenderEngineTests(unittest.TestCase, AssertStringMixin, Asser
|
|
engine = renderer._make_render_engine()
|
|
escape = engine.escape
|
|
|
|
- self.assertEqual(type(escape("foo")), unicode)
|
|
+ self.assertEqual(type(escape("foo")), str)
|
|
|
|
# Check that literal doesn't preserve unicode subclasses.
|
|
- class MyUnicode(unicode):
|
|
+ class MyUnicode(str):
|
|
pass
|
|
|
|
s = MyUnicode("abc")
|
|
|
|
self.assertEqual(type(s), MyUnicode)
|
|
- self.assertTrue(isinstance(s, unicode))
|
|
- self.assertEqual(type(escape(s)), unicode)
|
|
+ self.assertTrue(isinstance(s, str))
|
|
+ self.assertEqual(type(escape(s)), str)
|
|
|
|
## Test the missing_tags attribute.
|
|
|
|
@@ -706,7 +706,7 @@ class Renderer_MakeRenderEngineTests(unittest.TestCase, AssertStringMixin, Asser
|
|
stack = ContextStack({'foo': 'bar'})
|
|
|
|
self.assertEqual('bar', engine.resolve_context(stack, 'foo'))
|
|
- self.assertString(u'', engine.resolve_context(stack, 'missing'))
|
|
+ self.assertString('', engine.resolve_context(stack, 'missing'))
|
|
|
|
def test__resolve_context__missing_tags_strict(self):
|
|
"""
|
|
diff --git a/pystache/tests/test_simple.py b/pystache/tests/test_simple.py
|
|
index 07b059f..b88bf35 100644
|
|
--- a/pystache/tests/test_simple.py
|
|
+++ b/pystache/tests/test_simple.py
|
|
@@ -2,11 +2,11 @@ import unittest
|
|
|
|
import pystache
|
|
from pystache import Renderer
|
|
-from examples.nested_context import NestedContext
|
|
-from examples.complex import Complex
|
|
-from examples.lambdas import Lambdas
|
|
-from examples.template_partial import TemplatePartial
|
|
-from examples.simple import Simple
|
|
+from .examples.nested_context import NestedContext
|
|
+from .examples.complex import Complex
|
|
+from .examples.lambdas import Lambdas
|
|
+from .examples.template_partial import TemplatePartial
|
|
+from .examples.simple import Simple
|
|
|
|
from pystache.tests.common import EXAMPLES_DIR
|
|
from pystache.tests.common import AssertStringMixin
|
|
@@ -20,7 +20,7 @@ class TestSimple(unittest.TestCase, AssertStringMixin):
|
|
view.template = '{{#foo}}{{thing1}} and {{thing2}} and {{outer_thing}}{{/foo}}{{^foo}}Not foo!{{/foo}}'
|
|
|
|
actual = renderer.render(view)
|
|
- self.assertString(actual, u"one and foo and two")
|
|
+ self.assertString(actual, "one and foo and two")
|
|
|
|
def test_looping_and_negation_context(self):
|
|
template = '{{#item}}{{header}}: {{name}} {{/item}}{{^item}} Shouldnt see me{{/item}}'
|
|
@@ -40,7 +40,7 @@ class TestSimple(unittest.TestCase, AssertStringMixin):
|
|
|
|
renderer = Renderer()
|
|
actual = renderer.render(view)
|
|
- self.assertString(actual, u'bar != bar. oh, it does!')
|
|
+ self.assertString(actual, 'bar != bar. oh, it does!')
|
|
|
|
def test_rendering_partial(self):
|
|
renderer = Renderer(search_dirs=EXAMPLES_DIR)
|
|
@@ -49,11 +49,11 @@ class TestSimple(unittest.TestCase, AssertStringMixin):
|
|
view.template = '{{>inner_partial}}'
|
|
|
|
actual = renderer.render(view)
|
|
- self.assertString(actual, u'Again, Welcome!')
|
|
+ self.assertString(actual, 'Again, Welcome!')
|
|
|
|
view.template = '{{#looping}}{{>inner_partial}} {{/looping}}'
|
|
actual = renderer.render(view)
|
|
- self.assertString(actual, u"Again, Welcome! Again, Welcome! Again, Welcome! ")
|
|
+ self.assertString(actual, "Again, Welcome! Again, Welcome! Again, Welcome! ")
|
|
|
|
def test_non_existent_value_renders_blank(self):
|
|
view = Simple()
|
|
@@ -77,7 +77,7 @@ class TestSimple(unittest.TestCase, AssertStringMixin):
|
|
view = TemplatePartial(renderer=renderer)
|
|
|
|
actual = renderer.render(view)
|
|
- self.assertString(actual, u"""Welcome
|
|
+ self.assertString(actual, """Welcome
|
|
-------
|
|
|
|
## Again, Welcome! ##""")
|
|
diff --git a/pystache/tests/test_specloader.py b/pystache/tests/test_specloader.py
|
|
index cacc0fc..dcdc55f 100644
|
|
--- a/pystache/tests/test_specloader.py
|
|
+++ b/pystache/tests/test_specloader.py
|
|
@@ -9,11 +9,11 @@ import os.path
|
|
import sys
|
|
import unittest
|
|
|
|
-import examples
|
|
-from examples.simple import Simple
|
|
-from examples.complex import Complex
|
|
-from examples.lambdas import Lambdas
|
|
-from examples.inverted import Inverted, InvertedLists
|
|
+from . import examples
|
|
+from .examples.simple import Simple
|
|
+from .examples.complex import Complex
|
|
+from .examples.lambdas import Lambdas
|
|
+from .examples.inverted import Inverted, InvertedLists
|
|
from pystache import Renderer
|
|
from pystache import TemplateSpec
|
|
from pystache.common import TemplateNotFoundError
|
|
@@ -70,7 +70,7 @@ class ViewTestCase(unittest.TestCase, AssertStringMixin):
|
|
renderer2 = Renderer(search_dirs=EXAMPLES_DIR)
|
|
|
|
actual = renderer1.render(spec)
|
|
- self.assertString(actual, u"Partial: ")
|
|
+ self.assertString(actual, "Partial: ")
|
|
|
|
actual = renderer2.render(spec)
|
|
self.assertEqual(actual, "Partial: No tags...")
|
|
@@ -79,7 +79,7 @@ class ViewTestCase(unittest.TestCase, AssertStringMixin):
|
|
renderer = Renderer()
|
|
actual = renderer.render(Simple())
|
|
|
|
- self.assertString(actual, u"Hi pizza!")
|
|
+ self.assertString(actual, "Hi pizza!")
|
|
|
|
def test_non_callable_attributes(self):
|
|
view = Simple()
|
|
@@ -92,7 +92,7 @@ class ViewTestCase(unittest.TestCase, AssertStringMixin):
|
|
def test_complex(self):
|
|
renderer = Renderer()
|
|
actual = renderer.render(Complex())
|
|
- self.assertString(actual, u"""\
|
|
+ self.assertString(actual, """\
|
|
<h1>Colors</h1>
|
|
<ul>
|
|
<li><strong>red</strong></li>
|
|
@@ -111,7 +111,7 @@ class ViewTestCase(unittest.TestCase, AssertStringMixin):
|
|
|
|
renderer = Renderer()
|
|
actual = renderer.render(view)
|
|
- self.assertString(actual, u'nopqrstuvwxyz')
|
|
+ self.assertString(actual, 'nopqrstuvwxyz')
|
|
|
|
def test_higher_order_lambda(self):
|
|
view = Lambdas()
|
|
@@ -119,7 +119,7 @@ class ViewTestCase(unittest.TestCase, AssertStringMixin):
|
|
|
|
renderer = Renderer()
|
|
actual = renderer.render(view)
|
|
- self.assertString(actual, u'abcdefghijklmnopqrstuvwxyz')
|
|
+ self.assertString(actual, 'abcdefghijklmnopqrstuvwxyz')
|
|
|
|
def test_partials_with_lambda(self):
|
|
view = Lambdas()
|
|
@@ -127,7 +127,7 @@ class ViewTestCase(unittest.TestCase, AssertStringMixin):
|
|
|
|
renderer = Renderer(search_dirs=EXAMPLES_DIR)
|
|
actual = renderer.render(view)
|
|
- self.assertEqual(actual, u'nopqrstuvwxyz')
|
|
+ self.assertEqual(actual, 'nopqrstuvwxyz')
|
|
|
|
def test_hierarchical_partials_with_lambdas(self):
|
|
view = Lambdas()
|
|
@@ -135,12 +135,12 @@ class ViewTestCase(unittest.TestCase, AssertStringMixin):
|
|
|
|
renderer = Renderer(search_dirs=EXAMPLES_DIR)
|
|
actual = renderer.render(view)
|
|
- self.assertString(actual, u'nopqrstuvwxyznopqrstuvwxyz')
|
|
+ self.assertString(actual, 'nopqrstuvwxyznopqrstuvwxyz')
|
|
|
|
def test_inverted(self):
|
|
renderer = Renderer()
|
|
actual = renderer.render(Inverted())
|
|
- self.assertString(actual, u"""one, two, three, empty list""")
|
|
+ self.assertString(actual, """one, two, three, empty list""")
|
|
|
|
def test_accessing_properties_on_parent_object_from_child_objects(self):
|
|
parent = Thing()
|
|
@@ -152,12 +152,12 @@ class ViewTestCase(unittest.TestCase, AssertStringMixin):
|
|
renderer = Renderer()
|
|
actual = renderer.render(view, {'parent': parent})
|
|
|
|
- self.assertString(actual, u'derp')
|
|
+ self.assertString(actual, 'derp')
|
|
|
|
def test_inverted_lists(self):
|
|
renderer = Renderer()
|
|
actual = renderer.render(InvertedLists())
|
|
- self.assertString(actual, u"""one, two, three, empty list""")
|
|
+ self.assertString(actual, """one, two, three, empty list""")
|
|
|
|
|
|
def _make_specloader():
|
|
@@ -176,7 +176,7 @@ def _make_specloader():
|
|
"""
|
|
if encoding is None:
|
|
encoding = 'ascii'
|
|
- return unicode(s, encoding, 'strict')
|
|
+ return str(s, encoding, 'strict')
|
|
|
|
loader = Loader(file_encoding='ascii', to_unicode=to_unicode)
|
|
return SpecLoader(loader=loader)
|
|
@@ -222,7 +222,7 @@ class SpecLoaderTests(unittest.TestCase, AssertIsMixin, AssertStringMixin,
|
|
custom.template = "abc"
|
|
|
|
spec_loader = self._make_specloader()
|
|
- self._assert_template(spec_loader, custom, u"abc")
|
|
+ self._assert_template(spec_loader, custom, "abc")
|
|
|
|
def test_load__template__type_unicode(self):
|
|
"""
|
|
@@ -230,10 +230,10 @@ class SpecLoaderTests(unittest.TestCase, AssertIsMixin, AssertStringMixin,
|
|
|
|
"""
|
|
custom = TemplateSpec()
|
|
- custom.template = u"abc"
|
|
+ custom.template = "abc"
|
|
|
|
spec_loader = self._make_specloader()
|
|
- self._assert_template(spec_loader, custom, u"abc")
|
|
+ self._assert_template(spec_loader, custom, "abc")
|
|
|
|
def test_load__template__unicode_non_ascii(self):
|
|
"""
|
|
@@ -241,10 +241,10 @@ class SpecLoaderTests(unittest.TestCase, AssertIsMixin, AssertStringMixin,
|
|
|
|
"""
|
|
custom = TemplateSpec()
|
|
- custom.template = u"é"
|
|
+ custom.template = "é"
|
|
|
|
spec_loader = self._make_specloader()
|
|
- self._assert_template(spec_loader, custom, u"é")
|
|
+ self._assert_template(spec_loader, custom, "é")
|
|
|
|
def test_load__template__with_template_encoding(self):
|
|
"""
|
|
@@ -252,14 +252,14 @@ class SpecLoaderTests(unittest.TestCase, AssertIsMixin, AssertStringMixin,
|
|
|
|
"""
|
|
custom = TemplateSpec()
|
|
- custom.template = u'é'.encode('utf-8')
|
|
+ custom.template = 'é'.encode('utf-8')
|
|
|
|
spec_loader = self._make_specloader()
|
|
|
|
- self.assertRaises(UnicodeDecodeError, self._assert_template, spec_loader, custom, u'é')
|
|
+ self.assertRaises(UnicodeDecodeError, self._assert_template, spec_loader, custom, 'é')
|
|
|
|
custom.template_encoding = 'utf-8'
|
|
- self._assert_template(spec_loader, custom, u'é')
|
|
+ self._assert_template(spec_loader, custom, 'é')
|
|
|
|
# TODO: make this test complete.
|
|
def test_load__template__correct_loader(self):
|
|
@@ -279,10 +279,10 @@ class SpecLoaderTests(unittest.TestCase, AssertIsMixin, AssertStringMixin,
|
|
self.encoding = None
|
|
|
|
# Overrides the existing method.
|
|
- def unicode(self, s, encoding=None):
|
|
+ def str(self, s, encoding=None):
|
|
self.s = s
|
|
self.encoding = encoding
|
|
- return u"foo"
|
|
+ return "foo"
|
|
|
|
loader = MockLoader()
|
|
custom_loader = SpecLoader()
|
|
@@ -293,7 +293,7 @@ class SpecLoaderTests(unittest.TestCase, AssertIsMixin, AssertStringMixin,
|
|
view.template_encoding = "encoding-foo"
|
|
|
|
# Check that our unicode() above was called.
|
|
- self._assert_template(custom_loader, view, u'foo')
|
|
+ self._assert_template(custom_loader, view, 'foo')
|
|
self.assertEqual(loader.s, "template-foo")
|
|
self.assertEqual(loader.encoding, "encoding-foo")
|
|
|
|
@@ -410,7 +410,7 @@ class TemplateSpecTests(unittest.TestCase, AssertPathsMixin):
|
|
loader = self._make_loader()
|
|
actual = loader.load(custom)
|
|
|
|
- self.assertEqual(type(actual), unicode)
|
|
+ self.assertEqual(type(actual), str)
|
|
self.assertEqual(actual, expected)
|
|
|
|
def test_get_template(self):
|
|
@@ -420,7 +420,7 @@ class TemplateSpecTests(unittest.TestCase, AssertPathsMixin):
|
|
"""
|
|
view = SampleView()
|
|
|
|
- self._assert_get_template(view, u"ascii: abc")
|
|
+ self._assert_get_template(view, "ascii: abc")
|
|
|
|
def test_get_template__template_encoding(self):
|
|
"""
|
|
@@ -432,4 +432,4 @@ class TemplateSpecTests(unittest.TestCase, AssertPathsMixin):
|
|
self.assertRaises(UnicodeDecodeError, self._assert_get_template, view, 'foo')
|
|
|
|
view.template_encoding = 'utf-8'
|
|
- self._assert_get_template(view, u"non-ascii: é")
|
|
+ self._assert_get_template(view, "non-ascii: é")
|
|
diff --git a/setup.cfg b/setup.cfg
|
|
index 861a9f5..f6f1279 100644
|
|
--- a/setup.cfg
|
|
+++ b/setup.cfg
|
|
@@ -1,5 +1,71 @@
|
|
-[egg_info]
|
|
-tag_build =
|
|
-tag_date = 0
|
|
-tag_svn_revision = 0
|
|
+[metadata]
|
|
+name = pystache
|
|
+version = attr: pystache.__version__
|
|
+author = Chris Wanstrath
|
|
+author_email = chris@ozmm.org
|
|
+maintainer = Steve Arnold
|
|
+maintainer_email = nerdboy@gentoo.org
|
|
+description = Mustache for Python
|
|
+url = https://github.com/sarnold/pystache
|
|
+license = MIT
|
|
+license_files = LICENSE
|
|
+classifiers =
|
|
+ Development Status :: 4 - Beta
|
|
+ Intended Audience :: Developers
|
|
+ License :: OSI Approved :: MIT License
|
|
+ Programming Language :: Python :: 3
|
|
+ Programming Language :: Python :: 3.6
|
|
+ Programming Language :: Python :: 3.7
|
|
+ Programming Language :: Python :: 3.8
|
|
+ Programming Language :: Python :: 3.9
|
|
|
|
+[options]
|
|
+python_requires = >=3.6
|
|
+zip_safe = True
|
|
+include_package_data = True
|
|
+packages = find:
|
|
+
|
|
+[options.package_data]
|
|
+* = *.mustache, *.txt
|
|
+
|
|
+[options.entry_points]
|
|
+console_scripts =
|
|
+ pystache=pystache.commands.render:main
|
|
+ pystache-test=pystache.commands.test:main
|
|
+
|
|
+[options.extras_require]
|
|
+test =
|
|
+ nose
|
|
+
|
|
+cov =
|
|
+ coverage
|
|
+
|
|
+[bdist_wheel]
|
|
+universal = 0
|
|
+
|
|
+[check-manifest]
|
|
+ignore =
|
|
+ .codeclimate.yml
|
|
+ .gitattributes
|
|
+ .coveragerc
|
|
+ .gitignore
|
|
+ .pep8speaks.yml
|
|
+ codecov.yml
|
|
+
|
|
+[flake8]
|
|
+exclude =
|
|
+ .git,
|
|
+ __pycache__,
|
|
+ build,
|
|
+ dist
|
|
+
|
|
+max-line-length = 110
|
|
+
|
|
+[nosetests]
|
|
+traverse-namespace = 1
|
|
+verbosity = 3
|
|
+with-coverage = 1
|
|
+with-doctest = 1
|
|
+doctest-extension = rst
|
|
+cover-package = pystache
|
|
+cover-xml = 1
|
|
diff --git a/setup.py b/setup.py
|
|
index 0d99aae..f0b7d7f 100644
|
|
--- a/setup.py
|
|
+++ b/setup.py
|
|
@@ -28,7 +28,7 @@ it on the PyPI project page. If PyPI finds any issues, it will render it
|
|
instead as plain-text, which we do not want.
|
|
|
|
To check in advance that PyPI will accept and parse the reST file as HTML,
|
|
-you can use the rst2html program installed by the docutils package
|
|
+you can use the rst2html.py program installed by the docutils package
|
|
(http://docutils.sourceforge.net/). To install docutils:
|
|
|
|
$ pip install docutils
|
|
@@ -89,30 +89,7 @@ import os
|
|
import shutil
|
|
import sys
|
|
|
|
-
|
|
-py_version = sys.version_info
|
|
-
|
|
-# distutils does not seem to support the following setup() arguments.
|
|
-# It displays a UserWarning when setup() is passed those options:
|
|
-#
|
|
-# * entry_points
|
|
-# * install_requires
|
|
-#
|
|
-# distribute works with Python 2.3.5 and above:
|
|
-#
|
|
-# http://packages.python.org/distribute/setuptools.html#building-and-distributing-packages-with-distribute
|
|
-#
|
|
-if py_version < (2, 3, 5):
|
|
- # TODO: this might not work yet.
|
|
- import distutils as dist
|
|
- from distutils import core
|
|
- setup = core.setup
|
|
-else:
|
|
- import setuptools as dist
|
|
- setup = dist.setup
|
|
-
|
|
-
|
|
-VERSION = '0.5.4' # Also change in pystache/__init__.py.
|
|
+from setuptools import setup
|
|
|
|
FILE_ENCODING = 'utf-8'
|
|
|
|
@@ -126,22 +103,6 @@ TEMP_EXTENSION = '.temp'
|
|
|
|
PREP_COMMAND = 'prep'
|
|
|
|
-CLASSIFIERS = (
|
|
- 'Development Status :: 4 - Beta',
|
|
- 'License :: OSI Approved :: MIT License',
|
|
- 'Programming Language :: Python',
|
|
- 'Programming Language :: Python :: 2',
|
|
- 'Programming Language :: Python :: 2.4',
|
|
- 'Programming Language :: Python :: 2.5',
|
|
- 'Programming Language :: Python :: 2.6',
|
|
- 'Programming Language :: Python :: 2.7',
|
|
- 'Programming Language :: Python :: 3',
|
|
- 'Programming Language :: Python :: 3.1',
|
|
- 'Programming Language :: Python :: 3.2',
|
|
- 'Programming Language :: Python :: 3.3',
|
|
- 'Programming Language :: Python :: Implementation :: PyPy',
|
|
-)
|
|
-
|
|
# Comments in reST begin with two dots.
|
|
RST_LONG_DESCRIPTION_INTRO = """\
|
|
.. Do not edit this file. This file is auto-generated for PyPI by setup.py
|
|
@@ -221,7 +182,7 @@ def convert_md_to_rst(md_path, rst_temp_path):
|
|
|
|
"""
|
|
# Pandoc uses the UTF-8 character encoding for both input and output.
|
|
- command = "pandoc --write=rst --output=%s %s" % (rst_temp_path, md_path)
|
|
+ command = "pandoc -f markdown-smart --write=rst --output=%s %s" % (rst_temp_path, md_path)
|
|
print("converting with pandoc: %s to %s\n-->%s" % (md_path, rst_temp_path,
|
|
command))
|
|
|
|
@@ -308,65 +269,9 @@ Run the following command and commit the changes--
|
|
os.system('python setup.py sdist upload')
|
|
|
|
|
|
-# We use the package simplejson for older Python versions since Python
|
|
-# does not contain the module json before 2.6:
|
|
-#
|
|
-# http://docs.python.org/library/json.html
|
|
-#
|
|
-# Moreover, simplejson stopped officially support for Python 2.4 in version 2.1.0:
|
|
-#
|
|
-# https://github.com/simplejson/simplejson/blob/master/CHANGES.txt
|
|
-#
|
|
-requires = []
|
|
-if py_version < (2, 5):
|
|
- requires.append('simplejson<2.1')
|
|
-elif py_version < (2, 6):
|
|
- requires.append('simplejson')
|
|
-
|
|
-INSTALL_REQUIRES = requires
|
|
-
|
|
-# TODO: decide whether to use find_packages() instead. I'm not sure that
|
|
-# find_packages() is available with distutils, for example.
|
|
-PACKAGES = [
|
|
- 'pystache',
|
|
- 'pystache.commands',
|
|
- # The following packages are only for testing.
|
|
- 'pystache.tests',
|
|
- 'pystache.tests.data',
|
|
- 'pystache.tests.data.locator',
|
|
- 'pystache.tests.examples',
|
|
-]
|
|
-
|
|
-
|
|
-# The purpose of this function is to follow the guidance suggested here:
|
|
-#
|
|
-# http://packages.python.org/distribute/python3.html#note-on-compatibility-with-setuptools
|
|
-#
|
|
-# The guidance is for better compatibility when using setuptools (e.g. with
|
|
-# earlier versions of Python 2) instead of Distribute, because of new
|
|
-# keyword arguments to setup() that setuptools may not recognize.
|
|
-def get_extra_args():
|
|
- """
|
|
- Return a dictionary of extra args to pass to setup().
|
|
-
|
|
- """
|
|
- extra = {}
|
|
- # TODO: it might be more correct to check whether we are using
|
|
- # Distribute instead of setuptools, since use_2to3 doesn't take
|
|
- # effect when using Python 2, even when using Distribute.
|
|
- if py_version >= (3, ):
|
|
- # Causes 2to3 to be run during the build step.
|
|
- extra['use_2to3'] = True
|
|
-
|
|
- return extra
|
|
-
|
|
-
|
|
def main(sys_argv):
|
|
|
|
# TODO: use the logging module instead of printing.
|
|
- # TODO: include the following in a verbose mode.
|
|
- sys.stderr.write("pystache: using: version %s of %s\n" % (repr(dist.__version__), repr(dist)))
|
|
-
|
|
command = sys_argv[-1]
|
|
|
|
if command == 'publish':
|
|
@@ -377,35 +282,10 @@ def main(sys_argv):
|
|
sys.exit()
|
|
|
|
long_description = read(RST_DESCRIPTION_PATH)
|
|
- template_files = ['*.mustache', '*.txt']
|
|
- extra_args = get_extra_args()
|
|
-
|
|
- setup(name='pystache',
|
|
- version=VERSION,
|
|
- license='MIT',
|
|
- description='Mustache for Python',
|
|
- long_description=long_description,
|
|
- author='Chris Wanstrath',
|
|
- author_email='chris@ozmm.org',
|
|
- maintainer='Chris Jerdonek',
|
|
- maintainer_email='chris.jerdonek@gmail.com',
|
|
- url='http://github.com/defunkt/pystache',
|
|
- install_requires=INSTALL_REQUIRES,
|
|
- packages=PACKAGES,
|
|
- package_data = {
|
|
- # Include template files so tests can be run.
|
|
- 'pystache.tests.data': template_files,
|
|
- 'pystache.tests.data.locator': template_files,
|
|
- 'pystache.tests.examples': template_files,
|
|
- },
|
|
- entry_points = {
|
|
- 'console_scripts': [
|
|
- 'pystache=pystache.commands.render:main',
|
|
- 'pystache-test=pystache.commands.test:main',
|
|
- ],
|
|
- },
|
|
- classifiers = CLASSIFIERS,
|
|
- **extra_args
|
|
+
|
|
+ setup(
|
|
+ long_description=long_description,
|
|
+ long_description_content_type='text/x-rst',
|
|
)
|
|
|
|
|
|
diff --git a/setup_description.rst b/setup_description.rst
|
|
index 724c457..d7f1bc0 100644
|
|
--- a/setup_description.rst
|
|
+++ b/setup_description.rst
|
|
@@ -4,13 +4,17 @@
|
|
Pystache
|
|
========
|
|
|
|
-.. figure:: http://defunkt.github.com/pystache/images/logo_phillips.png
|
|
- :alt: mustachioed, monocled snake by David Phillips
|
|
+|ci| |Conda| |Wheels| |Release| |Python|
|
|
|
|
-.. figure:: https://secure.travis-ci.org/defunkt/pystache.png
|
|
- :alt: Travis CI current build status
|
|
+|Latest release| |License| |Maintainability| |codecov|
|
|
|
|
-`Pystache <http://defunkt.github.com/pystache>`__ is a Python
|
|
+This updated fork of Pystache is currently tested on Python 3.6+ and in
|
|
+Conda, on Linux, Macos, and Windows (Python 2.7 support has been
|
|
+removed).
|
|
+
|
|
+|image9|
|
|
+
|
|
+`Pystache <http://sarnold.github.com/pystache>`__ is a Python
|
|
implementation of `Mustache <http://mustache.github.com/>`__. Mustache
|
|
is a framework-agnostic, logic-free templating system inspired by
|
|
`ctemplate <http://code.google.com/p/google-ctemplate/>`__ and
|
|
@@ -23,62 +27,45 @@ page provides a good introduction to Mustache's syntax. For a more
|
|
complete (and more current) description of Mustache's behavior, see the
|
|
official `Mustache spec <https://github.com/mustache/spec>`__.
|
|
|
|
-Pystache is `semantically versioned <http://semver.org>`__ and can be
|
|
-found on `PyPI <http://pypi.python.org/pypi/pystache>`__. This version
|
|
-of Pystache passes all tests in `version
|
|
-1.1.2 <https://github.com/mustache/spec/tree/v1.1.2>`__ of the spec.
|
|
+Pystache is `semantically versioned <http://semver.org>`__ and older
|
|
+versions can still be found on
|
|
+`PyPI <http://pypi.python.org/pypi/pystache>`__. This version of
|
|
+Pystache now passes all tests in `version
|
|
+1.1.3 <https://github.com/mustache/spec/tree/v1.1.3>`__ of the spec.
|
|
|
|
Requirements
|
|
------------
|
|
|
|
Pystache is tested with--
|
|
|
|
-- Python 2.4 (requires simplejson `version
|
|
- 2.0.9 <http://pypi.python.org/pypi/simplejson/2.0.9>`__ or earlier)
|
|
-- Python 2.5 (requires
|
|
- `simplejson <http://pypi.python.org/pypi/simplejson/>`__)
|
|
-- Python 2.6
|
|
-- Python 2.7
|
|
-- Python 3.1
|
|
-- Python 3.2
|
|
-- Python 3.3
|
|
-- `PyPy <http://pypy.org/>`__
|
|
+- Python 3.6
|
|
+- Python 3.7
|
|
+- Python 3.8
|
|
+- Python 3.9
|
|
+- Conda (py36-py39)
|
|
|
|
`Distribute <http://packages.python.org/distribute/>`__ (the setuptools
|
|
-fork) is recommended over
|
|
-`setuptools <http://pypi.python.org/pypi/setuptools>`__, and is required
|
|
-in some cases (e.g. for Python 3 support). If you use
|
|
-`pip <http://www.pip-installer.org/>`__, you probably already satisfy
|
|
-this requirement.
|
|
+fork) is no longer required over
|
|
+`setuptools <http://pypi.python.org/pypi/setuptools>`__, as the current
|
|
+packaging is now PEP517-compliant.
|
|
|
|
JSON support is needed only for the command-line interface and to run
|
|
-the spec tests. We require simplejson for earlier versions of Python
|
|
-since Python's `json <http://docs.python.org/library/json.html>`__
|
|
-module was added in Python 2.6.
|
|
-
|
|
-For Python 2.4 we require an earlier version of simplejson since
|
|
-simplejson stopped officially supporting Python 2.4 in simplejson
|
|
-version 2.1.0. Earlier versions of simplejson can be installed manually,
|
|
-as follows:
|
|
-
|
|
-::
|
|
-
|
|
- pip install 'simplejson<2.1.0'
|
|
+the spec tests; PyYAML can still be used (see the Develop section).
|
|
|
|
-Official support for Python 2.4 will end with Pystache version 0.6.0.
|
|
+Official support for Python 2 will end with Pystache version 0.6.0.
|
|
|
|
Install It
|
|
----------
|
|
|
|
::
|
|
|
|
- pip install pystache
|
|
+ pip install -U pystache -f https://github.com/sarnold/pystache/releases/
|
|
|
|
And test it--
|
|
|
|
::
|
|
|
|
- pystache-test
|
|
+ pystache-test
|
|
|
|
To install and test from source (e.g. from GitHub), see the Develop
|
|
section.
|
|
@@ -88,68 +75,68 @@ Use It
|
|
|
|
::
|
|
|
|
- >>> import pystache
|
|
- >>> print pystache.render('Hi {{person}}!', {'person': 'Mom'})
|
|
- Hi Mom!
|
|
+ >>> import pystache
|
|
+ >>> print(pystache.render('Hi {{person}}!', {'person': 'Mom'}))
|
|
+ Hi Mom!
|
|
|
|
You can also create dedicated view classes to hold your view logic.
|
|
|
|
-Here's your view class (in .../examples/readme.py):
|
|
+Here's your view class (in ../pystache/tests/examples/readme.py):
|
|
|
|
::
|
|
|
|
- class SayHello(object):
|
|
- def to(self):
|
|
- return "Pizza"
|
|
+ class SayHello(object):
|
|
+ def to(self):
|
|
+ return "Pizza"
|
|
|
|
Instantiating like so:
|
|
|
|
::
|
|
|
|
- >>> from pystache.tests.examples.readme import SayHello
|
|
- >>> hello = SayHello()
|
|
+ >>> from pystache.tests.examples.readme import SayHello
|
|
+ >>> hello = SayHello()
|
|
|
|
-Then your template, say\_hello.mustache (by default in the same
|
|
-directory as your class definition):
|
|
+Then your template, say_hello.mustache (by default in the same directory
|
|
+as your class definition):
|
|
|
|
::
|
|
|
|
- Hello, {{to}}!
|
|
+ Hello, {{to}}!
|
|
|
|
Pull it together:
|
|
|
|
::
|
|
|
|
- >>> renderer = pystache.Renderer()
|
|
- >>> print renderer.render(hello)
|
|
- Hello, Pizza!
|
|
+ >>> renderer = pystache.Renderer()
|
|
+ >>> print(renderer.render(hello))
|
|
+ Hello, Pizza!
|
|
|
|
For greater control over rendering (e.g. to specify a custom template
|
|
directory), use the ``Renderer`` class like above. One can pass
|
|
attributes to the Renderer class constructor or set them on a Renderer
|
|
instance. To customize template loading on a per-view basis, subclass
|
|
``TemplateSpec``. See the docstrings of the
|
|
-`Renderer <https://github.com/defunkt/pystache/blob/master/pystache/renderer.py>`__
|
|
+`Renderer <https://github.com/sarnold/pystache/blob/master/pystache/renderer.py>`__
|
|
class and
|
|
-`TemplateSpec <https://github.com/defunkt/pystache/blob/master/pystache/template_spec.py>`__
|
|
+`TemplateSpec <https://github.com/sarnold/pystache/blob/master/pystache/template_spec.py>`__
|
|
class for more information.
|
|
|
|
You can also pre-parse a template:
|
|
|
|
::
|
|
|
|
- >>> parsed = pystache.parse(u"Hey {{#who}}{{.}}!{{/who}}")
|
|
- >>> print parsed
|
|
- [u'Hey ', _SectionNode(key=u'who', index_begin=12, index_end=18, parsed=[_EscapeNode(key=u'.'), u'!'])]
|
|
+ >>> parsed = pystache.parse(u"Hey {{#who}}{{.}}!{{/who}}")
|
|
+ >>> print(parsed)
|
|
+ ['Hey ', _SectionNode(key='who', index_begin=12, index_end=18, parsed=[_EscapeNode(key='.'), '!'])]
|
|
|
|
And then:
|
|
|
|
::
|
|
|
|
- >>> print renderer.render(parsed, {'who': 'Pops'})
|
|
- Hey Pops!
|
|
- >>> print renderer.render(parsed, {'who': 'you'})
|
|
- Hey you!
|
|
+ >>> print(renderer.render(parsed, {'who': 'Pops'}))
|
|
+ Hey Pops!
|
|
+ >>> print(renderer.render(parsed, {'who': 'you'}))
|
|
+ Hey you!
|
|
|
|
Python 3
|
|
--------
|
|
@@ -211,22 +198,24 @@ To test from a source distribution (without installing)--
|
|
|
|
::
|
|
|
|
- python test_pystache.py
|
|
+ python test_pystache.py
|
|
|
|
To test Pystache with multiple versions of Python (with a single
|
|
-command!), you can use `tox <http://pypi.python.org/pypi/tox>`__:
|
|
+command!) and different platforms, you can use
|
|
+`tox <http://pypi.python.org/pypi/tox>`__:
|
|
|
|
::
|
|
|
|
- pip install 'virtualenv<1.8' # Version 1.8 dropped support for Python 2.4.
|
|
- pip install 'tox<1.4' # Version 1.4 dropped support for Python 2.4.
|
|
- tox
|
|
+ pip install tox
|
|
+ tox -e setup
|
|
|
|
-If you do not have all Python versions listed in ``tox.ini``--
|
|
+To run tests on multiple versions with coverage, run:
|
|
|
|
::
|
|
|
|
- tox -e py26,py32 # for example
|
|
+ tox -e py38-linux,py39-linux # for example
|
|
+
|
|
+(substitute your platform above, eg, macos or windows)
|
|
|
|
The source distribution tests also include doctests and tests from the
|
|
Mustache spec. To include tests from the Mustache spec in your test
|
|
@@ -234,8 +223,8 @@ runs:
|
|
|
|
::
|
|
|
|
- git submodule init
|
|
- git submodule update
|
|
+ git submodule init
|
|
+ git submodule update
|
|
|
|
The test harness parses the spec's (more human-readable) yaml files if
|
|
`PyYAML <http://pypi.python.org/pypi/PyYAML>`__ is present. Otherwise,
|
|
@@ -243,94 +232,113 @@ it parses the json files. To install PyYAML--
|
|
|
|
::
|
|
|
|
- pip install pyyaml
|
|
+ pip install pyyaml
|
|
+
|
|
+Once the submodule is available, you can run the full test set with:
|
|
+
|
|
+::
|
|
+
|
|
+ tox -e setup . ext/spec/specs
|
|
|
|
To run a subset of the tests, you can use
|
|
`nose <http://somethingaboutorange.com/mrl/projects/nose/0.11.1/testing.html>`__:
|
|
|
|
::
|
|
|
|
- pip install nose
|
|
- nosetests --tests pystache/tests/test_context.py:GetValueTests.test_dictionary__key_present
|
|
+ pip install nose
|
|
+ nosetests --tests pystache/tests/test_context.py:GetValueTests.test_dictionary__key_present
|
|
|
|
-Using Python 3 with Pystache from source
|
|
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
+Mailing List (old)
|
|
+------------------
|
|
|
|
-Pystache is written in Python 2 and must be converted to Python 3 prior
|
|
-to using it with Python 3. The installation process (and tox) do this
|
|
-automatically.
|
|
+There is(was) a `mailing
|
|
+list <http://librelist.com/browser/pystache/>`__. Note that there is a
|
|
+bit of a delay between posting a message and seeing it appear in the
|
|
+mailing list archive.
|
|
|
|
-To convert the code to Python 3 manually (while using Python 3)--
|
|
+Credits
|
|
+-------
|
|
|
|
::
|
|
|
|
- python setup.py build
|
|
+ >>> import pystache
|
|
+ >>> context = { 'author': 'Chris Wanstrath', 'maintainer': 'Chris Jerdonek','refurbisher': 'Steve Arnold' }
|
|
+ >>> print(pystache.render("Author: {{author}}\nMaintainer: {{maintainer}}\nRefurbisher: {{refurbisher}}", context))
|
|
+ Author: Chris Wanstrath
|
|
+ Maintainer: Chris Jerdonek
|
|
+ Refurbisher: Steve Arnold
|
|
|
|
-This writes the converted code to a subdirectory called ``build``. By
|
|
-design, Python 3 builds
|
|
-`cannot <https://bitbucket.org/tarek/distribute/issue/292/allow-use_2to3-with-python-2>`__
|
|
-be created from Python 2.
|
|
+Pystache logo by `David Phillips <http://davidphillips.us/>`__ is
|
|
+licensed under a `Creative Commons Attribution-ShareAlike 3.0 Unported
|
|
+License <http://creativecommons.org/licenses/by-sa/3.0/deed.en_US>`__.
|
|
+|image10|
|
|
|
|
-To convert the code without using setup.py, you can use
|
|
-`2to3 <http://docs.python.org/library/2to3.html>`__ as follows (two
|
|
-steps)--
|
|
+History
|
|
+=======
|
|
|
|
-::
|
|
+**Note:** Official support for Python 2.7 will end with Pystache version
|
|
+0.6.0.
|
|
|
|
- 2to3 --write --nobackups --no-diffs --doctests_only pystache
|
|
- 2to3 --write --nobackups --no-diffs pystache
|
|
+0.6.0 (2021-03-04)
|
|
+------------------
|
|
|
|
-This converts the code (and doctests) in place.
|
|
+- Bump spec versions to latest => v1.1.3
|
|
+- Modernize python and CI tools, update docs/doctests
|
|
+- Update unicode conversion test for py3-only
|
|
+- Add pep8speaks cfg, cleanup warnings
|
|
+- Remove superfluous setup test/unused imports
|
|
+- Add conda recipe/CI build
|
|
|
|
-To ``import pystache`` from a source distribution while using Python 3,
|
|
-be sure that you are importing from a directory containing a converted
|
|
-version of the code (e.g. from the ``build`` directory after
|
|
-converting), and not from the original (unconverted) source directory.
|
|
-Otherwise, you will get a syntax error. You can help prevent this by not
|
|
-running the Python IDE from the project directory when importing
|
|
-Pystache while using Python 3.
|
|
+.. _section-1:
|
|
|
|
-Mailing List
|
|
-------------
|
|
+0.5.6 (2021-02-28)
|
|
+------------------
|
|
|
|
-There is a `mailing list <http://librelist.com/browser/pystache/>`__.
|
|
-Note that there is a bit of a delay between posting a message and seeing
|
|
-it appear in the mailing list archive.
|
|
+- Use correct wheel name in release workflow, limit wheels
|
|
+- Add install check/test of downloaded wheel
|
|
+- Update/add ci workflows and tox cfg, bump to next dev0 version
|
|
|
|
-Credits
|
|
--------
|
|
+.. _section-2:
|
|
|
|
-::
|
|
+0.5.5 (2020-12-16)
|
|
+------------------
|
|
|
|
- >>> context = { 'author': 'Chris Wanstrath', 'maintainer': 'Chris Jerdonek' }
|
|
- >>> print pystache.render("Author: {{author}}\nMaintainer: {{maintainer}}", context)
|
|
- Author: Chris Wanstrath
|
|
- Maintainer: Chris Jerdonek
|
|
+- fix document processing, update pandoc args and history
|
|
+- add release.yml to CI, test env settings
|
|
+- fix bogus commit message, update versions and tox cf
|
|
+- add post-test steps for building pkgs with/without doc updates
|
|
+- add CI build check, fix MANIFEST.in pruning
|
|
|
|
-Pystache logo by `David Phillips <http://davidphillips.us/>`__ is
|
|
-licensed under a `Creative Commons Attribution-ShareAlike 3.0 Unported
|
|
-License <http://creativecommons.org/licenses/by-sa/3.0/deed.en_US>`__.
|
|
-|image0|
|
|
+.. _section-3:
|
|
|
|
-History
|
|
-=======
|
|
+0.5.4-2 (2020-11-09)
|
|
+--------------------
|
|
|
|
-**Note:** Official support for Python 2.4 will end with Pystache version
|
|
-0.6.0.
|
|
+- Merge pull request #1 from sarnold/rebase-up
|
|
+- Bugfix: test_specloader.py: fix test_find__with_directory on other
|
|
+ OSs
|
|
+- Bugfix: pystache/loader.py: remove stray windows line-endings
|
|
+- fix crufty (and insecure) http urls
|
|
+- Bugfix: modernize python versions (keep py27) and fix spec_test load
|
|
+ cmd
|
|
+
|
|
+.. _section-4:
|
|
|
|
0.5.4 (2014-07-11)
|
|
------------------
|
|
|
|
- Bugfix: made test with filenames OS agnostic (issue #162).
|
|
|
|
+.. _section-5:
|
|
+
|
|
0.5.3 (2012-11-03)
|
|
------------------
|
|
|
|
- Added ability to customize string coercion (e.g. to have None render
|
|
as ``''``) (issue #130).
|
|
-- Added Renderer.render\_name() to render a template by name (issue
|
|
+- Added Renderer.render_name() to render a template by name (issue
|
|
#122).
|
|
-- Added TemplateSpec.template\_path to specify an absolute path to a
|
|
+- Added TemplateSpec.template_path to specify an absolute path to a
|
|
template (issue #41).
|
|
- Added option of raising errors on missing tags/partials:
|
|
``Renderer(missing_tags='strict')`` (issue #110).
|
|
@@ -355,6 +363,8 @@ History
|
|
- More robust handling of byte strings in Python 3.
|
|
- Added Creative Commons license for David Phillips's logo.
|
|
|
|
+.. _section-6:
|
|
+
|
|
0.5.2 (2012-05-03)
|
|
------------------
|
|
|
|
@@ -367,16 +377,20 @@ History
|
|
context stack (issue #113).
|
|
- Bugfix: lists of lambdas for sections were not rendered (issue #114).
|
|
|
|
+.. _section-7:
|
|
+
|
|
0.5.1 (2012-04-24)
|
|
------------------
|
|
|
|
- Added support for Python 3.1 and 3.2.
|
|
- Added tox support to test multiple Python versions.
|
|
- Added test script entry point: pystache-test.
|
|
-- Added \_\_version\_\_ package attribute.
|
|
+- Added \__version_\_ package attribute.
|
|
- Test harness now supports both YAML and JSON forms of Mustache spec.
|
|
- Test harness no longer requires nose.
|
|
|
|
+.. _section-8:
|
|
+
|
|
0.5.0 (2012-04-03)
|
|
------------------
|
|
|
|
@@ -435,11 +449,15 @@ Bug fixes:
|
|
- Passing ``**kwargs`` to ``Template()`` with no context no longer
|
|
raises an exception.
|
|
|
|
+.. _section-9:
|
|
+
|
|
0.4.1 (2012-03-25)
|
|
------------------
|
|
|
|
- Added support for Python 2.4. [wangtz, jvantuyl]
|
|
|
|
+.. _section-10:
|
|
+
|
|
0.4.0 (2011-01-12)
|
|
------------------
|
|
|
|
@@ -447,19 +465,25 @@ Bug fixes:
|
|
- Add support for inverted lists
|
|
- Decoupled template loading
|
|
|
|
+.. _section-11:
|
|
+
|
|
0.3.1 (2010-05-07)
|
|
------------------
|
|
|
|
- Fix package
|
|
|
|
+.. _section-12:
|
|
+
|
|
0.3.0 (2010-05-03)
|
|
------------------
|
|
|
|
-- View.template\_path can now hold a list of path
|
|
+- View.template_path can now hold a list of path
|
|
- Add {{& blah}} as an alias for {{{ blah }}}
|
|
- Higher Order Sections
|
|
- Inverted sections
|
|
|
|
+.. _section-13:
|
|
+
|
|
0.2.0 (2010-02-15)
|
|
------------------
|
|
|
|
@@ -473,12 +497,16 @@ Bug fixes:
|
|
[enaeseth]
|
|
- Template file encoding awareness. [enaeseth]
|
|
|
|
+.. _section-14:
|
|
+
|
|
0.1.1 (2009-11-13)
|
|
------------------
|
|
|
|
- Ensure we're dealing with strings, always
|
|
- Tests can be run by executing the test file directly
|
|
|
|
+.. _section-15:
|
|
+
|
|
0.1.0 (2009-11-12)
|
|
------------------
|
|
|
|
@@ -510,4 +538,23 @@ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
-.. |image0| image:: http://i.creativecommons.org/l/by-sa/3.0/88x31.png
|
|
+.. |ci| image:: https://github.com/sarnold/pystache/actions/workflows/ci.yml/badge.svg
|
|
+ :target: https://github.com/sarnold/pystache/actions/workflows/ci.yml
|
|
+.. |Conda| image:: https://github.com/sarnold/pystache/actions/workflows/conda.yml/badge.svg
|
|
+ :target: https://github.com/sarnold/pystache/actions/workflows/conda.yml
|
|
+.. |Wheels| image:: https://github.com/sarnold/pystache/actions/workflows/wheels.yml/badge.svg
|
|
+ :target: https://github.com/sarnold/pystache/actions/workflows/wheels.yml
|
|
+.. |Release| image:: https://github.com/sarnold/pystache/actions/workflows/release.yml/badge.svg
|
|
+ :target: https://github.com/sarnold/pystache/actions/workflows/release.yml
|
|
+.. |Python| image:: https://img.shields.io/badge/python-3.6+-blue.svg
|
|
+ :target: https://www.python.org/downloads/
|
|
+.. |Latest release| image:: https://img.shields.io/github/v/release/sarnold/pystache?include_prereleases
|
|
+ :target: https://github.com/sarnold/pystache/releases/latest
|
|
+.. |License| image:: https://img.shields.io/github/license/sarnold/pystache
|
|
+ :target: https://github.com/sarnold/pystache/blob/master/LICENSE
|
|
+.. |Maintainability| image:: https://api.codeclimate.com/v1/badges/a8fa1bf4638bfc6581b6/maintainability
|
|
+ :target: https://codeclimate.com/github/sarnold/pystache/maintainability
|
|
+.. |codecov| image:: https://codecov.io/gh/sarnold/pystache/branch/master/graph/badge.svg?token=5PZNMZBI6K
|
|
+ :target: https://codecov.io/gh/sarnold/pystache
|
|
+.. |image9| image:: gh/images/logo_phillips_small.png
|
|
+.. |image10| image:: http://i.creativecommons.org/l/by-sa/3.0/88x31.png
|
|
diff --git a/tox.ini b/tox.ini
|
|
index d1eaebf..66c4515 100644
|
|
--- a/tox.ini
|
|
+++ b/tox.ini
|
|
@@ -1,36 +1,110 @@
|
|
-# A tox configuration file to test across multiple Python versions.
|
|
-#
|
|
-# http://pypi.python.org/pypi/tox
|
|
-#
|
|
[tox]
|
|
-# Tox 1.4 drops py24 and adds py33. In the current version, we want to
|
|
-# support 2.4, so we can't simultaneously support 3.3.
|
|
-envlist = py24,py25,py26,py27,py27-yaml,py27-noargs,py31,py32,pypy
|
|
+envlist = py{36,37,38,39}-{linux,macos,windows}
|
|
+skip_missing_interpreters = true
|
|
+isolated_build = true
|
|
+#skipsdist = true
|
|
+
|
|
+[gh-actions]
|
|
+python =
|
|
+ 3.6: py36
|
|
+ 3.7: py37
|
|
+ 3.8: py38
|
|
+ 3.9: py39
|
|
+
|
|
+[gh-actions:env]
|
|
+PLATFORM =
|
|
+ ubuntu-18.04: linux
|
|
+ macos-latest: macos
|
|
+ windows-latest: windows
|
|
|
|
[testenv]
|
|
+passenv = CI PYTHON PYTHONIOENCODING
|
|
+
|
|
+deps =
|
|
+ pip>=20.0.1
|
|
+ nose
|
|
+ coverage
|
|
+
|
|
+commands =
|
|
+ nosetests -sx . {posargs}
|
|
+
|
|
+[testenv:bare]
|
|
# Change the working directory so that we don't import the pystache located
|
|
# in the original location.
|
|
+deps =
|
|
+ pip>=20.0.1
|
|
+ -e .
|
|
+
|
|
changedir =
|
|
{envbindir}
|
|
+
|
|
commands =
|
|
- pystache-test {toxinidir}
|
|
+ pystache-test
|
|
+
|
|
+[testenv:bench]
|
|
+passenv = CI PYTHON PYTHONIOENCODING
|
|
|
|
-# Check that the spec tests work with PyYAML.
|
|
-[testenv:py27-yaml]
|
|
-basepython =
|
|
- python2.7
|
|
deps =
|
|
- PyYAML
|
|
-changedir =
|
|
- {envbindir}
|
|
+ pip>=20.0.1
|
|
+ # uncomment for comparison, posargs expects a number, eg, 10000
|
|
+ #chevron
|
|
+
|
|
+commands_pre =
|
|
+ pip install .
|
|
+
|
|
commands =
|
|
- pystache-test {toxinidir}
|
|
+ python pystache/tests/benchmark.py {posargs}
|
|
+
|
|
+[testenv:setup]
|
|
+passenv = CI PYTHON PYTHONIOENCODING
|
|
+
|
|
+deps =
|
|
+ pyyaml
|
|
+ twine
|
|
+
|
|
+commands =
|
|
+ python setup.py install
|
|
+ twine check dist/*
|
|
+ pystache-test {posargs}
|
|
+
|
|
+[testenv:deploy]
|
|
+passenv = CI PYTHON PYTHONIOENCODING
|
|
+allowlist_externals = bash
|
|
+
|
|
+deps =
|
|
+ pip>=19.0.1
|
|
+ wheel
|
|
+ pep517
|
|
+ twine
|
|
+
|
|
+commands =
|
|
+ python -m pep517.build .
|
|
+ twine check dist/*
|
|
+
|
|
+[testenv:check]
|
|
+passenv = CI PYTHON PYTHONIOENCODING
|
|
+skip_install = true
|
|
+
|
|
+allowlist_externals = bash
|
|
+
|
|
+deps =
|
|
+ pip>=20.0.1
|
|
|
|
-# Check that pystache-test works from an install with no arguments.
|
|
-[testenv:py27-noargs]
|
|
-basepython =
|
|
- python2.7
|
|
-changedir =
|
|
- {envbindir}
|
|
commands =
|
|
+ bash -c 'export WHL_FILE=$(ls dist/*.whl); \
|
|
+ python -m pip install $WHL_FILE'
|
|
pystache-test
|
|
+
|
|
+[testenv:docs]
|
|
+passenv = CI PYTHON PYTHONIOENCODING
|
|
+allowlist_externals = bash
|
|
+
|
|
+deps =
|
|
+ pip>=19.0.1
|
|
+ wheel
|
|
+ docutils
|
|
+ # apt/emerge pandoc first
|
|
+
|
|
+commands =
|
|
+ python setup.py prep
|
|
+ bash -c 'python setup.py --long-description | rst2html.py -v --no-raw > out.html'
|
|
diff --git a/travis.yml_disabled b/travis.yml_disabled
|
|
new file mode 100644
|
|
index 0000000..f0b4042
|
|
--- /dev/null
|
|
+++ b/travis.yml_disabled
|
|
@@ -0,0 +1,52 @@
|
|
+dist: xenial
|
|
+language: python
|
|
+
|
|
+# Travis CI has no plans to support Jython and no longer supports Python 2.5.
|
|
+python:
|
|
+ - "2.7"
|
|
+ - "3.5"
|
|
+ - "3.6"
|
|
+ - "3.7"
|
|
+ - "3.8"
|
|
+ - "3.9-dev"
|
|
+ - "nightly"
|
|
+
|
|
+matrix:
|
|
+ fast_finish: true
|
|
+ include:
|
|
+ - os: osx
|
|
+ # osx is goofy, ``python`` is always py2, images mutate fast
|
|
+ language: shell
|
|
+ before_install:
|
|
+ - pip3 install --upgrade pip wheel
|
|
+ install:
|
|
+ - python3 setup.py install
|
|
+ script:
|
|
+ - pystache-test . ext/spec/specs
|
|
+ - os: windows
|
|
+ # windows is even goofier, install path is different for python/python3
|
|
+ # but either way you get python3 and the cmd is always ``python`` o.O
|
|
+ # (also versions mutuate like bacteria)
|
|
+ language: shell
|
|
+ before_install:
|
|
+ - choco install python3 --params "/InstallDir:C:\\Python"
|
|
+ - python -m pip install --upgrade pip wheel
|
|
+ env: PATH="/c/Python:/c/Python/Scripts:$PATH"
|
|
+ install:
|
|
+ - python setup.py install
|
|
+ script:
|
|
+ - pystache-test . ext/spec/specs
|
|
+ allow_failures:
|
|
+ - python: "nightly"
|
|
+
|
|
+# command to install dependencies
|
|
+install:
|
|
+ - pip install --upgrade pip
|
|
+ - pip install codecov
|
|
+
|
|
+script:
|
|
+ - python setup.py install
|
|
+ # Include the spec tests directory for Mustache spec tests and the
|
|
+ # project directory for doctests.
|
|
+ - pystache-test . ext/spec/specs
|
|
+ #- tox
|
|
--
|
|
2.33.0
|
|
|