From 902104c8753b568707b89e981c41db3a3b1d32026a3fd6a96af472eb748e5970 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Chv=C3=A1tal?= Date: Thu, 24 Sep 2020 11:40:00 +0000 Subject: [PATCH] Accepting request 836476 from home:pgajdos:python - version update to 0.8.2 #. Use any functions, any data structure of any python packages as jinja2 filters, tests, globals #. `#399 `_: content processor should be called only once #. content processor shall pass on options to content processors #. moban.plugins.jinja2.tests.files is moved to moban-ansible package #. moban.plugins.jinja2.filters.github is moved to moban-jinja2-github package #. `#396 `_: custom jinja2 plugins(filters, tests and globals) are not visible if a template is passed as a string. #. `#393 `_: Rendered content output to stdout once #. `#390 `_: single render action will print to stdout by default - modified patches % remove_nose.patch (extended, https://github.com/moremoban/moban/pull/404) - added sources + _multibuild OBS-URL: https://build.opensuse.org/request/show/836476 OBS-URL: https://build.opensuse.org/package/show/devel:languages:python/python-moban?expand=0&rev=16 --- _multibuild | 3 + moban-0.7.8.tar.gz | 3 - moban-0.8.2.tar.gz | 3 + python-moban.changes | 23 + python-moban.spec | 70 +- remove_nose.patch | 1978 ++++++++++++++++++++++++++++-------------- 6 files changed, 1397 insertions(+), 683 deletions(-) create mode 100644 _multibuild delete mode 100644 moban-0.7.8.tar.gz create mode 100644 moban-0.8.2.tar.gz diff --git a/_multibuild b/_multibuild new file mode 100644 index 0000000..fcc7b97 --- /dev/null +++ b/_multibuild @@ -0,0 +1,3 @@ + + test + diff --git a/moban-0.7.8.tar.gz b/moban-0.7.8.tar.gz deleted file mode 100644 index 635c88a..0000000 --- a/moban-0.7.8.tar.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:942526e7209622ea7c79676291b49bcf03cb554ec3d8b7aaf7ba0db2dfbb3424 -size 1000105 diff --git a/moban-0.8.2.tar.gz b/moban-0.8.2.tar.gz new file mode 100644 index 0000000..b69fc64 --- /dev/null +++ b/moban-0.8.2.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:884fa73c7feaa0b8b5cf8c11ac4f2b557cd06d581fe0845cc4c4634b139c00ea +size 1003121 diff --git a/python-moban.changes b/python-moban.changes index dab8084..c6ba5fb 100644 --- a/python-moban.changes +++ b/python-moban.changes @@ -1,3 +1,26 @@ +------------------------------------------------------------------- +Thu Sep 24 08:38:23 UTC 2020 - pgajdos@suse.com + +- version update to 0.8.2 + #. Use any functions, any data structure of any python packages as jinja2 + filters, tests, globals + #. `#399 `_: content processor + should be called only once + #. content processor shall pass on options to content processors + #. moban.plugins.jinja2.tests.files is moved to moban-ansible package + #. moban.plugins.jinja2.filters.github is moved to moban-jinja2-github package + #. `#396 `_: custom jinja2 + plugins(filters, tests and globals) are not visible if a template is passed + as a string. + #. `#393 `_: Rendered content + output to stdout once + #. `#390 `_: single render action + will print to stdout by default +- modified patches + % remove_nose.patch (extended, https://github.com/moremoban/moban/pull/404) +- added sources + + _multibuild + ------------------------------------------------------------------- Fri Sep 18 14:48:12 UTC 2020 - Matej Cepl diff --git a/python-moban.spec b/python-moban.spec index f0187fa..45a0f95 100644 --- a/python-moban.spec +++ b/python-moban.spec @@ -16,30 +16,30 @@ # -%define skip_python2 1 %{?!python_module:%define python_module() python-%{**} python3-%{**}} -Name: python-moban -Version: 0.7.8 +# Tests have dependency loop with moban-ansible +%global flavor @BUILD_FLAVOR@%{nil} +%if "%{flavor}" == "test" +%define test 1 +%define pkg_suffix -test +%bcond_without test +%else +%define pkg_suffix %{nil} +%bcond_with test +%endif + +%{?!python_module:%define python_module() python-%{**} python3-%{**}} +%define skip_python2 1 +Name: python-moban%{pkg_suffix} +Version: 0.8.2 Release: 0 Summary: Yet another jinja2 CLI for static text generation License: MIT Group: Development/Languages/Python URL: https://github.com/moremoban/moban Source: https://files.pythonhosted.org/packages/source/m/moban/moban-%{version}.tar.gz -# PATCH-FEATURE-UPSTREAM remove_nose.patch gh#moremoban/moban#364 mcepl@suse.com -# Ports test suite from nose to pytest WIP/alpha +# https://github.com/moremoban/moban/pull/404 Patch0: remove_nose.patch -BuildRequires: %{python_module Jinja2 >= 2.7.1} -BuildRequires: %{python_module appdirs >= 1.4.3} -BuildRequires: %{python_module crayons >= 0.1.0} -BuildRequires: %{python_module fs >= 2.4.11} -BuildRequires: %{python_module jinja2-fsloader >= 0.2.0} -BuildRequires: %{python_module jinja2-time} -BuildRequires: %{python_module lml >= 0.0.9} -BuildRequires: %{python_module mock} -BuildRequires: %{python_module pip} -BuildRequires: %{python_module pytest} -BuildRequires: %{python_module ruamel.yaml >= 0.15.98} BuildRequires: %{python_module setuptools} BuildRequires: fdupes BuildRequires: git-core @@ -54,9 +54,26 @@ Requires: python-lml >= 0.0.9 Requires: python-ruamel.yaml >= 0.15.98 Requires(post): update-alternatives Requires(postun): update-alternatives +Suggests: python-ansible Suggests: python-gitfs2 Suggests: python-pypifs BuildArch: noarch +# SECTION test requirements +%if %{with test} +BuildRequires: %{python_module Jinja2 >= 2.7.1} +BuildRequires: %{python_module appdirs >= 1.4.3} +BuildRequires: %{python_module crayons >= 0.1.0} +BuildRequires: %{python_module fs >= 2.4.11} +BuildRequires: %{python_module jinja2-fsloader >= 0.2.0} +BuildRequires: %{python_module jinja2-time} +BuildRequires: %{python_module lml >= 0.0.9} +BuildRequires: %{python_module moban-ansible} +BuildRequires: %{python_module mock} +BuildRequires: %{python_module pip} +BuildRequires: %{python_module pytest} +BuildRequires: %{python_module ruamel.yaml >= 0.15.98} +%endif +# /SECTION %python_subpackages %description @@ -70,18 +87,22 @@ consistent across the documentations of individual libraries. %setup -q -n moban-%{version} %autopatch -p1 -# integration tests need network -rm -r tests/integration_tests - +%if !%{with test} %build %python_build +%endif +%if !%{with test} %install %python_install %python_clone -a %{buildroot}%{_bindir}/moban %python_expand %fdupes %{buildroot}%{$python_sitelib} +%endif +%if %{with test} %check +# integration tests need network +rm -r tests/integration_tests # test_level_9_deprecated needs pypi-mobans-pkg just for templates... too much effort SKIP_TESTS="test_level_9_deprecated" # test_level_9 needs pypifs, which is now optional @@ -98,19 +119,28 @@ SKIP_TESTS="$SKIP_TESTS or test_handle_targets_sequence" SKIP_TESTS="$SKIP_TESTS or test_overrides_fs_url" # test_level_24 needs httpfs, which is optional SKIP_TESTS="$SKIP_TESTS or test_level_24" +# test_repo is probably online, requires git +SKIP_TESTS="$SKIP_TESTS or test_repo" export SKIP_TESTS -%pytest -k "not ($SKIP_TESTS)" || : +%pytest -k "not ($SKIP_TESTS)" +%endif +%if !%{with test} %post %python_install_alternative moban +%endif +%if !%{with test} %postun %python_uninstall_alternative moban +%endif +%if !%{with test} %files %{python_files} %{python_sitelib}/* %license LICENSE %doc README.rst CHANGELOG.rst %python_alternative %{_bindir}/moban +%endif %changelog diff --git a/remove_nose.patch b/remove_nose.patch index b8756b6..122251f 100644 --- a/remove_nose.patch +++ b/remove_nose.patch @@ -1,213 +1,88 @@ ---- - setup.py | 2 - tests/core/test_context.py | 9 +- - tests/core/test_engine.py | 16 ++-- - tests/core/test_moban_factory.py | 41 +++++----- - tests/data_loaders/test_json_loader.py | 3 - tests/data_loaders/test_merge_dict.py | 3 - tests/data_loaders/test_overrides.py | 18 ++-- - tests/data_loaders/test_yaml_loader.py | 12 +-- - tests/deprecated/test_handle_requires.py | 10 +- - tests/deprecated/test_repo.py | 19 ++-- - tests/integration_tests/test_command_line_options.py | 76 ++++++++----------- - tests/jinja2/test_engine.py | 8 -- - tests/jinja2/test_extensions.py | 8 -- - tests/jinja2/test_github.py | 6 - - tests/jinja2/test_repr.py | 8 -- - tests/jinja2/test_text.py | 6 - - tests/mobanfile/test_mobanfile.py | 24 ++---- - tests/mobanfile/test_targets.py | 22 ++--- - tests/mobanfile/test_templates.py | 18 ++-- - tests/requirements.txt | 1 - tests/test_buffered_writer.py | 8 -- - tests/test_copy_engine.py | 13 +-- - tests/test_definitions.py | 14 +-- - tests/test_docs.py | 4 - - tests/test_file_system.py | 49 ++++++------ - tests/test_hash_store.py | 7 + - tests/test_main.py | 37 ++++----- - tests/test_reporter.py | 34 ++++---- - tests/test_store.py | 4 - - tests/utils.py | 10 +- - 30 files changed, 231 insertions(+), 259 deletions(-) +diff --git a/CONTRIBUTORS.rst b/CONTRIBUTORS.rst +index 95a9784d..35c0a0e2 100644 +--- a/CONTRIBUTORS.rst ++++ b/CONTRIBUTORS.rst +@@ -4,11 +4,11 @@ + + In alphabetical order: + +-* `Andrew Scheller `_ +-* `Ayan Banerjee `_ +-* `Charlie Liu `_ +-* `John Vandenberg `_ +-* `Joshua Chung `_ +-* `PRAJWAL M `_ +-* `salotz `_ +-* `SerekKiri `_ ++* `Andrew Scheller `_ ++* `Ayan Banerjee `_ ++* `Charlie Liu `_ ++* `John Vandenberg `_ ++* `Joshua Chung `_ ++* `PRAJWAL M `_ ++* `salotz `_ ++* `SerekKiri `_ +diff --git a/moban/core/moban_factory.py b/moban/core/moban_factory.py +index da713376..df2df17d 100644 +--- a/moban/core/moban_factory.py ++++ b/moban/core/moban_factory.py +@@ -34,9 +34,11 @@ def register_extensions(self, extensions): + ) + ) + if template_type in self.extensions: +- self.extensions[template_type] = self.extensions[ +- user_template_type +- ].union(extensions[user_template_type]) ++ self.extensions[template_type] = list( ++ set(self.extensions[user_template_type]).union( ++ extensions[user_template_type] ++ ) ++ ) + else: + self.extensions[template_type] = extensions[user_template_type] + +diff --git a/moban/core/mobanfile/templates.py b/moban/core/mobanfile/templates.py +index a60c99c9..3d2b2cc9 100644 +--- a/moban/core/mobanfile/templates.py ++++ b/moban/core/mobanfile/templates.py +@@ -43,7 +43,7 @@ def _list_dir_files(fs, source, dest): + for file_name in fs.listdir(source): + # please note jinja2 does NOT like windows path + # hence the following statement looks like cross platform +- # src_file_under_dir = os.path.join(source, file_name) ++ # src_file_under_dir = fs.path.join(source, file_name) + # but actually it breaks windows instead. + src_file_under_dir = f"{source}/{file_name}" + if fs.isfile(src_file_under_dir): ---- a/tests/requirements.txt -+++ b/tests/requirements.txt -@@ -1,4 +1,4 @@ --nose -+pytest - codecov - coverage - mock ---- a/tests/test_file_system.py -+++ b/tests/test_file_system.py -@@ -3,9 +3,12 @@ import sys - import stat - from shutil import rmtree - --from mock import patch --from nose import SkipTest --from nose.tools import eq_, raises -+try: -+ from mock import patch -+except ImportError: -+ from unittest.mock import patch -+from unittest import SkipTest -+import pytest - - from moban.externals import file_system - from moban.exceptions import FileNotFound, UnsupportedPyFS2Protocol -@@ -48,7 +51,7 @@ TEST_FILE_CONTENT_SPECS = [ - def test_read_unicode(): - for url, expected in TEST_FILE_CONTENT_SPECS: - content = file_system.read_unicode(url) -- eq_(content, expected) -+ assert content == expected +diff --git a/tests/__init__.py b/tests/__init__.py +index fc28703f..c3dff238 100644 +--- a/tests/__init__.py ++++ b/tests/__init__.py +@@ -1,5 +1,5 @@ + from moban.main import load_engine_factory_and_engines - TEST_FILE_CONTENT_SPECS_BINARY = [ -@@ -61,7 +64,7 @@ TEST_FILE_CONTENT_SPECS_BINARY = [ - def test_read_binary(): - for url, expected in TEST_FILE_CONTENT_SPECS_BINARY: - content = file_system.read_binary(url) -- eq_(content, expected) -+ assert content == expected - - - TEST_WRITE_BYTES_SPEC = [ -@@ -77,7 +80,7 @@ def test_write_bytes(): - - for url, expected in TEST_WRITE_BYTES_SPEC: - content = file_system.read_bytes(url) -- eq_(content, expected) -+ assert content == expected - - for file_name in ["test.binary", "test.zip", "test.tar"]: - os.unlink(file_name) -@@ -96,14 +99,14 @@ TEST_DIR_SPEC = [ - def test_is_dir(): - for url, expected in TEST_DIR_SPEC: - status = file_system.is_dir(url) -- eq_(status, expected) -+ assert status == expected - - - def test_is_file(): - for url, is_dir in TEST_DIR_SPEC: - status = file_system.is_file(url) - expected = not is_dir -- eq_(status, expected) -+ assert status == expected - - - TEST_URL_EXITENCE_SPEC = [ -@@ -122,15 +125,15 @@ TEST_URL_EXITENCE_SPEC = [ - def test_exists(): - for url, expected in TEST_URL_EXITENCE_SPEC: - status = file_system.exists(url) -- eq_(status, expected) -+ assert status == expected - - --@raises(UnsupportedPyFS2Protocol) -+@pytest.mark.xfail(raises=UnsupportedPyFS2Protocol) - def test_exists_raise_exception(): - file_system.exists("git2://protocol/abc") - - --@raises(UnsupportedPyFS2Protocol) -+@pytest.mark.xfail(raises=UnsupportedPyFS2Protocol) - def test_is_file_raise_exception(): - file_system.is_file("git2://protocol/abc") - -@@ -154,7 +157,7 @@ TEST_LIST_DIR_SPEC = [ - def test_list_dir(): - for url, expected in TEST_LIST_DIR_SPEC: - file_list = sorted(list(file_system.list_dir(url))) -- eq_(file_list, sorted(expected)) -+ assert file_list == sorted(expected) - - - TEST_FILE_PATH = [ -@@ -170,7 +173,7 @@ TEST_FILE_PATH = [ - def test_abspath(): - for path, expected in TEST_FILE_PATH: - url = file_system.abspath(path) -- eq_(url, expected) -+ assert url == expected - - - TEST_FILE_URL = [ -@@ -187,7 +190,7 @@ TEST_FILE_URL = [ - def test_fs_url(): - for path, expected in TEST_FILE_URL: - url = file_system.fs_url(path) -- eq_(url, expected.replace("\\", "/")) -+ assert url == expected.replace("\\", "/") - - - URL_JOIN_TEST_FIXTURES = [ -@@ -200,7 +203,7 @@ URL_JOIN_TEST_FIXTURES = [ - def test_url_join(): - for parent, child, expected_path in URL_JOIN_TEST_FIXTURES: - actual = file_system.url_join(parent, child) -- eq_(actual, expected_path) -+ assert actual == expected_path - - - def create_file(test_file, permission): -@@ -218,10 +221,8 @@ def test_file_permission_copy(): - create_file(test_source, 0o755) - create_file(test_dest, 0o646) - file_system.file_permissions_copy(test_source, test_dest) -- eq_( -- stat.S_IMODE(os.lstat(test_source).st_mode), -- stat.S_IMODE(os.lstat(test_dest).st_mode), -- ) -+ assert stat.S_IMODE(os.lstat(test_source).st_mode) == \ -+ stat.S_IMODE(os.lstat(test_dest).st_mode) - os.unlink(test_source) - os.unlink(test_dest) - -@@ -229,12 +230,12 @@ def test_file_permission_copy(): - def file_permissions_disabled_on_windows(): - if sys.platform == "win32": - permissions = file_system.file_permissions("abc") -- eq_("no-permission-support", permissions) -+ assert "no-permission-support" == permissions - else: - raise SkipTest("No test required") - - --@raises(FileNotFound) -+@pytest.mark.xfail(raises=FileNotFound) - def test_file_permissions_file_not_found(): - file_system.file_permissions("I does not exist") - -@@ -249,10 +250,8 @@ def test_file_permission_copy_symlink(): - os.symlink(test_source, test_symlink) - create_file(test_dest, 0o646) - file_system.file_permissions_copy(test_source, test_dest) -- eq_( -- stat.S_IMODE(os.lstat(test_source).st_mode), -- stat.S_IMODE(os.lstat(test_dest).st_mode), -- ) -+ assert stat.S_IMODE(os.lstat(test_source).st_mode) == \ -+ stat.S_IMODE(os.lstat(test_dest).st_mode) - os.unlink(test_source) - os.unlink(test_dest) - os.unlink(test_symlink) +-def setup(): ++def setUpModule(): + load_engine_factory_and_engines() +diff --git a/tests/core/__init__.py b/tests/core/__init__.py +new file mode 100644 +index 00000000..e69de29b +diff --git a/tests/core/test_context.py b/tests/core/test_context.py +index d9e39bc7..9e149967 100644 --- a/tests/core/test_context.py +++ b/tests/core/test_context.py -@@ -1,7 +1,6 @@ +@@ -1,7 +1,7 @@ import os ++import pytest import fs.path -from nose.tools import eq_ from moban.core.context import Context -@@ -9,7 +8,7 @@ from moban.core.context import Context +@@ -9,7 +9,7 @@ def test_context(): context = Context(fs.path.join("tests", "fixtures")) data = context.get_data("simple.yaml") @@ -216,7 +91,7 @@ def test_environ_variables(): -@@ -18,7 +17,7 @@ def test_environ_variables(): +@@ -18,7 +18,7 @@ def test_environ_variables(): os.environ[test_var] = test_value context = Context(fs.path.join("tests", "fixtures")) data = context.get_data("simple.yaml") @@ -225,7 +100,7 @@ def test_json_data_overrides_environ_variables(): -@@ -27,7 +26,7 @@ def test_json_data_overrides_environ_var +@@ -27,7 +27,7 @@ def test_json_data_overrides_environ_variables(): os.environ[test_var] = test_value context = Context(fs.path.join("tests", "fixtures")) data = context.get_data("simple.json") @@ -234,36 +109,35 @@ def test_unknown_data_file(): -@@ -36,4 +35,4 @@ def test_unknown_data_file(): +@@ -36,4 +36,4 @@ def test_unknown_data_file(): os.environ[test_var] = test_value context = Context(fs.path.join("tests", "fixtures")) data = context.get_data("unknown.data") - eq_(data[test_var], test_value) + assert data[test_var] == test_value +diff --git a/tests/core/test_engine.py b/tests/core/test_engine.py +index b64a2f0a..28840751 100644 --- a/tests/core/test_engine.py +++ b/tests/core/test_engine.py -@@ -1,13 +1,15 @@ +@@ -1,13 +1,13 @@ import os ++import pytest import fs.path --from mock import patch + from mock import patch -from nose.tools import eq_ -+try: -+ from mock import patch -+except ImportError: -+ from unittest.mock import patch from moban.core import ENGINES -from moban.definitions import TemplateTarget -from moban.jinja2.engine import Engine -from moban.data_loaders.yaml import open_yaml +from moban.core.definitions import TemplateTarget -+from moban.plugins.jinja2.engine import Engine +from moban.plugins.yaml_loader import open_yaml ++from moban.plugins.jinja2.engine import Engine MODULE = "moban.core.moban_factory" -@@ -93,7 +95,7 @@ def test_get_user_defined_engine(): +@@ -93,7 +93,7 @@ def test_get_user_defined_engine(): template_types = open_yaml(test_fixture) ENGINES.register_options(template_types["template_types"]) engine = ENGINES.get_engine("custom_jinja", ".", ".") @@ -272,7 +146,7 @@ def test_custom_file_extension_is_assocated_with_user_defined_engine(): -@@ -103,7 +105,7 @@ def test_custom_file_extension_is_assoca +@@ -103,7 +103,7 @@ def test_custom_file_extension_is_assocated_with_user_defined_engine(): template_types = open_yaml(test_fixture) ENGINES.register_options(template_types["template_types"]) template_type = ENGINES.get_primary_key("demo_file_suffix") @@ -281,45 +155,67 @@ def test_built_in_jinja2_file_extension_still_works(): -@@ -113,4 +115,4 @@ def test_built_in_jinja2_file_extension_ +@@ -113,4 +113,4 @@ def test_built_in_jinja2_file_extension_still_works(): template_types = open_yaml(test_fixture) ENGINES.register_options(template_types["template_types"]) template_type = ENGINES.get_primary_key("jj2") - eq_("jinja2", template_type) + assert "jinja2" == template_type +diff --git a/tests/core/test_moban_factory.py b/tests/core/test_moban_factory.py +index 409b1d34..8aec972e 100644 --- a/tests/core/test_moban_factory.py +++ b/tests/core/test_moban_factory.py -@@ -2,14 +2,17 @@ import os +@@ -1,20 +1,20 @@ + import os import sys ++import pytest import fs.path --from mock import patch -+try: -+ from mock import patch -+except ImportError: -+ from unittest.mock import patch + from mock import patch from lml.plugin import PluginInfo -from nose.tools import eq_, raises -+import pytest import moban.exceptions as exceptions from moban.core import ENGINES from moban.core.context import Context -from moban.jinja2.engine import ( ++from moban.core.moban_factory import MobanEngine, expand_template_directories +from moban.plugins.jinja2.engine import ( Engine, is_extension_list_valid, import_module_of_extension, -@@ -20,7 +23,7 @@ USER_HOME = fs.path.join("user", "home", + ) +-from moban.core.moban_factory import MobanEngine, expand_template_directories + USER_HOME = fs.path.join("user", "home", ".moban", "repos") - @PluginInfo("library", tags=["testmobans"]) --class TestPypkg: -+class MyTestPypkg: +@@ -23,22 +23,29 @@ + class TestPypkg: def __init__(self): __package_path__ = os.path.normcase(os.path.dirname(__file__)) - self.resources_path = os.path.join(__package_path__, "fixtures") -@@ -38,7 +41,7 @@ def test_expand_repo_dir(_, __): +- self.resources_path = os.path.join(__package_path__, "fixtures") ++ self.resources_path = fs.path.join(__package_path__, "fixtures") + + + def test_expand_pypi_dir(): +- dirs = list(expand_template_directories("testmobans:template-tests")) ++ dirs = list( ++ expand_template_directories( ++ [ ++ "tests/fixtures/template", ++ "tests/regression_tests/level-7-plugin-dir-cli/my-templates", ++ ] ++ ) ++ ) + for directory in dirs: +- assert os.path.exists(directory) ++ assert os.path.exists(directory[7:]) + + + @patch("moban.deprecated.repo.get_moban_home", return_value=USER_HOME) +-@patch("moban.file_system.exists", return_value=True) ++@patch("moban.externals.file_system.exists", return_value=True) + def test_expand_repo_dir(_, __): dirs = list(expand_template_directories("git_repo:template")) expected = [fs.path.join(USER_HOME, "git_repo", "template")] @@ -328,34 +224,34 @@ def test_default_template_type(): -@@ -57,22 +60,22 @@ def test_default_mako_type(_): # fake m +@@ -57,22 +64,20 @@ def test_default_mako_type(_): # fake mako assert engine.engine.__class__ == FakeEngine -@raises(exceptions.NoThirdPartyEngine) -+@pytest.mark.xfail(raises=exceptions.NoThirdPartyEngine) def test_unknown_template_type(): - ENGINES.get_engine("unknown_template_type", [], "") +- ENGINES.get_engine("unknown_template_type", [], "") ++ with pytest.raises(exceptions.NoThirdPartyEngine): ++ ENGINES.get_engine("unknown_template_type", [], "") -@raises(exceptions.DirectoryNotFound) -+@pytest.mark.xfail(raises=exceptions.DirectoryNotFound) def test_non_existent_tmpl_directries(): - ENGINES.get_engine("jj2", "idontexist", "") +- ENGINES.get_engine("jj2", "idontexist", "") ++ with pytest.raises(fs.errors.CreateFailed): ++ ENGINES.get_engine("jj2", "idontexist", "") -@raises(exceptions.DirectoryNotFound) -+@pytest.mark.xfail(raises=exceptions.DirectoryNotFound) def test_non_existent_config_directries(): MobanEngine("tests", "abc", Engine) -@raises(exceptions.DirectoryNotFound) -+@pytest.mark.xfail(raises=exceptions.DirectoryNotFound) def test_non_existent_ctx_directries(): Context(["abc"]) -@@ -84,9 +87,9 @@ def test_file_tests(): +@@ -84,9 +89,9 @@ def test_file_tests(): engine.render_to_file("file_tests.template", "file_tests.yml", output) with open(output, "r") as output_file: content = output_file.read() @@ -368,7 +264,7 @@ os.unlink(output) -@@ -97,9 +100,9 @@ def test_render_string_to_file(): +@@ -97,9 +102,9 @@ def test_render_string_to_file(): engine.render_string_to_file("{{test}}", "file_tests.yml", output) with open(output, "r") as output_file: content = output_file.read() @@ -381,16 +277,18 @@ os.unlink(output) -@@ -110,7 +113,7 @@ def test_global_template_variables(): +@@ -110,7 +115,9 @@ def test_global_template_variables(): engine.render_to_file("variables.template", "variables.yml", output) with open(output, "r") as output_file: content = output_file.read() - eq_(content, "template: variables.template\ntarget: test.txt\nhere") -+ assert content == "template: variables.template\ntarget: test.txt\nhere" ++ assert ( ++ content == "template: variables.template\ntarget: test.txt\nhere" ++ ) os.unlink(output) -@@ -121,7 +124,7 @@ def test_nested_global_template_variable +@@ -121,7 +128,7 @@ def test_nested_global_template_variables(): engine.render_to_file("nested.template", "variables.yml", output) with open(output, "r") as output_file: content = output_file.read() @@ -399,7 +297,7 @@ os.unlink(output) -@@ -135,7 +138,7 @@ def test_environ_variables_as_data(): +@@ -135,7 +142,7 @@ def test_environ_variables_as_data(): engine.render_to_file("test.template", "this_does_not_exist.yml", output) with open(output, "r") as output_file: content = output_file.read() @@ -408,7 +306,7 @@ os.unlink(output) -@@ -146,7 +149,7 @@ def test_string_template(): +@@ -146,7 +153,7 @@ def test_string_template(): engine.render_string_to_file("{{simple}}", "simple.yaml", output) with open(output, "r") as output_file: content = output_file.read() @@ -417,7 +315,7 @@ os.unlink(output) -@@ -157,7 +160,7 @@ def test_extensions_validator(): +@@ -157,7 +164,7 @@ def test_extensions_validator(): for fixture in test_fixtures: actual.append(is_extension_list_valid(fixture)) @@ -426,44 +324,64 @@ def test_import(): +diff --git a/tests/data_loaders/test_json_loader.py b/tests/data_loaders/test_json_loader.py +index b8a51c0e..6a608272 100644 --- a/tests/data_loaders/test_json_loader.py +++ b/tests/data_loaders/test_json_loader.py -@@ -1,5 +1,4 @@ +@@ -1,5 +1,5 @@ ++import pytest import fs.path -from nose.tools import eq_ from moban.plugins.json_loader import open_json -@@ -7,4 +6,4 @@ from moban.plugins.json_loader import op +@@ -7,4 +7,4 @@ def test_open_json(): content = open_json(fs.path.join("tests", "fixtures", "child.json")) expected = {"key": "hello world", "pass": "ox"} - eq_(expected, content) + assert expected == content +diff --git a/tests/data_loaders/test_merge_dict.py b/tests/data_loaders/test_merge_dict.py +index 9029173f..12099be5 100644 --- a/tests/data_loaders/test_merge_dict.py +++ b/tests/data_loaders/test_merge_dict.py -@@ -1,4 +1,3 @@ +@@ -1,4 +1,4 @@ -from nose.tools import eq_ ++import pytest from ruamel.yaml import YAML from moban.core.data_loader import merge -@@ -63,4 +62,4 @@ L1: +@@ -63,4 +63,4 @@ def test_merge_value_as_list_in_yaml(): """ ) merged = merge(user, default) - eq_(merged, {"L1": ["a", "b", "c", "d"]}) + assert merged == {"L1": ["a", "b", "c", "d"]} +diff --git a/tests/data_loaders/test_overrides.py b/tests/data_loaders/test_overrides.py +index ab6d9e62..7ce24457 100644 --- a/tests/data_loaders/test_overrides.py +++ b/tests/data_loaders/test_overrides.py -@@ -1,7 +1,5 @@ +@@ -1,55 +1,56 @@ import os -from nose.tools import eq_ -- ++import fs ++import pytest + from moban.main import load_engine_factory_and_engines from moban.core.data_loader import load_data -@@ -16,9 +14,9 @@ def test_overrides_a_list_of_config_file + + def test_overrides_a_list_of_config_files(): +- base_dir = os.path.join("tests", "fixtures", "issue_126") +- config_dir = os.path.join(base_dir, "config") +- actual = load_data(config_dir, os.path.join(base_dir, "the_config.yaml")) ++ base_dir = fs.path.join("tests", "fixtures", "issue_126") ++ config_dir = fs.path.join(base_dir, "config") ++ actual = load_data(config_dir, fs.path.join(base_dir, "the_config.yaml")) + expected = [ + ("key", "value"), + ("key_from_a", "apple"), ("key_from_b", "bee"), ] for item, expected_item in zip(actual.items(), expected): @@ -475,7 +393,10 @@ def test_overrides_a_list_of_config_files_but_cannot_find_them(): -@@ -27,9 +25,9 @@ def test_overrides_a_list_of_config_file +- base_dir = os.path.join("tests", "fixtures", "issue_126") +- actual = load_data(None, os.path.join(base_dir, "the_config.yaml")) ++ base_dir = fs.path.join("tests", "fixtures", "issue_126") ++ actual = load_data(None, fs.path.join(base_dir, "the_config.yaml")) expected = [("key", "value")] for item, expected_item in zip(actual.items(), expected): @@ -487,7 +408,15 @@ def test_overrides_ignores_override_sequence(): -@@ -42,7 +40,7 @@ def test_overrides_ignores_override_sequ +- base_dir = os.path.join("tests", "fixtures", "issue_126") +- config_dir = os.path.join(base_dir, "config") +- actual = load_data(config_dir, os.path.join(base_dir, "the_config.yaml")) ++ base_dir = fs.path.join("tests", "fixtures", "issue_126") ++ config_dir = fs.path.join(base_dir, "config") ++ actual = load_data(config_dir, fs.path.join(base_dir, "the_config.yaml")) + expected = [ + ("key", "value"), + ("key_from_a", "apple"), ("key_from_b", "bee"), ] for item, expected_item in zip(actual.items(), expected): @@ -496,7 +425,17 @@ def test_overrides_select_keys_from_parent_files(): -@@ -57,7 +55,7 @@ def test_overrides_select_keys_from_pare +- base_dir = os.path.join("tests", "fixtures", "issue_126") +- config_dir = os.path.join(base_dir, "config") ++ base_dir = fs.path.join("tests", "fixtures", "issue_126") ++ config_dir = fs.path.join(base_dir, "config") + actual = load_data( +- config_dir, os.path.join(base_dir, "multi-key-config.yaml") ++ config_dir, fs.path.join(base_dir, "multi-key-config.yaml") + ) + expected = [ + ("cat", "from config"), +@@ -57,14 +58,14 @@ def test_overrides_select_keys_from_parent_files(): ("beta", "from b"), ] for item, expected_item in zip(actual.items(), expected): @@ -505,7 +444,17 @@ def test_overrides_select_keys(): -@@ -72,7 +70,7 @@ def test_overrides_select_keys(): +- base_dir = os.path.join("tests", "fixtures", "issue_126") +- config_dir = os.path.join(base_dir, "config") ++ base_dir = fs.path.join("tests", "fixtures", "issue_126") ++ config_dir = fs.path.join(base_dir, "config") + actual = load_data( +- config_dir, os.path.join(base_dir, "multi-key-config-override.yaml") ++ config_dir, fs.path.join(base_dir, "multi-key-config-override.yaml") + ) + expected = [ + ("alpha", "from config"), +@@ -72,13 +73,13 @@ def test_overrides_select_keys(): ("beta", "from b"), ] for item, expected_item in zip(actual.items(), expected): @@ -514,7 +463,16 @@ def test_overrides_nested_keys(): -@@ -92,7 +90,7 @@ def test_overrides_nested_keys(): +- base_dir = os.path.join("tests", "fixtures", "issue_126") +- config_dir = os.path.join(base_dir, "config") +- actual = load_data(config_dir, os.path.join(base_dir, "raspberry.yaml")) ++ base_dir = fs.path.join("tests", "fixtures", "issue_126") ++ config_dir = fs.path.join(base_dir, "config") ++ actual = load_data(config_dir, fs.path.join(base_dir, "raspberry.yaml")) + expected = { + "raspberry": { + "other": "OpenGL 3.0", +@@ -92,11 +93,11 @@ def test_overrides_nested_keys(): "tessel": {"version": 2, "USB": "micro", "wifi": "802.11gn"}, } @@ -523,16 +481,24 @@ def test_overrides_fs_url(): + load_engine_factory_and_engines() +- base_dir = os.path.join("tests", "fixtures") +- actual = load_data(None, os.path.join(base_dir, "override_fs_url.yaml")) ++ base_dir = fs.path.join("tests", "fixtures") ++ actual = load_data(None, fs.path.join(base_dir, "override_fs_url.yaml")) + assert "requires" in actual +diff --git a/tests/data_loaders/test_yaml_loader.py b/tests/data_loaders/test_yaml_loader.py +index b4262cf3..e345891b 100644 --- a/tests/data_loaders/test_yaml_loader.py +++ b/tests/data_loaders/test_yaml_loader.py @@ -1,5 +1,5 @@ ++import pytest import fs.path -from nose.tools import eq_, raises -+import pytest from moban.core.data_loader import load_data from moban.plugins.yaml_loader import open_yaml -@@ -8,28 +8,28 @@ from moban.plugins.yaml_loader import op +@@ -8,28 +8,28 @@ def test_simple_yaml(): test_file = fs.path.join("tests", "fixtures", "simple.yaml") data = open_yaml(test_file) @@ -555,30 +521,65 @@ -@raises(IOError) -+@pytest.mark.xfail(raises=IOError) def test_exception_2(): test_file = fs.path.join("tests", "fixtures", "dragon.yaml") - load_data(fs.path.join("tests", "fixtures", "config"), test_file) +- load_data(fs.path.join("tests", "fixtures", "config"), test_file) ++ with pytest.raises(IOError): ++ load_data(fs.path.join("tests", "fixtures", "config"), test_file) -@raises(IOError) -+@pytest.mark.xfail(raises=IOError) def test_exception_3(): test_file = fs.path.join("tests", "fixtures", "dragon.yaml") - load_data(None, test_file) +- load_data(None, test_file) ++ with pytest.raises(IOError): ++ load_data(None, test_file) +diff --git a/tests/deprecated/test_handle_requires.py b/tests/deprecated/test_handle_requires.py +index f2c66bd5..ea8add72 100644 --- a/tests/deprecated/test_handle_requires.py +++ b/tests/deprecated/test_handle_requires.py -@@ -1,5 +1,7 @@ --from mock import patch +@@ -1,5 +1,5 @@ ++import pytest + from mock import patch -from nose.tools import eq_ -+try: -+ from mock import patch -+except ImportError: -+ from unittest.mock import patch from moban.deprecated import GitRequire -@@ -60,7 +62,7 @@ def test_handle_requires_repos_with_subm +@@ -16,7 +16,7 @@ def test_handle_requires_pypkg(fake_pip_install): + @patch("moban.deprecated.pip_install") + def test_handle_requires_pypkg_with_alternative_syntax(fake_pip_install): + modules = [{"type": "pypi", "name": "pypi-mobans"}] +- from moban.mobanfile import handle_requires ++ from moban.deprecated import handle_requires + + handle_requires(modules) + fake_pip_install.assert_called_with(["pypi-mobans"]) +@@ -25,7 +25,7 @@ def test_handle_requires_pypkg_with_alternative_syntax(fake_pip_install): + @patch("moban.deprecated.git_clone") + def test_handle_requires_repos(fake_git_clone): + repos = ["https://github.com/my/repo", "https://gitlab.com/my/repo"] +- from moban.mobanfile import handle_requires ++ from moban.deprecated import handle_requires + + expected = [] + for repo in repos: +@@ -38,7 +38,7 @@ def test_handle_requires_repos(fake_git_clone): + @patch("moban.deprecated.git_clone") + def test_handle_requires_repos_with_alternative_syntax(fake_git_clone): + repos = [{"type": "git", "url": "https://github.com/my/repo"}] +- from moban.mobanfile import handle_requires ++ from moban.deprecated import handle_requires + + handle_requires(repos) + fake_git_clone.assert_called_with( +@@ -54,13 +54,13 @@ def test_handle_requires_repos_with_submodule( + repos = [ + {"type": "git", "url": "https://github.com/my/repo", "submodule": True} + ] +- from moban.mobanfile import handle_requires ++ from moban.deprecated import handle_requires + + handle_requires(repos) fake_git_clone.assert_called_with( [GitRequire(git_url="https://github.com/my/repo", submodule=True)] ) @@ -587,27 +588,41 @@ def test_is_repo(): -@@ -75,4 +77,4 @@ def test_is_repo(): +@@ -75,4 +75,4 @@ def test_is_repo(): actual = [is_repo(repo) for repo in repos] expected = [True, True, True, False, False] - eq_(expected, actual) + assert expected == actual +diff --git a/tests/deprecated/test_repo.py b/tests/deprecated/test_repo.py +index eacafbed..d8029a8d 100644 --- a/tests/deprecated/test_repo.py +++ b/tests/deprecated/test_repo.py -@@ -1,6 +1,9 @@ - import fs.path --from mock import patch --from nose.tools import eq_, raises -+try: -+ from mock import patch -+except ImportError: -+ from unittest.mock import patch +@@ -1,6 +1,8 @@ ++import unittest ++ +import pytest + import fs.path + from mock import patch +-from nose.tools import eq_, raises from moban.deprecated import GitRequire from moban.exceptions import NoGitCommand -@@ -44,7 +47,7 @@ class TestGitFunctions: +@@ -13,10 +15,10 @@ + + + @patch("appdirs.user_cache_dir", return_value="root") +-@patch("moban.utils.mkdir_p") +-@patch("moban.file_system.exists") ++@patch("moban.externals.file_system.mkdir_p") ++@patch("moban.externals.file_system.exists") + @patch("git.Repo", autospec=True) +-class TestGitFunctions: ++class TestGitFunctions(unittest.TestCase): + def setUp(self): + self.repo_name = "repoA" + self.repo = "https://github.com/my/" + self.repo_name +@@ -44,7 +46,7 @@ def test_checkout_new(self, fake_repo, local_folder_exists, *_): depth=2, ) repo = fake_repo.return_value @@ -616,7 +631,7 @@ def test_checkout_new_with_submodules( self, fake_repo, local_folder_exists, *_ -@@ -89,7 +92,7 @@ class TestGitFunctions: +@@ -89,7 +91,7 @@ def test_checkout_new_with_branch( depth=2, ) repo = fake_repo.return_value @@ -625,7 +640,7 @@ def test_update_existing_with_branch_parameter( self, fake_repo, local_folder_exists, *_ -@@ -112,7 +115,7 @@ class TestGitFunctions: +@@ -112,7 +114,7 @@ def test_checkout_new_with_reference( depth=2, ) repo = fake_repo.return_value @@ -634,7 +649,7 @@ def test_update_existing_with_reference_parameter( self, fake_repo, local_folder_exists, *_ -@@ -135,7 +138,7 @@ def test_get_repo_name(): +@@ -135,10 +137,10 @@ def test_get_repo_name(): ] actual = [get_repo_name(repo) for repo in repos] expected = ["repo"] * len(repos) @@ -642,8 +657,12 @@ + assert expected == actual - @patch("moban.reporter.report_error_message") -@@ -152,10 +155,10 @@ def test_get_repo_name_can_handle_invali +-@patch("moban.reporter.report_error_message") ++@patch("moban.externals.reporter.report_error_message") + def test_get_repo_name_can_handle_invalid_url(fake_reporter): + invalid_repo = "invalid" + try: +@@ -152,10 +154,10 @@ def test_get_repo_name_can_handle_invalid_url(fake_reporter): @patch("appdirs.user_cache_dir", return_value="root") def test_get_moban_home(_): actual = get_moban_home() @@ -652,68 +671,138 @@ -@raises(NoGitCommand) -+@pytest.mark.xfail(raises=NoGitCommand) @patch("subprocess.check_output", side_effect=Exception) def test_make_git_is_available(_): - make_sure_git_is_available() +- make_sure_git_is_available() ++ with pytest.raises(NoGitCommand): ++ make_sure_git_is_available() +diff --git a/tests/integration_tests/__init__.py b/tests/integration_tests/__init__.py +new file mode 100644 +index 00000000..c3dff238 +--- /dev/null ++++ b/tests/integration_tests/__init__.py +@@ -0,0 +1,5 @@ ++from moban.main import load_engine_factory_and_engines ++ ++ ++def setUpModule(): ++ load_engine_factory_and_engines() +diff --git a/tests/integration_tests/test_command_line_options.py b/tests/integration_tests/test_command_line_options.py +index 6056b6ff..40601162 100644 --- a/tests/integration_tests/test_command_line_options.py +++ b/tests/integration_tests/test_command_line_options.py -@@ -2,9 +2,12 @@ import os +@@ -1,10 +1,11 @@ + import os import sys ++import unittest from shutil import copyfile --from mock import MagicMock, patch ++import fs ++import pytest + from mock import MagicMock, patch -from nose import SkipTest -from nose.tools import eq_, raises, assert_raises -+try: -+ from mock import MagicMock, patch -+except ImportError: -+ from unittest.mock import MagicMock, patch -+from unittest import SkipTest -+import pytest from moban.core.definitions import TemplateTarget -@@ -57,7 +60,7 @@ class TestCustomOptions: - "a.jj2", "config.yaml", "moban.output" - ) +@@ -14,7 +15,7 @@ + from io import StringIO + + +-class TestCustomOptions: ++class TestCustomOptions(unittest.TestCase): + def setUp(self): + self.config_file = "config.yaml" + with open(self.config_file, "w") as f: +@@ -53,7 +54,6 @@ def test_minimal_options(self, fake_template_doer): + main() + fake_template_doer.assert_called_with("a.jj2", "config.yaml", "-") - @raises(SystemExit) -+ @pytest.mark.xfail(raises=SystemExit) def test_missing_template(self): test_args = ["moban", "-c", self.config_file] fake_stdin = MagicMock(isatty=MagicMock(return_value=True)) -@@ -105,7 +108,7 @@ class TestOptions: - string_template, "data.yml", "moban.output" +@@ -61,14 +61,15 @@ def test_missing_template(self): + with patch.object(sys, "argv", test_args): + from moban.main import main + +- main() ++ with pytest.raises(SystemExit): ++ main() + + def tearDown(self): + self.patcher1.stop() + os.unlink(self.config_file) + + +-class TestOptions: ++class TestOptions(unittest.TestCase): + def setUp(self): + self.config_file = "data.yml" + with open(self.config_file, "w") as f: +@@ -99,7 +100,6 @@ def test_string_template(self, fake_template_doer): + string_template, "data.yml", "-" ) - @raises(SystemExit) -+ @pytest.mark.xfail(raises=SystemExit) def test_no_argments(self): test_args = ["moban"] fake_stdin = MagicMock(isatty=MagicMock(return_value=True)) -@@ -143,17 +146,15 @@ class TestNoOptions: +@@ -107,18 +107,19 @@ def test_no_argments(self): + with patch.object(sys, "argv", test_args): + from moban.main import main + +- main() ++ with pytest.raises(SystemExit): ++ main() + + def tearDown(self): + self.patcher1.stop() + os.unlink(self.config_file) + + +-class TestNoOptions: ++class TestNoOptions(unittest.TestCase): + def setUp(self): + self.config_file = ".moban.yml" + copyfile( +- os.path.join("tests", "fixtures", self.config_file), ++ fs.path.join("tests", "fixtures", self.config_file), + self.config_file, + ) + self.data_file = "data.yaml" +@@ -137,24 +138,19 @@ def test_single_command(self, fake_template_doer): main() call_args = list(fake_template_doer.call_args[0][0]) - eq_( - call_args, -+ assert call_args == \ - [ - TemplateTarget( - "README.rst.jj2", "data.yaml", "README.rst" - ), - TemplateTarget("setup.py.jj2", "data.yaml", "setup.py"), +- [ +- TemplateTarget( +- "README.rst.jj2", "data.yaml", "README.rst" +- ), +- TemplateTarget("setup.py.jj2", "data.yaml", "setup.py"), - ], - ) -+ ] ++ assert call_args == [ ++ TemplateTarget("README.rst.jj2", "data.yaml", "README.rst"), ++ TemplateTarget("setup.py.jj2", "data.yaml", "setup.py"), ++ ] - @raises(Exception) -+ @pytest.mark.xfail(raises=Exception) @patch("moban.core.moban_factory.MobanEngine.render_to_files") def test_single_command_with_missing_output(self, fake_template_doer): test_args = ["moban", "-t", "README.rst.jj2"] -@@ -171,10 +172,8 @@ class TestNoOptions: + with patch.object(sys, "argv", test_args): + from moban.main import main + +- main() ++ with pytest.raises(Exception): ++ main() + + @patch("moban.core.moban_factory.MobanEngine.render_to_files") + def test_single_command_with_a_few_options(self, fake_template_doer): +@@ -165,10 +161,9 @@ def test_single_command_with_a_few_options(self, fake_template_doer): main() call_args = list(fake_template_doer.call_args[0][0]) @@ -721,12 +810,13 @@ - call_args, - [TemplateTarget("README.rst.jj2", "data.yaml", "xyz.output")], - ) -+ assert call_args == \ -+ [TemplateTarget("README.rst.jj2", "data.yaml", "xyz.output")] ++ assert call_args == [ ++ TemplateTarget("README.rst.jj2", "data.yaml", "xyz.output") ++ ] @patch("moban.core.moban_factory.MobanEngine.render_to_files") def test_single_command_with_options(self, fake_template_doer): -@@ -192,12 +191,10 @@ class TestNoOptions: +@@ -186,18 +181,17 @@ def test_single_command_with_options(self, fake_template_doer): main() call_args = list(fake_template_doer.call_args[0][0]) @@ -734,115 +824,221 @@ - call_args, - [TemplateTarget("README.rst.jj2", "new.yml", "xyz.output")], - ) -+ assert call_args == \ -+ [TemplateTarget("README.rst.jj2", "new.yml", "xyz.output")] ++ assert call_args == [ ++ TemplateTarget("README.rst.jj2", "new.yml", "xyz.output") ++ ] - @raises(Exception) -+ @pytest.mark.xfail(raises=Exception) def test_single_command_without_output_option(self): test_args = ["moban", "-t", "abc.jj2"] with patch.object(sys, "argv", test_args): -@@ -234,15 +231,13 @@ class TestNoOptions2: + from moban.main import main + +- main() ++ with pytest.raises(Exception): ++ main() + + def tearDown(self): + os.unlink(self.config_file) +@@ -205,11 +199,11 @@ def tearDown(self): + self.patcher1.stop() + + +-class TestNoOptions2: ++class TestNoOptions2(unittest.TestCase): + def setUp(self): + self.config_file = ".moban.yml" + copyfile( +- os.path.join("tests", "fixtures", self.config_file), ++ fs.path.join("tests", "fixtures", self.config_file), + self.config_file, + ) + self.data_file = "data.yaml" +@@ -228,15 +222,10 @@ def test_single_command(self, fake_template_doer): main() call_args = list(fake_template_doer.call_args[0][0]) - eq_( - call_args, -+ assert call_args == \ - [ - TemplateTarget( - "README.rst.jj2", "data.yaml", "README.rst" - ), - TemplateTarget("setup.py.jj2", "data.yaml", "setup.py"), +- [ +- TemplateTarget( +- "README.rst.jj2", "data.yaml", "README.rst" +- ), +- TemplateTarget("setup.py.jj2", "data.yaml", "setup.py"), - ], - ) -+ ] ++ assert call_args == [ ++ TemplateTarget("README.rst.jj2", "data.yaml", "README.rst"), ++ TemplateTarget("setup.py.jj2", "data.yaml", "setup.py"), ++ ] def tearDown(self): self.patcher1.stop() -@@ -272,15 +267,13 @@ class TestCustomMobanFile: +@@ -244,11 +233,11 @@ def tearDown(self): + os.unlink(self.data_file) + + +-class TestCustomMobanFile: ++class TestCustomMobanFile(unittest.TestCase): + def setUp(self): + self.config_file = "custom-moban.txt" + copyfile( +- os.path.join("tests", "fixtures", ".moban.yml"), self.config_file ++ fs.path.join("tests", "fixtures", ".moban.yml"), self.config_file + ) + self.data_file = "data.yaml" + with open(self.data_file, "w") as f: +@@ -266,15 +255,10 @@ def test_single_command(self, fake_template_doer): main() call_args = list(fake_template_doer.call_args[0][0]) - eq_( - call_args, -+ assert call_args == \ - [ - TemplateTarget( - "README.rst.jj2", "data.yaml", "README.rst" - ), - TemplateTarget("setup.py.jj2", "data.yaml", "setup.py"), +- [ +- TemplateTarget( +- "README.rst.jj2", "data.yaml", "README.rst" +- ), +- TemplateTarget("setup.py.jj2", "data.yaml", "setup.py"), - ], - ) -+ ] ++ assert call_args == [ ++ TemplateTarget("README.rst.jj2", "data.yaml", "README.rst"), ++ TemplateTarget("setup.py.jj2", "data.yaml", "setup.py"), ++ ] def tearDown(self): self.patcher1.stop() -@@ -334,7 +327,8 @@ def test_duplicated_targets_in_moban_fil +@@ -282,11 +266,11 @@ def tearDown(self): + os.unlink(self.data_file) + + +-class TestTemplateOption: ++class TestTemplateOption(unittest.TestCase): + def setUp(self): + self.config_file = "custom-moban.txt" + copyfile( +- os.path.join("tests", "fixtures", ".moban.yml"), self.config_file ++ fs.path.join("tests", "fixtures", ".moban.yml"), self.config_file + ) + self.patcher1 = patch( + "moban.core.utils.verify_the_existence_of_directories" +@@ -321,20 +305,19 @@ def tearDown(self): + @patch("moban.core.utils.verify_the_existence_of_directories") + def test_duplicated_targets_in_moban_file(fake_verify): + config_file = "duplicated.moban.yml" +- copyfile(os.path.join("tests", "fixtures", config_file), ".moban.yml") ++ copyfile(fs.path.join("tests", "fixtures", config_file), ".moban.yml") + test_args = ["moban"] with patch.object(sys, "argv", test_args): from moban.main import main - assert_raises(SystemExit, main) -+ with pytest.raises(SystemExit): -+ main() ++ pytest.raises(SystemExit, main) os.unlink(".moban.yml") -@@ -342,7 +336,7 @@ class TestInvalidMobanFile: +-class TestInvalidMobanFile: ++class TestInvalidMobanFile(unittest.TestCase): def setUp(self): self.config_file = ".moban.yml" - @raises(SystemExit) -+ @pytest.mark.xfail(raises=SystemExit) @patch("moban.core.moban_factory.MobanEngine.render_to_files") def test_no_configuration(self, fake_template_doer): with open(self.config_file, "w") as f: -@@ -353,7 +347,7 @@ class TestInvalidMobanFile: +@@ -343,9 +326,9 @@ def test_no_configuration(self, fake_template_doer): + with patch.object(sys, "argv", test_args): + from moban.main import main - main() +- main() ++ with pytest.raises(SystemExit): ++ main() - @raises(SystemExit) -+ @pytest.mark.xfail(raises=SystemExit) @patch("moban.core.moban_factory.MobanEngine.render_to_files") def test_no_configuration_2(self, fake_template_doer): with open(self.config_file, "w") as f: -@@ -364,7 +358,7 @@ class TestInvalidMobanFile: +@@ -354,9 +337,9 @@ def test_no_configuration_2(self, fake_template_doer): + with patch.object(sys, "argv", test_args): + from moban.main import main - main() +- main() ++ with pytest.raises(SystemExit): ++ main() - @raises(SystemExit) -+ @pytest.mark.xfail(raises=SystemExit) @patch("moban.core.moban_factory.MobanEngine.render_to_files") def test_no_targets(self, fake_template_doer): with open(self.config_file, "w") as f: -@@ -403,15 +397,13 @@ class TestComplexOptions: +@@ -365,17 +348,18 @@ def test_no_targets(self, fake_template_doer): + with patch.object(sys, "argv", test_args): + from moban.main import main + +- main() ++ with pytest.raises(SystemExit): ++ main() + + def tearDown(self): + os.unlink(self.config_file) + + +-class TestComplexOptions: ++class TestComplexOptions(unittest.TestCase): + def setUp(self): + self.config_file = ".moban.yml" + copyfile( +- os.path.join("tests", "fixtures", ".moban-2.yml"), self.config_file ++ fs.path.join("tests", "fixtures", ".moban-2.yml"), self.config_file + ) + self.data_file = "data.yaml" + with open(self.data_file, "w") as f: +@@ -395,22 +379,19 @@ def test_single_command(self, _): ) as fake: main() call_args = list(fake.call_args[0][0]) - eq_( - call_args, -+ assert call_args == \ - [ - TemplateTarget( - "README.rst.jj2", "custom-data.yaml", "README.rst" - ), - TemplateTarget("setup.py.jj2", "data.yml", "setup.py"), +- [ +- TemplateTarget( +- "README.rst.jj2", "custom-data.yaml", "README.rst" +- ), +- TemplateTarget("setup.py.jj2", "data.yml", "setup.py"), - ], - ) -+ ] ++ assert call_args == [ ++ TemplateTarget( ++ "README.rst.jj2", "custom-data.yaml", "README.rst" ++ ), ++ TemplateTarget("setup.py.jj2", "data.yml", "setup.py"), ++ ] def tearDown(self): os.unlink(self.config_file) -@@ -439,7 +431,7 @@ class TestTemplateTypeOption: + os.unlink(self.data_file) + + +-class TestTemplateTypeOption: ++class TestTemplateTypeOption(unittest.TestCase): + def setUp(self): + self.config_file = "data.yml" + with open(self.config_file, "w") as f: +@@ -429,13 +410,13 @@ def tearDown(self): os.unlink(self.config_file) -@raises(SystemExit) -+@pytest.mark.xfail(raises=SystemExit) def test_version_option(): test_args = ["moban", "-V"] with patch.object(sys, "argv", test_args): -@@ -497,7 +489,7 @@ def test_git_repo_example(_): + from moban.main import main + +- main() ++ with pytest.raises(SystemExit): ++ main() + + + @patch("logging.basicConfig") +@@ -487,7 +468,7 @@ def test_git_repo_example(_): main() with open("test_git_repo_example.py") as f: content = f.read() @@ -851,7 +1047,7 @@ os.unlink("test_git_repo_example.py") -@@ -518,7 +510,7 @@ def test_pypi_pkg_example(_): +@@ -508,13 +489,13 @@ def test_pypi_pkg_example(_): main() with open("test_pypi_pkg_example.py") as f: content = f.read() @@ -860,30 +1056,85 @@ os.unlink("test_pypi_pkg_example.py") -@@ -548,10 +540,8 @@ def test_add_extension(): + def test_add_extension(): + if sys.version_info[0] == 2: +- raise SkipTest("jinja2-python-version does not support python 2") ++ return pytest.skip("jinja2-python-version does not support python 2") + test_commands = [ + [ + "moban", +@@ -542,16 +523,15 @@ def test_add_extension(): main() with open("moban.output") as f: content = f.read() - eq_( - content, - "{}.{}".format(sys.version_info[0], sys.version_info[1]), -- ) -+ assert content == \ -+ "{}.{}".format(sys.version_info[0], sys.version_info[1]) ++ assert content == "{}.{}".format( ++ sys.version_info[0], sys.version_info[1] + ) os.unlink("moban.output") -@@ -566,5 +556,5 @@ def test_stdin_input(): + def test_stdin_input(): + if sys.platform == "win32": +- raise SkipTest("windows test fails with this pipe test 2") ++ return pytest.skip("windows test fails with this pipe test 2") + test_args = ["moban", "-d", "hello=world", "-o", "moban.output"] + with patch.object(sys, "stdin", StringIO("{{hello}}")): + with patch.object(sys, "argv", test_args): +@@ -560,7 +540,7 @@ def test_stdin_input(): main() with open("moban.output") as f: content = f.read() - eq_(content, "world") + assert content == "world" os.unlink("moban.output") + + +@@ -571,7 +551,7 @@ def test_stdout(): + from moban.main import main + + main() +- eq_(fake_stdout.getvalue(), "world\n") ++ assert fake_stdout.getvalue() == "world\n" + + + def test_render_file_stdout(): +@@ -587,7 +567,7 @@ def test_render_file_stdout(): + from moban.main import main + + main() +- eq_(fake_stdout.getvalue(), "world\n") ++ assert fake_stdout.getvalue() == "world\n" + + + def test_custom_jinja2_filters_tests(): +@@ -616,4 +596,4 @@ def test_custom_jinja2_filters_tests(): + + "any template, any data and any location.\n" + ) + main() +- eq_(fake_stdout.getvalue(), expected_output) ++ assert fake_stdout.getvalue() == expected_output +diff --git a/tests/jinja2/__init__.py b/tests/jinja2/__init__.py +new file mode 100644 +index 00000000..c3dff238 +--- /dev/null ++++ b/tests/jinja2/__init__.py +@@ -0,0 +1,5 @@ ++from moban.main import load_engine_factory_and_engines ++ ++ ++def setUpModule(): ++ load_engine_factory_and_engines() +diff --git a/tests/jinja2/test_engine.py b/tests/jinja2/test_engine.py +index 4ebb396f..ac89ef20 100644 --- a/tests/jinja2/test_engine.py +++ b/tests/jinja2/test_engine.py -@@ -1,9 +1,7 @@ - import os +@@ -1,28 +1,27 @@ +-import os ++import fs ++import pytest -from nose.tools import eq_ - @@ -894,7 +1145,13 @@ def test_jinja2_template(): -@@ -14,7 +12,7 @@ def test_jinja2_template(): +- path = os.path.join("tests", "fixtures", "jinja_tests") +- fs = file_system.get_multi_fs([path]) +- engine = Engine(fs) ++ path = fs.path.join("tests", "fixtures", "jinja_tests") ++ fsys = file_system.get_multi_fs([path]) ++ engine = Engine(fsys) + template = engine.get_template("file_tests.template") data = dict(test="here") result = engine.apply_template(template, data, None) expected = "yes\nhere" @@ -903,56 +1160,60 @@ def test_jinja2_template_string(): -@@ -25,4 +23,4 @@ def test_jinja2_template_string(): +- path = os.path.join("tests", "fixtures", "jinja_tests") +- fs = file_system.get_multi_fs([path]) +- engine = Engine(fs) ++ path = fs.path.join("tests", "fixtures", "jinja_tests") ++ fsys = file_system.get_multi_fs([path]) ++ engine = Engine(fsys) + template = engine.get_template_from_string("{{test}}") data = dict(test="here") result = engine.apply_template(template, data, None) expected = "here" - eq_(expected, result) + assert expected == result +diff --git a/tests/jinja2/test_extensions.py b/tests/jinja2/test_extensions.py +index 4d602fc9..2a09cf2b 100644 --- a/tests/jinja2/test_extensions.py +++ b/tests/jinja2/test_extensions.py -@@ -1,10 +1,8 @@ +@@ -1,22 +1,23 @@ import os -from nose.tools import eq_ -- ++import fs ++import pytest + -from moban import file_system -from moban.jinja2.engine import Engine -from moban.jinja2.extensions import jinja_global +from moban.externals import file_system + from moban.core.moban_factory import MobanEngine +from moban.plugins.jinja2.engine import Engine +from moban.plugins.jinja2.extensions import jinja_global - from moban.core.moban_factory import MobanEngine -@@ -18,5 +16,5 @@ def test_globals(): + def test_globals(): + output = "globals.txt" + test_dict = dict(hello="world") + jinja_global("test", test_dict) +- path = os.path.join("tests", "fixtures", "globals") ++ path = fs.path.join("tests", "fixtures", "globals") + template_fs = file_system.get_multi_fs([path]) + engine = MobanEngine(template_fs, path, Engine(template_fs)) engine.render_to_file("basic.template", "basic.yml", output) with open(output, "r") as output_file: content = output_file.read() - eq_(content, "world\n\ntest") + assert content == "world\n\ntest" os.unlink(output) ---- a/tests/jinja2/test_github.py -+++ b/tests/jinja2/test_github.py -@@ -1,6 +1,4 @@ --from nose.tools import eq_ -- --from moban.jinja2.filters.github import github_expand -+from moban.plugins.jinja2.filters.github import github_expand - - - def test_github_expand(): -@@ -36,4 +34,4 @@ def test_github_expand(): - ] - for input_line, expect in zip(inputs, expectations): - actual = github_expand(*input_line) -- eq_(actual, expect) -+ assert actual == expect +diff --git a/tests/jinja2/test_repr.py b/tests/jinja2/test_repr.py +index 01d388ea..76a0af8d 100644 --- a/tests/jinja2/test_repr.py +++ b/tests/jinja2/test_repr.py -@@ -1,15 +1,13 @@ +@@ -1,15 +1,15 @@ -from nose.tools import eq_ -- ++import pytest + -from moban.jinja2.filters.repr import repr as repr_function +from moban.plugins.jinja2.filters.repr import repr as repr_function @@ -969,30 +1230,105 @@ expected = repr_function(me) - eq_(expected, ["'1'", "'2'", "'3'"]) + assert expected == ["'1'", "'2'", "'3'"] +diff --git a/tests/jinja2/test_text.py b/tests/jinja2/test_text.py +index 17f000df..1cb50079 100644 --- a/tests/jinja2/test_text.py +++ b/tests/jinja2/test_text.py -@@ -1,6 +1,4 @@ +@@ -1,6 +1,6 @@ -from nose.tools import eq_ -- ++import pytest + -from moban.jinja2.filters.text import split_length +from moban.plugins.jinja2.filters.text import split_length def test_split_length(): -@@ -18,4 +16,4 @@ def test_split_length(): +@@ -18,4 +18,4 @@ def test_split_length(): ] for test, expect in zip(inputs, expectations): actual = split_length(*test) - eq_(list(actual), expect) + assert list(actual) == expect +diff --git a/tests/mobanfile/test_mobanfile.py b/tests/mobanfile/test_mobanfile.py +index 905a72df..501e75c1 100644 +--- a/tests/mobanfile/test_mobanfile.py ++++ b/tests/mobanfile/test_mobanfile.py +@@ -1,6 +1,6 @@ ++import pytest + import fs.path + from mock import patch +-from nose.tools import eq_ + + from moban.core.definitions import TemplateTarget + +@@ -25,17 +25,14 @@ def test_handle_targets(fake_renderer): + handle_targets(options, short_hand_targets) + + call_args = list(fake_renderer.call_args[0][0]) +- eq_( +- call_args, +- [ +- TemplateTarget( +- "copier-test01.csv", +- "child.yaml", +- "output.csv", +- template_type="jinja2", +- ) +- ], +- ) ++ assert call_args == [ ++ TemplateTarget( ++ "copier-test01.csv", ++ "child.yaml", ++ "output.csv", ++ template_type="jinja2", ++ ) ++ ] + + + @patch("moban.core.moban_factory.MobanEngine.render_to_files") +@@ -63,21 +60,15 @@ def test_handle_targets_sequence(fake_renderer): + + call_args = list(fake_renderer.call_args_list) + +- eq_( +- call_args[0][0][0][0], +- TemplateTarget( +- "a.template.jj2", +- "child.yaml", +- "filterme.handlebars", +- template_type="jj2", +- ), ++ assert call_args[0][0][0][0] == TemplateTarget( ++ "a.template.jj2", ++ "child.yaml", ++ "filterme.handlebars", ++ template_type="jj2", + ) +- eq_( +- call_args[1][0][0][0], +- TemplateTarget( +- "filterme.handlebars", +- "child.yaml", +- "filtered_output.txt", +- template_type="handlebars", +- ), ++ assert call_args[1][0][0][0] == TemplateTarget( ++ "filterme.handlebars", ++ "child.yaml", ++ "filtered_output.txt", ++ template_type="handlebars", + ) +diff --git a/tests/mobanfile/test_targets.py b/tests/mobanfile/test_targets.py +index 836b481b..bb2280ae 100644 --- a/tests/mobanfile/test_targets.py +++ b/tests/mobanfile/test_targets.py @@ -1,7 +1,7 @@ import uuid ++import pytest import fs.path -from nose.tools import eq_, raises -+import pytest from moban.exceptions import GroupTargetNotFound from moban.core.mobanfile import targets @@ -1014,19 +1350,21 @@ -@raises(GroupTargetNotFound) -+@pytest.mark.xfail(raises=GroupTargetNotFound) def test_extract_group_targets_not_found(): test_targets = [ {"copy": [{"output": "source"}], "copy1": [{"output1": "source1"}]} ] - actual = targets.extract_group_targets("copy2", test_targets) - expected = [] +- actual = targets.extract_group_targets("copy2", test_targets) +- expected = [] - eq_(expected, actual) -+ assert expected == actual ++ with pytest.raises(GroupTargetNotFound): ++ actual = targets.extract_group_targets("copy2", test_targets) ++ expected = [] ++ assert expected == actual class TestImplicitTarget: -@@ -67,7 +67,7 @@ class TestImplicitTarget: +@@ -67,7 +67,7 @@ def test_derive_template_type_from_target_template_file(self): targets._handle_implicit_target(options, TEMPLATE, OUTPUT) ) expected = [TemplateTarget(TEMPLATE, CONFIGURATION, OUTPUT, "jj2")] @@ -1035,7 +1373,7 @@ def test_use_moban_default_template_from_options(self): template_without_suffix = "template" -@@ -91,7 +91,7 @@ class TestImplicitTarget: +@@ -91,7 +91,7 @@ def test_use_moban_default_template_from_options(self): DEFAULT_TEMPLATE_TYPE, ) ] @@ -1044,7 +1382,7 @@ class TestExplicitTarget: -@@ -106,7 +106,7 @@ class TestExplicitTarget: +@@ -106,7 +106,7 @@ def test_use_target_template_type(self): actual = list(targets._handle_explicit_target(options, target)) expected = [TemplateTarget(TEMPLATE, CONFIGURATION, OUTPUT, "use-me")] @@ -1053,7 +1391,7 @@ def test_derive_template_type_from_target_template_file(self): -@@ -119,7 +119,7 @@ class TestExplicitTarget: +@@ -119,7 +119,7 @@ def test_derive_template_type_from_target_template_file(self): actual = list(targets._handle_explicit_target(options, target)) expected = [TemplateTarget(TEMPLATE, CONFIGURATION, OUTPUT, "jj2")] @@ -1062,7 +1400,7 @@ def test_use_moban_default_template_from_options(self): template_without_suffix = "template" -@@ -139,7 +139,7 @@ class TestExplicitTarget: +@@ -139,7 +139,7 @@ def test_use_moban_default_template_from_options(self): DEFAULT_TEMPLATE_TYPE, ) ] @@ -1071,26 +1409,33 @@ def test_ad_hoc_type(self): target = dict(template=TEMPLATE, output=OUTPUT) -@@ -163,4 +163,4 @@ class TestExplicitTarget: +@@ -163,4 +163,4 @@ def test_ad_hoc_type(self): expected = [ TemplateTarget(TEMPLATE, CONFIGURATION, OUTPUT, file_extension) ] - eq_(actual, expected) + assert actual == expected +diff --git a/tests/mobanfile/test_templates.py b/tests/mobanfile/test_templates.py +index c3b54613..e49011d9 100644 --- a/tests/mobanfile/test_templates.py +++ b/tests/mobanfile/test_templates.py -@@ -1,6 +1,8 @@ +@@ -1,11 +1,13 @@ ++import unittest ++ ++import pytest import fs.path --from mock import patch + from mock import patch -from nose.tools import eq_ -+try: -+ from mock import patch -+except ImportError: -+ from unittest.mock import patch from moban.core.mobanfile.templates import handle_template -@@ -14,7 +16,7 @@ class TestHandleTemplateFunction: + +-class TestHandleTemplateFunction: ++class TestHandleTemplateFunction(unittest.TestCase): + def setUp(self): + self.base_dir = [fs.path.join("tests", "fixtures")] + +@@ -14,7 +16,7 @@ def test_copy_files(self): handle_template("copier-test01.csv", "/tmp/test", self.base_dir) ) expected = [("copier-test01.csv", "/tmp/test", "csv")] @@ -1099,7 +1444,7 @@ @patch("moban.externals.reporter.report_error_message") def test_file_not_found(self, reporter): -@@ -39,7 +41,7 @@ class TestHandleTemplateFunction: +@@ -39,7 +41,7 @@ def test_listing_dir(self): None, ) ] @@ -1108,37 +1453,68 @@ def test_listing_dir_recusively(self): test_dir = "/tmp/copy-a-directory" -@@ -60,10 +62,8 @@ class TestHandleTemplateFunction: +@@ -60,9 +62,8 @@ def test_listing_dir_recusively(self): None, ), ] - eq_( - sorted(results, key=lambda x: x[0]), - sorted(expected, key=lambda x: x[0]), -- ) -+ assert sorted(results, key=lambda x: x[0]) == \ -+ sorted(expected, key=lambda x: x[0]) ++ assert sorted(results, key=lambda x: x[0]) == sorted( ++ expected, key=lambda x: x[0] + ) @patch("moban.externals.reporter.report_error_message") - def test_listing_dir_recusively_with_error(self, reporter): -@@ -73,4 +73,4 @@ class TestHandleTemplateFunction: +@@ -73,4 +74,4 @@ def test_listing_dir_recusively_with_error(self, reporter): "copier-directory-does-not-exist/**", test_dir, self.base_dir ) ) - eq_(reporter.call_count, 1) + assert reporter.call_count == 1 +diff --git a/tests/requirements.txt b/tests/requirements.txt +index 505db119..75ee15c0 100644 +--- a/tests/requirements.txt ++++ b/tests/requirements.txt +@@ -1,4 +1,5 @@ +-nose ++pytest ++pytest-cov + codecov + coverage + mock +@@ -7,6 +8,7 @@ flake8 + black + isort + moban-handlebars ++moban-ansible + pypi-mobans-pkg==0.0.12 + arrow + jinja2_time +diff --git a/tests/test_buffered_writer.py b/tests/test_buffered_writer.py +index 02e5caaa..a4dc313c 100644 --- a/tests/test_buffered_writer.py +++ b/tests/test_buffered_writer.py -@@ -1,8 +1,6 @@ +@@ -1,7 +1,9 @@ import os import tempfile ++import unittest -from nose.tools import eq_ -- ++import fs ++import pytest + from moban.externals import file_system from moban.externals.buffered_writer import BufferedWriter, write_file_out +@@ -16,7 +18,7 @@ + EXPECTED = "\n helloworld\n\n\n\n\n " -@@ -25,7 +23,7 @@ class TestBufferedWriter: + +-class TestBufferedWriter: ++class TestBufferedWriter(unittest.TestCase): + def setUp(self): + self.writer = BufferedWriter() + +@@ -25,7 +27,7 @@ def test_write_text(self): self.writer.write_file_out(test_file, CONTENT) self.writer.close() content = file_system.read_text(test_file) @@ -1147,44 +1523,65 @@ os.unlink(test_file) def test_write_a_zip(self): -@@ -34,7 +32,7 @@ class TestBufferedWriter: +@@ -34,8 +36,8 @@ def test_write_a_zip(self): self.writer.write_file_out(test_file, CONTENT) self.writer.close() content = file_system.read_text(test_file) - eq_(content, EXPECTED) +- os.unlink(os.path.join(tmp_dir, "testout.zip")) + assert content == EXPECTED - os.unlink(os.path.join(tmp_dir, "testout.zip")) ++ os.unlink(fs.path.join(tmp_dir, "testout.zip")) -@@ -43,4 +41,4 @@ def test_write_file_out(): + def test_write_file_out(): +@@ -43,4 +45,4 @@ def test_write_file_out(): write_file_out(test_file, CONTENT) with open(test_file, "r") as f: content = f.read() - eq_(content, EXPECTED) + assert content == EXPECTED +diff --git a/tests/test_copy_engine.py b/tests/test_copy_engine.py +index 0dcb42d3..44e987b4 100644 --- a/tests/test_copy_engine.py +++ b/tests/test_copy_engine.py -@@ -1,7 +1,6 @@ +@@ -1,42 +1,45 @@ import os ++import unittest - import fs.path +-import fs.path -from nose.tools import eq_ ++import fs ++import pytest from moban.core import ENGINES from moban.externals import file_system -@@ -17,23 +16,23 @@ class TestContentForwardEngine: + + +-class TestContentForwardEngine: ++class TestContentForwardEngine(unittest.TestCase): + def setUp(self): +- template_path = os.path.join("tests", "fixtures") +- fs = file_system.get_multi_fs([template_path]) ++ template_path = fs.path.join("tests", "fixtures") ++ fsys = file_system.get_multi_fs([template_path]) + ContentForwardEngine = ENGINES.load_me_now("copy") +- self.engine = ContentForwardEngine(fs) ++ self.engine = ContentForwardEngine(fsys) + def test_get_template(self): template_content = self.engine.get_template("copier-test01.csv") # remove '\r' for windows - eq_("test 01\n", template_content.decode("utf-8").replace("\r", "")) -+ assert "test 01\n" == template_content.decode("utf-8").replace("\r", "") ++ assert "test 01\n", template_content.decode("utf-8").replace( ++ "\r" == "" ++ ) def test_encoding_of_template(self): template_content_ = self.engine.get_template("coala_color.svg") with open("tests/fixtures/coala_color.svg", "r") as expected: expected = expected.read() - eq_(expected, template_content_.decode("utf-8").replace("\r", "")) -+ assert expected == template_content_.decode("utf-8").replace("\r", "") ++ assert expected, template_content_.decode("utf-8").replace("\r" == "") def test_get_template_from_string(self): test_content = "simply forwarded" @@ -1199,8 +1596,12 @@ + assert test_content == template_content - class TestCopyEncoding: -@@ -47,8 +46,8 @@ class TestCopyEncoding: +-class TestCopyEncoding: ++class TestCopyEncoding(unittest.TestCase): + def setUp(self): + template_path = fs.path.join("tests", "fixtures") + template_fs = file_system.get_multi_fs([template_path]) +@@ -47,8 +50,8 @@ def test_encoding_of_template(self): template_content = self.engine.get_template("coala_color.svg") with open("tests/fixtures/coala_color.svg", "rb") as expected: expected = expected.read() @@ -1211,14 +1612,17 @@ expected = expected.read() - eq_(expected, template_content) + assert expected == template_content +diff --git a/tests/test_definitions.py b/tests/test_definitions.py +index a9a6a9d5..59b6b7d4 100644 --- a/tests/test_definitions.py +++ b/tests/test_definitions.py -@@ -1,24 +1,22 @@ +@@ -1,4 +1,4 @@ -from nose.tools import eq_ -- ++import pytest + from moban.deprecated import GitRequire from moban.core.definitions import TemplateTarget - +@@ -6,19 +6,19 @@ def test_git_require_repr(): require = GitRequire(git_url="http://github.com/some/repo") @@ -1241,7 +1645,7 @@ def test_template_target_output_suffix_updates_after_set(): -@@ -26,14 +24,14 @@ def test_template_target_output_suffix_u +@@ -26,14 +26,14 @@ def test_template_target_output_suffix_updates_after_set(): "template_file", "dat_file", "output.copy", template_type="copy" ) require.set_template_type("jinja2") @@ -1258,23 +1662,35 @@ def test_branch_params(): -@@ -42,4 +40,4 @@ def test_branch_params(): +@@ -42,4 +42,4 @@ def test_branch_params(): ) actual = require.clone_params() expected = {"single_branch": True, "branch": "ghpages", "depth": 2} - eq_(expected, actual) + assert expected == actual +diff --git a/tests/test_docs.py b/tests/test_docs.py +index 1b7f30fb..d3acf137 100644 --- a/tests/test_docs.py +++ b/tests/test_docs.py -@@ -1,7 +1,5 @@ +@@ -1,6 +1,7 @@ import os -from nose.tools import eq_ -- ++import fs ++import pytest + from .utils import Docs, custom_dedent +@@ -129,7 +130,7 @@ def test_level_7(self): + def test_level_8(self): + expected = "it is a test\n" + folder = "level-8-pass-a-folder-full-of-templates" +- check_file = os.path.join("templated-folder", "my") ++ check_file = fs.path.join("templated-folder", "my") + self.run_moban(["moban"], folder, [(check_file, expected)]) -@@ -314,7 +312,7 @@ class TestTutorial(Docs): + def test_level_9(self): +@@ -341,7 +342,7 @@ def test_level_19_with_group_target(self): ["moban", "-g", "copy"], folder, [("simple.file", expected)] ) # make sure only copy target is executed @@ -1283,132 +1699,401 @@ def test_level_22_intermediate_targets(self): expected = "a world\n" +diff --git a/tests/test_file_system.py b/tests/test_file_system.py +index 967642fa..374ce189 100644 +--- a/tests/test_file_system.py ++++ b/tests/test_file_system.py +@@ -3,9 +3,9 @@ + import stat + from shutil import rmtree + ++import fs ++import pytest + from mock import patch +-from nose import SkipTest +-from nose.tools import eq_, raises + + from moban.externals import file_system + from moban.exceptions import FileNotFound, UnsupportedPyFS2Protocol +@@ -48,7 +48,7 @@ def test_open_fs(): + def test_read_unicode(): + for url, expected in TEST_FILE_CONTENT_SPECS: + content = file_system.read_unicode(url) +- eq_(content, expected) ++ assert content == expected + + + TEST_FILE_CONTENT_SPECS_BINARY = [ +@@ -61,7 +61,7 @@ def test_read_unicode(): + def test_read_binary(): + for url, expected in TEST_FILE_CONTENT_SPECS_BINARY: + content = file_system.read_binary(url) +- eq_(content, expected) ++ assert content == expected + + + TEST_WRITE_BYTES_SPEC = [ +@@ -77,7 +77,7 @@ def test_write_bytes(): + + for url, expected in TEST_WRITE_BYTES_SPEC: + content = file_system.read_bytes(url) +- eq_(content, expected) ++ assert content == expected + + for file_name in ["test.binary", "test.zip", "test.tar"]: + os.unlink(file_name) +@@ -96,14 +96,14 @@ def test_write_bytes(): + def test_is_dir(): + for url, expected in TEST_DIR_SPEC: + status = file_system.is_dir(url) +- eq_(status, expected) ++ assert status == expected + + + def test_is_file(): + for url, is_dir in TEST_DIR_SPEC: + status = file_system.is_file(url) + expected = not is_dir +- eq_(status, expected) ++ assert status == expected + + + TEST_URL_EXITENCE_SPEC = [ +@@ -122,17 +122,17 @@ def test_is_file(): + def test_exists(): + for url, expected in TEST_URL_EXITENCE_SPEC: + status = file_system.exists(url) +- eq_(status, expected) ++ assert status == expected + + +-@raises(UnsupportedPyFS2Protocol) + def test_exists_raise_exception(): +- file_system.exists("git2://protocol/abc") ++ with pytest.raises(UnsupportedPyFS2Protocol): ++ file_system.exists("git2://protocol/abc") + + +-@raises(UnsupportedPyFS2Protocol) + def test_is_file_raise_exception(): +- file_system.is_file("git2://protocol/abc") ++ with pytest.raises(UnsupportedPyFS2Protocol): ++ file_system.is_file("git2://protocol/abc") + + + TEST_LIST_DIR_SPEC = [ +@@ -154,14 +154,14 @@ def test_is_file_raise_exception(): + def test_list_dir(): + for url, expected in TEST_LIST_DIR_SPEC: + file_list = sorted(list(file_system.list_dir(url))) +- eq_(file_list, sorted(expected)) ++ assert file_list == sorted(expected) + + + TEST_FILE_PATH = [ + [ + LOCAL_FOLDER + "/file_system", + os.path.normpath( +- os.path.join(os.getcwd(), "tests/fixtures/file_system") ++ fs.path.join(os.getcwd(), "tests/fixtures/file_system") + ), + ] + ] +@@ -170,7 +170,7 @@ def test_list_dir(): + def test_abspath(): + for path, expected in TEST_FILE_PATH: + url = file_system.abspath(path) +- eq_(url, expected) ++ assert url == expected + + + TEST_FILE_URL = [ +@@ -178,7 +178,7 @@ def test_abspath(): + LOCAL_FOLDER + "/file_system", + "osfs://" + + os.path.normpath( +- os.path.join(os.getcwd(), "tests/fixtures/file_system") ++ fs.path.join(os.getcwd(), "tests/fixtures/file_system") + ), + ] + ] +@@ -187,7 +187,7 @@ def test_abspath(): + def test_fs_url(): + for path, expected in TEST_FILE_URL: + url = file_system.fs_url(path) +- eq_(url, expected.replace("\\", "/")) ++ assert url, expected.replace("\\" == "/") + + + URL_JOIN_TEST_FIXTURES = [ +@@ -200,7 +200,7 @@ def test_fs_url(): + def test_url_join(): + for parent, child, expected_path in URL_JOIN_TEST_FIXTURES: + actual = file_system.url_join(parent, child) +- eq_(actual, expected_path) ++ assert actual == expected_path + + + def create_file(test_file, permission): +@@ -212,15 +212,14 @@ def create_file(test_file, permission): + + def test_file_permission_copy(): + if sys.platform == "win32": +- raise SkipTest("No actual chmod on windows") ++ return pytest.skip("No actual chmod on windows") + test_source = "test_file_permission_copy1" + test_dest = "test_file_permission_copy2" + create_file(test_source, 0o755) + create_file(test_dest, 0o646) + file_system.file_permissions_copy(test_source, test_dest) +- eq_( +- stat.S_IMODE(os.lstat(test_source).st_mode), +- stat.S_IMODE(os.lstat(test_dest).st_mode), ++ assert stat.S_IMODE(os.lstat(test_source).st_mode) == stat.S_IMODE( ++ os.lstat(test_dest).st_mode + ) + os.unlink(test_source) + os.unlink(test_dest) +@@ -229,19 +228,19 @@ def test_file_permission_copy(): + def file_permissions_disabled_on_windows(): + if sys.platform == "win32": + permissions = file_system.file_permissions("abc") +- eq_("no-permission-support", permissions) ++ assert "no-permission-support" == permissions + else: +- raise SkipTest("No test required") ++ return pytest.skip("No test required") + + +-@raises(FileNotFound) + def test_file_permissions_file_not_found(): +- file_system.file_permissions("I does not exist") ++ with pytest.raises(FileNotFound): ++ file_system.file_permissions("I does not exist") + + + def test_file_permission_copy_symlink(): + if sys.platform == "win32": +- raise SkipTest("No symlink on windows") ++ return pytest.skip("No symlink on windows") + test_source = "test_file_permission_copy1" + test_dest = "test_file_permission_copy2" + test_symlink = "test_file_permission_symlink" +@@ -249,9 +248,8 @@ def test_file_permission_copy_symlink(): + os.symlink(test_source, test_symlink) + create_file(test_dest, 0o646) + file_system.file_permissions_copy(test_source, test_dest) +- eq_( +- stat.S_IMODE(os.lstat(test_source).st_mode), +- stat.S_IMODE(os.lstat(test_dest).st_mode), ++ assert stat.S_IMODE(os.lstat(test_source).st_mode) == stat.S_IMODE( ++ os.lstat(test_dest).st_mode + ) + os.unlink(test_source) + os.unlink(test_dest) +diff --git a/tests/test_hash_store.py b/tests/test_hash_store.py +index 0f098d64..af4ad15e 100644 --- a/tests/test_hash_store.py +++ b/tests/test_hash_store.py -@@ -1,8 +1,11 @@ +@@ -1,15 +1,16 @@ import os import sys --from unittest.mock import patch -+try: -+ from mock import patch -+except ImportError: -+ from unittest.mock import patch ++import unittest + from unittest.mock import patch -from nose import SkipTest -+from unittest import SkipTest ++import pytest from moban.externals import file_system from moban.exceptions import NoPermissionsNeeded + from moban.core.hashstore import HashStore, get_file_hash + + +-class TestHashStore: ++class TestHashStore(unittest.TestCase): + def setUp(self): + self.source_template = file_system.path_join( + "tests", "fixtures", "a.jj2" +@@ -102,7 +103,7 @@ def test_dest_file_file_permision_changed(self): + the generated file had file permision change + """ + if sys.platform == "win32": +- raise SkipTest("No file permission check on windows") ++ return pytest.skip("No file permission check on windows") + hs = HashStore() + flag = hs.is_file_changed(*self.fixture) + if flag: +diff --git a/tests/test_main.py b/tests/test_main.py +index 070354d4..b3f40cbb 100644 --- a/tests/test_main.py +++ b/tests/test_main.py -@@ -2,8 +2,11 @@ import os +@@ -1,14 +1,16 @@ + import os import sys ++import unittest from shutil import copyfile --from mock import MagicMock, patch --from nose.tools import eq_, raises, assert_raises -+try: -+ from mock import MagicMock, patch -+except ImportError: -+ from unittest.mock import MagicMock, patch ++import fs +import pytest + from mock import MagicMock, patch +-from nose.tools import eq_, raises, assert_raises import moban.exceptions as exceptions -@@ -19,7 +22,7 @@ class TestException: + +-class TestException: ++class TestException(unittest.TestCase): + def setUp(self): + self.moban_file = ".moban.yml" + self.data_file = "data.yml" +@@ -19,15 +21,15 @@ def tearDown(self): if os.path.exists(self.data_file): os.unlink(self.data_file) - @raises(exceptions.MobanfileGrammarException) -+ @pytest.mark.xfail(raises=exceptions.MobanfileGrammarException) def test_handle_moban_file(self): copyfile( - os.path.join("tests", "fixtures", ".moban-version-1234.yml"), -@@ -54,17 +57,13 @@ class TestException: +- os.path.join("tests", "fixtures", ".moban-version-1234.yml"), ++ fs.path.join("tests", "fixtures", ".moban-version-1234.yml"), + self.moban_file, + ) + import moban.main as main + +- main.handle_moban_file(self.moban_file, {}) ++ with pytest.raises(exceptions.MobanfileGrammarException): ++ main.handle_moban_file(self.moban_file, {}) + + def test_check_none(self): + from ruamel.yaml import YAML +@@ -55,7 +57,7 @@ def test_check_none(self): ] for data in (yaml.load(d) for d in invalid_data): - assert_raises( -- exceptions.MobanfileGrammarException, -- main.check_none, -- data, -- ".moban.yaml", -- ) -+ with pytest.raises(exceptions.MobanfileGrammarException): -+ main.check_none(data, ".moban.yaml") - ++ pytest.raises( + exceptions.MobanfileGrammarException, + main.check_none, + data, +@@ -65,21 +67,20 @@ def test_check_none(self): for data in (yaml.load(d) for d in valid_data): main.check_none(data, ".moban.yaml") - @raises(exceptions.MobanfileGrammarException) -+ @pytest.mark.xfail(raises=exceptions.MobanfileGrammarException) def test_version_1_is_recognized(self): copyfile( - os.path.join("tests", "fixtures", ".moban-version-1.0.yml"), -@@ -78,7 +77,7 @@ class TestException: +- os.path.join("tests", "fixtures", ".moban-version-1.0.yml"), ++ fs.path.join("tests", "fixtures", ".moban-version-1.0.yml"), + self.moban_file, + ) + copyfile( +- os.path.join("tests", "fixtures", ".moban-version-1.0.yml"), ++ fs.path.join("tests", "fixtures", ".moban-version-1.0.yml"), + self.data_file, + ) + import moban.main as main - main.handle_moban_file(self.moban_file, {}) +- main.handle_moban_file(self.moban_file, {}) ++ with pytest.raises(exceptions.MobanfileGrammarException): ++ main.handle_moban_file(self.moban_file, {}) - @raises(SystemExit) -+ @pytest.mark.xfail(raises=SystemExit) @patch("os.path.exists") @patch("moban.main.handle_moban_file") @patch("moban.externals.reporter.report_error_message") -@@ -94,7 +93,7 @@ class TestException: - - main() - -- @raises(SystemExit) -+ @pytest.mark.xfail(raises=SystemExit) - @patch("os.path.exists") - @patch("moban.main.handle_moban_file") - @patch("moban.externals.reporter.report_error_message") -@@ -108,7 +107,7 @@ class TestException: +@@ -93,9 +94,9 @@ def test_directory_not_found( with patch.object(sys, "argv", ["moban"]): - main() + from moban.main import main + +- main() ++ with pytest.raises(SystemExit): ++ main() + +- @raises(SystemExit) + @patch("os.path.exists") + @patch("moban.main.handle_moban_file") + @patch("moban.externals.reporter.report_error_message") +@@ -107,9 +108,9 @@ def test_unknown_protocol(self, fake_reporter, fake_moban_file, fake_file): + from moban.main import main + + with patch.object(sys, "argv", ["moban"]): +- main() ++ with pytest.raises(SystemExit): ++ main() - @raises(SystemExit) -+ @pytest.mark.xfail(raises=SystemExit) @patch("os.path.exists") @patch("moban.main.handle_command_line") @patch("moban.externals.reporter.report_error_message") -@@ -124,7 +123,7 @@ class TestException: +@@ -123,9 +124,9 @@ def test_unknown_protocol_at_command_line( + from moban.main import main + with patch.object(sys, "argv", ["moban"]): - main() +- main() ++ with pytest.raises(SystemExit): ++ main() - @raises(SystemExit) -+ @pytest.mark.xfail(raises=SystemExit) @patch("os.path.exists") @patch("moban.main.handle_moban_file") @patch("moban.externals.reporter.report_error_message") -@@ -140,7 +139,7 @@ class TestException: +@@ -139,9 +140,9 @@ def test_no_third_party_engine( + from moban.main import main + with patch.object(sys, "argv", ["moban"]): - main() +- main() ++ with pytest.raises(SystemExit): ++ main() - @raises(SystemExit) -+ @pytest.mark.xfail(raises=SystemExit) @patch("os.path.exists") @patch("moban.main.handle_moban_file") @patch("moban.externals.reporter.report_error_message") -@@ -158,7 +157,7 @@ class TestException: +@@ -155,11 +156,11 @@ def test_double_underscore_main( + from moban.__main__ import main + + with patch.object(sys, "argv", ["moban"]): +- main() ++ with pytest.raises(SystemExit): ++ main() class TestExitCodes: - @raises(SystemExit) -+ @pytest.mark.xfail(raises=SystemExit) @patch("moban.main.handle_moban_file") @patch("moban.main.find_default_moban_file") def test_has_many_files_with_exit_code( -@@ -171,7 +170,7 @@ class TestExitCodes: +@@ -170,9 +171,9 @@ def test_has_many_files_with_exit_code( + from moban.main import main + with patch.object(sys, "argv", ["moban", "--exit-code"]): - main() +- main() ++ with pytest.raises(SystemExit): ++ main() - @raises(SystemExit) -+ @pytest.mark.xfail(raises=SystemExit) @patch("moban.main.handle_command_line") @patch("moban.main.find_default_moban_file") def test_handle_single_change_with_exit_code( -@@ -220,14 +219,14 @@ class TestFinder: +@@ -183,7 +184,8 @@ def test_handle_single_change_with_exit_code( + from moban.main import main + + with patch.object(sys, "argv", ["moban", "--exit-code"]): +- main() ++ with pytest.raises(SystemExit): ++ main() + + @patch("moban.main.handle_moban_file") + @patch("moban.main.find_default_moban_file") +@@ -206,7 +208,7 @@ def test_handle_single_change(self, fake_find_file, fake_command_line): + main() + + +-class TestFinder: ++class TestFinder(unittest.TestCase): + def setUp(self): + self.patcher = patch("moban.externals.file_system.exists") + self.fake_file_existence = self.patcher.start() +@@ -221,14 +223,14 @@ def test_moban_yml(self): from moban.main import find_default_moban_file actual = find_default_moban_file() @@ -1425,143 +2110,172 @@ def test_no_moban_file(self): self.fake_file_existence.side_effect = [False, False] +diff --git a/tests/test_regression.py b/tests/test_regression.py +index e1b337fd..ac635ab1 100644 +--- a/tests/test_regression.py ++++ b/tests/test_regression.py +@@ -1,15 +1,16 @@ + import os + import sys + import filecmp ++import unittest + +-import fs.path ++import fs + from mock import patch + + from moban.main import main + from .utils import Docs + + +-class TestRegression(Docs): ++class TestRegression(Docs, unittest.TestCase): + def setUp(self): + super(TestRegression, self).setUp() + self.base_folder = fs.path.join("tests", "regression_tests") +diff --git a/tests/test_reporter.py b/tests/test_reporter.py +index 386c0512..e0e020a5 100644 --- a/tests/test_reporter.py +++ b/tests/test_reporter.py -@@ -1,7 +1,9 @@ +@@ -1,7 +1,8 @@ import sys ++import unittest --from mock import patch ++import pytest + from mock import patch -from nose.tools import eq_ -+try: -+ from mock import patch -+except ImportError: -+ from unittest.mock import patch from moban.externals import reporter -@@ -17,7 +19,7 @@ def test_partial_run(): - fake_stdout = patcher.start() - reporter.report_partial_run("Actioned", 1, 20) - patcher.stop() -- eq_(fake_stdout.getvalue(), "Actioned 1 out of 20 files.\n") -+ assert fake_stdout.getvalue() == "Actioned 1 out of 20 files.\n" +@@ -12,7 +13,7 @@ + from io import StringIO - def test_full_run(): -@@ -25,7 +27,7 @@ def test_full_run(): - fake_stdout = patcher.start() - reporter.report_full_run("Worked on", 20) - patcher.stop() -- eq_(fake_stdout.getvalue(), "Worked on 20 files.\n") -+ assert fake_stdout.getvalue() == "Worked on 20 files.\n" +-class TestReporter: ++class TestReporter(unittest.TestCase): + def setUp(self): + reporter.GLOBAL["PRINT"] = True +@@ -21,63 +22,63 @@ def test_partial_run(self): + fake_stdout = patcher.start() + reporter.report_partial_run("Actioned", 1, 20) + patcher.stop() +- eq_(fake_stdout.getvalue(), "Actioned 1 out of 20 files.\n") ++ assert fake_stdout.getvalue() == "Actioned 1 out of 20 files.\n" - def test_error_message(): -@@ -33,7 +35,7 @@ def test_error_message(): - fake_stdout = patcher.start() - reporter.report_error_message("something wrong") - patcher.stop() -- eq_(fake_stdout.getvalue(), "Error: something wrong\n") -+ assert fake_stdout.getvalue() == "Error: something wrong\n" + def test_full_run(self): + patcher = patch("sys.stdout", new_callable=StringIO) + fake_stdout = patcher.start() + reporter.report_full_run("Worked on", 20) + patcher.stop() +- eq_(fake_stdout.getvalue(), "Worked on 20 files.\n") ++ assert fake_stdout.getvalue() == "Worked on 20 files.\n" + def test_error_message(self): + patcher = patch("sys.stderr", new_callable=StringIO) + fake_stdout = patcher.start() + reporter.report_error_message("something wrong") + patcher.stop() +- eq_(fake_stdout.getvalue(), "Error: something wrong\n") ++ assert fake_stdout.getvalue() == "Error: something wrong\n" - def test_info_message(): -@@ -41,7 +43,7 @@ def test_info_message(): - fake_stdout = patcher.start() - reporter.report_info_message("for your information") - patcher.stop() -- eq_(fake_stdout.getvalue(), "Info: for your information\n") -+ assert fake_stdout.getvalue() == "Info: for your information\n" + def test_info_message(self): + patcher = patch("sys.stdout", new_callable=StringIO) + fake_stdout = patcher.start() + reporter.report_info_message("for your information") + patcher.stop() +- eq_(fake_stdout.getvalue(), "Info: for your information\n") ++ assert fake_stdout.getvalue() == "Info: for your information\n" + def test_warning_message(self): + patcher = patch("sys.stderr", new_callable=StringIO) + fake_stdout = patcher.start() + reporter.report_warning_message("Maybe you wanna know") + patcher.stop() +- eq_(fake_stdout.getvalue(), "Warning: Maybe you wanna know\n") ++ assert fake_stdout.getvalue() == "Warning: Maybe you wanna know\n" - def test_warning_message(): -@@ -49,7 +51,7 @@ def test_warning_message(): - fake_stdout = patcher.start() - reporter.report_warning_message("Maybe you wanna know") - patcher.stop() -- eq_(fake_stdout.getvalue(), "Warning: Maybe you wanna know\n") -+ assert fake_stdout.getvalue() == "Warning: Maybe you wanna know\n" + def test_report_templating(self): + patcher = patch("sys.stdout", new_callable=StringIO) + fake_stdout = patcher.start() + reporter.report_templating("Transforming", "a", "b") + patcher.stop() +- eq_(fake_stdout.getvalue(), "Transforming a to b\n") ++ assert fake_stdout.getvalue() == "Transforming a to b\n" + def test_no_action(self): + patcher = patch("sys.stdout", new_callable=StringIO) + fake_stdout = patcher.start() + reporter.report_no_action() + patcher.stop() +- eq_(fake_stdout.getvalue(), "No actions performed\n") ++ assert fake_stdout.getvalue() == "No actions performed\n" - def test_report_templating(): -@@ -57,7 +59,7 @@ def test_report_templating(): - fake_stdout = patcher.start() - reporter.report_templating("Transforming", "a", "b") - patcher.stop() -- eq_(fake_stdout.getvalue(), "Transforming a to b\n") -+ assert fake_stdout.getvalue() == "Transforming a to b\n" + def test_format_single(self): + message = "1 files" + ret = reporter._format_single(message, 1) +- eq_(ret, "1 file") ++ assert ret == "1 file" + def test_report_template_not_in_moban_file(self): + patcher = patch("sys.stderr", new_callable=StringIO) + fake_stdout = patcher.start() + reporter.report_template_not_in_moban_file("test.jj2") + patcher.stop() +- eq_( +- fake_stdout.getvalue(), +- "Warning: test.jj2 is not defined in your moban file!\n", ++ assert ( ++ fake_stdout.getvalue() ++ == "Warning: test.jj2 is not defined in your moban file!\n" + ) - def test_no_action(): -@@ -65,13 +67,13 @@ def test_no_action(): - fake_stdout = patcher.start() - reporter.report_no_action() - patcher.stop() -- eq_(fake_stdout.getvalue(), "No actions performed\n") -+ assert fake_stdout.getvalue() == "No actions performed\n" - - - def test_format_single(): - message = "1 files" - ret = reporter._format_single(message, 1) -- eq_(ret, "1 file") -+ assert ret == "1 file" - - - def test_report_template_not_in_moban_file(): -@@ -79,10 +81,8 @@ def test_report_template_not_in_moban_fi - fake_stdout = patcher.start() - reporter.report_template_not_in_moban_file("test.jj2") - patcher.stop() -- eq_( -- fake_stdout.getvalue(), -- "Warning: test.jj2 is not defined in your moban file!\n", -- ) -+ assert fake_stdout.getvalue() == \ -+ "Warning: test.jj2 is not defined in your moban file!\n" - - - def test_report_file_extension_not_needed(): -@@ -90,7 +90,5 @@ def test_report_file_extension_not_neede - fake_stdout = patcher.start() - reporter.report_file_extension_not_needed() - patcher.stop() -- eq_( -- fake_stdout.getvalue(), -- "Info: File extension is not required for ad-hoc type\n", -- ) -+ assert fake_stdout.getvalue() == \ -+ "Info: File extension is not required for ad-hoc type\n" + def test_report_file_extension_not_needed(self): +@@ -85,7 +86,7 @@ def test_report_file_extension_not_needed(self): + fake_stdout = patcher.start() + reporter.report_file_extension_not_needed() + patcher.stop() +- eq_( +- fake_stdout.getvalue(), +- "Info: File extension is not required for ad-hoc type\n", ++ assert ( ++ fake_stdout.getvalue() ++ == "Info: File extension is not required for ad-hoc type\n" + ) +diff --git a/tests/test_store.py b/tests/test_store.py +index 6fa8309f..3d2e9bcb 100644 --- a/tests/test_store.py +++ b/tests/test_store.py -@@ -1,5 +1,3 @@ +@@ -1,4 +1,4 @@ -from nose.tools import eq_ -- ++import pytest + from moban.core.definitions import TemplateTarget from moban.core.mobanfile.store import Store - -@@ -9,4 +7,4 @@ def test_store(): +@@ -9,4 +9,4 @@ def test_store(): output = "output" target = TemplateTarget("template_file", "data_file", output) store.add(target) - eq_(target, store.look_up_by_output.get(output)) + assert target == store.look_up_by_output.get(output) +diff --git a/tests/utils.py b/tests/utils.py +index 9f9983c4..320c5298 100644 --- a/tests/utils.py +++ b/tests/utils.py -@@ -2,8 +2,10 @@ import os +@@ -1,9 +1,11 @@ + import os import sys ++import unittest from textwrap import dedent --from mock import patch ++import fs ++import pytest + from mock import patch -from nose.tools import eq_ -+try: -+ from mock import patch -+except ImportError: -+ from unittest.mock import patch from fs.opener.parse import parse_fs_url from moban.main import main -@@ -13,12 +15,12 @@ from moban.externals import file_system +@@ -13,12 +15,12 @@ def verify_content(file_name, expected): with open(file_name, "r") as f: content = f.read() @@ -1576,83 +2290,27 @@ def run_moban(args, folder, criterias): ---- a/setup.py -+++ b/setup.py -@@ -261,7 +261,7 @@ if __name__ == "__main__": - keywords=KEYWORDS, - python_requires=PYTHON_REQUIRES, - extras_require=EXTRAS_REQUIRE, -- tests_require=["nose"], -+ tests_require=["pytest"], - install_requires=INSTALL_REQUIRES, - packages=PACKAGES, - include_package_data=True, ---- a/tests/mobanfile/test_mobanfile.py -+++ b/tests/mobanfile/test_mobanfile.py -@@ -1,6 +1,8 @@ - import fs.path --from mock import patch --from nose.tools import eq_ -+try: -+ from mock import patch -+except ImportError: -+ from unittest.mock import patch - - from moban.core.definitions import TemplateTarget - -@@ -25,8 +27,7 @@ def test_handle_targets(fake_renderer): - handle_targets(options, short_hand_targets) - - call_args = list(fake_renderer.call_args[0][0]) -- eq_( -- call_args, -+ assert call_args == \ - [ - TemplateTarget( - "copier-test01.csv", -@@ -34,8 +35,7 @@ def test_handle_targets(fake_renderer): - "output.csv", - template_type="jinja2", - ) -- ], -- ) -+ ] +@@ -39,7 +41,7 @@ def run_moban_with_fs(args, folder, criterias): + os.unlink(result.resource) # delete the zip file - @patch("moban.core.moban_factory.MobanEngine.render_to_files") -@@ -63,21 +63,17 @@ def test_handle_targets_sequence(fake_re +-class Docs(object): ++class Docs(unittest.TestCase): + def setUp(self): + self.current = os.getcwd() + self.base_folder = "docs" +@@ -50,11 +52,11 @@ def tearDown(self): + os.chdir(self.current) - call_args = list(fake_renderer.call_args_list) + def run_moban(self, moban_cli, working_directory, assertions): +- os.chdir(os.path.join(self.base_folder, working_directory)) ++ os.chdir(fs.path.join(self.base_folder, working_directory)) + run_moban(moban_cli, None, assertions) -- eq_( -- call_args[0][0][0][0], -+ assert call_args[0][0][0][0] == \ - TemplateTarget( - "a.template.jj2", - "child.yaml", - "filterme.handlebars", - template_type="jj2", -- ), -- ) -- eq_( -- call_args[1][0][0][0], -+ ) -+ assert call_args[1][0][0][0] == \ - TemplateTarget( - "filterme.handlebars", - "child.yaml", - "filtered_output.txt", - template_type="handlebars", -- ), -- ) -+ ) ---- /dev/null -+++ b/tests/core/__init__.py -@@ -0,0 +1 @@ -+# This file is intentionally left blank. -\ No newline at end of file ---- /dev/null -+++ b/tests/jinja2/__init__.py -@@ -0,0 +1 @@ -+# This file is intentionally left blank. -\ No newline at end of file + def run_moban_with_fs(self, moban_cli, working_directory, assertions): +- os.chdir(os.path.join(self.base_folder, working_directory)) ++ os.chdir(fs.path.join(self.base_folder, working_directory)) + run_moban_with_fs(moban_cli, None, assertions) + + +