Merge pull request #354 from untitaker/packaging-guidelines

Add packaging guidelines
This commit is contained in:
Markus Unterwaditzer 2016-03-04 15:08:16 +01:00
commit 88547294a7
9 changed files with 150 additions and 34 deletions

View file

@ -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 *

View file

@ -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

2
docs-requirements.txt Normal file
View file

@ -0,0 +1,2 @@
sphinx
sphinx_rtd_theme

View file

@ -29,6 +29,7 @@ Table of Contents
problems
vdir
contributing
packaging
contact
changelog
license

65
docs/packaging.rst Normal file
View file

@ -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
<https://pypi.python.org/pypi/vdirsyncer>`_, 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
<https://github.com/untitaker/vdirsyncer/releases.atom>`_ 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.

View file

@ -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
}
)

5
test-requirements.txt Normal file
View file

@ -0,0 +1,5 @@
hypothesis>=3
pytest
pytest-localserver
pytest-subtesthack
pytest-xprocess

View file

@ -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]

View file

@ -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")