diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..0fa458b --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,34 @@ +# This workflow will install Python dependencies, run tests and lint with a variety of Python versions +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions + +name: ci + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + + runs-on: ubuntu-20.04 + strategy: + matrix: + python-version: [3.5, 3.6, 3.7, 3.8, 3.9] + + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + sudo apt-get install -y libnanomsg-dev nanomsg-utils + pip install tox + - name: Test with tox + run: | + tox -e py + # pytest tests --flake8 nanomsg -v --cov nanomsg nanomsg_wrappers _nanomsg_ctypes --cov-report term-missing diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 7167a59..0000000 --- a/.travis.yml +++ /dev/null @@ -1,25 +0,0 @@ -language: python -python: - - "3.2" - - "3.3" - - "3.4" - - "2.7" - - "2.6" - -# command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors -# Build steps taken from -# https://github.com/nanomsg/nanomsg#build-it-with-cmake -install: - - git clone --quiet --depth=100 "https://github.com/nanomsg/nanomsg.git" ~/builds/nanomsg - && pushd ~/builds/nanomsg - && mkdir build - && cd build - && cmake .. - && cmake --build . - && ctest -C Debug . - && sudo cmake --build . --target install - && sudo ldconfig - && popd - -# command to run tests, e.g. python setup.py test -script: LD_LIBRARY_PATH=/lib:/usr/lib:/usr/local/lib python setup.py test diff --git a/README.md b/README.md index 5788325..8b05fe0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,10 @@ nanomsg-python ============== +![GitHub CI Workflow Status](https://img.shields.io/github/workflow/status/freepn/nanomsg-python/ci) + +This fork of nanomsg-python is currently tested on Python 2.7 and Python 3.6+ on Linux, Darwin, and Windows (the latter two somewhat theoretical). + Python library for [nanomsg](http://nanomsg.org/) which does not compromise on usability or performance. diff --git a/_nanomsg_ctypes/__init__.py b/_nanomsg_ctypes/__init__.py index 43aefc1..7382778 100644 --- a/_nanomsg_ctypes/__init__.py +++ b/_nanomsg_ctypes/__init__.py @@ -1,8 +1,6 @@ -from __future__ import division, absolute_import, print_function,\ - unicode_literals +from __future__ import division, absolute_import, print_function, unicode_literals import ctypes -import platform import sys if sys.platform in ('win32', 'cygwin'): @@ -19,7 +17,7 @@ def _c_func_wrapper_factory(cdecl_text): def move_pointer_and_strip(type_def, name): if '*' in name: - type_def += ' ' + name[:name.rindex('*')+1] + type_def += ' ' + name[:name.rindex('*') + 1] name = name.rsplit('*', 1)[1] return type_def.strip(), name.strip() @@ -31,35 +29,34 @@ def type_lookup(type_def): 'int': ctypes.c_int, 'int *': ctypes.POINTER(ctypes.c_int), 'void *': ctypes.c_void_p, - 'size_t': ctypes.c_size_t, - 'size_t *': ctypes.POINTER(ctypes.c_size_t), + 'size_t': ctypes.c_size_t, + 'size_t *': ctypes.POINTER(ctypes.c_size_t), 'struct nn_msghdr *': ctypes.c_void_p, 'struct nn_pollfd *': ctypes.c_void_p, } - type_def_without_const = type_def.replace('const ','') + type_def_without_const = type_def.replace('const ', '') if type_def_without_const in types: return types[type_def_without_const] - elif (type_def_without_const.endswith('*') and - type_def_without_const[:-1] in types): + elif (type_def_without_const.endswith('*') and type_def_without_const[:-1] in types): return ctypes.POINTER(types[type_def_without_const[:-1]]) else: raise KeyError(type_def) - return types[type_def.replace('const ','')] + return types[type_def.replace('const ', '')] - a, b = [i.strip() for i in cdecl_text.split('(',1)] - params, _ = b.rsplit(')',1) + a, b = [i.strip() for i in cdecl_text.split('(', 1)] + params, dummy = b.rsplit(')', 1) rtn_type, name = move_pointer_and_strip(*a.rsplit(' ', 1)) param_spec = [] for param in params.split(','): if param != 'void': param_spec.append(move_pointer_and_strip(*param.rsplit(' ', 1))) - func = _functype(type_lookup(rtn_type), - *[type_lookup(type_def) for type_def, _ in param_spec])( - (name, _lib), - tuple((2 if '**' in type_def else 1, name) - for type_def, name in param_spec) - ) + func = ( + _functype(type_lookup(rtn_type), + *[type_lookup(type_def) for type_def, _ in param_spec]) + ((name, _lib), tuple((2 if '**' in type_def else 1, name) + for type_def, name in param_spec))) + func.__name__ = name return func @@ -136,7 +133,7 @@ def create_writable_buffer(size): This is the ctypes implementation. """ - return (ctypes.c_ubyte*size)() + return (ctypes.c_ubyte * size)() def nn_setsockopt(socket, level, option, value): @@ -188,7 +185,7 @@ def nn_send(socket, msg, flags): def _create_message(address, length): class Message(ctypes.Union): - _fields_ = [('_buf', ctypes.c_ubyte*length)] + _fields_ = [('_buf', ctypes.c_ubyte * length)] _len = length _address = address @@ -237,7 +234,7 @@ def nn_poll(fds, timeout=-1): s.revents = 0 polls.append(s) - poll_array = (PollFds*len(fds))(*polls) + poll_array = (PollFds * len(fds))(*polls) res = _nn_poll(poll_array, len(fds), int(timeout)) if res <= 0: return res, {} @@ -276,7 +273,7 @@ def nn_recv(socket, *args): else: _nclib = ctypes.cdll.LoadLibrary('libnanoconfig.so') except OSError: - pass # No nanoconfig, sorry + pass # No nanoconfig, sorry else: # int nc_configure (int s, const char *addr) nc_configure = _functype(ctypes.c_int, ctypes.c_int, ctypes.c_char_p)( diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 6db46c8..0000000 --- a/appveyor.yml +++ /dev/null @@ -1,66 +0,0 @@ -# The template for this file was from https://packaging.python.org/appveyor/ - -environment: - matrix: - # For Python versions available on Appveyor, see - # http://www.appveyor.com/docs/installed-software#python - - PYTHON: "C:\\Python27" - CMAKE_GENERATOR: "Visual Studio 9 2008" - - PYTHON: "C:\\Python34" - CMAKE_GENERATOR: "Visual Studio 10 2010" - - PYTHON: "C:\\Python35" - CMAKE_GENERATOR: "Visual Studio 14 2015" - - PYTHON: "C:\\Python36" - CMAKE_GENERATOR: "Visual Studio 14 2015" - - PYTHON: "C:\\Python27" - CMAKE_GENERATOR: "Visual Studio 9 2008 Win64" - - PYTHON: "C:\\Python34-x64" - CMAKE_GENERATOR: "Visual Studio 10 2010 Win64" - - PYTHON: "C:\\Python35-x64" - CMAKE_GENERATOR: "Visual Studio 14 2015 Win64" - - PYTHON: "C:\\Python36-x64" - CMAKE_GENERATOR: "Visual Studio 14 2015 Win64" - -install: - # We need wheel installed to build wheels - - "%PYTHON%\\python.exe -m pip install wheel" - # Visual Studio 9 2008 does not come with stdint.h, so we'll copy over a - # different version. We only need to do it whenever we're building with - # 2008, but it doesn't hurt to copy it unconditionally. The first copy is to - # build nanomsg, the second is to build the extension. - - ps: cp "C:\\Program Files (x86)\\Microsoft Visual Studio 10.0\\VC\\include\\stdint.h" - "C:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\VC\\include\\stdint.h" - - ps: cp "C:\\Program Files (x86)\\Microsoft Visual Studio 10.0\\VC\\include\\stdint.h" - "C:\\Users\\appveyor\\AppData\\Local\\Programs\\Common\\Microsoft\\Visual C++ for Python\\9.0\\VC\include\\stdint.h" - - git clone https://github.com/nanomsg/nanomsg.git nanomsg-src - - pwd - - ps: pushd nanomsg-src - - git checkout 1.0.0 - - ps: mkdir build - - ps: cd build - - cmake -DNN_STATIC_LIB=ON -G"%CMAKE_GENERATOR%" .. - - cmake --build . - - cmake --build . --target install - - ps: cp Debug\nanomsg.lib ..\.. - - ps: popd - - pwd - -build_script: - - "%PYTHON%\\python.exe setup.py install" - -test_script: - - "build.cmd %PYTHON%\\python.exe setup.py test" - -after_test: - # build the wheel. - # build.cmd sets up necessary variables for 64-bit builds - - "build.cmd %PYTHON%\\python.exe setup.py bdist_wheel" - -artifacts: - # bdist_wheel puts your built wheel in the dist directory - - path: dist\* - -#on_success: -# You can use this step to upload your artifacts to a public website. -# See Appveyor's documentation for more details. Or you can simply -# access your wheels from the Appveyor "artifacts" tab for your build. diff --git a/appveyor_yml.disabled b/appveyor_yml.disabled new file mode 100644 index 0000000..88d44fb --- /dev/null +++ b/appveyor_yml.disabled @@ -0,0 +1,50 @@ +# What Python version is installed where: +# http://www.appveyor.com/docs/installed-software#python + +image: + - Visual Studio 2019 + +environment: + global: + PYTHONIOENCODING: utf-8 + matrix: + - PYTHON: "C:\\Python36-x64" + TOX_ENV: "py36" + - PYTHON: "C:\\Python37-x64" + TOX_ENV: "py37" + - PYTHON: "C:\\Python38-x64" + TOX_ENV: "py38" + - PYTHON: "C:\\Python39-x64" + TOX_ENV: "py39" + +## Before repo cloning +init: + ## without this, temporary directory could be created in current dir + ## which will make some tests fail. + - mkdir C:\TMP + - set PATH=%PYTHON%;%PYTHON%\Scripts;%PATH% + - set TOX_TESTENV_PASSENV=DISTUTILS_USE_SDK MSSdk INCLUDE LIB + - python -V + +## After repo cloning +install: + - cmd: cd c:\tools\vcpkg + - cmd: vcpkg integrate install + - cmd: vcpkg install nanomsg:x64-windows + - cmd: cd "%APPVEYOR_BUILD_FOLDER%" + +build: false + +## Before tests +before_test: + - python -m pip install --upgrade pip wheel + - pip install tox virtualenv codecov + +## Custom test script +test_script: + + ## real tests + - "%PYTHON%/Scripts/tox -e %TOX_ENV%" + + ## installable + - pip install . diff --git a/nanomsg/__init__.py b/nanomsg/__init__.py index ab584dc..6825162 100644 --- a/nanomsg/__init__.py +++ b/nanomsg/__init__.py @@ -1,8 +1,6 @@ from __future__ import division, absolute_import, print_function, unicode_literals -from .version import __version__ from struct import Struct as _Struct -import warnings from . import wrapper @@ -13,7 +11,7 @@ nanoconfig_started = False -#Import constants into module with NN_ prefix stripped +# Import constants into module with NN_ prefix stripped for name, value in wrapper.nn_symbols(): if name.startswith('NN_'): name = name[3:] @@ -112,7 +110,7 @@ def poll(in_sockets, out_sockets, timeout=-1): # convert to milliseconds or -1 if timeout >= 0: - timeout_ms = int(timeout*1000) + timeout_ms = int(timeout * 1000) else: timeout_ms = -1 res, sockets = wrapper.nn_poll(sockets, timeout_ms) @@ -159,7 +157,7 @@ class Socket(object): """ - _INT_PACKER = _Struct(str('l')) + _INT_PACKER = _Struct(str('i')) class _Endpoint(object): def __init__(self, socket, endpoint_id, address): @@ -174,7 +172,7 @@ def address(self): def shutdown(self): self._fdocket._endpoints.remove(self) _nn_check_positive_rtn(wrapper.nn_shutdown(self._fdocket._fd, - self._endpoint_id)) + self._endpoint_id)) def __repr__(self): return '<%s socket %r, id %r, address %r>' % ( @@ -258,8 +256,8 @@ def _set_reconnect_interval_max(self, value): send_fd = property(_get_send_fd, doc='Send file descripter') recv_fd = property(_get_recv_fd, doc='Receive file descripter') - linger = property(_get_linger, _set_linger, doc='Socket linger in ' - 'milliseconds (0.001 seconds)') + linger = property(_get_linger, _set_linger, doc='Socket linger in ' + 'milliseconds (0.001 seconds)') recv_buffer_size = property(_get_recv_buffer_size, _set_recv_buffer_size, doc='Receive buffer size in bytes') send_buffer_size = property(_get_send_buffer_size, _set_send_buffer_size, @@ -298,8 +296,8 @@ def endpoints(self): @property def uses_nanoconfig(self): - return (self._endpoints and - isinstance(self._endpoints[0], Socket.NanoconfigEndpoint)) + return (self._endpoints and isinstance(self._endpoints[0], + Socket.NanoconfigEndpoint)) def bind(self, address): """Add a local endpoint to the socket""" @@ -382,10 +380,10 @@ def get_int_option(self, level, option): _nn_check_positive_rtn(rtn) if length != size: raise NanoMsgError(('Returned option size (%r) should be the same' - ' as size of int (%r)') % (rtn, size)) + ' as size of int (%r)') % (length, size)) return Socket._INT_PACKER.unpack_from(buffer(buf))[0] - def get_string_option(self, level, option, max_len=16*1024): + def get_string_option(self, level, option, max_len=16 * 1024): buf = create_writable_buffer(max_len) rtn, length = wrapper.nn_getsockopt(self._fd, level, option, buf) _nn_check_positive_rtn(rtn) diff --git a/nanomsg/version.py b/nanomsg/version.py index 5ac9e42..095a760 100644 --- a/nanomsg/version.py +++ b/nanomsg/version.py @@ -1,2 +1 @@ - -__version__ = '1.0' +__version__ = '1.0.2-4' diff --git a/nanomsg_wrappers/__init__.py b/nanomsg_wrappers/__init__.py index 1da62f5..33ad56b 100644 --- a/nanomsg_wrappers/__init__.py +++ b/nanomsg_wrappers/__init__.py @@ -7,10 +7,12 @@ _choice = None + def set_wrapper_choice(name): global _choice _choice = name + def load_wrapper(): if _choice is not None: return importlib.import_module('_nanomsg_' + _choice) @@ -22,6 +24,7 @@ def load_wrapper(): "%s, performance may be affected!") % (default,)) return importlib.import_module('_nanomsg_ctypes') + def get_default_for_platform(): if python_implementation() == 'CPython': return 'cpy' @@ -30,5 +33,5 @@ def get_default_for_platform(): def list_wrappers(): - return [module_name.split('_',2)[-1] for _, module_name, _ in - pkgutil.iter_modules() if module_name.startswith('_nanomsg_')] + return [module_name.split('_', 2)[-1] for _, module_name, _ in + pkgutil.iter_modules() if module_name.startswith('_nanomsg_')] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..ed95be6 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,2 @@ +[build-system] +requires = ["setuptools>=30.3.0", "wheel"] diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 0000000..19f6008 --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1,3 @@ +pytest +pytest-flake8 +pytest-cov diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..9d06e8a --- /dev/null +++ b/setup.cfg @@ -0,0 +1,7 @@ +[tool:pytest] +flake8-max-line-length = 109 + +flake8-ignore = + nanomsg/__init__.py F821 + _nanomsg_ctypes/__init__.py F821 + tests/*.py ALL diff --git a/setup.py b/setup.py index 9d31dc1..91f4b18 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ libraries = [str('nanomsg')] # add additional necessary library/include path info if we're on Windows -if sys.platform in ("win32", "cygwin"): +if sys.platform in ("win32", "cygwin") or platform.system() == "Windows": libraries.extend([str('ws2_32'), str('advapi32'), str('mswsock')]) # nanomsg installs to different directory based on architecture arch = platform.architecture()[0] @@ -27,7 +27,7 @@ try: import ctypes - if sys.platform in ('win32', 'cygwin'): + if platform.system() == "Windows": _lib = ctypes.windll.nanoconfig elif sys.platform == 'darwin': _lib = ctypes.cdll.LoadLibrary('libnanoconfig.dylib') @@ -63,15 +63,17 @@ install_requires=install_requires, description='Python library for nanomsg.', classifiers=[ - "Development Status :: 3 - Alpha", + "Development Status :: 4 - Beta", "Intended Audience :: Developers", "Programming Language :: Python", "Programming Language :: Python :: 2", - "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.2", - "Programming Language :: Python :: 3.3", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", ], author='Tony Simpson', author_email='agjasimpson@gmail.com', diff --git a/tests/test_pubsub.py b/tests/test_pubsub.py index 0678b65..bd6ae3c 100644 --- a/tests/test_pubsub.py +++ b/tests/test_pubsub.py @@ -30,7 +30,7 @@ def test_subscribe_works(self): actual = s2.recv() - self.assertEquals(expected, actual) + self.assertEqual(expected, actual) if __name__ == '__main__': unittest.main() diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..fa73dda --- /dev/null +++ b/tox.ini @@ -0,0 +1,17 @@ +[tox] +envlist = py27, py3{5,6,7,8,9} +skip_missing_interpreters = true + +[tox:travis] +2.7 = py27 +3.5 = py35 +3.6 = py36 +3.7 = py37 +3.8 = py38 +3.9 = py39 + +[testenv] +deps = -rrequirements-dev.txt +commands = + # pip install . + py.test tests --flake8 nanomsg -v --cov nanomsg nanomsg_wrappers _nanomsg_ctypes --cov-report term-missing diff --git a/travis.yml_disabled b/travis.yml_disabled new file mode 100644 index 0000000..8a9a1cf --- /dev/null +++ b/travis.yml_disabled @@ -0,0 +1,31 @@ +sudo: required + +language: python +python: + - "2.7" + - "3.5" + - "3.6" + - "3.7" + - "3.8" + - "3.9-dev" + - "nightly" + +matrix: + fast_finish: true + allow_failures: + - python: "nightly" + +before_install: + - sudo apt-get -qq update + - sudo apt-get install -y software-properties-common + - sudo add-apt-repository -y ppa:nerdboy/embedded + - sudo apt-get -qq update + - sudo apt-get install libnanomsg-dev + +# command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors +install: + - pip install tox-travis + +# command to run tests, e.g. python setup.py test +script: + - tox