pytest-remotedata-0.3.2/0000755000077000000240000000000013514621172015107 5ustar tomstaff00000000000000pytest-remotedata-0.3.2/.gitignore0000644000077000000240000000107613514617321017104 0ustar tomstaff00000000000000# Compiled files *.py[cod] *.a *.o *.so *.pyd __pycache__ # Ignore .c files by default to avoid including generated code. If you want to # add a non-generated .c extension, use `git add -f filename.c`. *.c # Other generated files MANIFEST # Sphinx _build _generated docs/api docs/generated # Packages/installer info *.egg *.egg-info dist build eggs .eggs parts bin var sdist develop-eggs .installed.cfg distribute-*.tar.gz # Other .cache .tox .*.swp .*.swo *~ .project .pydevproject .settings .coverage cover htmlcov .pytest_cache # Mac OSX .DS_Store # PyCharm .idea pytest-remotedata-0.3.2/.travis.yml0000644000077000000240000000274113514617521017227 0ustar tomstaff00000000000000# We set the language to c because python isn't supported on the MacOS X nodes # on Travis. However, the language ends up being irrelevant anyway, since we # install Python ourselves using conda. language: c os: - linux # Use Travis' container-based architecture sudo: false env: global: # The following versions are the 'default' for tests, unless # overidden underneath. They are defined here in order to save having # to repeat them for all configurations. - PYTHON_VERSION=3.6 - PYTEST_VERSION=4.6 - PYTEST_COMMAND='pytest' - NUMPY_VERSION=stable - CONDA_DEPENDENCIES='six' matrix: - PYTHON_VERSION=2.7 PYTEST_VERSION=3.1 PYTEST_COMMAND='py.test' - PYTHON_VERSION=2.7 - PYTHON_VERSION=3.5 - PYTHON_VERSION=3.6 PYTEST_VERSION=3.4 - PYTHON_VERSION=3.6 PYTEST_VERSION=4.5 - PYTHON_VERSION=3.6 - PYTHON_VERSION=3.7 PYTEST_VERSION=5.0 matrix: include: # Try a run on OSX with latest versions of python and pytest - os: osx env: PYTHON_VERSION=3.7 PYTEST_VERSION=3.7 install: - git clone git://github.com/astropy/ci-helpers.git - source ci-helpers/travis/setup_conda.sh - python ./setup.py install script: - $PYTEST_COMMAND - $PYTEST_COMMAND --remote-data - $PYTEST_COMMAND --remote-data=none - $PYTEST_COMMAND --remote-data=github - $PYTEST_COMMAND --remote-data=astropy - $PYTEST_COMMAND --remote-data=any pytest-remotedata-0.3.2/CHANGES.rst0000644000077000000240000000167013514617657016732 0ustar tomstaff000000000000000.3.2 (2019-07-20) ================== - Fixed compatibility with pytest 4.2 and later. [#38, #40] 0.3.1 (2018-10-23) ================== - Fix warnings that occur with pytest 3.7 and later. [#34] 0.3.0 (2018-05-29) ================== - Allow ``remote_data`` argument to be passed without ``source`` keyword. [#27] - Add ``source='github'`` option. Also fix IP lookup error for ``source='astropy'`` option. [#28] 0.2.1 (2018-04-20) ================== - Fix packaging error: tests are no longer included in package distribution. [#24] 0.2.0 (2017-11-10) ================== - Do not accept invalid values passed to ``--remote-data`` argument. [#15] - Update list of valid hosts URLs recognized as astropy data sources. [#13] - Remove test dependency on astropy core. [#14] - Allow strict remote data checking to be configurable. This introduces a dependency on ``pytest>=3.1``. [#18] 0.1 (2017-10-10) ================ - Alpha release. pytest-remotedata-0.3.2/LICENSE.rst0000644000077000000240000000273013514611660016726 0ustar tomstaff00000000000000Copyright (c) 2011-2017, Astropy Developers All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Astropy Team nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. pytest-remotedata-0.3.2/MANIFEST.in0000644000077000000240000000020313514617341016643 0ustar tomstaff00000000000000include LICENSE.rst include README.rst include CHANGES.rst include setup.cfg recursive-include tests * global-exclude *.pyc *.o pytest-remotedata-0.3.2/PKG-INFO0000644000077000000240000001411613514621172016207 0ustar tomstaff00000000000000Metadata-Version: 1.2 Name: pytest-remotedata Version: 0.3.2 Summary: Pytest plugin for controlling remote data access. Home-page: https://astropy.org Author: The Astropy Developers Author-email: astropy.team@gmail.com License: BSD Description: ================= pytest-remotedata ================= This package provides a plugin for the `pytest`_ framework that allows developers to control unit tests that require access to data from the internet. It was originally part of the `astropy`_ core package, but has been moved to a separate package in order to be of more general use. .. _pytest: https://pytest.org/en/latest/ .. _astropy: https://astropy.org/en/latest/ Motivation ---------- Many software packages provide features that require access to data from the internet. These features need to be tested, but unit tests that access the internet can dominate the overall runtime of a test suite. The ``pytest-remotedata`` plugin allows developers to indicate which unit tests require access to the internet, and to control when and whether such tests should execute as part of any given run of the test suite. Installation ------------ The ``pytest-remotedata`` plugin can be installed using ``pip``:: $ pip install pytest-remotedata It is also possible to install the latest development version from the source repository:: $ git clone https://github.com/astropy/pytest-remotedata $ cd pytest-remotedata $ python ./setup.py install In either case, the plugin will automatically be registered for use with ``pytest``. Usage ----- Installing this plugin makes two decorators available for use with ``pytest``: * ``remote_data`` for marking tests that require data from the internet * ``internet_off`` for marking tests that should run only when internet access is disabled These decorators can be used to mark test functions, methods, and classes using ``@pytest.mark``. For example, consider the following test function that requires access to data from the internet: .. code-block:: python import pytest from urllib.request import urlopen @pytest.mark.remote_data def test_remote_data(): urlopen('https://astropy.org') Marking the ``test_remote_data`` function with ``@pytest.mark.remote_data`` indicates to ``pytest`` that this test should be run only when access to remote data sources is explicitly requested. When this plugin is installed, the ``--remote-data`` command line option is added to the ``pytest`` command line interface. The default behavior is to skip tests that are marked with ``remote_data``. If the ``--remote-data`` option is not provided to the ``pytest`` command, or if ``--remote-data=none`` is provided, all tests that are marked with ``remote_data`` will be skipped. All tests that are marked with ``internet_off`` will be executed. Sometimes it is useful to check that certain tests do not unexpectedly access the internet. Strict remote data access checking can be enabled by setting ``remote_data_strict = true`` in the tested package's ``setup.cfg`` file. If this option is enabled, any test that attempts to access the network but is not marked with ``@pytest.mark.remote_data`` will fail. Providing either the ``--remote-data`` option, or ``--remote-data=any`` to the ``pytest`` command line interface will cause all tests that are marked with ``remote-data`` to execute. Any tests that are marked with ``internet_off`` will be skipped. Running the tests with ``--remote-data=astropy`` will cause only tests that receive remote data from Astropy data sources to be run. Tests with any other data sources will be skipped. This is indicated in the test code by marking test functions with ``@pytest.mark.remote_data(source='astropy')``. In the future, we intend to support a configurable way to indicate specific remote data sources in addition to ``astropy``. Development Status ------------------ .. image:: https://travis-ci.org/astropy/pytest-remotedata.svg :target: https://travis-ci.org/astropy/pytest-remotedata :alt: Travis CI Status .. image:: https://ci.appveyor.com/api/projects/status/ym7lxajcs5qwm31e/branch/master?svg=true :target: https://ci.appveyor.com/project/Astropy/pytest-remotedata/branch/master :alt: Appveyor Status Questions, bug reports, and feature requests can be submitted on `github`_. .. _github: https://github.com/astropy/pytest-remotedata License ------- This plugin is licensed under a 3-clause BSD style license - see the ``LICENSE.rst`` file. Keywords: remote,data,pytest,py.test Platform: UNKNOWN Classifier: Development Status :: 3 - Alpha Classifier: Framework :: Pytest Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: BSD License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Topic :: Software Development :: Testing Classifier: Topic :: Utilities Requires-Python: >=2.7 pytest-remotedata-0.3.2/README.rst0000644000077000000240000001024713514611660016603 0ustar tomstaff00000000000000================= pytest-remotedata ================= This package provides a plugin for the `pytest`_ framework that allows developers to control unit tests that require access to data from the internet. It was originally part of the `astropy`_ core package, but has been moved to a separate package in order to be of more general use. .. _pytest: https://pytest.org/en/latest/ .. _astropy: https://astropy.org/en/latest/ Motivation ---------- Many software packages provide features that require access to data from the internet. These features need to be tested, but unit tests that access the internet can dominate the overall runtime of a test suite. The ``pytest-remotedata`` plugin allows developers to indicate which unit tests require access to the internet, and to control when and whether such tests should execute as part of any given run of the test suite. Installation ------------ The ``pytest-remotedata`` plugin can be installed using ``pip``:: $ pip install pytest-remotedata It is also possible to install the latest development version from the source repository:: $ git clone https://github.com/astropy/pytest-remotedata $ cd pytest-remotedata $ python ./setup.py install In either case, the plugin will automatically be registered for use with ``pytest``. Usage ----- Installing this plugin makes two decorators available for use with ``pytest``: * ``remote_data`` for marking tests that require data from the internet * ``internet_off`` for marking tests that should run only when internet access is disabled These decorators can be used to mark test functions, methods, and classes using ``@pytest.mark``. For example, consider the following test function that requires access to data from the internet: .. code-block:: python import pytest from urllib.request import urlopen @pytest.mark.remote_data def test_remote_data(): urlopen('https://astropy.org') Marking the ``test_remote_data`` function with ``@pytest.mark.remote_data`` indicates to ``pytest`` that this test should be run only when access to remote data sources is explicitly requested. When this plugin is installed, the ``--remote-data`` command line option is added to the ``pytest`` command line interface. The default behavior is to skip tests that are marked with ``remote_data``. If the ``--remote-data`` option is not provided to the ``pytest`` command, or if ``--remote-data=none`` is provided, all tests that are marked with ``remote_data`` will be skipped. All tests that are marked with ``internet_off`` will be executed. Sometimes it is useful to check that certain tests do not unexpectedly access the internet. Strict remote data access checking can be enabled by setting ``remote_data_strict = true`` in the tested package's ``setup.cfg`` file. If this option is enabled, any test that attempts to access the network but is not marked with ``@pytest.mark.remote_data`` will fail. Providing either the ``--remote-data`` option, or ``--remote-data=any`` to the ``pytest`` command line interface will cause all tests that are marked with ``remote-data`` to execute. Any tests that are marked with ``internet_off`` will be skipped. Running the tests with ``--remote-data=astropy`` will cause only tests that receive remote data from Astropy data sources to be run. Tests with any other data sources will be skipped. This is indicated in the test code by marking test functions with ``@pytest.mark.remote_data(source='astropy')``. In the future, we intend to support a configurable way to indicate specific remote data sources in addition to ``astropy``. Development Status ------------------ .. image:: https://travis-ci.org/astropy/pytest-remotedata.svg :target: https://travis-ci.org/astropy/pytest-remotedata :alt: Travis CI Status .. image:: https://ci.appveyor.com/api/projects/status/ym7lxajcs5qwm31e/branch/master?svg=true :target: https://ci.appveyor.com/project/Astropy/pytest-remotedata/branch/master :alt: Appveyor Status Questions, bug reports, and feature requests can be submitted on `github`_. .. _github: https://github.com/astropy/pytest-remotedata License ------- This plugin is licensed under a 3-clause BSD style license - see the ``LICENSE.rst`` file. pytest-remotedata-0.3.2/appveyor.yml0000644000077000000240000000300613514617521017501 0ustar tomstaff00000000000000# AppVeyor.com is a Continuous Integration service to build and run tests under # Windows environment: global: PYTHON: "C:\\conda" MINICONDA_VERSION: "latest" CMD_IN_ENV: "cmd /E:ON /V:ON /C .\\ci-helpers\\appveyor\\windows_sdk.cmd" PYTEST_COMMAND: "pytest" NUMPY_VERSION: "stable" CONDA_DEPENDENCIES: "six" PYTHON_ARCH: "64" matrix: - PYTHON_VERSION: "2.7" PYTEST_VESION: "3.1" PYTEST_COMMAND: "py.test" platform: x86 - PYTHON_VERSION: "2.7" platform: x64 - PYTHON_VERSION: "3.5" NUMPY_VERSION: "1.15" platform: x64 - PYTHON_VERSION: "3.6" PYTEST_VERSION: "3.4" platform: x64 - PYTHON_VERSION: "3.6" PYTEST_VERSION: "4.1" platform: x64 - PYTHON_VERSION: "3.6" platform: x64 - PYTHON_VERSION: "3.7" PYTEST_VERSION: "5.0" platform: x64 install: - "git clone git://github.com/astropy/ci-helpers.git" - "powershell ci-helpers/appveyor/install-miniconda.ps1" - "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%" - "activate test" - "%CMD_IN_ENV% python setup.py install" # Not a .NET project build: false test_script: - "%CMD_IN_ENV% %PYTEST_COMMAND%" - "%CMD_IN_ENV% %PYTEST_COMMAND% --remote-data" - "%CMD_IN_ENV% %PYTEST_COMMAND% --remote-data=none" - "%CMD_IN_ENV% %PYTEST_COMMAND% --remote-data=github" - "%CMD_IN_ENV% %PYTEST_COMMAND% --remote-data=astropy" - "%CMD_IN_ENV% %PYTEST_COMMAND% --remote-data=any" pytest-remotedata-0.3.2/pytest_remotedata/0000755000077000000240000000000013514621172020644 5ustar tomstaff00000000000000pytest-remotedata-0.3.2/pytest_remotedata/__init__.py0000644000077000000240000000022613514611660022756 0ustar tomstaff00000000000000# Licensed under a 3-clause BSD style license - see LICENSE.rst """ This package contains pytest plugins that are used by the astropy test suite. """ pytest-remotedata-0.3.2/pytest_remotedata/disable_internet.py0000644000077000000240000001416413514611660024540 0ustar tomstaff00000000000000# Licensed under a 3-clause BSD style license - see LICENSE.rst import contextlib import socket from six.moves import urllib # save original socket method for restoration # These are global so that re-calling the turn_off_internet function doesn't # overwrite them again socket_original = socket.socket socket_create_connection = socket.create_connection socket_bind = socket.socket.bind socket_connect = socket.socket.connect GITHUB_HOSTS = ['www.github.io'] ASTROPY_HOSTS = (['data.astropy.org', 'astropy.stsci.edu', 'www.astropy.org'] + GITHUB_HOSTS) INTERNET_OFF = False # urllib2 uses a global variable to cache its default "opener" for opening # connections for various protocols; we store it off here so we can restore to # the default after re-enabling internet use _orig_opener = None def _resolve_host_ips(hostname, port=80): """ Obtain all the IPs, including aliases, in a way that supports IPv4/v6 dual stack. """ try: ips = set([s[-1][0] for s in socket.getaddrinfo(hostname, port)]) except socket.gaierror: ips = set([]) ips.add(hostname) return ips # ::1 is apparently another valid name for localhost? # it is returned by getaddrinfo when that function is given localhost def check_internet_off(original_function, allow_astropy_data=False, allow_github_data=False): """ Wraps ``original_function``, which in most cases is assumed to be a `socket.socket` method, to raise an `IOError` for any operations on non-local AF_INET sockets. Allowing Astropy data also automatically allow GitHub data. """ def new_function(*args, **kwargs): if isinstance(args[0], socket.socket): if not args[0].family in (socket.AF_INET, socket.AF_INET6): # Should be fine in all but some very obscure cases # More to the point, we don't want to affect AF_UNIX # sockets. return original_function(*args, **kwargs) host = args[1][0] addr_arg = 1 valid_hosts = set(['localhost', '127.0.0.1', '::1']) else: # The only other function this is used to wrap currently is # socket.create_connection, which should be passed a 2-tuple, but # we'll check just in case if not (isinstance(args[0], tuple) and len(args[0]) == 2): return original_function(*args, **kwargs) host = args[0][0] addr_arg = 0 valid_hosts = set(['localhost', '127.0.0.1']) # Astropy + GitHub data if allow_astropy_data: for valid_host in ASTROPY_HOSTS: valid_hosts = valid_hosts.union(_resolve_host_ips(valid_host)) # Only GitHub data elif allow_github_data: for valid_host in GITHUB_HOSTS: valid_hosts = valid_hosts.union(_resolve_host_ips(valid_host)) hostname = socket.gethostname() fqdn = socket.getfqdn() if host in (hostname, fqdn): host = 'localhost' host_ips = set([host]) new_addr = (host, args[addr_arg][1]) args = args[:addr_arg] + (new_addr,) + args[addr_arg + 1:] else: host_ips = _resolve_host_ips(host) if len(host_ips & valid_hosts) > 0: # Any overlap is acceptable return original_function(*args, **kwargs) else: raise IOError("An attempt was made to connect to the internet " "by a test that was not marked `remote_data`. The " "requested host was: {0}".format(host)) return new_function def turn_off_internet(verbose=False, allow_astropy_data=False, allow_github_data=False): """ Disable internet access via python by preventing connections from being created using the socket module. Presumably this could be worked around by using some other means of accessing the internet, but all default python modules (urllib, requests, etc.) use socket [citation needed]. """ global INTERNET_OFF global _orig_opener if INTERNET_OFF: return INTERNET_OFF = True __tracebackhide__ = True if verbose: print("Internet access disabled") # Update urllib2 to force it not to use any proxies # Must use {} here (the default of None will kick off an automatic search # for proxies) _orig_opener = urllib.request.build_opener() no_proxy_handler = urllib.request.ProxyHandler({}) opener = urllib.request.build_opener(no_proxy_handler) urllib.request.install_opener(opener) socket.create_connection = check_internet_off( socket_create_connection, allow_astropy_data=allow_astropy_data, allow_github_data=allow_github_data) socket.socket.bind = check_internet_off( socket_bind, allow_astropy_data=allow_astropy_data, allow_github_data=allow_github_data) socket.socket.connect = check_internet_off( socket_connect, allow_astropy_data=allow_astropy_data, allow_github_data=allow_github_data) return socket def turn_on_internet(verbose=False): """ Restore internet access. Not used, but kept in case it is needed. """ global INTERNET_OFF global _orig_opener if not INTERNET_OFF: return INTERNET_OFF = False if verbose: print("Internet access enabled") urllib.request.install_opener(_orig_opener) socket.create_connection = socket_create_connection socket.socket.bind = socket_bind socket.socket.connect = socket_connect return socket @contextlib.contextmanager def no_internet(verbose=False): """Context manager to temporarily disable internet access (if not already disabled). If it was already disabled before entering the context manager (i.e. `turn_off_internet` was called previously) then this is a no-op and leaves internet access disabled until a manual call to `turn_on_internet`. """ already_disabled = INTERNET_OFF turn_off_internet(verbose=verbose) try: yield finally: if not already_disabled: turn_on_internet(verbose=verbose) pytest-remotedata-0.3.2/pytest_remotedata/plugin.py0000644000077000000240000000732413514617521022525 0ustar tomstaff00000000000000# Licensed under a 3-clause BSD style license - see LICENSE.rst """ This plugin provides command-line options for controlling whether and how tests make use of online data. """ import pytest from .disable_internet import turn_off_internet, turn_on_internet from distutils.version import LooseVersion def pytest_addoption(parser): # The following means that if --remote-data is not specified, the default # is 'none', but if it is specified without arguments (--remote-data), it # defaults to '--remote-data=any'. parser.addoption( "--remote-data", nargs="?", const='any', default='none', help="run tests with online data") parser.addini( 'remote_data_strict', "If 'True', tests will fail if they attempt to access the internet " "but are not explicitly marked with 'remote_data'", type="bool", default=False) def pytest_configure(config): config.getini('markers').append( 'remote_data: Apply to tests that require data from remote servers') config.getini('markers').append( 'internet_off: Apply to tests that should only run when ' 'network access is deactivated') strict_check = bool(config.getini('remote_data_strict')) remote_data = config.getoption('remote_data') if remote_data not in ['astropy', 'any', 'github', 'none']: raise pytest.UsageError( "'{}' is not a valid source for remote data".format(remote_data)) # Monkeypatch to deny access to remote resources unless explicitly told # otherwise if strict_check: if remote_data == 'github': # GitHub only turn_off_internet( verbose=config.option.verbose, allow_github_data=True) elif remote_data != 'any': # Astropy + GitHub or nothing turn_off_internet( verbose=config.option.verbose, allow_astropy_data=(remote_data == 'astropy')) def pytest_unconfigure(): """ Cleanup post-testing """ # restore internet connectivity (only lost if remote_data=False and # turn_off_internet previously called) # this is harmless / does nothing if socket connections were never disabled turn_on_internet() def pytest_runtest_setup(item): if LooseVersion(pytest.__version__) < LooseVersion("3.6"): remote_data = item.get_marker('remote_data') internet_off = item.get_marker('internet_off') else: remote_data = item.get_closest_marker('remote_data') internet_off = item.get_closest_marker('internet_off') remote_data_config = item.config.getvalue("remote_data") if remote_data is not None and internet_off is not None: raise ValueError("remote_data and internet_off are not compatible") if remote_data is not None: if len(remote_data.args) > 0: source = remote_data.args[0] else: source = remote_data.kwargs.get('source', 'any') if source not in ('astropy', 'any', 'github'): raise ValueError("source should be 'astropy', 'any', or 'github'") if remote_data_config == 'none': pytest.skip("need --remote-data option to run") elif remote_data_config == 'github': if source in ('any', 'astropy'): pytest.skip("need --remote-data or " "--remote-data=astropy option to run") elif remote_data_config == 'astropy': # When --remote-data=astropy is given, skip tests simply # marked as --remote-data if source == 'any': pytest.skip("need --remote-data option to run") if internet_off is not None: if remote_data_config != 'none': pytest.skip("run this test only when network access is disabled") pytest-remotedata-0.3.2/pytest_remotedata.egg-info/0000755000077000000240000000000013514621172022336 5ustar tomstaff00000000000000pytest-remotedata-0.3.2/pytest_remotedata.egg-info/PKG-INFO0000644000077000000240000001411613514621171023435 0ustar tomstaff00000000000000Metadata-Version: 1.2 Name: pytest-remotedata Version: 0.3.2 Summary: Pytest plugin for controlling remote data access. Home-page: https://astropy.org Author: The Astropy Developers Author-email: astropy.team@gmail.com License: BSD Description: ================= pytest-remotedata ================= This package provides a plugin for the `pytest`_ framework that allows developers to control unit tests that require access to data from the internet. It was originally part of the `astropy`_ core package, but has been moved to a separate package in order to be of more general use. .. _pytest: https://pytest.org/en/latest/ .. _astropy: https://astropy.org/en/latest/ Motivation ---------- Many software packages provide features that require access to data from the internet. These features need to be tested, but unit tests that access the internet can dominate the overall runtime of a test suite. The ``pytest-remotedata`` plugin allows developers to indicate which unit tests require access to the internet, and to control when and whether such tests should execute as part of any given run of the test suite. Installation ------------ The ``pytest-remotedata`` plugin can be installed using ``pip``:: $ pip install pytest-remotedata It is also possible to install the latest development version from the source repository:: $ git clone https://github.com/astropy/pytest-remotedata $ cd pytest-remotedata $ python ./setup.py install In either case, the plugin will automatically be registered for use with ``pytest``. Usage ----- Installing this plugin makes two decorators available for use with ``pytest``: * ``remote_data`` for marking tests that require data from the internet * ``internet_off`` for marking tests that should run only when internet access is disabled These decorators can be used to mark test functions, methods, and classes using ``@pytest.mark``. For example, consider the following test function that requires access to data from the internet: .. code-block:: python import pytest from urllib.request import urlopen @pytest.mark.remote_data def test_remote_data(): urlopen('https://astropy.org') Marking the ``test_remote_data`` function with ``@pytest.mark.remote_data`` indicates to ``pytest`` that this test should be run only when access to remote data sources is explicitly requested. When this plugin is installed, the ``--remote-data`` command line option is added to the ``pytest`` command line interface. The default behavior is to skip tests that are marked with ``remote_data``. If the ``--remote-data`` option is not provided to the ``pytest`` command, or if ``--remote-data=none`` is provided, all tests that are marked with ``remote_data`` will be skipped. All tests that are marked with ``internet_off`` will be executed. Sometimes it is useful to check that certain tests do not unexpectedly access the internet. Strict remote data access checking can be enabled by setting ``remote_data_strict = true`` in the tested package's ``setup.cfg`` file. If this option is enabled, any test that attempts to access the network but is not marked with ``@pytest.mark.remote_data`` will fail. Providing either the ``--remote-data`` option, or ``--remote-data=any`` to the ``pytest`` command line interface will cause all tests that are marked with ``remote-data`` to execute. Any tests that are marked with ``internet_off`` will be skipped. Running the tests with ``--remote-data=astropy`` will cause only tests that receive remote data from Astropy data sources to be run. Tests with any other data sources will be skipped. This is indicated in the test code by marking test functions with ``@pytest.mark.remote_data(source='astropy')``. In the future, we intend to support a configurable way to indicate specific remote data sources in addition to ``astropy``. Development Status ------------------ .. image:: https://travis-ci.org/astropy/pytest-remotedata.svg :target: https://travis-ci.org/astropy/pytest-remotedata :alt: Travis CI Status .. image:: https://ci.appveyor.com/api/projects/status/ym7lxajcs5qwm31e/branch/master?svg=true :target: https://ci.appveyor.com/project/Astropy/pytest-remotedata/branch/master :alt: Appveyor Status Questions, bug reports, and feature requests can be submitted on `github`_. .. _github: https://github.com/astropy/pytest-remotedata License ------- This plugin is licensed under a 3-clause BSD style license - see the ``LICENSE.rst`` file. Keywords: remote,data,pytest,py.test Platform: UNKNOWN Classifier: Development Status :: 3 - Alpha Classifier: Framework :: Pytest Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: BSD License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Topic :: Software Development :: Testing Classifier: Topic :: Utilities Requires-Python: >=2.7 pytest-remotedata-0.3.2/pytest_remotedata.egg-info/SOURCES.txt0000644000077000000240000000113713514621171024223 0ustar tomstaff00000000000000.gitignore .travis.yml CHANGES.rst LICENSE.rst MANIFEST.in README.rst appveyor.yml setup.cfg setup.py pytest_remotedata/__init__.py pytest_remotedata/disable_internet.py pytest_remotedata/plugin.py pytest_remotedata.egg-info/PKG-INFO pytest_remotedata.egg-info/SOURCES.txt pytest_remotedata.egg-info/dependency_links.txt pytest_remotedata.egg-info/entry_points.txt pytest_remotedata.egg-info/not-zip-safe pytest_remotedata.egg-info/requires.txt pytest_remotedata.egg-info/top_level.txt tests/__init__.py tests/conftest.py tests/test_skip_remote_data.py tests/test_socketblocker.py tests/test_strict_check.pypytest-remotedata-0.3.2/pytest_remotedata.egg-info/dependency_links.txt0000644000077000000240000000000113514621171026403 0ustar tomstaff00000000000000 pytest-remotedata-0.3.2/pytest_remotedata.egg-info/entry_points.txt0000644000077000000240000000007113514621171025631 0ustar tomstaff00000000000000[pytest11] pytest_remotedata = pytest_remotedata.plugin pytest-remotedata-0.3.2/pytest_remotedata.egg-info/not-zip-safe0000644000077000000240000000000113514620615024565 0ustar tomstaff00000000000000 pytest-remotedata-0.3.2/pytest_remotedata.egg-info/requires.txt0000644000077000000240000000002013514621171024725 0ustar tomstaff00000000000000six pytest>=3.1 pytest-remotedata-0.3.2/pytest_remotedata.egg-info/top_level.txt0000644000077000000240000000002213514621171025061 0ustar tomstaff00000000000000pytest_remotedata pytest-remotedata-0.3.2/setup.cfg0000644000077000000240000000227713514621172016740 0ustar tomstaff00000000000000[metadata] name = pytest-remotedata version = 0.3.2 url = https://astropy.org author = The Astropy Developers author_email = astropy.team@gmail.com classifiers = Development Status :: 3 - Alpha Framework :: Pytest Intended Audience :: Developers License :: OSI Approved :: BSD License Operating System :: OS Independent Programming Language :: Python Programming Language :: Python :: 2.7 Programming Language :: Python :: 3 Programming Language :: Python :: 3.3 Programming Language :: Python :: 3.4 Programming Language :: Python :: 3.5 Programming Language :: Python :: 3.6 Programming Language :: Python :: Implementation :: CPython Topic :: Software Development :: Testing Topic :: Utilities license = BSD description = Pytest plugin for controlling remote data access. long_description = file: README.rst keywords = remote, data, pytest, py.test [options] zip_safe = False packages = find: python_requires = >=2.7 install_requires = six pytest>=3.1 [options.entry_points] pytest11 = pytest_remotedata = pytest_remotedata.plugin [options.packages.find] exclude = tests [tool:pytest] minversion = 3.1 testpaths = tests remote_data_strict = true [egg_info] tag_build = tag_date = 0 pytest-remotedata-0.3.2/setup.py0000755000077000000240000000067013514617572016640 0ustar tomstaff00000000000000#!/usr/bin/env python import sys import setuptools from distutils.version import LooseVersion from setuptools import setup # Setuptools 30.3.0 or later is needed for setup.cfg options to be used if LooseVersion(setuptools.__version__) < LooseVersion('30.3.0'): sys.stderr.write("ERROR: sphinx-automodapi requires setuptools 30.3.0 or " "later (found {0})".format(setuptools.__version__)) sys.exit(1) setup() pytest-remotedata-0.3.2/tests/0000755000077000000240000000000013514621172016251 5ustar tomstaff00000000000000pytest-remotedata-0.3.2/tests/__init__.py0000644000077000000240000000015513514611660020364 0ustar tomstaff00000000000000from __future__ import (absolute_import, division, print_function, unicode_literals) pytest-remotedata-0.3.2/tests/conftest.py0000644000077000000240000000014513514611660020451 0ustar tomstaff00000000000000# This enables the meta-testing of this plugin via the testdir fixture pytest_plugins = ['pytester'] pytest-remotedata-0.3.2/tests/test_skip_remote_data.py0000644000077000000240000000751413514612637023211 0ustar tomstaff00000000000000# Licensed under a 3-clause BSD style license - see LICENSE.rst # this test doesn't actually use any online data, it should just be skipped # by run_tests because it has the remote_data decorator. import pytest from contextlib import closing import six from six.moves.urllib.request import urlopen ASTROPY_DATA_URL = "http://data.astropy.org/" GITHUB_DATA_URL = "http://astropy.github.io/" EXTERNAL_URL = "http://www.google.com" TIMEOUT = 10 if six.PY2: _EXPECTED_ERROR = IOError else: from six.moves.urllib.error import URLError _EXPECTED_ERROR = URLError def download_file(remote_url): with closing(urlopen(remote_url, timeout=TIMEOUT)) as remote: remote.read() @pytest.mark.remote_data def test_skip_remote_data(pytestconfig): # astropy.test() has remote_data=none or remote_data=astropy but we still # got here somehow, so fail with a helpful message if pytestconfig.getoption('remote_data') == 'none': pytest.fail('@remote_data was not skipped with remote_data=none') elif pytestconfig.getoption('remote_data') == 'astropy': pytest.fail('@remote_data was not skipped with remote_data=astropy') elif pytestconfig.getoption('remote_data') == 'github': pytest.fail('@remote_data was not skipped with remote_data=github') # Test Astropy URL download_file(ASTROPY_DATA_URL + 'galactic_center/gc_2mass_k.fits') # Test GitHub URL download_file(GITHUB_DATA_URL) # Test unrelated URL download_file(EXTERNAL_URL) @pytest.mark.remote_data(source='astropy') def test_skip_remote_data_astropy(pytestconfig): # astropy.test() has remote_data=none but we still got here somehow, # so fail with a helpful message if pytestconfig.getoption('remote_data') in ('none', 'github'): pytest.fail('@remote_data was not skipped with remote_data=none' 'or remote_data=github') # Test Astropy URL download_file(ASTROPY_DATA_URL + 'galactic_center/gc_2mass_k.fits') # Test non-Astropy URL if pytestconfig.getoption('remote_data') == 'astropy': with pytest.raises(Exception) as exc: download_file(EXTERNAL_URL) assert "An attempt was made to connect to the internet" in str(exc.value) # noqa else: # remote_data=any download_file(EXTERNAL_URL) @pytest.mark.remote_data(source='github') def test_skip_remote_data_github(pytestconfig): if pytestconfig.getoption('remote_data') == 'none': pytest.fail('@remote_data was not skipped with remote_data=none') # Test GitHub URL download_file(GITHUB_DATA_URL) # Test non-GitHub URL if pytestconfig.getoption('remote_data') == 'github': with pytest.raises(Exception) as exc: download_file(ASTROPY_DATA_URL) assert "An attempt was made to connect to the internet" in str(exc.value) else: # remote_data=any or remote_data=astropy download_file(ASTROPY_DATA_URL) @pytest.mark.internet_off def test_internet_off_decorator(pytestconfig): # This test should only run when internet access has been disabled if pytestconfig.getoption('remote_data') != 'none': pytest.fail('@internet_off test ran when remote_data!=none') def test_block_internet_connection(pytestconfig): if pytestconfig.getoption('remote_data') == 'none': with pytest.raises(_EXPECTED_ERROR): download_file(EXTERNAL_URL) elif pytestconfig.getoption('remote_data') == 'astropy': with pytest.raises(_EXPECTED_ERROR): download_file(EXTERNAL_URL) elif pytestconfig.getoption('remote_data') == 'github': with pytest.raises(_EXPECTED_ERROR): download_file(EXTERNAL_URL) else: download_file(EXTERNAL_URL) @pytest.mark.internet_off def test_block_internet_connection_internet_off(): with pytest.raises(_EXPECTED_ERROR): download_file(EXTERNAL_URL) pytest-remotedata-0.3.2/tests/test_socketblocker.py0000644000077000000240000000460113514611660022516 0ustar tomstaff00000000000000# Licensed under a 3-clause BSD style license - see LICENSE.rst import sys import time from threading import Thread from six.moves import BaseHTTPServer, SimpleHTTPServer from six.moves.urllib.request import urlopen import pytest from pytest_remotedata.disable_internet import no_internet def test_outgoing_fails(): with pytest.raises(IOError): with no_internet(): urlopen('http://www.python.org') class StoppableHTTPServer(BaseHTTPServer.HTTPServer, object): def __init__(self, *args): super(StoppableHTTPServer, self).__init__(*args) self.stop = False def handle_request(self): self.stop = True super(StoppableHTTPServer, self).handle_request() def serve_forever(self): """ Serve until stop set, which will happen if any request is handled """ while not self.stop: self.handle_request() @pytest.mark.parametrize(('localhost'), ('localhost', '127.0.0.1')) def test_localconnect_succeeds(localhost): """ Ensure that connections to localhost are allowed, since these are genuinely not remotedata. """ # port "0" means find open port # see http://stackoverflow.com/questions/1365265/on-localhost-how-to-pick-a-free-port-number httpd = StoppableHTTPServer(('localhost', 0), SimpleHTTPServer.SimpleHTTPRequestHandler) port = httpd.socket.getsockname()[1] server = Thread(target=httpd.serve_forever) server.setDaemon(True) server.start() time.sleep(0.1) urlopen('http://{localhost:s}:{port:d}'.format(localhost=localhost, port=port)).close() PY3_4 = sys.version_info[:2] >= (3, 4) # Used for the below test--inline functions aren't pickleable # by multiprocessing? def _square(x): return x ** 2 @pytest.mark.skipif('not PY3_4 or sys.platform == "win32" or sys.platform.startswith("gnu0")') def test_multiprocessing_forkserver(): """ Test that using multiprocessing with forkserver works. Perhaps a simpler more direct test would be to just open some local sockets and pass something through them. Regression test for https://github.com/astropy/astropy/pull/3713 """ import multiprocessing ctx = multiprocessing.get_context('forkserver') pool = ctx.Pool(1) result = pool.map(_square, [1, 2, 3, 4, 5]) pool.close() pool.join() assert result == [1, 4, 9, 16, 25] pytest-remotedata-0.3.2/tests/test_strict_check.py0000644000077000000240000000332213514617504022333 0ustar tomstaff00000000000000# Licensed under a 3-clause BSD style license - see LICENSE.rst import os import pytest PYFILE_CONTENTS = """ import pytest from six.moves.urllib.request import urlopen def test_config_setting(pytestconfig): assert pytestconfig.getini('remote_data_strict') == {} {} def test_internet_access(): urlopen('http://astropy.org') """ def _write_config_file(testdir, entry): config = testdir.tmpdir.join('setup.cfg') config.write(""" [tool:pytest] {} """.format(entry)) # Just a sanity check to make sure we actually write the config file assert os.path.exists(str(testdir.tmpdir.join('setup.cfg'))) def test_local_config(pytestconfig): assert pytestconfig.getini('remote_data_strict') == True def test_default_behavior(testdir): _write_config_file(testdir, '') testdir.makepyfile(PYFILE_CONTENTS.format('False', '')) result = testdir.runpytest_subprocess() result.assert_outcomes(passed=2) def test_strict_behavior(testdir): _write_config_file(testdir, 'remote_data_strict = true') testdir.makepyfile(PYFILE_CONTENTS.format('True', '')) result = testdir.runpytest_subprocess() result.assert_outcomes(passed=1, failed=1) @pytest.mark.parametrize('source', ['none', 'any']) def test_strict_with_decorator(testdir, source): _write_config_file(testdir, 'remote_data_strict = true') decorator = '@pytest.mark.remote_data' testdir.makepyfile(PYFILE_CONTENTS.format('True', decorator)) clarg = '--remote-data=' + source result = testdir.runpytest_subprocess(clarg) if source == 'none': outcomes = dict(passed=1, skipped=1) else: outcomes = dict(passed=2) result.assert_outcomes(**outcomes)