diff --git a/MANIFEST.in b/MANIFEST.in index 24ea06d..4faef4e 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -3,6 +3,8 @@ include CHANGELOG.rst include LICENSE include config.example include Makefile +include test-requirements.txt +include docs-requirements.txt recursive-include docs * recursive-include tests * diff --git a/Makefile b/Makefile index 2f2ea0d..4596864 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,4 @@ -# Packagers who want to run the testsuite against an installed vdirsyncer: -# -# - Create a virtualenv -# - Somehow link your installation of vdirsyncer into the virtualenv, e.g. by -# using --system-site-packages when creating the virtualenv -# - Inside the virtualenv: `make install-test test` -# -# The `install-test` target requires internet access. +# See the documentation on how to run the tests. export DAV_SERVER := skip export REMOTESTORAGE_SERVER := skip @@ -13,6 +6,7 @@ export RADICALE_BACKEND := filesystem export REQUIREMENTS := release export TESTSERVER_BASE := ./tests/storage/servers/ export TRAVIS := false +export DETERMINISTIC_TESTS := false install-servers: set -ex; \ @@ -28,14 +22,12 @@ install-servers: install-test: install-servers (python --version | grep -vq 'Python 3.3') || pip install enum34 + pip install -r test-requirements.txt set -xe && if [ "$$REQUIREMENTS" = "devel" ]; then \ pip install -U --force-reinstall \ git+https://github.com/DRMacIver/hypothesis \ git+https://github.com/pytest-dev/pytest; \ - else \ - pip install pytest hypothesis; \ fi - pip install pytest-xprocess pytest-localserver pytest-subtesthack [ $(TRAVIS) != "true" ] || pip install coverage codecov test: @@ -62,7 +54,7 @@ travis-conf: python3 scripts/make_travisconf.py > .travis.yml install-docs: - pip install sphinx sphinx_rtd_theme + pip install -r docs-requirements.txt docs: cd docs && make html @@ -88,7 +80,7 @@ install-dev: set -xe && if [ "$$REQUIREMENTS" = "devel" ]; then \ pip install -U --force-reinstall git+https://github.com/kennethreitz/requests; \ elif [ "$$REQUIREMENTS" = "minimal" ]; then \ - pip install -U --force-reinstall lxml==3.1 requests==2.4.1 requests_toolbelt==0.4.0 click==5.0; \ + pip install -U --force-reinstall $$(python setup.py --quiet minimal_requirements); \ fi .PHONY: docs diff --git a/docs-requirements.txt b/docs-requirements.txt new file mode 100644 index 0000000..8213302 --- /dev/null +++ b/docs-requirements.txt @@ -0,0 +1,2 @@ +sphinx +sphinx_rtd_theme diff --git a/docs/index.rst b/docs/index.rst index 5f72d14..50aa337 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -29,6 +29,7 @@ Table of Contents problems vdir contributing + packaging contact changelog license diff --git a/docs/packaging.rst b/docs/packaging.rst new file mode 100644 index 0000000..a86b417 --- /dev/null +++ b/docs/packaging.rst @@ -0,0 +1,65 @@ +==================== +Packaging guidelines +==================== + +Thank you very much for packaging vdirsyncer! The following guidelines should +help you to avoid some common pitfalls. + +While they are called guidelines and therefore theoretically not mandatory, if +you consider going a different direction, please first open an issue or contact +me otherwise instead of just going ahead. These guidelines exist for my own +convenience too. + +Obtaining the source code +========================= + +The main distribution channel is `PyPI +`_, and source tarballs can be +obtained there. Do not use the ones from GitHub: Their tarballs contain useless +junk and are more of a distraction than anything else. + +I give each release a tag in the git repo. If you want to get notified of new +releases, `GitHub's feed +`_ is a good way. + +Dependency versions +=================== + +It is strongly discouraged to package vdirsyncer as a Python 2 application. +Future releases will only work on Python 3.3 and newer versions. + +As with most Python packages, ``setup.py`` denotes the runtime dependencies of +vdirsyncer. It also contains lower-bound versions of each dependency. Older +versions will be rejected by the testsuite. + +Testing +======= + +Everything testing-related goes through the ``Makefile`` in the root of the +repository or PyPI package. Trying to e.g. run ``py.test`` directly will +require a lot of environment variables to be set (for configuration) and you +probably don't want to deal with that. + +You can install the testing dependencies with ``make test-install``. You +probably don't want this since it will use pip to download the dependencies. +Alternatively you can find the testing dependencies in +``test-requirements.txt``, again with lower-bound version requirements. + +You also have to have vdirsyncer fully installed at this point. Merely +``cd``-ing into the tarball will not be sufficient. + +Running the tests happens with ``make test``. + +Hypothesis will randomly generate test input. If you care about deterministic +tests, set the ``DETERMINISTIC_TESTS`` variable to ``"true"``:: + + make DETERMINISTIC_TESTS=true test + +Documentation +============= + +You can find a list of dependencies in ``docs-requirements.txt``. + +Change into the ``docs/`` directory and build whatever format you want. That +said, I only take care of the HTML docs' formatting -- other targets (such as +the generated manpage) may look like garbage. diff --git a/setup.py b/setup.py index f721e18..5b8ffde 100644 --- a/setup.py +++ b/setup.py @@ -12,9 +12,48 @@ Vdirsyncer is a synchronization tool for vdir. See the README for more details. import platform -from setuptools import find_packages, setup +from setuptools import Command, find_packages, setup +requirements = [ + # https://github.com/mitsuhiko/click/issues/200 + 'click>=5.0', + 'click-log>=0.1.3', + 'click-threading>=0.1.2', + # https://github.com/kennethreitz/requests/issues/2930 + 'requests >=2.0.1, !=2.9.0', + 'lxml >=3.1' + ( + # See https://github.com/untitaker/vdirsyncer/issues/298 + # We pin some LXML version that is known to work with PyPy + # I assume nobody actually uses PyPy with vdirsyncer, so this is + # moot + ', <=3.4.4' + if platform.python_implementation() == 'PyPy' + else '' + ), + # https://github.com/sigmavirus24/requests-toolbelt/pull/28 + 'requests_toolbelt >=0.3.0', + # https://github.com/untitaker/python-atomicwrites/commit/4d12f23227b6a944ab1d99c507a69fdbc7c9ed6d # noqa + 'atomicwrites>=0.1.7' +] + + +class PrintRequirements(Command): + + description = 'Prints minimal requirements' + + user_options = [] + + def initialize_options(self): + pass + + def finalize_options(self): + pass + + def run(self): + for requirement in requirements: + print(requirement.replace(">", "=").replace(" ", "")) + setup( name='vdirsyncer', use_scm_version={ @@ -32,27 +71,11 @@ setup( entry_points={ 'console_scripts': ['vdirsyncer = vdirsyncer.cli:main'] }, - install_requires=[ - # https://github.com/mitsuhiko/click/issues/200 - 'click>=5.0', - 'click-log', - 'click-threading', - # https://github.com/kennethreitz/requests/issues/2930 - 'requests !=2.9.0', - 'lxml >=3.1' + ( - # See https://github.com/untitaker/vdirsyncer/issues/298 - # We pin some LXML version that is known to work with PyPy - # I assume nobody actually uses PyPy with vdirsyncer, so this is - # moot - ', <=3.4.4' - if platform.python_implementation() == 'PyPy' - else '' - ), - # https://github.com/sigmavirus24/requests-toolbelt/pull/28 - 'requests_toolbelt >=0.5.0', - 'atomicwrites' - ], + install_requires=requirements, extras_require={ 'remotestorage': ['requests-oauthlib'] + }, + cmdclass={ + 'minimal_requirements': PrintRequirements } ) diff --git a/test-requirements.txt b/test-requirements.txt new file mode 100644 index 0000000..85cb644 --- /dev/null +++ b/test-requirements.txt @@ -0,0 +1,5 @@ +hypothesis>=3 +pytest +pytest-localserver +pytest-subtesthack +pytest-xprocess diff --git a/tests/cli/test_main.py b/tests/cli/test_main.py index bb89c76..1cd8e2b 100644 --- a/tests/cli/test_main.py +++ b/tests/cli/test_main.py @@ -8,12 +8,22 @@ from click.testing import CliRunner from hypothesis import example, given import hypothesis.strategies as st +from pkg_resources import load_entry_point + import pytest import vdirsyncer.cli as cli from vdirsyncer.utils.compat import PY2, to_native +def test_entry_points(monkeypatch, capsys): + monkeypatch.setattr('sys.argv', ['--help']) + with pytest.raises(SystemExit) as excinfo: + load_entry_point('vdirsyncer', 'console_scripts', 'vdirsyncer')() + + assert excinfo.value.code == 0 + + def test_simple_run(tmpdir, runner): runner.write_with_general(dedent(''' [pair my_pair] diff --git a/tests/conftest.py b/tests/conftest.py index f233759..2268df9 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -3,9 +3,12 @@ General-purpose fixtures for vdirsyncer's testsuite. ''' import logging +import os import click_log +from hypothesis import Verbosity, settings + import pytest @@ -27,3 +30,16 @@ except ImportError: return lambda x: x() else: del pytest_benchmark + +settings.register_profile("ci", settings( + max_examples=1000, + verbosity=Verbosity.verbose, +)) +settings.register_profile("deterministic", settings( + derandomize=True, +)) + +if os.getenv('DETERMINISTIC_TESTS').lower == 'true': + settings.load_profile("deterministic") +elif os.getenv('TRAVIS').lower == 'true': + settings.load_profile("ci")