From 0c4bc5feb9bcf0df6d9cb3e37836500a0bdf0efc Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Tue, 27 Feb 2018 14:07:24 +0000 Subject: [PATCH 1/6] Implement reader and writer which connect over ZMQ connection --- .../backend/tests/test_zmqstream.py | 19 +++ spyder_unittest/backend/zmqstream.py | 113 ++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 spyder_unittest/backend/tests/test_zmqstream.py create mode 100644 spyder_unittest/backend/zmqstream.py diff --git a/spyder_unittest/backend/tests/test_zmqstream.py b/spyder_unittest/backend/tests/test_zmqstream.py new file mode 100644 index 00000000..eda5cda9 --- /dev/null +++ b/spyder_unittest/backend/tests/test_zmqstream.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# +# Copyright © 2018 Spyder Project Contributors +# Licensed under the terms of the MIT License +# (see LICENSE.txt for details) +"""Tests for zmqstream.py""" + +# Local imports +from spyder_unittest.backend.zmqstream import ZmqStreamReader, ZmqStreamWriter + + +def test_zmqstream(qtbot): + manager = ZmqStreamReader() + worker = ZmqStreamWriter(manager.port) + with qtbot.waitSignal(manager.sig_received) as blocker: + worker.write(42) + assert blocker.args == [[42]] + worker.close() + manager.close() diff --git a/spyder_unittest/backend/zmqstream.py b/spyder_unittest/backend/zmqstream.py new file mode 100644 index 00000000..35723ecd --- /dev/null +++ b/spyder_unittest/backend/zmqstream.py @@ -0,0 +1,113 @@ +# -*- coding: utf-8 -*- +# +# Copyright © 2018 Spyder Project Contributors +# Licensed under the terms of the MIT License +# (see LICENSE.txt for details) +""" +Reader and writer for sending stream of python objects over a ZMQ socket. + +The intended usage is that you construct a reader in one process and a writer +(with the same port number as the reader) in a worker process. The worker +process can then use the stream to send its result to the reader. +""" + +# Standard library imports +import sys + +# Third party imports +from qtpy.QtCore import QObject, QProcess, QSocketNotifier, Signal +from qtpy.QtWidgets import QApplication +import zmq + + +class ZmqStreamWriter: + """Writer for sending stream of Python object over a ZMQ stream.""" + + def __init__(self, port): + """ + Constructor. + + Arguments + --------- + port : int + TCP port number to be used for the stream. This should equal the + `port` attribute of the corresponding `ZmqStreamReader`. + """ + context = zmq.Context() + self.socket = context.socket(zmq.PAIR) + self.socket.connect('tcp://localhost:{}'.format(port)) + + def write(self, obj): + """Write arbitrary Python object to stream.""" + self.socket.send_pyobj(obj) + + def close(self): + """Close stream.""" + self.socket.close() + + +class ZmqStreamReader(QObject): + """ + Reader for receiving stream of Python objects via a ZMQ stream. + + Attributes + ---------- + port : int + TCP port number used for the stream. + + Signals + ------- + sig_received(list) + Emitted when objects are received; argument is list of received + objects. + """ + + sig_received = Signal(object) + + def __init__(self): + """Constructor; also constructs ZMQ stream.""" + super(QObject, self).__init__() + self.context = zmq.Context() + self.socket = self.context.socket(zmq.PAIR) + self.port = self.socket.bind_to_random_port('tcp://*') + fid = self.socket.getsockopt(zmq.FD) + self.notifier = QSocketNotifier(fid, QSocketNotifier.Read, self) + self.notifier.activated.connect(self.received_message) + + def received_message(self): + """Called when a message is received.""" + self.notifier.setEnabled(False) + messages = [] + try: + while 1: + message = self.socket.recv_pyobj(flags=zmq.NOBLOCK) + messages.append(message) + except zmq.ZMQError: + pass + finally: + self.notifier.setEnabled(True) + if messages: + self.sig_received.emit(messages) + + def close(self): + """Read any remaining messages and close stream.""" + self.received_message() # Flush remaining messages + self.notifier.setEnabled(False) + self.socket.close() + self.context.destroy() + + +if __name__ == '__main__': + # For testing, construct a ZMQ stream between two processes and send + # the number 42 over the stream + if len(sys.argv) == 1: + app = QApplication(sys.argv) + manager = ZmqStreamReader() + manager.sig_received.connect(print) + process = QProcess() + process.start('python', [sys.argv[0], str(manager.port)]) + process.finished.connect(app.quit) + sys.exit(app.exec_()) + else: + worker = ZmqStreamWriter(sys.argv[1]) + worker.write(42) From 21873642edd09d7bd381eea3c1de666982dba1f8 Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Tue, 27 Feb 2018 14:11:50 +0000 Subject: [PATCH 2/6] Replace JSON stream by ZMQ stream in pytest runner and worker --- spyder_unittest/backend/pytestrunner.py | 26 ++++------- spyder_unittest/backend/pytestworker.py | 46 ++++++++----------- .../backend/tests/test_pytestrunner.py | 26 +++-------- .../backend/tests/test_pytestworker.py | 33 +++---------- 4 files changed, 42 insertions(+), 89 deletions(-) diff --git a/spyder_unittest/backend/pytestrunner.py b/spyder_unittest/backend/pytestrunner.py index a962eeac..19796741 100644 --- a/spyder_unittest/backend/pytestrunner.py +++ b/spyder_unittest/backend/pytestrunner.py @@ -10,8 +10,8 @@ import os.path as osp # Local imports -from spyder_unittest.backend.jsonstream import JSONStreamReader from spyder_unittest.backend.runnerbase import Category, RunnerBase, TestResult +from spyder_unittest.backend.zmqstream import ZmqStreamReader class PyTestRunner(RunnerBase): @@ -23,27 +23,15 @@ class PyTestRunner(RunnerBase): def create_argument_list(self): """Create argument list for testing process.""" pyfile = os.path.join(os.path.dirname(__file__), 'pytestworker.py') - return [pyfile] - - def _prepare_process(self, config, pythonpath): - """Prepare and return process for running the unit test suite.""" - process = RunnerBase._prepare_process(self, config, pythonpath) - process.readyReadStandardOutput.connect(self.read_output) - return process + return [pyfile, str(self.reader.port)] def start(self, config, pythonpath): """Start process which will run the unit test suite.""" self.config = config - self.reader = JSONStreamReader() - self.output = '' + self.reader = ZmqStreamReader() + self.reader.sig_received.connect(self.process_output) RunnerBase.start(self, config, pythonpath) - def read_output(self): - """Called when test process emits output.""" - output = self.read_all_process_output() - result = self.reader.consume(output) - self.process_output(result) - def process_output(self, output): """ Process output of test process. @@ -88,7 +76,9 @@ def finished(self): This function emits `sig_finished`. """ - self.sig_finished.emit(None, self.output) + self.reader.close() + output = self.read_all_process_output() + self.sig_finished.emit(None, output) def normalize_module_name(name): @@ -137,7 +127,7 @@ def logreport_to_testresult(report, config): message = report['message'] if 'message' in report else '' if 'longrepr' not in report: extra_text = '' - elif isinstance(report['longrepr'], list): + elif isinstance(report['longrepr'], tuple): extra_text = report['longrepr'][2] else: extra_text = report['longrepr'] diff --git a/spyder_unittest/backend/pytestworker.py b/spyder_unittest/backend/pytestworker.py index 9ecdba5d..8289ef65 100644 --- a/spyder_unittest/backend/pytestworker.py +++ b/spyder_unittest/backend/pytestworker.py @@ -12,30 +12,29 @@ """ # Standard library imports -import io import sys # Third party imports import pytest # Local imports -from spyder_unittest.backend.jsonstream import JSONStreamWriter +from spyder_unittest.backend.zmqstream import ZmqStreamWriter -class StdoutBuffer(io.TextIOWrapper): - """ - Wrapper for binary stream which accepts both text and binary strings. +class FileStub(): + """Stub for ZmqStreamWriter which instead writes to a file.""" - Source: https://stackoverflow.com/a/19344871 - """ + def __init__(self, filename): + """Constructor; connect to specified filename.""" + self.file = open(filename, 'w') - def write(self, string): - """Write text or binary string to underlying stream.""" - try: - return super(StdoutBuffer, self).write(string) - except TypeError: - # redirect encoded byte strings directly to buffer - return super(StdoutBuffer, self).buffer.write(string) + def write(self, obj): + """Write Python object to file.""" + self.file.write(str(obj) + '\n') + + def close(self): + """Close file.""" + self.file.close() class SpyderPlugin(): @@ -99,18 +98,13 @@ def pytest_runtest_logreport(self, report): def main(args): """Run py.test with the Spyder plugin.""" - old_stdout = sys.stdout - stdout_buffer = StdoutBuffer(io.BytesIO(), sys.stdout.encoding) - sys.stdout = stdout_buffer - - writer = JSONStreamWriter(old_stdout) - pytest.main(args, plugins=[SpyderPlugin(writer)]) - - stdout_buffer.seek(0) - data = {'event': 'finished', 'stdout': stdout_buffer.read()} - writer.write(data) - sys.stdout = old_stdout + if args[1] == 'file': + writer = FileStub('pytestworker.log') + else: + writer = ZmqStreamWriter(int(args[1])) + pytest.main(args[2:], plugins=[SpyderPlugin(writer)]) + writer.close() if __name__ == '__main__': - main(sys.argv[1:]) + main(sys.argv) diff --git a/spyder_unittest/backend/tests/test_pytestrunner.py b/spyder_unittest/backend/tests/test_pytestrunner.py index 2e21637e..2a1f1fe8 100644 --- a/spyder_unittest/backend/tests/test_pytestrunner.py +++ b/spyder_unittest/backend/tests/test_pytestrunner.py @@ -45,11 +45,12 @@ def test_pytestrunner_start(monkeypatch): monkeypatch.setattr('spyder_unittest.backend.runnerbase.os.remove', mock_remove) - MockJSONStreamReader = Mock() + MockZMQStreamReader = Mock() monkeypatch.setattr( - 'spyder_unittest.backend.pytestrunner.JSONStreamReader', - MockJSONStreamReader) - mock_reader = MockJSONStreamReader() + 'spyder_unittest.backend.pytestrunner.ZmqStreamReader', + MockZMQStreamReader) + mock_reader = MockZMQStreamReader() + mock_reader.port = 42 runner = PyTestRunner(None, 'results') config = Config('py.test', 'wdir') @@ -63,7 +64,7 @@ def test_pytestrunner_start(monkeypatch): workerfile = os.path.abspath( os.path.join(os.path.dirname(__file__), os.pardir, 'pytestworker.py')) mock_process.start.assert_called_once_with( - get_python_executable(), [workerfile]) + get_python_executable(), [workerfile, '42']) mock_environment.insert.assert_any_call('VAR', 'VALUE') # mock_environment.insert.assert_any_call('PYTHONPATH', 'pythondir:old') @@ -72,19 +73,6 @@ def test_pytestrunner_start(monkeypatch): assert runner.reader is mock_reader -def test_pytestrunner_read_output(monkeypatch): - runner = PyTestRunner(None) - runner.process = Mock() - qbytearray = QByteArray(b'encoded') - runner.process.readAllStandardOutput = Mock(return_value=qbytearray) - runner.reader = Mock() - runner.reader.consume = Mock(return_value='decoded') - runner.process_output = Mock() - - runner.read_output() - assert runner.reader.consume.called_once_with('encoded') - assert runner.process_output.called_once_with('decoded') - def test_pytestrunner_process_output_with_collected(qtbot): runner = PyTestRunner(None) output = [{'event': 'collected', 'nodeid': 'spam.py::ham'}, @@ -156,7 +144,7 @@ def test_logreport_to_testresult_skipped(): report = standard_logreport_output() report['when'] = 'setup' report['outcome'] = 'skipped' - report['longrepr'] = ['file', 24, 'skipmsg'] + report['longrepr'] = ('file', 24, 'skipmsg') expected = TestResult(Category.SKIP, 'skipped', 'foo.bar', time=42, extra_text='skipmsg', filename=osp.join('ham', 'foo.py'), lineno=24) diff --git a/spyder_unittest/backend/tests/test_pytestworker.py b/spyder_unittest/backend/tests/test_pytestworker.py index 8b010269..4a1bb002 100644 --- a/spyder_unittest/backend/tests/test_pytestworker.py +++ b/spyder_unittest/backend/tests/test_pytestworker.py @@ -12,8 +12,8 @@ import pytest # Local imports -from spyder_unittest.backend.jsonstream import JSONStreamWriter from spyder_unittest.backend.pytestworker import SpyderPlugin, main +from spyder_unittest.backend.zmqstream import ZmqStreamWriter try: from unittest.mock import call, create_autospec, Mock @@ -27,7 +27,7 @@ class EmptyClass: @pytest.fixture def plugin(): - mock_writer = create_autospec(JSONStreamWriter) + mock_writer = create_autospec(ZmqStreamWriter) return SpyderPlugin(mock_writer) def test_spyderplugin_test_collectreport_with_success(plugin): @@ -167,22 +167,6 @@ def test_spyderplugin_runtest_logreport_ignores_teardown_passed(plugin): plugin.pytest_runtest_logreport(report) plugin.writer.write.assert_not_called() -def test_main_captures_stdout_and_stderr(monkeypatch): - def mock_main(args, plugins): - print('output') - monkeypatch.setattr( - 'spyder_unittest.backend.pytestworker.pytest.main', mock_main) - - mock_writer = create_autospec(JSONStreamWriter) - MockJSONStreamWriter = Mock(return_value=mock_writer) - monkeypatch.setattr( - 'spyder_unittest.backend.pytestworker.JSONStreamWriter', - MockJSONStreamWriter) - - main(None) - mock_writer.write.assert_called_once_with({ - 'event': 'finished', 'stdout': 'output\n'}) - def test_pytestworker_integration(monkeypatch, tmpdir): os.chdir(tmpdir.strpath) testfilename = tmpdir.join('test_foo.py').strpath @@ -190,12 +174,12 @@ def test_pytestworker_integration(monkeypatch, tmpdir): f.write("def test_ok(): assert 1+1 == 2\n" "def test_fail(): assert 1+1 == 3\n") - mock_writer = create_autospec(JSONStreamWriter) - MockJSONStreamWriter = Mock(return_value=mock_writer) + mock_writer = create_autospec(ZmqStreamWriter) + MockZmqStreamWriter = Mock(return_value=mock_writer) monkeypatch.setattr( - 'spyder_unittest.backend.pytestworker.JSONStreamWriter', - MockJSONStreamWriter) - main([testfilename]) + 'spyder_unittest.backend.pytestworker.ZmqStreamWriter', + MockZmqStreamWriter) + main(['mockscriptname', '42', testfilename]) args = mock_writer.write.call_args_list @@ -228,6 +212,3 @@ def test_pytestworker_integration(monkeypatch, tmpdir): assert args[5][0][0]['filename'] == 'test_foo.py' assert args[5][0][0]['lineno'] == 1 assert 'duration' in args[5][0][0] - - assert args[6][0][0]['event'] == 'finished' - assert 'pytest' in args[6][0][0]['stdout'] From 5645e299d812d5302bd759c6daaf00e875dbd536 Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Tue, 27 Feb 2018 14:18:13 +0000 Subject: [PATCH 3/6] Remove JSON stream implementation since no longer used --- spyder_unittest/backend/jsonstream.py | 109 ------------------ .../backend/tests/test_jsonstream.py | 71 ------------ 2 files changed, 180 deletions(-) delete mode 100644 spyder_unittest/backend/jsonstream.py delete mode 100644 spyder_unittest/backend/tests/test_jsonstream.py diff --git a/spyder_unittest/backend/jsonstream.py b/spyder_unittest/backend/jsonstream.py deleted file mode 100644 index 019fa0ed..00000000 --- a/spyder_unittest/backend/jsonstream.py +++ /dev/null @@ -1,109 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright © 2013 Spyder Project Contributors -# Licensed under the terms of the MIT License -# (see LICENSE.txt for details) -r""" -Reader and writer for sending stream of python objects using JSON. - -These classes can be used to send Python objects (specifically, ints, floats, -strings, bools, lists, dictionaries or None) over a text stream. Partially -received objects are correctly handled. - -Since multiple JSON-encoded objects cannot simply concatenated (i.e., JSON is -not a framed protocol), every object is sent over the text channel in the -format "N \n s \n", where the string s is its JSON encoding and N is the length -of s. -""" - -# Standard library imports -import json - -# Third party imports -from spyder.py3compat import PY2, to_text_string - - -class JSONStreamWriter: - """ - Writer for sending stream of python objects using JSON. - - This class can be used to send a stream of python objects over a text - stream using JSON. It is the responsibility of the caller to open and - close the stream. - - Attributes - ---------- - stream : TextIOBase - text stream that the objects are sent over. - """ - - def __init__(self, stream): - """Constructor.""" - self.stream = stream - - def write(self, obj): - """ - Write Python object to the stream and flush. - - Arguments - --------- - obj : object - Object to be written. The type should be supported by JSON (i.e., - int, float, str, bool, list, dict or None). - """ - txt = json.dumps(obj) - if PY2: - txt = to_text_string(txt) - self.stream.write(to_text_string(len(txt)) + '\n') - self.stream.write(txt + '\n') - self.stream.flush() - - -class JSONStreamReader: - """ - Reader for sending stream of Python objects using JSON. - - This class is used to receive a stream sent by JSONStreamWriter. - - Attributes - ---------- - buffer : str - Text encoding an object that has not been completely received yet. - """ - - def __init__(self): - """Constructor.""" - self.buffer = '' - - def consume(self, txt): - """ - Decode given text and return list of objects encoded in it. - - If only a part of the encoded text of an object is passed, then it is - stored and combined with the remainder in the next call. - """ - index = 0 - res = [] - txt = self.buffer + txt - while index < len(txt): - has_r = False # whether line ends with \r\n or \n - end_of_line1 = txt.find('\n', index) - try: - len_encoding = int(txt[index:end_of_line1]) - except ValueError: - raise ValueError('txt = %s index = %d end_of_line1 = %d' - % (repr(txt), index, end_of_line1)) - if end_of_line1 + len_encoding + 2 > len(txt): # 2 for two \n - break - if txt[end_of_line1 + len_encoding + 1] == '\r': - if end_of_line1 + len_encoding + 3 > len(txt): - break - else: - has_r = True - encoding = txt[end_of_line1 + 1:end_of_line1 + len_encoding + 1] - res.append(json.loads(encoding)) - index = end_of_line1 + len_encoding + 2 - if has_r: - index += 1 - self.buffer = txt[index:] - return res diff --git a/spyder_unittest/backend/tests/test_jsonstream.py b/spyder_unittest/backend/tests/test_jsonstream.py deleted file mode 100644 index b5c88a27..00000000 --- a/spyder_unittest/backend/tests/test_jsonstream.py +++ /dev/null @@ -1,71 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright © 2017 Spyder Project Contributors -# Licensed under the terms of the MIT License -# (see LICENSE.txt for details) -"""Tests for jsonstream.py""" - -# Standard library imports -from io import StringIO, TextIOBase - -# Local imports -from spyder_unittest.backend.jsonstream import (JSONStreamReader, - JSONStreamWriter) - -try: - from unittest.mock import create_autospec -except ImportError: - from mock import create_autospec # Python 2 - - -def test_jsonstreamwriter_with_list(): - stream = StringIO() - writer = JSONStreamWriter(stream) - writer.write([1, 2]) - assert stream.getvalue() == '6\n[1, 2]\n' - - -def test_jsonstreamwriter_with_unicode(): - stream = StringIO() - writer = JSONStreamWriter(stream) - writer.write(u'三') # u prefix for Python2 compatibility - assert stream.getvalue() == '8\n"\\u4e09"\n' - - -def test_jsonstreamwriter_flushes(): - stream = create_autospec(TextIOBase) - writer = JSONStreamWriter(stream) - writer.write(1) - stream.flush.assert_called_once_with() - - -def test_jsonstreamreader_with_list(): - reader = JSONStreamReader() - assert reader.consume('6\n[1, 2]\n') == [[1, 2]] - - -def test_jsonstreamreader_with_windows_lineending(): - reader = JSONStreamReader() - assert reader.consume('6\r\n[1, 2]\r\n') == [[1, 2]] - - -def test_jsonstreamreader_with_unicode(): - reader = JSONStreamReader() - assert reader.consume('8\n"\\u4e09"\n') == [u'三'] - - -def test_jsonstreamreader_with_partial_frames(): - reader = JSONStreamReader() - txt = '1\n2\n' * 3 - assert reader.consume(txt[:2]) == [] - assert reader.consume(txt[2:-2]) == [2, 2] - assert reader.consume(txt[-2:]) == [2] - - -def test_jsonsteamreader_writer_integration(): - stream = StringIO() - writer = JSONStreamWriter(stream) - reader = JSONStreamReader() - writer.write([1, 2]) - writer.write({'a': 'b'}) - assert reader.consume(stream.getvalue()) == [[1, 2], {'a': 'b'}] From 43226db0f56b5485ea951e6a26cd10363e0df5f2 Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Tue, 27 Feb 2018 15:05:45 +0000 Subject: [PATCH 4/6] Python 2 compatibility fix --- spyder_unittest/backend/zmqstream.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spyder_unittest/backend/zmqstream.py b/spyder_unittest/backend/zmqstream.py index 35723ecd..a764440f 100644 --- a/spyder_unittest/backend/zmqstream.py +++ b/spyder_unittest/backend/zmqstream.py @@ -11,6 +11,8 @@ process can then use the stream to send its result to the reader. """ +from __future__ import print_function + # Standard library imports import sys From 44f860ebf2f352429e1a30edd620c67cb335efe0 Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Tue, 27 Feb 2018 15:08:04 +0000 Subject: [PATCH 5/6] Declare zmq as a new dependency --- .travis.yml | 2 +- appveyor.yml | 4 ++-- circle.yml | 4 ++-- conda.recipe/meta.yaml | 1 + setup.py | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9cbe5d0b..03fc6c26 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,7 @@ env: - TEST_CI="True" - TEST_CI_APP="True" # Environment variables used by astropy helpers - - CONDA_DEPENDENCIES="lxml mock nose pytest spyder" + - CONDA_DEPENDENCIES="lxml mock nose pytest spyder zmq" - PIP_DEPENDENCIES="coveralls pytest-qt" matrix: diff --git a/appveyor.yml b/appveyor.yml index 540b4755..166b7119 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -5,7 +5,7 @@ matrix: branches: only: - - master + - master environment: global: @@ -18,7 +18,7 @@ environment: PYTHON_ARCH: "64" # needs to be set for CMD_IN_ENV to succeed. If a mix # of 32 bit and 64 bit builds are needed, move this # to the matrix section. - CONDA_DEPENDENCIES: "lxml mock nose pytest spyder" + CONDA_DEPENDENCIES: "lxml mock nose pytest spyder zmq" PIP_DEPENDENCIES_2: "coveralls pytest-qt" # Fix when fixed upstream matrix: diff --git a/circle.yml b/circle.yml index 78ac472b..fd5409a3 100644 --- a/circle.yml +++ b/circle.yml @@ -13,14 +13,14 @@ machine: COVERALLS_REPO_TOKEN: c5Qt1n27dLFCAIESYVkuCmVpUU8doney1 # Environment variables used by astropy helpers TRAVIS_OS_NAME: "linux" - CONDA_DEPENDENCIES: "lxml mock nose pytest" + CONDA_DEPENDENCIES: "lxml mock nose pytest zmq" PIP_DEPENDENCIES: "coveralls pytest-qt" dependencies: override: # First convert PY_VERSIONS to an array and then select the python version based on the CIRCLE_NODE_INDEX - export PY_VERSIONS=($PY_VERSIONS) && - export TRAVIS_PYTHON_VERSION=${PY_VERSIONS[$CIRCLE_NODE_INDEX]} && + export TRAVIS_PYTHON_VERSION=${PY_VERSIONS[$CIRCLE_NODE_INDEX]} && echo -e "PYTHON = $TRAVIS_PYTHON_VERSION \n============" && git clone git://github.com/astropy/ci-helpers.git && source ci-helpers/travis/setup_conda_$TRAVIS_OS_NAME.sh && diff --git a/conda.recipe/meta.yaml b/conda.recipe/meta.yaml index 1df06dd4..50d9cce7 100644 --- a/conda.recipe/meta.yaml +++ b/conda.recipe/meta.yaml @@ -25,6 +25,7 @@ requirements: - lxml - python - spyder >=3 + - zmq test: imports: diff --git a/setup.py b/setup.py index 1c3bf7d8..05269437 100644 --- a/setup.py +++ b/setup.py @@ -37,7 +37,7 @@ def get_package_data(name, extlist): # Requirements -REQUIREMENTS = ['lxml', 'spyder>=3'] +REQUIREMENTS = ['lxml', 'spyder>=3', 'zmq'] EXTLIST = ['.jpg', '.png', '.json', '.mo', '.ini'] LIBNAME = 'spyder_unittest' From 0e0e7f3cfb77a31ea7f7921b97394557c460ca9f Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Tue, 27 Feb 2018 16:50:12 +0000 Subject: [PATCH 6/6] Package is called pyzmq, not zmq --- .travis.yml | 2 +- appveyor.yml | 2 +- circle.yml | 2 +- conda.recipe/meta.yaml | 2 +- setup.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 03fc6c26..2415b972 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,7 @@ env: - TEST_CI="True" - TEST_CI_APP="True" # Environment variables used by astropy helpers - - CONDA_DEPENDENCIES="lxml mock nose pytest spyder zmq" + - CONDA_DEPENDENCIES="lxml mock nose pytest spyder pyzmq" - PIP_DEPENDENCIES="coveralls pytest-qt" matrix: diff --git a/appveyor.yml b/appveyor.yml index 166b7119..0b13db94 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -18,7 +18,7 @@ environment: PYTHON_ARCH: "64" # needs to be set for CMD_IN_ENV to succeed. If a mix # of 32 bit and 64 bit builds are needed, move this # to the matrix section. - CONDA_DEPENDENCIES: "lxml mock nose pytest spyder zmq" + CONDA_DEPENDENCIES: "lxml mock nose pytest spyder pyzmq" PIP_DEPENDENCIES_2: "coveralls pytest-qt" # Fix when fixed upstream matrix: diff --git a/circle.yml b/circle.yml index fd5409a3..fa252749 100644 --- a/circle.yml +++ b/circle.yml @@ -13,7 +13,7 @@ machine: COVERALLS_REPO_TOKEN: c5Qt1n27dLFCAIESYVkuCmVpUU8doney1 # Environment variables used by astropy helpers TRAVIS_OS_NAME: "linux" - CONDA_DEPENDENCIES: "lxml mock nose pytest zmq" + CONDA_DEPENDENCIES: "lxml mock nose pytest pyzmq" PIP_DEPENDENCIES: "coveralls pytest-qt" dependencies: diff --git a/conda.recipe/meta.yaml b/conda.recipe/meta.yaml index 50d9cce7..4250a6f3 100644 --- a/conda.recipe/meta.yaml +++ b/conda.recipe/meta.yaml @@ -25,7 +25,7 @@ requirements: - lxml - python - spyder >=3 - - zmq + - pyzmq test: imports: diff --git a/setup.py b/setup.py index 05269437..9692b799 100644 --- a/setup.py +++ b/setup.py @@ -37,7 +37,7 @@ def get_package_data(name, extlist): # Requirements -REQUIREMENTS = ['lxml', 'spyder>=3', 'zmq'] +REQUIREMENTS = ['lxml', 'spyder>=3', 'pyzmq'] EXTLIST = ['.jpg', '.png', '.json', '.mo', '.ini'] LIBNAME = 'spyder_unittest'