Hello community, here is the log from the commit of package python-neovim for openSUSE:Factory checked in at 2020-02-21 16:43:12 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-neovim (Old) and /work/SRC/openSUSE:Factory/.python-neovim.new.26092 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-neovim" Fri Feb 21 16:43:12 2020 rev:14 rq:777951 version:0.4.1 Changes: -------- --- /work/SRC/openSUSE:Factory/python-neovim/python-neovim.changes 2019-01-24 14:12:28.755427260 +0100 +++ /work/SRC/openSUSE:Factory/.python-neovim.new.26092/python-neovim.changes 2020-02-21 16:43:28.310166577 +0100 @@ -1,0 +2,25 @@ +Fri Feb 21 13:23:49 CET 2020 - Matej Cepl <[email protected]> + +- Update to 0.4.1: + - Logging will be disabled on release tarballs and pip packages + for performance reasons. use scripts/enable_log_statements.sh + and scripts/disable_log_statements.sh to toggle the + availability of logging. + - 09bba08 remove scrutinizer + - f048531 make pytest_runner an optional dependency + - 5b50ce9 fix missing self.name for nvim_error_event + - 175a2cc Test with python 3.8 + - 5a2b552 fix the disable logging script. + - 2a31195 Update docs/tests to use --headless when needed + - 1d121e0 Update tests for new global/local option behavior + - 6310063 session: set client info (not only for host) + - 58ff62f python2 compat: fix buffer inequality + - a63cddb ci: fix coverage reporting + - f4f3bf5 api: key deletion; use KeyError for maps (if_python + compat) + - d3c389f host: do not run __init__ in plugin until the plugin + is invoked +- Add temporary patch setup_version.patch setting the version + number in setup.py correctly. gh#neovim/pynvim#431 + +------------------------------------------------------------------- Old: ---- pynvim-0.3.2.tar.gz New: ---- pynvim-0.4.1.tar.gz setup_version.patch ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-neovim.spec ++++++ --- /var/tmp/diff_new_pack.LzIbkw/_old 2020-02-21 16:43:29.266168487 +0100 +++ /var/tmp/diff_new_pack.LzIbkw/_new 2020-02-21 16:43:29.274168503 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-neovim # -# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2020 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -20,13 +20,16 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-neovim -Version: 0.3.2 +Version: 0.4.1 Release: 0 Summary: Python client to Neovim License: Apache-2.0 Group: Productivity/Text/Editors URL: https://github.com/neovim/pynvim -Source: https://github.com/neovim/pynvim/archive/%{version}/pynvim-%{version}.tar.gz +Source: https://github.com/neovim/%{modname}/archive/%{version}/%{modname}-%{version}.tar.gz +# PATCH-FIX-UPSTREAM setup_version.patch gh#neovim/pynvim#431 [email protected] +# Upstream setup.py has incorrect version. +Patch0: setup_version.patch BuildRequires: fdupes %if 0%{?rhel} >= 7 BuildRequires: python34-pytest ++++++ pynvim-0.3.2.tar.gz -> pynvim-0.4.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynvim-0.3.2/.coveragerc new/pynvim-0.4.1/.coveragerc --- old/pynvim-0.3.2/.coveragerc 1970-01-01 01:00:00.000000000 +0100 +++ new/pynvim-0.4.1/.coveragerc 2020-01-25 10:16:18.000000000 +0100 @@ -0,0 +1,8 @@ +[run] +source = . +branch = true +parallel = 1 + +[report] +show_missing = true +include = pynvim/*,test/* diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynvim-0.3.2/.scrutinizer.yml new/pynvim-0.4.1/.scrutinizer.yml --- old/pynvim-0.3.2/.scrutinizer.yml 2019-01-20 16:22:43.000000000 +0100 +++ new/pynvim-0.4.1/.scrutinizer.yml 1970-01-01 01:00:00.000000000 +0100 @@ -1,134 +0,0 @@ -checks: - python: - imports_relative_import: true - imports_wildcard_import: true - classes_no_self_argument: true - classes_bad_mcs_method_argument: true - classes_bad_classmethod_argument: true - code_rating: true - duplicate_code: true - variables_unused_variable: true - variables_unused_import: true - variables_unused_wildcard_import: true - variables_unused_argument: true - variables_global_variable_not_assigned: true - typecheck_redundant_keyword_arg: true - imports_import_self: true - format_superfluous_parens: true - exceptions_pointless_except: true - design_interface_not_implemented: true - design_abstract_class_not_used: true - basic_useless_else_on_loop: true - basic_unreachable: true - basic_unnecessary_pass: true - basic_unnecessary_lambda: true - basic_pointless_string_statement: true - basic_pointless_statement: true - basic_expression_not_assigned: true - variables_redefined_outer_name: true - variables_redefined_builtin: true - variables_redefine_in_handler: true - newstyle_bad_super_call: true - logging_not_lazy: true - exceptions_broad_except: true - exceptions_bare_except: true - classes_super_init_not_called: true - classes_protected_access: true - classes_non_parent_init_called: true - classes_bad_mcs_classmethod_argument: true - classes_attribute_defined_outside_init: true - classes_method_hidden: true - basic_lost_exception: true - basic_function_redefined: true - basic_exec_used: true - basic_eval_used: true - basic_dangerous_default_value: true - design_abstract_class_little_used: true - imports_deprecated_module: true - format_old_ne_operator: true - format_backtick: true - basic_old_raise_syntax: true - variables_used_before_assignment: true - variables_unpacking_non_sequence: true - variables_undefined_variable: true - variables_undefined_loop_variable: true - variables_undefined_all_variable: true - variables_unbalanced_tuple_unpacking: true - variables_no_name_in_module: true - variables_invalid_all_object: true - variables_global_variable_undefined: true - typecheck_unexpected_keyword_arg: true - typecheck_not_callable: true - typecheck_no_value_for_parameter: true - typecheck_no_member: true - typecheck_too_many_function_args: true - typecheck_missing_kwoa: true - typecheck_maybe_no_member: true - typecheck_duplicate_keyword_arg: true - typecheck_assignment_from_none: true - typecheck_assignment_from_no_return: true - string_unused_format_string_key: true - string_truncated_format_string: true - string_too_many_format_args: true - string_too_few_format_args: true - string_mixed_format_string: true - string_missing_format_string_key: true - string_format_needs_mapping: true - string_constant_anomalous_unicode_escape_in_string: true - string_constant_anomalous_backslash_in_string: true - string_bad_str_strip_call: true - string_bad_format_string_key: true - string_bad_format_character: true - open_mode_bad_open_mode: true - logging_unsupported_format: true - logging_too_many_args: true - logging_too_few_args: true - logging_format_truncated: true - imports_reimported: true - imports_import_error: true - imports_cyclic_import: true - exceptions_raising_string: true - exceptions_raising_non_exception: true - exceptions_raising_bad_type: true - exceptions_notimplemented_raised: true - exceptions_catching_non_exception: true - exceptions_bad_except_order: true - classes_valid_slots: true - classes_signature_differs: true - classes_non_iterator_returned: true - classes_no_method_argument: true - classes_missing_interface_method: true - classes_interface_is_not_class: true - classes_bad_staticmethod_argument: true - classes_bad_context_manager: true - classes_arguments_differ: true - classes_access_member_before_definition: true - classes_abstract_method: true - basic_yield_outside_function: true - basic_return_outside_function: true - basic_return_in_init: true - basic_return_arg_in_generator: true - basic_not_in_loop: true - basic_nonexistent_operator: true - basic_missing_reversed_argument: true - basic_missing_module_attribute: true - basic_init_is_generator: true - basic_duplicate_key: true - basic_duplicate_argument_name: true - basic_bad_reversed_sequence: true - basic_assert_on_tuple: true - basic_abstract_class_instantiated: true - format_lowercase_l_suffix: true - classes_no_self_use: true - classes_no_init: true - exceptions_binary_op_exception: true - variables_global_statement: true - -filter: - excluded_paths: - - test/* - -tools: - external_code_coverage: - timeout: 1200 - runs: 6 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynvim-0.3.2/.travis.yml new/pynvim-0.4.1/.travis.yml --- old/pynvim-0.3.2/.travis.yml 2019-01-20 16:22:43.000000000 +0100 +++ new/pynvim-0.4.1/.travis.yml 2020-01-25 10:16:18.000000000 +0100 @@ -2,7 +2,7 @@ language: python env: global: - - PYTEST_ADDOPTS=-vv + - PYTEST_ADDOPTS="-vv --cov-append" matrix: - CI_TARGET=tests matrix: @@ -11,27 +11,30 @@ dist: trusty sudo: false - python: 3.6 - env: CI_TARGET=checkqa TOXENV=checkqa + env: CI_TARGET=checkqa TOXENV=checkqa,docs python: - # If the build matrix gets bigger, also update the number of runs - # at the bottom of .scrutinizer.yml. - 2.7 - 3.4 - 3.5 - 3.6 - 3.7 -before_install: + - 3.8 +install: - if [ $CI_TARGET = tests ]; then eval "$(curl -Ss https://raw.githubusercontent.com/neovim/bot-ci/master/scripts/travis-setup.sh) nightly-x64"; - pip install -q scrutinizer-ocular tox-travis; + pip install -q tox-travis; else pip install -q tox; fi -install: - - pip install . script: - tox after_script: - if [ $CI_TARGET = tests ]; then - ocular; + set -x; + pip install coverage; + coverage combine; + coverage report -m; + coverage xml; + bash <(curl --retry 5 --silent --fail https://codecov.io/bash) -f coverage.xml; + set +x; fi diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynvim-0.3.2/MANIFEST.in new/pynvim-0.4.1/MANIFEST.in --- old/pynvim-0.3.2/MANIFEST.in 2019-01-20 16:22:43.000000000 +0100 +++ new/pynvim-0.4.1/MANIFEST.in 2020-01-25 10:16:18.000000000 +0100 @@ -1 +1,2 @@ include README.md LICENSE +recursive-include test *.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynvim-0.3.2/README.md new/pynvim-0.4.1/README.md --- old/pynvim-0.3.2/README.md 2019-01-20 16:22:43.000000000 +0100 +++ new/pynvim-0.4.1/README.md 2020-01-25 10:16:18.000000000 +0100 @@ -2,8 +2,7 @@ [](https://travis-ci.org/neovim/pynvim) [](http://pynvim.readthedocs.io/en/latest/?badge=latest) -[](https://scrutinizer-ci.com/g/neovim/pynvim/?branch=master) -[](https://scrutinizer-ci.com/g/neovim/pynvim/?branch=master) +[](https://codecov.io/gh/neovim/pynvim) Pynvim implements support for python plugins in Nvim. It also works as a library for connecting to and scripting Nvim processes through its msgpack-rpc API. @@ -103,12 +102,17 @@ [1, 2, 3] ``` -You can embed neovim into your python application instead of binding to a -running neovim instance. +You can embed Neovim into your python application instead of connecting to +a running Neovim instance. ```python >>> from pynvim import attach ->>> nvim = attach('child', argv=["/bin/env", "nvim", "--embed"]) +>>> nvim = attach('child', argv=["/bin/env", "nvim", "--embed", "--headless"]) ``` -The tests can be consulted for more examples. +- The ` --headless` argument tells `nvim` not to wait for a UI to connect. +- Alternatively, use `--embed` _without_ `--headless` if your client is a UI + and you want `nvim` to wait for your client to `nvim_ui_attach` before + continuing startup. + +See the tests for more examples. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynvim-0.3.2/codecov.yml new/pynvim-0.4.1/codecov.yml --- old/pynvim-0.3.2/codecov.yml 1970-01-01 01:00:00.000000000 +0100 +++ new/pynvim-0.4.1/codecov.yml 2020-01-25 10:16:18.000000000 +0100 @@ -0,0 +1,6 @@ +coverage: + status: + project: true + patch: true + changes: true +comment: false diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynvim-0.3.2/docs/development.rst new/pynvim-0.4.1/docs/development.rst --- old/pynvim-0.3.2/docs/development.rst 2019-01-20 16:22:43.000000000 +0100 +++ new/pynvim-0.4.1/docs/development.rst 2020-01-25 10:16:18.000000000 +0100 @@ -26,7 +26,7 @@ If you want to test a different version than ``nvim`` in ``$PATH`` use:: - NVIM_CHILD_ARGV='["/path/to/nvim", "-u", "NONE", "--embed"]' pytest + NVIM_CHILD_ARGV='["/path/to/nvim", "-u", "NONE", "--embed", "--headless"]' pytest Alternatively, if you want to see the state of nvim, you could use:: @@ -86,6 +86,6 @@ .. code-block:: python >>> from pynvim import attach - >>> nvim = attach('child', argv=["/bin/env", "nvim", "--embed"]) + >>> nvim = attach('child', argv=["/bin/env", "nvim", "--embed", "--headless"]) The tests can be consulted for more examples. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynvim-0.3.2/docs/usage/remote-plugins.rst new/pynvim-0.4.1/docs/usage/remote-plugins.rst --- old/pynvim-0.3.2/docs/usage/remote-plugins.rst 2019-01-20 16:22:43.000000000 +0100 +++ new/pynvim-0.4.1/docs/usage/remote-plugins.rst 2020-01-25 10:16:18.000000000 +0100 @@ -46,12 +46,15 @@ .. note:: - Plugins must not invoke API methods in ``__init__`` or global module scope - (or really do anything with non-trivial side-effects). A well-behaved rplugin - will not start executing until its functionality is requested by the user. - Initialize the plugin the first time the user invokes a command, or use an - appropriate autocommand, if it e.g. makes sense to automatically start the - plugin for a given filetype. + Plugin objects are constructed the first time any request of the class is + invoked. Any error in ``__init__`` will be reported as an error from this + first request. A well-behaved rplugin will not start executing until its + functionality is requested by the user. Initialize the plugin when user + invokes a command, or use an appropriate autocommand, e.g. FileType if it + makes sense to automatically start the plugin for a given filetype. Plugins + must not invoke API methods (or really do anything with non-trivial + side-effects) in global module scope, as the module might be loaded as part + of executing `UpdateRemotePlugins`. You need to run ``:UpdateRemotePlugins`` in Neovim for changes in the specifications to have effect. For details see ``:help remote-plugin`` in Neovim. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynvim-0.3.2/pynvim/__init__.py new/pynvim-0.4.1/pynvim/__init__.py --- old/pynvim-0.3.2/pynvim/__init__.py 2019-01-20 16:22:43.000000000 +0100 +++ new/pynvim-0.4.1/pynvim/__init__.py 2020-01-25 10:16:18.000000000 +0100 @@ -135,12 +135,14 @@ '%(filename)s:%(funcName)s:%(lineno)s] %(process)s - %(message)s') logging.root.addHandler(handler) level = logging.INFO - if 'NVIM_PYTHON_LOG_LEVEL' in os.environ: - lvl = getattr(logging, - os.environ['NVIM_PYTHON_LOG_LEVEL'].strip(), - level) + env_log_level = os.environ.get('NVIM_PYTHON_LOG_LEVEL', None) + if env_log_level is not None: + lvl = getattr(logging, env_log_level.strip(), None) if isinstance(lvl, int): level = lvl + else: + logger.warning('Invalid NVIM_PYTHON_LOG_LEVEL: %r, using INFO.', + env_log_level) logger.setLevel(level) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynvim-0.3.2/pynvim/api/buffer.py new/pynvim-0.4.1/pynvim/api/buffer.py --- old/pynvim-0.3.2/pynvim/api/buffer.py 2019-01-20 16:22:43.000000000 +0100 +++ new/pynvim-0.4.1/pynvim/api/buffer.py 2020-01-25 10:16:18.000000000 +0100 @@ -83,6 +83,13 @@ """ self.__setitem__(idx, None) + def __ne__(self, other): + """Test inequality of Buffers. + + Necessary for Python 2 compatibility. + """ + return not self.__eq__(other) + def append(self, lines, index=-1): """Append a string or list of lines to the buffer.""" if isinstance(lines, (basestring, bytes)): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynvim-0.3.2/pynvim/api/common.py new/pynvim-0.4.1/pynvim/api/common.py --- old/pynvim-0.3.2/pynvim/api/common.py 2019-01-20 16:22:43.000000000 +0100 +++ new/pynvim-0.4.1/pynvim/api/common.py 2020-01-25 10:16:18.000000000 +0100 @@ -5,6 +5,12 @@ from ..compat import unicode_errors_default +__all__ = () + + +class NvimError(Exception): + pass + class Remote(object): @@ -26,7 +32,8 @@ self.handle = unpackb(code_data[1]) self.api = RemoteApi(self, self._api_prefix) self.vars = RemoteMap(self, self._api_prefix + 'get_var', - self._api_prefix + 'set_var') + self._api_prefix + 'set_var', + self._api_prefix + 'del_var') self.options = RemoteMap(self, self._api_prefix + 'get_option', self._api_prefix + 'set_option') @@ -65,8 +72,16 @@ return functools.partial(self._obj.request, self._api_prefix + name) -class RemoteMap(object): +def transform_keyerror(exc): + if isinstance(exc, NvimError): + if exc.args[0].startswith('Key not found:'): + return KeyError(exc.args[0]) + if exc.args[0].startswith('Invalid option name:'): + return KeyError(exc.args[0]) + return exc + +class RemoteMap(object): """Represents a string->object map stored in Nvim. This is the dict counterpart to the `RemoteSequence` class, but it is used @@ -76,16 +91,23 @@ It is used to provide a dict-like API to vim variables and options. """ - def __init__(self, obj, get_method, set_method=None): + _set = None + _del = None + + def __init__(self, obj, get_method, set_method=None, del_method=None): """Initialize a RemoteMap with session, getter/setter.""" self._get = functools.partial(obj.request, get_method) - self._set = None if set_method: self._set = functools.partial(obj.request, set_method) + if del_method: + self._del = functools.partial(obj.request, del_method) def __getitem__(self, key): """Return a map value by key.""" - return self._get(key) + try: + return self._get(key) + except NvimError as exc: + raise transform_keyerror(exc) def __setitem__(self, key, value): """Set a map value by key(if the setter was provided).""" @@ -95,9 +117,12 @@ def __delitem__(self, key): """Delete a map value by associating None with the key.""" - if not self._set: + if not self._del: raise TypeError('This dict is read-only') - return self._set(key, None) + try: + return self._del(key) + except NvimError as exc: + raise transform_keyerror(exc) def __contains__(self, key): """Check if key is present in the map.""" @@ -110,8 +135,8 @@ def get(self, key, default=None): """Return value for key if present, else a default value.""" try: - return self._get(key) - except Exception: + return self.__getitem__(key) + except KeyError: return default diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynvim-0.3.2/pynvim/api/nvim.py new/pynvim-0.4.1/pynvim/api/nvim.py --- old/pynvim-0.3.2/pynvim/api/nvim.py 2019-01-20 16:22:43.000000000 +0100 +++ new/pynvim-0.4.1/pynvim/api/nvim.py 2020-01-25 10:16:18.000000000 +0100 @@ -8,7 +8,7 @@ from msgpack import ExtType from .buffer import Buffer -from .common import (Remote, RemoteApi, RemoteMap, RemoteSequence, +from .common import (NvimError, Remote, RemoteApi, RemoteMap, RemoteSequence, decode_if_bytes, walk) from .tabpage import Tabpage from .window import Window @@ -76,8 +76,8 @@ queries Nvim metadata for type information and sets a SessionHook for creating specialized objects from Nvim remote handles. """ - session.error_wrapper = lambda e: NvimError(e[1]) - channel_id, metadata = session.request(b'vim_get_api_info') + session.error_wrapper = lambda e: NvimError(decode_if_bytes(e[1])) + channel_id, metadata = session.request(b'nvim_get_api_info') if IS_PYTHON3: # decode all metadata strings for python3 @@ -107,8 +107,8 @@ self.version = Version(**version) self.types = types self.api = RemoteApi(self, 'nvim_') - self.vars = RemoteMap(self, 'nvim_get_var', 'nvim_set_var') - self.vvars = RemoteMap(self, 'nvim_get_vvar', None) + self.vars = RemoteMap(self, 'nvim_get_var', 'nvim_set_var', 'nvim_del_var') + self.vvars = RemoteMap(self, 'nvim_get_vvar', None, None) self.options = RemoteMap(self, 'nvim_get_option', 'nvim_set_option') self.buffers = Buffers(self) self.windows = RemoteSequence(self, 'nvim_list_wins') @@ -389,11 +389,17 @@ from_part, do_lt, special) def out_write(self, msg, **kwargs): - """Print `msg` as a normal message.""" + r"""Print `msg` as a normal message. + + The message is buffered (won't display) until linefeed ("\n"). + """ return self.request('nvim_out_write', msg, **kwargs) def err_write(self, msg, **kwargs): - """Print `msg` as an error message.""" + r"""Print `msg` as an error message. + + The message is buffered (won't display) until linefeed ("\n"). + """ if self._thread_invalid(): # special case: if a non-main thread writes to stderr # i.e. due to an uncaught exception, pass it through @@ -569,7 +575,3 @@ pattern = "return {}(...)" if not async_ else "{}(...)" code = pattern.format(self.name) return self._nvim.exec_lua(code, *args, **kwargs) - - -class NvimError(Exception): - pass diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynvim-0.3.2/pynvim/msgpack_rpc/__init__.py new/pynvim-0.4.1/pynvim/msgpack_rpc/__init__.py --- old/pynvim-0.3.2/pynvim/msgpack_rpc/__init__.py 2019-01-20 16:22:43.000000000 +0100 +++ new/pynvim-0.4.1/pynvim/msgpack_rpc/__init__.py 2020-01-25 10:16:18.000000000 +0100 @@ -8,6 +8,7 @@ from .event_loop import EventLoop from .msgpack_stream import MsgpackStream from .session import ErrorResponse, Session +from ..util import get_client_info __all__ = ('tcp_session', 'socket_session', 'stdio_session', 'child_session', @@ -19,6 +20,8 @@ msgpack_stream = MsgpackStream(loop) async_session = AsyncSession(msgpack_stream) session = Session(async_session) + session.request(b'nvim_set_client_info', + *get_client_info('client', 'remote', {}), async_=True) return session diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynvim-0.3.2/pynvim/msgpack_rpc/async_session.py new/pynvim-0.4.1/pynvim/msgpack_rpc/async_session.py --- old/pynvim-0.3.2/pynvim/msgpack_rpc/async_session.py 2019-01-20 16:22:43.000000000 +0100 +++ new/pynvim-0.4.1/pynvim/msgpack_rpc/async_session.py 2020-01-25 10:16:18.000000000 +0100 @@ -57,7 +57,7 @@ def run(self, request_cb, notification_cb): """Run the event loop to receive requests and notifications from Nvim. - While the event loop is running, `request_cb` and `_notification_cb` + While the event loop is running, `request_cb` and `notification_cb` will be called whenever requests or notifications are respectively available. """ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynvim-0.3.2/pynvim/msgpack_rpc/event_loop/base.py new/pynvim-0.4.1/pynvim/msgpack_rpc/event_loop/base.py --- old/pynvim-0.3.2/pynvim/msgpack_rpc/event_loop/base.py 2019-01-20 16:22:43.000000000 +0100 +++ new/pynvim-0.4.1/pynvim/msgpack_rpc/event_loop/base.py 2020-01-25 10:16:18.000000000 +0100 @@ -33,7 +33,7 @@ named pipe. - `_connect_stdio()`: Use stdin/stdout as the connection to Nvim - `_connect_child(argv)`: Use the argument vector `argv` to spawn an - embedded Nvim that has it's stdin/stdout connected to the event loop. + embedded Nvim that has its stdin/stdout connected to the event loop. - `_start_reading()`: Called after any of _connect_* methods. Can be used to perform any post-connection setup or validation. - `_send(data)`: Send `data`(byte array) to Nvim. The data is only @@ -70,7 +70,8 @@ Traceback (most recent call last): ... AttributeError: 'BaseEventLoop' object has no attribute '_init' - >>> BaseEventLoop('child', ['nvim', '--embed', '-u', 'NONE']) + >>> BaseEventLoop('child', + ['nvim', '--embed', '--headless', '-u', 'NONE']) Traceback (most recent call last): ... AttributeError: 'BaseEventLoop' object has no attribute '_init' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynvim-0.3.2/pynvim/plugin/host.py new/pynvim-0.4.1/pynvim/plugin/host.py --- old/pynvim-0.3.2/pynvim/plugin/host.py 2019-01-20 16:22:43.000000000 +0100 +++ new/pynvim-0.4.1/pynvim/plugin/host.py 2020-01-25 10:16:18.000000000 +0100 @@ -5,7 +5,6 @@ import os import os.path import re -import sys from functools import partial from traceback import format_exc @@ -13,7 +12,7 @@ from ..api import decode_if_bytes, walk from ..compat import IS_PYTHON3, find_module from ..msgpack_rpc import ErrorResponse -from ..util import VERSION, format_exc_skip +from ..util import format_exc_skip, get_client_info __all__ = ('Host') @@ -60,6 +59,7 @@ errmsg = "{}: Async request caused an error:\n{}\n".format( self.name, decode_if_bytes(msg)) self.nvim.err_write(errmsg, async_=True) + return errmsg def start(self, plugins): """Start listening for msgpack-rpc requests and notifications.""" @@ -73,6 +73,26 @@ self._unload() self.nvim.stop_loop() + def _wrap_delayed_function(self, cls, delayed_handlers, name, sync, + module_handlers, path, *args): + # delete the delayed handlers to be sure + for handler in delayed_handlers: + method_name = handler._nvim_registered_name + if handler._nvim_rpc_sync: + del self._request_handlers[method_name] + else: + del self._notification_handlers[method_name] + # create an instance of the plugin and pass the nvim object + plugin = cls(self._configure_nvim_for(cls)) + + # discover handlers in the plugin instance + self._discover_functions(plugin, module_handlers, path, False) + + if sync: + self._request_handlers[name](*args) + else: + self._notification_handlers[name](*args) + def _wrap_function(self, fn, sync, decode, nvim_bind, name, *args): if decode: args = walk(decode_if_bytes, args, decode) @@ -145,7 +165,7 @@ module = imp.load_module(name, file, pathname, descr) handlers = [] self._discover_classes(module, handlers, path) - self._discover_functions(module, handlers, path) + self._discover_functions(module, handlers, path, False) if not handlers: error('{} exports no handlers'.format(path)) continue @@ -156,23 +176,17 @@ error(err) self._load_errors[path] = err - if len(plugins) == 1 and has_script: - kind = "script" - else: - kind = "rplugin" - name = "python{}-{}-host".format(sys.version_info[0], kind) - attributes = {"license": "Apache v2", - "website": "github.com/neovim/pynvim"} - self.name = name - self.nvim.api.set_client_info( - name, VERSION.__dict__, "host", host_method_spec, - attributes, async_=True) + kind = ("script-host" if len(plugins) == 1 and has_script + else "rplugin-host") + info = get_client_info(kind, 'host', host_method_spec) + self.name = info[0] + self.nvim.api.set_client_info(*info, async_=True) def _unload(self): for path, plugin in self._loaded.items(): handlers = plugin['handlers'] for handler in handlers: - method_name = handler._nvim_rpc_method_name + method_name = handler._nvim_registered_name if hasattr(handler, '_nvim_shutdown_hook'): handler() elif handler._nvim_rpc_sync: @@ -185,31 +199,35 @@ def _discover_classes(self, module, handlers, plugin_path): for _, cls in inspect.getmembers(module, inspect.isclass): if getattr(cls, '_nvim_plugin', False): - # create an instance of the plugin and pass the nvim object - plugin = cls(self._configure_nvim_for(cls)) # discover handlers in the plugin instance - self._discover_functions(plugin, handlers, plugin_path) + self._discover_functions(cls, handlers, plugin_path, True) - def _discover_functions(self, obj, handlers, plugin_path): + def _discover_functions(self, obj, handlers, plugin_path, delay): def predicate(o): return hasattr(o, '_nvim_rpc_method_name') + cls_handlers = [] specs = [] objdecode = getattr(obj, '_nvim_decode', self._decode_default) for _, fn in inspect.getmembers(obj, predicate): - sync = fn._nvim_rpc_sync - decode = getattr(fn, '_nvim_decode', objdecode) - nvim_bind = None - if fn._nvim_bind: - nvim_bind = self._configure_nvim_for(fn) - method = fn._nvim_rpc_method_name if fn._nvim_prefix_plugin_path: method = '{}:{}'.format(plugin_path, method) + sync = fn._nvim_rpc_sync + if delay: + fn_wrapped = partial(self._wrap_delayed_function, obj, + cls_handlers, method, sync, + handlers, plugin_path) + else: + decode = getattr(fn, '_nvim_decode', objdecode) + nvim_bind = None + if fn._nvim_bind: + nvim_bind = self._configure_nvim_for(fn) - fn_wrapped = partial(self._wrap_function, fn, - sync, decode, nvim_bind, method) + fn_wrapped = partial(self._wrap_function, fn, + sync, decode, nvim_bind, method) self._copy_attributes(fn, fn_wrapped) + fn_wrapped._nvim_registered_name = method # register in the rpc handler dict if sync: if method in self._request_handlers: @@ -224,6 +242,7 @@ if hasattr(fn, '_nvim_rpc_spec'): specs.append(fn._nvim_rpc_spec) handlers.append(fn_wrapped) + cls_handlers.append(fn_wrapped) if specs: self._specs[plugin_path] = specs diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynvim-0.3.2/pynvim/util.py new/pynvim-0.4.1/pynvim/util.py --- old/pynvim-0.3.2/pynvim/util.py 2019-01-20 16:22:43.000000000 +0100 +++ new/pynvim-0.4.1/pynvim/util.py 2020-01-25 10:16:18.000000000 +0100 @@ -14,7 +14,6 @@ # Taken from SimpleNamespace in python 3 class Version: - """Helper class for version info.""" def __init__(self, **kwargs): @@ -32,4 +31,12 @@ return self.__dict__ == other.__dict__ -VERSION = Version(major=0, minor=3, patch=2, prerelease='') +def get_client_info(kind, type_, method_spec): + """Returns a tuple describing the client.""" + name = "python{}-{}".format(sys.version_info[0], kind) + attributes = {"license": "Apache v2", + "website": "github.com/neovim/pynvim"} + return (name, VERSION.__dict__, type_, method_spec, attributes) + + +VERSION = Version(major=0, minor=4, patch=1, prerelease='') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynvim-0.3.2/scripts/disable_log_statements.sh new/pynvim-0.4.1/scripts/disable_log_statements.sh --- old/pynvim-0.3.2/scripts/disable_log_statements.sh 2019-01-20 16:22:43.000000000 +0100 +++ new/pynvim-0.4.1/scripts/disable_log_statements.sh 2020-01-25 10:16:18.000000000 +0100 @@ -1,4 +1,4 @@ #!/bin/sh -e -cd neovim +cd pynvim find -name '*.py' | xargs -i{} ../scripts/logging_statement_modifier.py {} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynvim-0.3.2/scripts/enable_log_statements.sh new/pynvim-0.4.1/scripts/enable_log_statements.sh --- old/pynvim-0.3.2/scripts/enable_log_statements.sh 2019-01-20 16:22:43.000000000 +0100 +++ new/pynvim-0.4.1/scripts/enable_log_statements.sh 2020-01-25 10:16:18.000000000 +0100 @@ -1,4 +1,4 @@ #!/bin/sh -e -cd neovim +cd pynvim find -name '*.py' | xargs -i{} ../scripts/logging_statement_modifier.py --restore {} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynvim-0.3.2/scripts/logging_statement_modifier.py new/pynvim-0.4.1/scripts/logging_statement_modifier.py --- old/pynvim-0.3.2/scripts/logging_statement_modifier.py 2019-01-20 16:22:43.000000000 +0100 +++ new/pynvim-0.4.1/scripts/logging_statement_modifier.py 2020-01-25 10:16:18.000000000 +0100 @@ -105,7 +105,7 @@ min_level_value = 0 if options.min_level == 'NONE' else get_level_value(options.min_level) if options.min_level is None: parser.error("min level must be an integer or one of these values: %s" % ', '.join(LEVEL_CHOICES)) - max_level_value = sys.maxint if options.max_level == 'NONE' else get_level_value(options.max_level) + max_level_value = 9000 if options.max_level == 'NONE' else get_level_value(options.max_level) if options.max_level is None: parser.error("max level must be an integer or one of these values: %s" % ', '.join(LEVEL_CHOICES)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynvim-0.3.2/setup.cfg new/pynvim-0.4.1/setup.cfg --- old/pynvim-0.3.2/setup.cfg 2019-01-20 16:22:43.000000000 +0100 +++ new/pynvim-0.4.1/setup.cfg 2020-01-25 10:16:18.000000000 +0100 @@ -1,5 +1,15 @@ +[aliases] +test = pytest + [flake8] -ignore = D211,E731,D401,W503 +extend-ignore = D211,E731,D401,W503 +max-line-length = 88 +per-file-ignores = + test/*:D1 +application-import-names = pynvim + +[isort] +known_first_party = pynvim [tool:pytest] testpaths = test diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynvim-0.3.2/setup.py new/pynvim-0.4.1/setup.py --- old/pynvim-0.3.2/setup.py 2019-01-20 16:22:43.000000000 +0100 +++ new/pynvim-0.4.1/setup.py 2020-01-25 10:16:18.000000000 +0100 @@ -8,6 +8,12 @@ 'msgpack>=0.5.0', ] +needs_pytest = {'pytest', 'test', 'ptr'}.intersection(sys.argv) +pytest_runner = ['pytest-runner'] if needs_pytest else [] + +setup_requires = [ +] + pytest_runner, + tests_require = [ 'pytest>=3.4.0', ] @@ -29,10 +35,10 @@ install_requires.append('greenlet') setup(name='pynvim', - version='0.3.2', + version='0.4.0', description='Python client to neovim', - url='http://github.com/neovim/python-client', - download_url='https://github.com/neovim/python-client/archive/0.3.2.tar.gz', + url='http://github.com/neovim/pynvim', + download_url='https://github.com/neovim/pynvim/archive/0.4.1.tar.gz', author='Thiago de Arruda', author_email='[email protected]', license='Apache', @@ -40,6 +46,7 @@ 'pynvim.msgpack_rpc.event_loop', 'pynvim.plugin', 'neovim', 'neovim.api'], install_requires=install_requires, + setup_requires=setup_requires, tests_require=tests_require, extras_require=extras_require, zip_safe=False) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynvim-0.3.2/test/conftest.py new/pynvim-0.4.1/test/conftest.py --- old/pynvim-0.3.2/test/conftest.py 2019-01-20 16:22:43.000000000 +0100 +++ new/pynvim-0.4.1/test/conftest.py 2020-01-25 10:16:18.000000000 +0100 @@ -1,55 +1,11 @@ import json import os -import textwrap -import pynvim import pytest -pynvim.setup_logging("test") - +import pynvim [email protected](autouse=True) -def cleanup_func(vim): - fun = textwrap.dedent('''function! BeforeEachTest() - set all& - redir => groups - silent augroup - redir END - for group in split(groups) - exe 'augroup '.group - autocmd! - augroup END - endfor - autocmd! - tabnew - let curbufnum = eval(bufnr('%')) - redir => buflist - silent ls! - redir END - let bufnums = [] - for buf in split(buflist, '\\n') - let bufnum = eval(split(buf, '[ u]')[0]) - if bufnum != curbufnum - call add(bufnums, bufnum) - endif - endfor - if len(bufnums) > 0 - exe 'silent bwipeout! '.join(bufnums, ' ') - endif - silent tabonly - for k in keys(g:) - exe 'unlet g:'.k - endfor - filetype plugin indent off - mapclear - mapclear! - abclear - comclear - endfunction - ''') - vim.command(fun) - vim.command('call BeforeEachTest()') - assert len(vim.tabpages) == len(vim.windows) == len(vim.buffers) == 1 +pynvim.setup_logging("test") @pytest.fixture @@ -57,11 +13,12 @@ child_argv = os.environ.get('NVIM_CHILD_ARGV') listen_address = os.environ.get('NVIM_LISTEN_ADDRESS') if child_argv is None and listen_address is None: - child_argv = '["nvim", "-u", "NONE", "--embed"]' + child_argv = '["nvim", "-u", "NONE", "--embed", "--headless"]' if child_argv is not None: editor = pynvim.attach('child', argv=json.loads(child_argv)) else: + assert listen_address is None or listen_address != '' editor = pynvim.attach('socket', path=listen_address) return editor diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynvim-0.3.2/test/test_buffer.py new/pynvim-0.4.1/test/test_buffer.py --- old/pynvim-0.3.2/test/test_buffer.py 2019-01-20 16:22:43.000000000 +0100 +++ new/pynvim-0.4.1/test/test_buffer.py 2020-01-25 10:16:18.000000000 +0100 @@ -1,10 +1,13 @@ import os +import pytest + +from pynvim.api import NvimError from pynvim.compat import IS_PYTHON3 def test_repr(vim): - assert repr(vim.current.buffer) == "<Buffer(handle=2)>" + assert repr(vim.current.buffer) == "<Buffer(handle=1)>" def test_get_length(vim): @@ -74,6 +77,17 @@ vim.current.buffer.vars['python'] = [1, 2, {'3': 1}] assert vim.current.buffer.vars['python'] == [1, 2, {'3': 1}] assert vim.eval('b:python') == [1, 2, {'3': 1}] + assert vim.current.buffer.vars.get('python') == [1, 2, {'3': 1}] + + del vim.current.buffer.vars['python'] + with pytest.raises(KeyError): + vim.current.buffer.vars['python'] + assert vim.eval('exists("b:python")') == 0 + + with pytest.raises(KeyError): + del vim.current.buffer.vars['python'] + + assert vim.current.buffer.vars.get('python', 'default') == 'default' def test_api(vim): @@ -93,7 +107,11 @@ vim.current.buffer.options['define'] = 'test' assert vim.current.buffer.options['define'] == 'test' # Doesn't change the global value - assert vim.options['define'] == '^\s*#\s*define' + assert vim.options['define'] == r'^\s*#\s*define' + + with pytest.raises(KeyError) as excinfo: + vim.current.buffer.options['doesnotexist'] + assert excinfo.value.args == ("Invalid option name: 'doesnotexist'",) def test_number(vim): @@ -154,21 +172,30 @@ def test_get_exceptions(vim): - try: + with pytest.raises(KeyError) as excinfo: vim.current.buffer.options['invalid-option'] - assert False - except vim.error: - pass + + assert not isinstance(excinfo.value, NvimError) + assert excinfo.value.args == ("Invalid option name: 'invalid-option'",) + def test_set_items_for_range(vim): vim.current.buffer[:] = ['a', 'b', 'c', 'd', 'e'] r = vim.current.buffer.range(1, 3) - r[1:3] = ['foo']*3 + r[1:3] = ['foo'] * 3 assert vim.current.buffer[:] == ['a', 'foo', 'foo', 'foo', 'd', 'e'] + # NB: we can't easily test the effect of this. But at least run the lua # function sync, so we know it runs without runtime error with simple args. def test_update_highlights(vim): vim.current.buffer[:] = ['a', 'b', 'c'] src_id = vim.new_highlight_source() - vim.current.buffer.update_highlights(src_id, [["Comment", 0, 0, -1], ("String", 1, 0, 1)], clear=True, async_=False) + vim.current.buffer.update_highlights( + src_id, [["Comment", 0, 0, -1], ("String", 1, 0, 1)], clear=True, async_=False + ) + + +def test_buffer_inequality(vim): + b = vim.current.buffer + assert not (b != vim.current.buffer) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynvim-0.3.2/test/test_client_rpc.py new/pynvim-0.4.1/test/test_client_rpc.py --- old/pynvim-0.3.2/test/test_client_rpc.py 2019-01-20 16:22:43.000000000 +0100 +++ new/pynvim-0.4.1/test/test_client_rpc.py 2020-01-25 10:16:18.000000000 +0100 @@ -4,6 +4,7 @@ def test_call_and_reply(vim): cid = vim.channel_id + def setup_cb(): cmd = 'let g:result = rpcrequest(%d, "client-call", 1, 2, 3)' % cid vim.command(cmd) @@ -20,6 +21,7 @@ def test_call_api_before_reply(vim): cid = vim.channel_id + def setup_cb(): cmd = 'let g:result = rpcrequest(%d, "client-call2", 1, 2, 3)' % cid vim.command(cmd) @@ -32,6 +34,7 @@ vim.run_loop(request_cb, None, setup_cb) + def test_async_call(vim): def request_cb(name, args): @@ -52,6 +55,7 @@ def test_recursion(vim): cid = vim.channel_id + def setup_cb(): vim.vars['result1'] = 0 vim.vars['result2'] = 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynvim-0.3.2/test/test_concurrency.py new/pynvim-0.4.1/test/test_concurrency.py --- old/pynvim-0.3.2/test/test_concurrency.py 2019-01-20 16:22:43.000000000 +0100 +++ new/pynvim-0.4.1/test/test_concurrency.py 2020-01-25 10:16:18.000000000 +0100 @@ -4,13 +4,13 @@ def test_interrupt_from_another_thread(vim): timer = Timer(0.5, lambda: vim.async_call(lambda: vim.stop_loop())) timer.start() - assert vim.next_message() == None + assert vim.next_message() is None def test_exception_in_threadsafe_call(vim): # an exception in a threadsafe_call shouldn't crash the entire host msgs = [] - vim.async_call(lambda: [vim.eval("3"), undefined_variable]) + vim.async_call(lambda: [vim.eval("3"), undefined_variable]) # noqa: F821 timer = Timer(0.5, lambda: vim.async_call(lambda: vim.stop_loop())) timer.start() vim.run_loop(None, None, err_cb=msgs.append) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynvim-0.3.2/test/test_decorators.py new/pynvim-0.4.1/test/test_decorators.py --- old/pynvim-0.3.2/test/test_decorators.py 2019-01-20 16:22:43.000000000 +0100 +++ new/pynvim-0.4.1/test/test_decorators.py 2020-01-25 10:16:18.000000000 +0100 @@ -3,7 +3,7 @@ def test_command_count(): def function(): - "A dummy function to decorate." + """A dummy function to decorate.""" return # ensure absence with default value of None diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynvim-0.3.2/test/test_events.py new/pynvim-0.4.1/test/test_events.py --- old/pynvim-0.3.2/test/test_events.py 2019-01-20 16:22:43.000000000 +0100 +++ new/pynvim-0.4.1/test/test_events.py 2020-01-25 10:16:18.000000000 +0100 @@ -28,6 +28,13 @@ assert vim.eval('g:data') == 'xyz' +def test_async_error(vim): + # Invoke a bogus Ex command via notify (async). + vim.command("lolwut", async_=True) + event = vim.next_message() + assert event[1] == 'nvim_error_event' + + def test_broadcast(vim): vim.subscribe('event2') vim.command('call rpcnotify(0, "event1", 1, 2, 3)') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynvim-0.3.2/test/test_host.py new/pynvim-0.4.1/test/test_host.py --- old/pynvim-0.3.2/test/test_host.py 2019-01-20 16:22:43.000000000 +0100 +++ new/pynvim-0.4.1/test/test_host.py 2020-01-25 10:16:18.000000000 +0100 @@ -2,6 +2,22 @@ from pynvim.plugin.host import Host, host_method_spec -def test_host_method_spec(vim): + +def test_host_clientinfo(vim): h = Host(vim) assert h._request_handlers.keys() == host_method_spec.keys() + assert 'remote' == vim.api.get_chan_info(vim.channel_id)['client']['type'] + h._load([]) + assert 'host' == vim.api.get_chan_info(vim.channel_id)['client']['type'] + + +# Smoke test for Host._on_error_event(). #425 +def test_host_async_error(vim): + h = Host(vim) + h._load([]) + # Invoke a bogus Ex command via notify (async). + vim.command("lolwut", async_=True) + event = vim.next_message() + assert event[1] == 'nvim_error_event' + assert 'rplugin-host: Async request caused an error:\nboom\n' \ + in h._on_error_event(None, 'boom') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynvim-0.3.2/test/test_logging.py new/pynvim-0.4.1/test/test_logging.py --- old/pynvim-0.3.2/test/test_logging.py 1970-01-01 01:00:00.000000000 +0100 +++ new/pynvim-0.4.1/test/test_logging.py 2020-01-25 10:16:18.000000000 +0100 @@ -0,0 +1,36 @@ +import os +import sys + + +def test_setup_logging(monkeypatch, tmpdir, caplog): + from pynvim import setup_logging + + major_version = sys.version_info[0] + + setup_logging('name1') + assert caplog.messages == [] + + def get_expected_logfile(prefix, name): + return '{}_py{}_{}'.format(prefix, major_version, name) + + prefix = tmpdir.join('testlog1') + monkeypatch.setenv('NVIM_PYTHON_LOG_FILE', str(prefix)) + setup_logging('name2') + assert caplog.messages == [] + logfile = get_expected_logfile(prefix, 'name2') + assert os.path.exists(logfile) + assert open(logfile, 'r').read() == '' + + monkeypatch.setenv('NVIM_PYTHON_LOG_LEVEL', 'invalid') + setup_logging('name3') + assert caplog.record_tuples == [ + ('pynvim', 30, "Invalid NVIM_PYTHON_LOG_LEVEL: 'invalid', using INFO."), + ] + logfile = get_expected_logfile(prefix, 'name2') + assert os.path.exists(logfile) + with open(logfile, 'r') as f: + lines = f.readlines() + assert len(lines) == 1 + assert lines[0].endswith( + "- Invalid NVIM_PYTHON_LOG_LEVEL: 'invalid', using INFO.\n" + ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynvim-0.3.2/test/test_tabpage.py new/pynvim-0.4.1/test/test_tabpage.py --- old/pynvim-0.3.2/test/test_tabpage.py 2019-01-20 16:22:43.000000000 +0100 +++ new/pynvim-0.4.1/test/test_tabpage.py 2020-01-25 10:16:18.000000000 +0100 @@ -1,3 +1,6 @@ +import pytest + + def test_windows(vim): vim.command('tabnew') vim.command('vsplit') @@ -12,6 +15,17 @@ vim.current.tabpage.vars['python'] = [1, 2, {'3': 1}] assert vim.current.tabpage.vars['python'] == [1, 2, {'3': 1}] assert vim.eval('t:python') == [1, 2, {'3': 1}] + assert vim.current.tabpage.vars.get('python') == [1, 2, {'3': 1}] + + del vim.current.tabpage.vars['python'] + with pytest.raises(KeyError): + vim.current.tabpage.vars['python'] + assert vim.eval('exists("t:python")') == 0 + + with pytest.raises(KeyError): + del vim.current.tabpage.vars['python'] + + assert vim.current.tabpage.vars.get('python', 'default') == 'default' def test_valid(vim): @@ -31,4 +45,4 @@ def test_repr(vim): - assert repr(vim.current.tabpage) == "<Tabpage(handle=2)>" + assert repr(vim.current.tabpage) == "<Tabpage(handle=1)>" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynvim-0.3.2/test/test_vim.py new/pynvim-0.4.1/test/test_vim.py --- old/pynvim-0.3.2/test/test_vim.py 2019-01-20 16:22:43.000000000 +0100 +++ new/pynvim-0.4.1/test/test_vim.py 2020-01-25 10:16:18.000000000 +0100 @@ -3,6 +3,8 @@ import sys import tempfile +import pytest + def source(vim, code): fd, fname = tempfile.mkstemp() @@ -12,6 +14,10 @@ os.unlink(fname) +def test_clientinfo(vim): + assert 'remote' == vim.api.get_chan_info(vim.channel_id)['client']['type'] + + def test_command(vim): fname = tempfile.mkstemp()[1] vim.command('new') @@ -30,14 +36,22 @@ assert vim.command_output('echo "test"') == 'test' +def test_command_error(vim): + with pytest.raises(vim.error) as excinfo: + vim.current.window.cursor = -1, -1 + assert excinfo.value.args == ('Cursor position outside buffer',) + + def test_eval(vim): vim.command('let g:v1 = "a"') vim.command('let g:v2 = [1, 2, {"v3": 3}]') - assert vim.eval('g:'), {'v1': 'a', 'v2': [1, 2 == {'v3': 3}]} + g = vim.eval('g:') + assert g['v1'] == 'a' + assert g['v2'] == [1, 2, {'v3': 3}] def test_call(vim): - assert vim.funcs.join(['first', 'last'], ', '), 'first == last' + assert vim.funcs.join(['first', 'last'], ', ') == 'first, last' source(vim, """ function! Testfun(a,b) return string(a:a).":".a:b @@ -87,12 +101,29 @@ vim.vars['python'] = [1, 2, {'3': 1}] assert vim.vars['python'], [1, 2 == {'3': 1}] assert vim.eval('g:python'), [1, 2 == {'3': 1}] + assert vim.vars.get('python') == [1, 2, {'3': 1}] + + del vim.vars['python'] + with pytest.raises(KeyError): + vim.vars['python'] + assert vim.eval('exists("g:python")') == 0 + + with pytest.raises(KeyError): + del vim.vars['python'] + + assert vim.vars.get('python', 'default') == 'default' def test_options(vim): - assert vim.options['listchars'] == 'tab:> ,trail:-,nbsp:+' - vim.options['listchars'] = 'tab:xy' - assert vim.options['listchars'] == 'tab:xy' + assert vim.options['background'] == 'dark' + vim.options['background'] = 'light' + assert vim.options['background'] == 'light' + + +def test_local_options(vim): + assert vim.windows[0].options['foldmethod'] == 'manual' + vim.windows[0].options['foldmethod'] = 'syntax' + assert vim.windows[0].options['foldmethod'] == 'syntax' def test_buffers(vim): @@ -178,6 +209,7 @@ assert cwd_python == cwd_vim assert cwd_python != cwd_before + lua_code = """ local a = vim.api local y = ... @@ -194,15 +226,16 @@ return a.nvim_buf_line_count(buf) end -pynvimtest = {setbuf=setbuf,getbuf=getbuf} +pynvimtest = {setbuf=setbuf, getbuf=getbuf} return "eggspam" """ + def test_lua(vim): - assert vim.exec_lua(lua_code, 7) == "eggspam" - assert vim.lua.pynvimtest_func(3) == 10 - testmod = vim.lua.pynvimtest - buf = vim.current.buffer - testmod.setbuf(buf, ["a", "b", "c", "d"], async_=True) - assert testmod.getbuf(buf) == 4 + assert vim.exec_lua(lua_code, 7) == "eggspam" + assert vim.lua.pynvimtest_func(3) == 10 + lua_module = vim.lua.pynvimtest + buf = vim.current.buffer + lua_module.setbuf(buf, ["a", "b", "c", "d"], async_=True) + assert lua_module.getbuf(buf) == 4 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynvim-0.3.2/test/test_window.py new/pynvim-0.4.1/test/test_window.py --- old/pynvim-0.3.2/test/test_window.py 2019-01-20 16:22:43.000000000 +0100 +++ new/pynvim-0.4.1/test/test_window.py 2020-01-25 10:16:18.000000000 +0100 @@ -1,3 +1,6 @@ +import pytest + + def test_buffer(vim): assert vim.current.buffer == vim.windows[0].buffer vim.command('new') @@ -40,6 +43,17 @@ vim.current.window.vars['python'] = [1, 2, {'3': 1}] assert vim.current.window.vars['python'] == [1, 2, {'3': 1}] assert vim.eval('w:python') == [1, 2, {'3': 1}] + assert vim.current.window.vars.get('python') == [1, 2, {'3': 1}] + + del vim.current.window.vars['python'] + with pytest.raises(KeyError): + vim.current.window.vars['python'] + assert vim.eval('exists("w:python")') == 0 + + with pytest.raises(KeyError): + del vim.current.window.vars['python'] + + assert vim.current.window.vars.get('python', 'default') == 'default' def test_options(vim): @@ -50,6 +64,10 @@ assert vim.current.window.options['statusline'] == 'window-status' assert vim.options['statusline'] == '' + with pytest.raises(KeyError) as excinfo: + vim.current.window.options['doesnotexist'] + assert excinfo.value.args == ("Invalid option name: 'doesnotexist'",) + def test_position(vim): height = vim.windows[0].height @@ -103,4 +121,4 @@ def test_repr(vim): - assert repr(vim.current.window) == "<Window(handle=1001)>" + assert repr(vim.current.window) == "<Window(handle=1000)>" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynvim-0.3.2/tox.ini new/pynvim-0.4.1/tox.ini --- old/pynvim-0.3.2/tox.ini 2019-01-20 16:22:43.000000000 +0100 +++ new/pynvim-0.4.1/tox.ini 2020-01-25 10:16:18.000000000 +0100 @@ -1,16 +1,19 @@ [tox] envlist = - py{27,34,35,36}-{asyncio,pyuv},pypy - py36-docs + py{27,34,35,36,37,38}-{asyncio,pyuv}-cov,pypy-cov + checkqa [testenv] +extras = test deps = - pytest - pytest-xdist pytest-timeout + cov: pytest-cov pyuv: pyuv +setenv = + cov: PYTEST_ADDOPTS=--cov=. {env:PYTEST_ADDOPTS:} passenv = PYTEST_ADDOPTS -commands = python -m pytest {posargs} +commands = + python -m pytest {posargs} [testenv:checkqa] deps = @@ -18,7 +21,7 @@ flake8-import-order flake8-docstrings pep8-naming -commands = flake8 {posargs:pynvim} +commands = flake8 {posargs:pynvim test} [testenv:docs] deps = ++++++ setup_version.patch ++++++ --- a/setup.py +++ b/setup.py @@ -35,7 +35,7 @@ if platform.python_implementation() != ' install_requires.append('greenlet') setup(name='pynvim', - version='0.4.0', + version='0.4.1', description='Python client to neovim', url='http://github.com/neovim/pynvim', download_url='https://github.com/neovim/pynvim/archive/0.4.1.tar.gz',
