diff --git a/.moban.cd/changelog.yml b/.moban.cd/changelog.yml index ce785105..6b719e6c 100644 --- a/.moban.cd/changelog.yml +++ b/.moban.cd/changelog.yml @@ -1,6 +1,16 @@ name: moban organisation: moremoban releases: + - changes: + - action: Removed + details: + - "`#360`: make gitfs2 and pypifs optional." + - "`#303`: python 2.7 support is dropped." + - action: Updated + details: + - "`#360`: show friendlier error when unknown protocol exception was raised." + date: 18.01.2020 + version: 0.7.0 - changes: - action: Updated details: diff --git a/.moban.cd/moban.yml b/.moban.cd/moban.yml index b73096a0..103ade72 100644 --- a/.moban.cd/moban.yml +++ b/.moban.cd/moban.yml @@ -4,9 +4,9 @@ organisation: moremoban author: C. W. contact: wangc_2011@hotmail.com license: MIT -version: 0.6.8 -current_version: 0.6.8 -release: 0.6.8 +version: 0.7.0 +current_version: 0.7.0 +release: 0.7.0 branch: master master: index command_line_interface: "moban" @@ -27,12 +27,11 @@ dependencies: - appdirs>=1.4.3 - crayons>= 0.1.0 - fs>=2.4.11 - - gitfs2>=0.0.2 - - pypifs>=0.0.1 - jinja2-fsloader>=0.2.0 -description: Yet another jinja2 cli command for static text generation +description: General purpose static text generator scm_host: github.com lint_command: make install_test format git-diff-check lint moban_command: make update git-diff-check setup_use_markers: true setup_use_markers_fix: true +python_requires: ">=3.6" diff --git a/.moban.d/moban_travis.yml.jj2 b/.moban.d/moban_travis.yml.jj2 index 5a68710f..0123c0e6 100644 --- a/.moban.d/moban_travis.yml.jj2 +++ b/.moban.d/moban_travis.yml.jj2 @@ -8,10 +8,7 @@ env: {%block custom_python_versions%} python: - - &pypy2 pypy2.7-6.0 - 3.7 - 3.6 - - 3.5 - - 2.7 - 3.8 {%endblock%} diff --git a/.travis.yml b/.travis.yml index 11350c54..d6fb2b1e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,11 +4,8 @@ language: python notifications: email: false python: - - &pypy2 pypy2.7-6.0 - 3.7 - 3.6 - - 3.5 - - 2.7 - 3.8 env: - MINREQ=0 diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 06c2bf60..f1f59bda 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,21 @@ Change log ================================================================================ +0.7.0 - 18.01.2020 +-------------------------------------------------------------------------------- + +**Removed** + +#. `#360 `_: make gitfs2 and + pypifs optional. +#. `#303 `_: python 2.7 support + is dropped. + +**Updated** + +#. `#360 `_: show friendlier + error when unknown protocol exception was raised. + 0.6.8 - 7.12.2019 -------------------------------------------------------------------------------- diff --git a/README.rst b/README.rst index 41355eb6..23652806 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ ================================================================================ -moban - 模板 Any template, any data in any location +mó bǎn - 模板 General purpose static text generator ================================================================================ .. image:: https://api.travis-ci.org/moremoban/moban.svg?branch=master @@ -28,6 +28,17 @@ moban - 模板 Any template, any data in any location :License: MIT +Announcement +================================================================================ + +For existing moban users, python 2 support has been dropped. Please stay with +versions lower than 0.7.0 if you are still using python 2. + +From 2020 onwards, minimum requirement is Python 3.6 + +Introduction +================================================================================ + **moban** started with bringing the high performance template engine (JINJA2) for web into static text generation. It has been used in `pyexcel` and `coala` project to keep documentation consistent across the documentations of individual libraries in the same @@ -38,6 +49,11 @@ haml, slim and tornado, can read other data format: json and yaml, and can acces template file and configuration file in any location: zip, git, pypi package, s3, etc. +Vision +================================================================================ + +Any template, any data in any location + Support ================================================================================ @@ -49,6 +65,11 @@ the project and develop it further. With your financial support, I will be able to invest a little bit more time in coding, documentation and writing interesting extensions. +Credit +================================================================================ + +`jinja2-fsloader` is the key component to enable PyFilesystem2 support in moban +v0.6x. Please show your stars there too! Installation ================================================================================ @@ -129,7 +150,8 @@ All use cases are documented `here `_ is installed by default since v0.6.1 +`gitfs2 `_ is optional since v0.7.0 but was +installed by default since v0.6.1 You can do the following with moban: @@ -150,7 +172,8 @@ You can do the following with moban: Work with files in a python package ================================================================================ -`pypifs `_ is installed by default since v0.6.1 +`pypifs `_ is optional since v0.7.0 but +was installed by default since v0.6.1 You can do the following with moban: diff --git a/docs/conf.py b/docs/conf.py index 6350db0c..7797a47e 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- DESCRIPTION = ( - 'Yet another jinja2 cli command for static text generation' + + 'General purpose static text generator' + '' ) # Configuration file for the Sphinx documentation builder. @@ -25,9 +25,9 @@ copyright = '2017-2019 Onni Software Ltd.' author = 'C. W.' # The short X.Y version -version = '0.6.8' +version = '0.7.0' # The full version, including alpha/beta/rc tags -release = '0.6.8' +release = '0.7.0' # -- General configuration --------------------------------------------------- diff --git a/min_requirements.txt b/min_requirements.txt index 098725ab..c3cac050 100644 --- a/min_requirements.txt +++ b/min_requirements.txt @@ -7,6 +7,4 @@ lml==0.0.9 appdirs==1.4.3 crayons== 0.1.0 fs==2.4.11 -gitfs2==0.0.2 -pypifs==0.0.1 jinja2-fsloader==0.2.0 diff --git a/moban/_version.py b/moban/_version.py index fdefb44c..a5e28e1e 100644 --- a/moban/_version.py +++ b/moban/_version.py @@ -1,2 +1,2 @@ -__version__ = "0.6.8" +__version__ = "0.7.0" __author__ = "C. W." diff --git a/moban/core/hashstore.py b/moban/core/hashstore.py index 3987ce65..aae1d4b5 100644 --- a/moban/core/hashstore.py +++ b/moban/core/hashstore.py @@ -1,20 +1,15 @@ -import sys import json import hashlib from moban import constants from moban.externals import file_system -PY2 = sys.version_info[0] == 2 - class HashStore: IGNORE_CACHE_FILE = False def __init__(self): - self.cache_file = file_system.to_unicode( - constants.DEFAULT_MOBAN_CACHE_FILE - ) + self.cache_file = constants.DEFAULT_MOBAN_CACHE_FILE if ( file_system.exists(self.cache_file) and self.IGNORE_CACHE_FILE is False @@ -68,13 +63,10 @@ def get_file_hash(afile): def get_hash(content): md5 = hashlib.md5() - if PY2 and content.__class__.__name__ == "unicode": - content = content.encode("utf-8") md5.update(content) return md5.digest().decode("latin1") def _mix(content, file_permissions_copy): - if not PY2: - file_permissions_copy = file_permissions_copy.encode("utf-8") + file_permissions_copy = file_permissions_copy.encode("utf-8") return content + file_permissions_copy diff --git a/moban/core/moban_factory.py b/moban/core/moban_factory.py index b341802a..a5081c7f 100644 --- a/moban/core/moban_factory.py +++ b/moban/core/moban_factory.py @@ -117,7 +117,6 @@ def number_of_templated_files(self): return self.templated_count def render_to_file(self, template_file, data_file, output_file): - template_file = file_system.to_unicode(template_file) data = self.context.get_data(data_file) template = self.engine.get_template(template_file) try: @@ -143,7 +142,7 @@ def render_string_to_file( self, template_in_string, data_file, output_file ): template = self.engine.get_template_from_string(template_in_string) - template_abs_path = template_in_string[:10] + "..." + template_abs_path = f"{template_in_string[:10]}..." data = self.context.get_data(data_file) flag = self.apply_template( template_abs_path, template, data, output_file @@ -178,7 +177,7 @@ def apply_template(self, template_abs_path, template, data, output_file): return flag except exceptions.FileNotFound: # the template is a string from command line - LOG.info("{} is not a file".format(template_abs_path)) + LOG.info(f"{template_abs_path} is not a file") self.buffered_writer.write_file_out(output_file, rendered_content) return True @@ -197,7 +196,7 @@ def _render_with_finding_template_first(self, template_file_index): for (template_file, data_output_pairs) in template_file_index.items(): template = self.engine.get_template(template_file) template_abs_path = self.template_fs.geturl( - file_system.to_unicode(template_file), purpose="fs" + template_file, purpose="fs" ) for (data_file, output) in data_output_pairs: data = self.context.get_data(data_file) @@ -217,7 +216,7 @@ def _render_with_finding_data_first(self, data_file_index): for (template_file, output) in template_output_pairs: template = self.engine.get_template(template_file) template_abs_path = self.template_fs.geturl( - file_system.to_unicode(template_file), purpose="fs" + template_file, purpose="fs" ) flag = self.apply_template( template_abs_path, template, data, output @@ -231,7 +230,7 @@ def _render_with_finding_data_first(self, data_file_index): def expand_template_directories(dirs): - LOG.debug("Expanding %s..." % dirs) + LOG.debug(f"Expanding {dirs}...") if not isinstance(dirs, list): dirs = [dirs] @@ -240,7 +239,7 @@ def expand_template_directories(dirs): def expand_template_directory(directory): - LOG.debug("Expanding %s..." % directory) + LOG.debug(f"Expanding {directory}...") translated_directory = None if ":" in directory and directory[1] != ":" and "://" not in directory: translated_directory = deprecated_moban_path_notation(directory) diff --git a/moban/core/mobanfile/targets.py b/moban/core/mobanfile/targets.py index f0a6a2d8..c496cf9e 100644 --- a/moban/core/mobanfile/targets.py +++ b/moban/core/mobanfile/targets.py @@ -20,7 +20,7 @@ def extract_target(options): if template: if output is None: raise Exception( - "Please specify a output file name for %s." % template + f"Please specify a output file name for {template}" ) if config: result = { @@ -43,7 +43,7 @@ def extract_group_targets(group, targets): if isinstance(group_targets, str) is False and group_name == group: # grouping by template type feature return [{group_name: group_targets}] - raise exceptions.GroupTargetNotFound("%s is not found" % group) + raise exceptions.GroupTargetNotFound(f"{group} is not found") def parse_targets(options, targets): diff --git a/moban/core/mobanfile/templates.py b/moban/core/mobanfile/templates.py index 5de94640..f3cd55ac 100644 --- a/moban/core/mobanfile/templates.py +++ b/moban/core/mobanfile/templates.py @@ -8,35 +8,33 @@ def handle_template(template_file, output, template_dirs): - LOG.info("handling %s" % template_file) + LOG.info(f"handling {template_file}") - template_file = file_system.to_unicode(template_file) + template_file = template_file multi_fs = file_system.get_multi_fs(template_dirs) if template_file.endswith("**"): source_dir = template_file[:-3] _, fs = multi_fs.which(source_dir) if fs: - for a_triple in _listing_directory_files_recusively( + yield from _listing_directory_files_recusively( fs, source_dir, output - ): - yield a_triple + ) else: if STORE.look_up_by_output.get(template_file) is None: reporter.report_error_message( - "{0} cannot be found".format(template_file) + f"{template_file} cannot be found" ) else: _, fs = multi_fs.which(template_file) if fs is None: if STORE.look_up_by_output.get(template_file) is None: reporter.report_error_message( - "{0} cannot be found".format(template_file) + f"{template_file} cannot be found" ) else: yield _create_a_single_target(template_file, output) elif fs.isdir(template_file): - for a_triple in _list_dir_files(fs, template_file, output): - yield a_triple + yield from _list_dir_files(fs, template_file, output) else: yield _create_a_single_target(template_file, output) @@ -47,25 +45,24 @@ def _list_dir_files(fs, source, dest): # hence the following statement looks like cross platform # src_file_under_dir = os.path.join(source, file_name) # but actually it breaks windows instead. - src_file_under_dir = "%s/%s" % (source, file_name) + src_file_under_dir = f"{source}/{file_name}" if fs.isfile(src_file_under_dir): - dest_file_under_dir = dest + "/" + file_name + dest_file_under_dir = f"{dest}/{file_name}" template_type = _get_template_type(src_file_under_dir) yield (src_file_under_dir, dest_file_under_dir, template_type) def _listing_directory_files_recusively(fs, source, dest): for file_name in fs.listdir(source): - src_file_under_dir = source + "/" + file_name - dest_file_under_dir = dest + "/" + file_name + src_file_under_dir = f"{source}/{file_name}" + dest_file_under_dir = f"{dest}/{file_name}" if fs.isfile(src_file_under_dir): template_type = _get_template_type(src_file_under_dir) yield (src_file_under_dir, dest_file_under_dir, template_type) elif fs.isdir(src_file_under_dir): - for a_triple in _listing_directory_files_recusively( + yield from _listing_directory_files_recusively( fs, src_file_under_dir, dest_file_under_dir - ): - yield a_triple + ) def _create_a_single_target(template_file, output): @@ -73,9 +70,8 @@ def _create_a_single_target(template_file, output): # output.jj2: source.jj2 means 'copy' if template_type and output.endswith("." + template_type): LOG.info( - "template type switched to from {0} to {1}".format( - template_type, constants.TEMPLATE_COPY - ) + f"template type switched to from {template_type} to " + + constants.TEMPLATE_COPY ) template_type = constants.TEMPLATE_COPY return (template_file, output, template_type) diff --git a/moban/exceptions.py b/moban/exceptions.py index f214acba..b3907dfc 100644 --- a/moban/exceptions.py +++ b/moban/exceptions.py @@ -28,3 +28,7 @@ class GroupTargetNotFound(Exception): class NoGitCommand(Exception): pass + + +class UnsupportedPyFS2Protocol(Exception): + pass diff --git a/moban/externals/buffered_writer.py b/moban/externals/buffered_writer.py index dd8b5242..42b56b3f 100644 --- a/moban/externals/buffered_writer.py +++ b/moban/externals/buffered_writer.py @@ -1,13 +1,10 @@ import os -import sys import fs import fs.path from moban.externals import file_system -PY2 = sys.version_info[0] == 2 - class BufferedWriter(object): def __init__(self): @@ -22,15 +19,11 @@ def write_file_out(self, filename, content): def write_file_out_to_zip(self, filename, content): zip_file, file_name = file_system.url_split(filename) if zip_file not in self.fs_list: - self.fs_list[zip_file] = fs.open_fs( - file_system.to_unicode(zip_file), create=True - ) + self.fs_list[zip_file] = fs.open_fs(zip_file, create=True) base_dirs = fs.path.dirname(file_name) if not self.fs_list[zip_file].exists(base_dirs): self.fs_list[zip_file].makedirs(base_dirs) - self.fs_list[zip_file].writebytes( - file_system.to_unicode(file_name), content - ) + self.fs_list[zip_file].writebytes(file_name, content) def close(self): for fsx in self.fs_list.values(): @@ -38,9 +31,6 @@ def close(self): def write_file_out(filename, content): - if PY2 and content.__class__.__name__ == "unicode": - content = content.encode("utf-8") - if not file_system.is_zip_alike_url(filename): dest_folder = os.path.dirname(filename) if dest_folder: diff --git a/moban/externals/file_system.py b/moban/externals/file_system.py index 3aaf4497..e890fd47 100644 --- a/moban/externals/file_system.py +++ b/moban/externals/file_system.py @@ -17,7 +17,6 @@ from urlparse import urlparse -PY2 = sys.version_info[0] == 2 LOG = logging.getLogger(__name__) path_join = fs.path.join @@ -27,9 +26,9 @@ def url_join(path, path2): result = urlparse(path) if result.scheme and path.endswith(result.scheme): - return path + to_unicode("!/") + path2 + return f"{path}!/{path2}" else: - return path + to_unicode("/") + path2 + return f"{path}/{path2}" def log_fs_failure(function_in_this_module): @@ -37,12 +36,15 @@ def wrapper(*args, **kwds): try: return function_in_this_module(*args, **kwds) except fs.errors.CreateFailed: - from moban import reporter + from moban.externals import reporter message = "Failed to open %s" % args[0] LOG.debug(message) reporter.report_error_message(message) raise exceptions.FileNotFound(args[0]) + except fs.opener.errors.UnsupportedProtocol as e: + LOG.exception(e) + raise exceptions.UnsupportedPyFS2Protocol(e) return wrapper @@ -50,7 +52,6 @@ def wrapper(*args, **kwds): @log_fs_failure @contextmanager def open_fs(path): - path = to_unicode(path) if is_zip_alike_url(path): zip_file, folder = url_split(path) the_fs = fs.open_fs(zip_file) @@ -65,7 +66,6 @@ def open_fs(path): @log_fs_failure @contextmanager def open_file(path): - path = to_unicode(path) if is_zip_alike_url(path): zip_file, folder = url_split(path) the_fs = fs.open_fs(zip_file) @@ -85,7 +85,6 @@ def open_file(path): @log_fs_failure @contextmanager def open_binary_file(path): - path = to_unicode(path) if is_zip_alike_url(path): zip_file, folder = url_split(path) the_fs = fs.open_fs(zip_file) @@ -120,7 +119,6 @@ def read_bytes(path): @log_fs_failure def write_bytes(filename, bytes_content): - filename = to_unicode(filename) if "://" in filename: zip_file, folder = url_split(filename) with fs.open_fs(zip_file, create=True) as the_fs: @@ -146,10 +144,7 @@ def is_file(path): return the_fs.isfile(path) -@log_fs_failure def exists(path): - path = to_unicode(path) - if is_zip_alike_url(path): zip_file, folder = url_split(path) try: @@ -159,6 +154,9 @@ def exists(path): return True except fs.errors.CreateFailed: return False + except fs.opener.errors.UnsupportedProtocol as e: + LOG.exception(e) + raise exceptions.UnsupportedPyFS2Protocol(e) dir_name = fs.path.dirname(path) the_file_name = fs.path.basename(path) @@ -167,11 +165,13 @@ def exists(path): return the_fs.exists(the_file_name) except fs.errors.CreateFailed: return False + except fs.opener.errors.UnsupportedProtocol as e: + LOG.exception(e) + raise exceptions.UnsupportedPyFS2Protocol(e) @log_fs_failure def list_dir(path): - path = to_unicode(path) folder_or_file, path = _path_split(path) with fs.open_fs(folder_or_file) as the_fs: for file_name in the_fs.listdir(path): @@ -180,7 +180,6 @@ def list_dir(path): @log_fs_failure def abspath(path): - path = to_unicode(path) folder_or_file, path = _path_split(path) with fs.open_fs(folder_or_file) as the_fs: return the_fs.getsyspath(path) @@ -188,7 +187,6 @@ def abspath(path): @log_fs_failure def fs_url(path): - path = to_unicode(path) folder_or_file, path = _path_split(path) with fs.open_fs(folder_or_file) as the_fs: return the_fs.geturl(path, purpose="fs") @@ -196,15 +194,12 @@ def fs_url(path): @log_fs_failure def system_path(path): - path = to_unicode(path) folder_or_file, path = _path_split(path) with fs.open_fs(folder_or_file) as the_fs: return the_fs.getsyspath(path) def to_unicode(path): - if PY2 and path.__class__.__name__ != "unicode": - return u"".__class__(path) return path @@ -250,7 +245,6 @@ def url_split(url): def _path_split(url_or_path): - url_or_path = to_unicode(url_or_path) if is_zip_alike_url(url_or_path): return url_split(url_or_path) else: diff --git a/moban/main.py b/moban/main.py index ed7abf5a..379dd8e7 100644 --- a/moban/main.py +++ b/moban/main.py @@ -4,7 +4,7 @@ Bring jinja2 to command line - :copyright: (c) 2016-2019 by Onni Software Ltd. + :copyright: (c) 2016-2020 by Onni Software Ltd. :license: MIT License, see LICENSE for more details """ @@ -32,9 +32,6 @@ def main(): - """ - program entry point - """ parser = create_parser() options = vars(parser.parse_args()) handle_verbose(options[constants.LABEL_VERBOSE]) @@ -58,6 +55,7 @@ def main(): exceptions.DirectoryNotFound, exceptions.NoThirdPartyEngine, exceptions.MobanfileGrammarException, + exceptions.UnsupportedPyFS2Protocol, ) as e: LOG.exception(e) reporter.report_error_message(str(e)) @@ -66,7 +64,10 @@ def main(): try: count = handle_command_line(options) moban_exit(options[constants.LABEL_EXIT_CODE], count) - except exceptions.NoTemplate as e: + except ( + exceptions.NoTemplate, + exceptions.UnsupportedPyFS2Protocol, + ) as e: reporter.report_error_message(str(e)) moban_exit(options[constants.LABEL_EXIT_CODE], constants.ERROR) @@ -81,9 +82,6 @@ def moban_exit(exit_code_toggle_flag, exit_code): def create_parser(): - """ - construct the program options - """ parser = argparse.ArgumentParser( prog=constants.PROGRAM_NAME, description=constants.PROGRAM_DESCRIPTION ) @@ -108,13 +106,13 @@ def create_parser(): ) advanced.add_argument( "-td", - "--%s" % constants.LABEL_TMPL_DIRS, + f"--{constants.LABEL_TMPL_DIRS}", nargs="*", help="add more directories for template file lookup", ) advanced.add_argument( "-cd", - "--%s" % constants.LABEL_CONFIG_DIR, + f"--{constants.LABEL_CONFIG_DIR}", help="the directory for configuration file lookup", ) advanced.add_argument( @@ -124,12 +122,12 @@ def create_parser(): "-g", "--%s" % constants.LABEL_GROUP, help="a subset of targets" ) advanced.add_argument( - "--%s" % constants.LABEL_TEMPLATE_TYPE.replace("_", "-"), + f"--{constants.LABEL_TEMPLATE_TYPE.replace('_', '-')}", help="the template type, default is jinja2", ) advanced.add_argument( "-d", - "--%s" % constants.LABEL_DEFINE, + f"--{constants.LABEL_DEFINE}", nargs="+", help=( "to supply additional or override predefined variables," @@ -138,7 +136,7 @@ def create_parser(): ) advanced.add_argument( "-e", - "--%s" % constants.LABEL_EXTENSION, + f"--{constants.LABEL_EXTENSION}", nargs="+", help="to to TEMPLATE_TYPE=EXTENSION_NAME", ) @@ -153,7 +151,7 @@ def create_parser(): "Developer options", "For debugging and development" ) developer.add_argument( - "--%s" % constants.LABEL_EXIT_CODE, + f"--{constants.LABEL_EXIT_CODE}", action="store_true", dest=constants.LABEL_EXIT_CODE, default=False, @@ -161,7 +159,7 @@ def create_parser(): ) developer.add_argument( "-V", - "--%s" % constants.LABEL_VERSION, + f"--{constants.LABEL_VERSION}", action="version", version="%(prog)s {v}".format(v=__version__), ) diff --git a/moban/plugins/copy.py b/moban/plugins/copy.py index d92d1473..2b5913fe 100644 --- a/moban/plugins/copy.py +++ b/moban/plugins/copy.py @@ -1,7 +1,6 @@ from lml.plugin import PluginInfo from moban import constants -from moban.externals import file_system @PluginInfo( @@ -28,9 +27,7 @@ def __init__(self, template_fs, extensions=None): self.template_fs = template_fs def get_template(self, template_file): - return self.template_fs.readbytes( - file_system.to_unicode(template_file) - ) + return self.template_fs.readbytes(template_file) def get_template_from_string(self, string): return string diff --git a/requirements.txt b/requirements.txt index d5e54712..8ad69281 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,6 +7,4 @@ lml>=0.0.9 appdirs>=1.4.3 crayons>= 0.1.0 fs>=2.4.11 -gitfs2>=0.0.2 -pypifs>=0.0.1 jinja2-fsloader>=0.2.0 diff --git a/setup.py b/setup.py index 55393984..e54ee5e5 100644 --- a/setup.py +++ b/setup.py @@ -1,14 +1,17 @@ #!/usr/bin/env python3 -# Template by pypi-mobans +""" +Template by pypi-mobans +""" + +import os +import sys import codecs import locale -import os import platform -import sys from shutil import rmtree -from setuptools import Command, find_packages, setup +from setuptools import Command, setup, find_packages from setuptools import __version__ as setuptools_version from pkg_resources import parse_version @@ -38,7 +41,7 @@ NAME = "moban" AUTHOR = "C. W." -VERSION = "0.6.8" +VERSION = "0.7.0" EMAIL = "wangc_2011@hotmail.com" LICENSE = "MIT" ENTRY_POINTS = { @@ -47,10 +50,10 @@ ], } DESCRIPTION = ( - "Yet another jinja2 cli command for static text generation" + "General purpose static text generator" ) URL = "https://github.com/moremoban/moban" -DOWNLOAD_URL = "%s/archive/0.6.8.tar.gz" % URL +DOWNLOAD_URL = "%s/archive/0.7.0.tar.gz" % URL FILES = ["README.rst", "CONTRIBUTORS.rst", "CHANGELOG.rst"] KEYWORDS = [ "python", @@ -68,27 +71,24 @@ "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", ] +PYTHON_REQUIRES = ">=3.6" + INSTALL_REQUIRES = [ "jinja2>=2.7.1", "lml>=0.0.9", "appdirs>=1.4.3", "crayons>= 0.1.0", "fs>=2.4.11", - "gitfs2>=0.0.2", - "pypifs>=0.0.1", "jinja2-fsloader>=0.2.0", ] SETUP_COMMANDS = {} - -PACKAGES = find_packages(exclude=["ez_setup", "examples", "tests"]) +PACKAGES = find_packages(exclude=["ez_setup", "examples", "tests", "tests.*"]) EXTRAS_REQUIRE = { ":python_version == '3.4'": ["ruamel.yaml>=0.15.5,<=0.15.94"], ":python_version == '3.7'": ["ruamel.yaml>=0.15.42"], @@ -97,8 +97,8 @@ } # You do not need to read beyond this line PUBLISH_COMMAND = "{0} setup.py sdist bdist_wheel upload -r pypi".format(sys.executable) -GS_COMMAND = ("gs moban v0.6.8 " + - "Find 0.6.8 in changelog for more details") +GS_COMMAND = ("gs moban v0.7.0 " + + "Find 0.7.0 in changelog for more details") NO_GS_MESSAGE = ("Automatic github release is disabled. " + "Please install gease to enable it.") UPLOAD_FAILED_MSG = ( @@ -260,6 +260,7 @@ def default_environment(): long_description=read_files(*FILES), license=LICENSE, keywords=KEYWORDS, + python_requires=PYTHON_REQUIRES, extras_require=EXTRAS_REQUIRE, tests_require=["nose"], install_requires=INSTALL_REQUIRES, diff --git a/tests/test_file_system.py b/tests/test_file_system.py index a9fbe33f..362fb281 100644 --- a/tests/test_file_system.py +++ b/tests/test_file_system.py @@ -8,7 +8,7 @@ from nose.tools import eq_, raises from moban.externals import file_system -from moban.exceptions import FileNotFound +from moban.exceptions import FileNotFound, UnsupportedPyFS2Protocol LOCAL_FOLDER = "tests/fixtures" LOCAL_FILE = LOCAL_FOLDER + "/a.jj2" @@ -125,6 +125,16 @@ def test_exists(): eq_(status, expected) +@raises(UnsupportedPyFS2Protocol) +def test_exists_raise_exception(): + file_system.exists("git2://protocol/abc") + + +@raises(UnsupportedPyFS2Protocol) +def test_is_file_raise_exception(): + file_system.is_file("git2://protocol/abc") + + TEST_LIST_DIR_SPEC = [ [ LOCAL_FOLDER + "/file_system", diff --git a/tests/test_main.py b/tests/test_main.py index abf381bd..61001080 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -94,6 +94,36 @@ def test_directory_not_found( main() + @raises(SystemExit) + @patch("os.path.exists") + @patch("moban.main.handle_moban_file") + @patch("moban.externals.reporter.report_error_message") + def test_unknown_protocol(self, fake_reporter, fake_moban_file, fake_file): + fake_file.return_value = True + fake_moban_file.side_effect = exceptions.UnsupportedPyFS2Protocol + fake_stdin = MagicMock(isatty=MagicMock(return_value=True)) + with patch.object(sys, "stdin", fake_stdin): + from moban.main import main + + with patch.object(sys, "argv", ["moban"]): + main() + + @raises(SystemExit) + @patch("os.path.exists") + @patch("moban.main.handle_command_line") + @patch("moban.externals.reporter.report_error_message") + def test_unknown_protocol_at_command_line( + self, fake_reporter, fake_moban_file, fake_file + ): + fake_file.return_value = False + fake_moban_file.side_effect = exceptions.UnsupportedPyFS2Protocol + fake_stdin = MagicMock(isatty=MagicMock(return_value=True)) + with patch.object(sys, "stdin", fake_stdin): + from moban.main import main + + with patch.object(sys, "argv", ["moban"]): + main() + @raises(SystemExit) @patch("os.path.exists") @patch("moban.main.handle_moban_file")