From e8f4f4c73a15ce8fef98baf1dc4cfdf4e0addf38 Mon Sep 17 00:00:00 2001 From: Philipp A Date: Thu, 3 Dec 2020 11:04:35 +0100 Subject: [PATCH 1/4] Switch to flit This reverts commit d6457902 --- .azure-pipelines.yml | 8 +- .gitignore | 1 + .travis.yml | 1 - MANIFEST.in | 4 - docs/conf.py | 1 - docs/installation.rst | 23 +++- docs/release-notes/1.8.0.rst | 5 + pyproject.toml | 108 +++++++++++++++++- requirements.txt | 24 ---- scanpy/__init__.py | 81 +++++++------ scanpy/_metadata.py | 35 +++++- scanpy/_utils.py | 3 + ...test_docs.py => test_package_structure.py} | 26 ++++- setup.py | 82 ------------- 14 files changed, 235 insertions(+), 167 deletions(-) delete mode 100644 MANIFEST.in delete mode 100644 requirements.txt rename scanpy/tests/{test_docs.py => test_package_structure.py} (67%) delete mode 100644 setup.py diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml index 8bb3d3325b..02970df9e1 100644 --- a/.azure-pipelines.yml +++ b/.azure-pipelines.yml @@ -28,8 +28,8 @@ jobs: - task: Cache@2 inputs: - key: '"python $(python.version)" | "$(Agent.OS)" | requirements.txt' - restoreKeys: | + key: '"python $(python.version)" | "$(Agent.OS)" | pyproject.toml' + restoreKeys: | python | "$(Agent.OS)" python path: $(PIP_CACHE_DIR) @@ -43,7 +43,7 @@ jobs: - script: | python -m pip install --upgrade pip pip install pytest-cov wheel - pip install -e .[dev,doc,test,louvain,leiden,magic,scvi,harmony,scrublet,scanorama] + pip install .[dev,doc,test,louvain,leiden,magic,scvi,harmony,scrublet,scanorama] displayName: 'Install dependencies' - script: | @@ -102,6 +102,6 @@ jobs: displayName: 'Display installed versions' - script: | - python setup.py sdist bdist_wheel + flit build twine check dist/* displayName: 'Build & Twine check' diff --git a/.gitignore b/.gitignore index 079c5b0cea..baa3c9b7f1 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,7 @@ __pycache__/ /scanpy.egg-info/ /*-env/ /env-*/ +/setup.py # OS stuff .DS_Store diff --git a/.travis.yml b/.travis.yml index 1c6219b607..cb5c7a96eb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,6 @@ matrix: - pip install .[dev,doc] script: - black . --check --diff - - python setup.py check --restructuredtext --strict - rst2html.py --halt=2 README.rst >/dev/null after_success: skip - name: "anndata dev" diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 98d1521a1c..0000000000 --- a/MANIFEST.in +++ /dev/null @@ -1,4 +0,0 @@ -# Exclude everything not needed for importing, building, and tests -exclude .coveragerc .editorconfig .gitattributes .gitignore .readthedocs.yml .travis.yml -exclude CONTRIBUTING.md -prune docs diff --git a/docs/conf.py b/docs/conf.py index eba759716c..2e2b3c5157 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,6 +1,5 @@ import os import sys -import warnings from pathlib import Path from datetime import datetime diff --git a/docs/installation.rst b/docs/installation.rst index 37bf2e592b..b51f9012eb 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -7,7 +7,7 @@ If you do not have a working installation of Python 3.6 (or later), consider installing Miniconda_ (see `Installing Miniconda`_). Then run:: conda install seaborn scikit-learn statsmodels numba pytables - conda install -c conda-forge python-igraph leidenalg + conda install -c conda-forge python-igraph leidenalg Pull Scanpy from `PyPI `__ (consider using ``pip3`` to access Python 3):: @@ -35,7 +35,9 @@ To work with the latest version `on GitHub`_: clone the repository and `cd` into its root directory. To install using symbolic links (stay up to date with your cloned version after you update with `git pull`) call:: - pip install -e . + flit install -s # from an activated venv or conda env + # or + flit install -s --python path/to/venv/bin/python If you intend to do development work, there are some extra dependencies you'll want. These can be install with `scanpy` via:: @@ -44,6 +46,21 @@ These can be install with `scanpy` via:: .. _on GitHub: https://github.com/theislab/scanpy +If you want to let conda_ handle the installations of dependencies, do:: + + pip install beni + beni pyproject.toml > environment.yml + conda env create -f environment.yml + conda activate scanpy + flit install -s + +On Windows, you might have to use `flit install --pth-file` +if you are not able to give yourself the `create symbolic links`_ privilege. +Be aware that a `conda bug`_ might prevent `conda list` from working then. + +.. _create symbolic links: https://docs.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/create-symbolic-links +.. _conda bug: https://github.com/conda/conda/issues/9074 + Docker ~~~~~~ If you're using Docker_, you can use the minimal `fastgenomics/scanpy`_ image from the Docker Hub. @@ -78,6 +95,8 @@ Download those and install them using `pip install ./path/to/file.whl` .. _compiling igraph: https://stackoverflow.com/q/29589696/247482 .. _unofficial binaries: https://www.lfd.uci.edu/~gohlke/pythonlibs/ +.. _conda: + Installing Miniconda ~~~~~~~~~~~~~~~~~~~~ After downloading Miniconda_, in a unix shell (Linux, Mac), run diff --git a/docs/release-notes/1.8.0.rst b/docs/release-notes/1.8.0.rst index f85c0c4fd1..b98676558a 100644 --- a/docs/release-notes/1.8.0.rst +++ b/docs/release-notes/1.8.0.rst @@ -3,6 +3,11 @@ .. rubric:: Features +- Switched to flit_ for building and deploying the package, + a simple tool with an easy to understand command line interface and metadata. + +.. _flit: https://flit.readthedocs.io/en/latest/ + .. rubric:: External tools .. rubric:: Performance enhancements diff --git a/pyproject.toml b/pyproject.toml index 5e4e46f851..901f1dd7e1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,16 +1,114 @@ [build-system] -requires = ['setuptools', 'setuptools_scm', 'wheel', 'pytoml'] -build-backend = 'setuptools.build_meta' +build-backend = 'flit_core.buildapi' +requires = [ + 'flit_core >=2,<4', + 'setuptools_scm', + 'pytoml', + 'importlib_metadata>=0.7; python_version < "3.8"', +] -# uses the format of tool.flit.metadata because we’ll move to it anyway -[tool.scanpy] -author = """ +[tool.flit.metadata] +module = 'scanpy' +author = """\ Alex Wolf, Philipp Angerer, Fidel Ramirez, Isaac Virshup, \ Sergei Rybakov, Gokcen Eraslan, Tom White, Malte Luecken, \ Davide Cittaro, Tobias Callies, Marius Lange, Andrés R. Muñoz-Rojas\ """ # We don’t need all emails, the main authors are sufficient. author-email = 'f.alex.wolf@gmx.de, philipp.angerer@helmholtz-muenchen.de' +description-file = 'README.rst' +home-page = 'http://github.com/theislab/scanpy' +urls = { Documentation = 'https://scanpy.readthedocs.io/' } +classifiers = [ + 'License :: OSI Approved :: BSD License', + 'Development Status :: 5 - Production/Stable', + 'Environment :: Console', + 'Framework :: Jupyter', + 'Intended Audience :: Developers', + 'Intended Audience :: Science/Research', + 'Natural Language :: English', + 'Operating System :: MacOS :: MacOS X', + 'Operating System :: Microsoft :: Windows', + 'Operating System :: POSIX :: Linux', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Topic :: Scientific/Engineering :: Bio-Informatics', + 'Topic :: Scientific/Engineering :: Visualization', +] +requires-python = '>=3.6' +requires = [ + 'anndata>=0.7.4', + # numpy needs a version due to #1320 + 'numpy>=1.17.0', + # Matplotlib 3.1 causes an error in 3d scatter plots (https://github.com/matplotlib/matplotlib/issues/14298) + # But matplotlib 3.0 causes one in heatmaps + 'matplotlib>=3.1.2', + 'pandas>=0.21', + 'scipy>=1.4', + 'seaborn', + 'h5py>=2.10.0', + 'tables', + 'tqdm', + 'scikit-learn>=0.21.2', + 'statsmodels>=0.10.0rc2', + 'patsy', + 'networkx>=2.3', + 'natsort', + 'joblib', + 'numba>=0.41.0', + 'umap-learn>=0.3.10', + 'legacy-api-wrap', + 'packaging', + 'sinfo', + # for getting the stable version + 'importlib_metadata>=0.7; python_version < "3.8"', +] + +[tool.flit.metadata.requires-extra] +louvain = ['python-igraph', 'louvain>=0.6,!=0.6.2'] +leiden = ['python-igraph', 'leidenalg'] +bbknn = ['bbknn'] +scvi = ['scvi==0.6.7'] +rapids = ['cudf>=0.9', 'cuml>=0.9', 'cugraph>=0.9'] +magic = ['magic-impute>=2.0'] +skmisc = ['scikit-misc>=0.1.3'] +harmony = ['harmonypy'] +scanorama = ['scanorama'] +scrublet = ['scrublet'] +dev = [ + # getting the dev version + 'setuptools_scm', + 'pytoml', + # static checking + 'black>=20.8b1', + 'docutils', +] +doc = [ + 'sphinx>=3.2', + 'sphinx-rtd-theme>=0.3.1', + 'sphinx-autodoc-typehints', + 'readthedocs-sphinx-search', + 'scanpydoc>=0.5', + 'typing_extensions; python_version < "3.8"', # for `Literal` +] +test = [ + 'pytest>=4.4', + 'pytest-nunit', + 'dask[array]!=2.17.0', + 'fsspec', + 'zappy', + 'zarr', + 'profimp', + # Test the metadata while this exists: https://github.com/takluyver/flit/issues/387 + 'flit_core', +] + +[tool.flit.scripts] +scanpy = 'scanpy.cli:console_main' + +[tool.flit.sdist] +exclude = ['scanpy/tests'] [tool.pytest.ini_options] python_files = 'test_*.py' diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index e74f23c397..0000000000 --- a/requirements.txt +++ /dev/null @@ -1,24 +0,0 @@ -anndata>=0.7.4 -# numpy needs a version due to #1320 -numpy>=1.17.0 -# Matplotlib 3.1 causes an error in 3d scatter plots (https://github.com/matplotlib/matplotlib/issues/14298) -# But matplotlib 3.0 causes one in heatmaps -matplotlib>=3.1.2 -pandas>=0.21 -scipy>=1.4 -seaborn -h5py>=2.10.0 -tables -tqdm -importlib_metadata>=0.7; python_version < '3.8' -scikit-learn>=0.21.2 -statsmodels>=0.10.0rc2 -patsy -networkx>=2.3 -natsort -joblib -numba>=0.41.0 -umap-learn>=0.3.10 -legacy-api-wrap -packaging -sinfo diff --git a/scanpy/__init__.py b/scanpy/__init__.py index 71eb75e977..fa1124b85e 100644 --- a/scanpy/__init__.py +++ b/scanpy/__init__.py @@ -1,43 +1,42 @@ """Single-Cell Analysis in Python.""" -from ._metadata import __version__, __author__, __email__ - -from ._utils import check_versions - -check_versions() -del check_versions - -# the actual API -from ._settings import ( - settings, - Verbosity, -) # start with settings as several tools are using it -from . import tools as tl -from . import preprocessing as pp -from . import plotting as pl -from . import datasets, logging, queries, external, get - -from anndata import AnnData, concat -from anndata import ( - read_h5ad, - read_csv, - read_excel, - read_hdf, - read_loom, - read_mtx, - read_text, - read_umi_tools, -) -from .readwrite import read, read_10x_h5, read_10x_mtx, write, read_visium -from .neighbors import Neighbors - -set_figure_params = settings.set_figure_params - -# has to be done at the end, after everything has been imported -import sys - -sys.modules.update({f'{__name__}.{m}': globals()[m] for m in ['tl', 'pp', 'pl']}) -from ._utils import annotate_doc_types - -annotate_doc_types(sys.modules[__name__], 'scanpy') -del sys, annotate_doc_types +from ._metadata import __version__, __author__, __email__, within_flit + +if not within_flit(): # see function docstring on why this is there + from ._utils import check_versions + + check_versions() + del check_versions, within_flit + + # the actual API + # (start with settings as several tools are using it) + from ._settings import settings, Verbosity + from . import tools as tl + from . import preprocessing as pp + from . import plotting as pl + from . import datasets, logging, queries, external, get + + from anndata import AnnData, concat + from anndata import ( + read_h5ad, + read_csv, + read_excel, + read_hdf, + read_loom, + read_mtx, + read_text, + read_umi_tools, + ) + from .readwrite import read, read_10x_h5, read_10x_mtx, write, read_visium + from .neighbors import Neighbors + + set_figure_params = settings.set_figure_params + + # has to be done at the end, after everything has been imported + import sys + + sys.modules.update({f'{__name__}.{m}': globals()[m] for m in ['tl', 'pp', 'pl']}) + from ._utils import annotate_doc_types + + annotate_doc_types(sys.modules[__name__], 'scanpy') + del sys, annotate_doc_types diff --git a/scanpy/_metadata.py b/scanpy/_metadata.py index fda12a4350..500c83f67e 100644 --- a/scanpy/_metadata.py +++ b/scanpy/_metadata.py @@ -1,14 +1,34 @@ +import traceback from pathlib import Path here = Path(__file__).parent + +def refresh_entry_points(): + """\ + Under some circumstances, (e.g. when installing a PEP 517 package via pip), + pkg_resources.working_set.entries is stale. This tries to fix that. + See https://github.com/pypa/setuptools_scm/issues/513 + """ + try: + import sys + import pkg_resources + + ws: pkg_resources.WorkingSet = pkg_resources.working_set + for entry in sys.path: + ws.add_entry(entry) + except Exception: + pass + + try: from setuptools_scm import get_version import pytoml proj = pytoml.loads((here.parent / 'pyproject.toml').read_text()) - metadata = proj['tool']['scanpy'] + metadata = proj['tool']['flit']['metadata'] + refresh_entry_points() __version__ = get_version(root='..', relative_to=__file__) __author__ = metadata['author'] __email__ = metadata['author-email'] @@ -19,3 +39,16 @@ __version__ = metadata['Version'] __author__ = metadata['Author'] __email__ = metadata['Author-email'] + + +def within_flit(): + """\ + Checks if we are being imported by flit. + This is necessary so flit can import __version__ without all depedencies installed. + There are a few options to make this hack unnecessary, see: + https://github.com/takluyver/flit/issues/253#issuecomment-737870438 + """ + for frame in traceback.extract_stack(): + if frame.name == 'get_docstring_and_version_via_import': + return True + return False diff --git a/scanpy/_utils.py b/scanpy/_utils.py index 207f40f0b6..7903a6300e 100644 --- a/scanpy/_utils.py +++ b/scanpy/_utils.py @@ -141,6 +141,9 @@ def descend_classes_and_funcs(mod: ModuleType, root: str, encountered=None): if callable(m) and _one_of_ours(m, root): yield m elif isinstance(obj, ModuleType) and obj not in encountered: + if obj.__name__.startswith('scanpy.tests'): + # Python’s import mechanism seems to add this to `scanpy`’s attributes + continue encountered.add(obj) yield from descend_classes_and_funcs(obj, root, encountered) diff --git a/scanpy/tests/test_docs.py b/scanpy/tests/test_package_structure.py similarity index 67% rename from scanpy/tests/test_docs.py rename to scanpy/tests/test_package_structure.py index 0c82178be5..8c87d91b6d 100644 --- a/scanpy/tests/test_docs.py +++ b/scanpy/tests/test_package_structure.py @@ -1,5 +1,8 @@ +import email import inspect +import os from types import FunctionType +from pathlib import Path import pytest from scanpy._utils import descend_classes_and_funcs @@ -8,6 +11,9 @@ import scanpy.cli +mod_dir = Path(scanpy.__file__).parent +proj_dir = mod_dir.parent + scanpy_functions = [ c_or_f for c_or_f in descend_classes_and_funcs(scanpy, "scanpy") @@ -15,6 +21,16 @@ ] +@pytest.fixture +def in_project_dir(): + wd_orig = Path.cwd() + os.chdir(proj_dir) + try: + yield proj_dir + finally: + os.chdir(wd_orig) + + @pytest.mark.parametrize("f", scanpy_functions) def test_function_headers(f): name = f"{f.__module__}.{f.__qualname__}" @@ -41,5 +57,11 @@ def test_function_headers(f): raise SyntaxError(msg, (filename, lineno, 2, text)) -def test_plot_doc_signatures(): - pass +def test_metadata(tmp_path, in_project_dir): + import flit_core.buildapi + + flit_core.buildapi.prepare_metadata_for_build_wheel(tmp_path) + + metadata_path = next(tmp_path.glob('*.dist-info')) / 'METADATA' + metadata = email.message_from_bytes(metadata_path.read_bytes()) + assert not metadata.defects diff --git a/setup.py b/setup.py deleted file mode 100644 index cf0e22bf02..0000000000 --- a/setup.py +++ /dev/null @@ -1,82 +0,0 @@ -import sys - -if sys.version_info < (3, 6): - sys.exit('scanpy requires Python >= 3.6') -from pathlib import Path - -from setuptools import setup, find_packages - -try: - import pytoml -except ImportError: - sys.exit('Please use `pip install .` or install pytoml first.') - -proj = pytoml.loads(Path('pyproject.toml').read_text()) -metadata = proj['tool']['scanpy'] - -setup( - name='scanpy', - use_scm_version=True, - setup_requires=['setuptools_scm'], - description='Single-Cell Analysis in Python.', - long_description=Path('README.rst').read_text('utf-8'), - url='http://github.com/theislab/scanpy', - author=metadata['author'], - author_email=metadata['author-email'], - license='BSD', - python_requires='>=3.6', - install_requires=[ - l.strip() for l in Path('requirements.txt').read_text('utf-8').splitlines() - ], - extras_require=dict( - louvain=['python-igraph', 'louvain>=0.6,!=0.6.2'], - leiden=['python-igraph', 'leidenalg'], - bbknn=['bbknn'], - scvi=['scvi==0.6.7'], - rapids=['cudf>=0.9', 'cuml>=0.9', 'cugraph>=0.9'], - magic=['magic-impute>=2.0'], - skmisc=['scikit-misc>=0.1.3'], - harmony=['harmonypy'], - scanorama=['scanorama'], - scrublet=['scrublet'], - dev=['setuptools_scm', 'pytoml', 'black>=20.8b1'], - doc=[ - 'sphinx>=3.2', - 'sphinx_rtd_theme>=0.3.1', - 'readthedocs-sphinx-search', - 'sphinx_autodoc_typehints', - 'scanpydoc>=0.5', - 'typing_extensions; python_version < "3.8"', # for `Literal` - ], - test=[ - 'pytest>=4.4', - 'pytest-nunit', - 'dask[array]!=2.17.0', - 'fsspec', - 'zappy', - 'zarr', - 'profimp', - ], - ), - packages=find_packages(), - include_package_data=True, - entry_points=dict(console_scripts=['scanpy=scanpy.cli:console_main']), - zip_safe=False, - classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'Environment :: Console', - 'Framework :: Jupyter', - 'Intended Audience :: Developers', - 'Intended Audience :: Science/Research', - 'Natural Language :: English', - 'Operating System :: MacOS :: MacOS X', - 'Operating System :: Microsoft :: Windows', - 'Operating System :: POSIX :: Linux', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Topic :: Scientific/Engineering :: Bio-Informatics', - 'Topic :: Scientific/Engineering :: Visualization', - ], -) From 4bdebd6ac2b8398fead5ad48a53f4c32c73062ef Mon Sep 17 00:00:00 2001 From: Philipp A Date: Fri, 15 Jan 2021 15:51:45 +0100 Subject: [PATCH 2/4] add setup.py while leaving it ignored --- .gitignore | 1 - pyproject.toml | 7 ++++- setup.py | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 setup.py diff --git a/.gitignore b/.gitignore index baa3c9b7f1..079c5b0cea 100644 --- a/.gitignore +++ b/.gitignore @@ -33,7 +33,6 @@ __pycache__/ /scanpy.egg-info/ /*-env/ /env-*/ -/setup.py # OS stuff .DS_Store diff --git a/pyproject.toml b/pyproject.toml index 901f1dd7e1..2ef0aba357 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,6 +5,8 @@ requires = [ 'setuptools_scm', 'pytoml', 'importlib_metadata>=0.7; python_version < "3.8"', + # setup.py stuff + 'packaging', ] [tool.flit.metadata] @@ -108,7 +110,10 @@ test = [ scanpy = 'scanpy.cli:console_main' [tool.flit.sdist] -exclude = ['scanpy/tests'] +exclude = [ + 'scanpy/tests', + 'setup.py', +] [tool.pytest.ini_options] python_files = 'test_*.py' diff --git a/setup.py b/setup.py new file mode 100644 index 0000000000..458fff1899 --- /dev/null +++ b/setup.py @@ -0,0 +1,72 @@ +"""Temporary setuptools bridge +Don't use this except if you have a deadline or you encounter a bug. +""" +import re +import sys +from warnings import warn + +import setuptools +from pathlib import Path + +from flit_core import common, config +from setuptools_scm.integration import find_files + + +field_map = dict( + description="summary", + long_description="description", + long_description_content_type="description_content_type", + python_requires="requires_python", + url="home_page", + **{ + n: n + for n in ["name", "version", "author", "author_email", "license", "classifiers"] + }, +) + + +def setup_args(config_path=Path("pyproject.toml")): + cfg = config.read_flit_config(config_path) + module = common.Module(cfg.module, config_path.parent) + metadata = common.make_metadata(module, cfg) + kwargs = {} + for st_field, metadata_field in field_map.items(): + val = getattr(metadata, metadata_field, None) + if val is not None: + kwargs[st_field] = val + else: + msg = f"{metadata_field} not found in {dir(metadata)}" + assert metadata_field in {"license"}, msg + kwargs["packages"] = setuptools.find_packages(include=[metadata.name + "*"]) + if metadata.requires_dist: + kwargs["install_requires"] = [ + req for req in metadata.requires_dist if "extra ==" not in req + ] + if cfg.reqs_by_extra: + kwargs["extras_require"] = cfg.reqs_by_extra + scripts = cfg.entrypoints.get("console_scripts") + if scripts is not None: + kwargs["entry_points"] = dict( + console_scipts=[" = ".join(ep) for ep in scripts.items()] + ) + kwargs["include_package_data"] = True + kwargs["package_data"] = { + module.name: [ + re.escape(f[len(module.name) + 1 :]) for f in find_files(module.path) + ] + } + return kwargs + + +if __name__ == "__main__": + if "develop" in sys.argv: + msg = ( + "Please use `flit install -s` or `flit install --pth-file` " + "instead of `pip install -e`/`python setup.py develop`" + ) + elif "install" in sys.argv: + msg = 'Please use `pip install "$d"` instead of `python "$d/setup.py" install`' + else: + msg = "Please use `pip ...` or `flit ...` instead of `python setup.py ...`" + warn(msg, FutureWarning) + setuptools.setup(**setup_args()) From 667de766e5639a88320357052fa26a2b9fb98a4f Mon Sep 17 00:00:00 2001 From: Philipp A Date: Thu, 14 Jan 2021 12:23:10 +0100 Subject: [PATCH 3/4] Update install instructions --- docs/installation.rst | 24 +++++++++++++----------- setup.py | 3 ++- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/docs/installation.rst b/docs/installation.rst index b51f9012eb..4ef33bf0af 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -35,16 +35,20 @@ To work with the latest version `on GitHub`_: clone the repository and `cd` into its root directory. To install using symbolic links (stay up to date with your cloned version after you update with `git pull`) call:: - flit install -s # from an activated venv or conda env + flit install -s --deps=develop # from an activated venv or conda env # or - flit install -s --python path/to/venv/bin/python + flit install -s --deps=develop --python path/to/venv/bin/python -If you intend to do development work, there are some extra dependencies you'll want. -These can be install with `scanpy` via:: +.. _on GitHub: https://github.com/theislab/scanpy - pip install -e ".[dev,doc,test]" +.. note:: -.. _on GitHub: https://github.com/theislab/scanpy + Due to a `bug in pip`_, packages installed by `flit` can be uninstalled by normal pip operations. + For now, you can avoid this by using:: + + pip install -e ".[dev,doc,test]" + +.. _bug in pip: https://github.com/pypa/pip/issues/9670 If you want to let conda_ handle the installations of dependencies, do:: @@ -52,21 +56,19 @@ If you want to let conda_ handle the installations of dependencies, do:: beni pyproject.toml > environment.yml conda env create -f environment.yml conda activate scanpy - flit install -s + flit install -s --deps=develop # or: pip install -e ".[dev,doc,test]" On Windows, you might have to use `flit install --pth-file` if you are not able to give yourself the `create symbolic links`_ privilege. -Be aware that a `conda bug`_ might prevent `conda list` from working then. .. _create symbolic links: https://docs.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/create-symbolic-links -.. _conda bug: https://github.com/conda/conda/issues/9074 Docker ~~~~~~ -If you're using Docker_, you can use the minimal `fastgenomics/scanpy`_ image from the Docker Hub. +If you're using Docker_, you can use e.g. the image `gcfntnu/scanpy`_ from Docker Hub. .. _Docker: https://en.wikipedia.org/wiki/Docker_(software) -.. _fastgenomics/scanpy: https://hub.docker.com/r/fastgenomics/scanpy +.. _gcfntnu/scanpy: https://hub.docker.com/r/gcfntnu/scanpy .. _bioconda: https://bioconda.github.io/ Troubleshooting diff --git a/setup.py b/setup.py index 458fff1899..244084d7a0 100644 --- a/setup.py +++ b/setup.py @@ -62,7 +62,8 @@ def setup_args(config_path=Path("pyproject.toml")): if "develop" in sys.argv: msg = ( "Please use `flit install -s` or `flit install --pth-file` " - "instead of `pip install -e`/`python setup.py develop`" + "instead of `pip install -e`/`python setup.py develop` " + "once https://github.com/pypa/pip/issues/9670 is fixed." ) elif "install" in sys.argv: msg = 'Please use `pip install "$d"` instead of `python "$d/setup.py" install`' From f653c3c873aba229c21f01fae7fe8ec0992c7627 Mon Sep 17 00:00:00 2001 From: Philipp A Date: Thu, 11 Feb 2021 11:27:18 +0100 Subject: [PATCH 4/4] Circumvent new pip check (see pypa/pip#9628) --- .azure-pipelines.yml | 2 ++ .pip-2033.txt | 4 ++++ .readthedocs.yml | 1 + 3 files changed, 7 insertions(+) create mode 100644 .pip-2033.txt diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml index 02970df9e1..2019573954 100644 --- a/.azure-pipelines.yml +++ b/.azure-pipelines.yml @@ -42,6 +42,7 @@ jobs: - script: | python -m pip install --upgrade pip + pip install -r .pip-2033.txt pip install pytest-cov wheel pip install .[dev,doc,test,louvain,leiden,magic,scvi,harmony,scrublet,scanorama] displayName: 'Install dependencies' @@ -102,6 +103,7 @@ jobs: displayName: 'Display installed versions' - script: | + pip install flit flit build twine check dist/* displayName: 'Build & Twine check' diff --git a/.pip-2033.txt b/.pip-2033.txt new file mode 100644 index 0000000000..3c5aa646e0 --- /dev/null +++ b/.pip-2033.txt @@ -0,0 +1,4 @@ +# Flit mangles the +local part of the version spec in compliance with PEP 427, +# but pip 20.3.4 started expecting wheel filenames to contain the local part unmangled. +# https://github.com/pypa/pip/issues/9628 +pip==20.3.3 diff --git a/.readthedocs.yml b/.readthedocs.yml index 58e2487826..de089915c5 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -6,6 +6,7 @@ sphinx: python: version: 3.8 install: + - requirements: .pip-2033.txt - method: pip path: . extra_requirements: