flit icon indicating copy to clipboard operation
flit copied to clipboard

Q: can flit take care of documentation and test suite?

Open kloczek opened this issue 4 years ago • 10 comments

I've jsut started working on package as rpm package https://github.com/pexpect/ptyprocess/. Tis module uses flit. In the source tree is as well documentation and test suite however flit build does not produce sdist tar ball without those two directories. I cannot find anything in flit documentation about documentation and test suite description.

Q: Is it possible to describe in project.toml/setup.cfg documentation and test suite? If yes: how to add necessary description in project.toml/setup.cfg? If not: is it possible to generate setup.py but which will be importing setuptools instead distutils.core?

If that woud be possible such setup.py would be possible to use python setup.py build_sphinx

kloczek avatar Aug 11 '21 14:08 kloczek

Normally, everything which is checked into git should be included in the sdist made by flit build. That should include tests and docs (source files).

Flit does not concern itself with running tests or building documentation, and it doesn't provide any extension points to do those things. I've never seen the attraction of running tools like Sphinx through setup.py, as if it was some ugly Makefile equivalent.

Please don't rely on the generated setup.py in sdists. It's there so old versions of pip can install packages made by Flit automatically, and it's going to go away fairly soon now that PEP 517 is well adopted.

takluyver avatar Aug 12 '21 13:08 takluyver

Flit does not concern itself with running tests or building documentation, and it doesn't provide any extension points to do those things. I've never seen the attraction of running tools like Sphinx through setup.py, as if it was some ugly Makefile equivalent.

python setup.py build_sphinx -b <format> is still most frequently used way of generating documentation. I have rpm macro %py3_build_sphinx_man which looks like that:

[tkloczko@barrel SPECS]$ rpm -E %py3_build_sphinx_man
\
        PBR_VERSION=%{version} \
        SETUPTOOLS_SCM_PRETEND_VERSION=%{version} \
        SPHINXOPTS="-j48" \
        /usr/bin/python3 setup.py build_sphinx -b man --build-dir build/sphinx

Which I'm usin g in almost half of my pythom packaginfg procedures:

[tkloczko@barrel SPECS]$ grep %py3_build_sphinx_man python-* | wc -l; ls -1 python-*|wc -l
230
577

and still +100 modules in that set can be enriched to add build and install documentation that way.

Quoting from gawk info page: "Documentation is like sex. Wen it is good it is really good. When it is bad it is better than nothing" :)

It would be good if flit like setuptools would provide possibility to pug in extensions like it has that module. setuptools build_sphinx command is available when setuptools and sphinx are installed and it is very useful because it allows do not care where in source tree is sphinx copy.py file and as well allows store results of building documentation in exact location. Only missing bit in that duet is that setuptools install command does not know anything about generated documentation to install it. It would be good if on flit on build would allow choose documentation format and according to what have bee chosen install for example man pages in standard location. Without that setuptools will still have more actual useful functionalities than flit.

kloczek avatar Aug 12 '21 14:08 kloczek

From point of test suite bits. Sometimes test suite needs to be executed in venv or wrapped over tox. Sometime still it is python setup.py test, and sometimes it needs to be sued one of many test suit frameworks like pytest, unitest, nose, ntox, nox .. All that details about testing methodology should be IMO possible to describe somehow in project.toml/setup.cfg.

kloczek avatar Aug 12 '21 14:08 kloczek

I'm not arguing with the need for tests or docs. But I don't see them as part of packaging. If you want to try to push standard ways for projects to define how to run their tests or build their docs, by all means do so. You can write your own tool to be the entry point, and try to persuade people to use it. Or you can propose a PEP for official standard entry points for these things. It can use information stored in pyproject.toml if you like (any project foo on PyPI can define a [tool.foo] table for other projects to use). I don't see any reason to try to do that within Flit.

takluyver avatar Aug 12 '21 15:08 takluyver

Really it would be nice if flit would be able to handle sphinx integration in which is possibe to add in setyp.cfg https://www.sphinx-doc.org/en/master/usage/advanced/setuptools.html Without that flit is now nothing more than just plain archivig tool which adds some checksums in .dist-info metadata :/

kloczek avatar Aug 18 '21 21:08 kloczek

From my point of view, insisting that a packaging tool should have a way to build documentation is like saying that a toaster should be able to boil water - boiling water is useful, but you get a kettle for that and use it alongside the toaster. In the same way, Sphinx is great, you can use it alongside Flit, but I don't see any need to connect them together. If you want to build docs, run make -C doc html, or the equivalent sphinx-build command. What do you gain from running some hypothetical flit sphinx command instead?

I'm not interested in the fact that it's possible with setuptools, because I'm not trying to copy setuptools.

Your argument above seems to amount to "it should be possible to build docs without knowing the path to the docs folder". Which is fine, but all the Sphinx setuptools integration does is look for a folder called either doc or docs. So if that's what you need, you can write about 5 lines of Python or shell code, no need to integrate with Flit, and it will work regardless of whether a package uses Setuptools, Flit, Poetry, Enscons, or anything else.

takluyver avatar Aug 19 '21 16:08 takluyver

Analogy is not tool of proving thesis. It can only make easier to understand some aspect which is hard to understand straight. Issue is that setuptools module it is not packaging but build/install/testing framework. Part of the processes which is possible to define using setuptools is generate wheel or sdist archives. If flit, poetry want to replace setuptools it cannot be dine selectively by provide only achieving functionality. Without taking over these areas flit or poetry never would be able to replace setuptools. I'm not aware of any issues of the setuptools on area of generating wheel or sdists archive. More .. looking on all my currently cleaned python modules I see that ((% of those modules packaging procedures are able successfully use setuptools as build/install framework.

[tkloczko@barrel SPECS]$ grep -wl %py3_build python-* |wc -l; ls -1 python-*|wc -l
587
591

In that situation all what can be used is so called McGyver rule "If it ain't broke, don't fix it."

kloczek avatar Aug 22 '21 14:08 kloczek

If you want to build docs, run make -C doc html, or the equivalent sphinx-build command. What do you gain from running some hypothetical flit sphinx command instead?

Issue is that already ~halt of my packages is using setuptools<>sphinx integration and flit cannot provide anything on that area to standardise such processes.

[tkloczko@barrel SPECS]$ grep -w %py3_build_sphinx_man python-* |wc -l; ls -1 python-*|wc -l
256
591
[tkloczko@barrel SPECS]$ rpm -E  %py3_build_sphinx_man
\
        PBR_VERSION=%{version} \
        SETUPTOOLS_SCM_PRETEND_VERSION=%{version} \
        SPHINXOPTS="-j48" \
        /usr/bin/python3 setup.py build_sphinx -b man --build-dir build/sphinx

Result of that is:

[tkloczko@barrel SPECS]$ man python-<tab><tab>
Display all 248 possibilities? (y or n)
python-amqp                               python-httplib2                           python-path                               python-sos
python-anyiodoc                           python-hypercorn                          python-pathspec                           python-sphinx-argparse
python-anytree                            python-hyperframe                         python-pillow                             python-sphinx-click
python-argcomplete                        python-hyperlink                          python-platformdirs                       python-sphinxcontrib-asyncio
python-arrow                              python-hypothesis                         python-pluggy                             python-sphinxcontrib-autoprogram
python-asgi                               python-ifaddr                             python-polib                              python-sphinxcontrib-bibtex
python-aspectlib                          python-importlib-metadata                 python-prb                                python-sphinxcontrib-httpdomain
python-astor                              python-inflect                            python-priority                           python-sphinxcontrib-programoutput
python-astroid                            python-ipykernel                          python-productmd-compose                  python-sphinxcontrib-trio
python-async_generator                    python-ipythonparallel                    python-productmd-composeinfo              python-sphinxcopybutton
python-atomicwrites                       python-itsdangerous                       python-productmd-discinfo                 python-sphinxext-opengraph
python-attrs                              python-jaraco-classes                     python-productmd-images                   python-sphinx-inline-tabs
python-augeas                             python-jaraco-collections                 python-productmd-rpms                     python-sphinx-removed-in
python-autodocsumm                        python-jaraco-envs                        python-productmd-terminology              python-sphinx_rtd_theme
python-babel                              python-jaraco-functools                   python-productmd-treeinfo                 python-sphinx-tabs
python-backcall                           python-jaraco.itertools                   python-prompt_toolkit                     python-sphinx-typlog-theme
python-backports.entry-points-selectable  python-jaraco-packaging                   python-ptyprocess                         python-sphobjinv
python-benchmark                          python-jaraco-path                        python-purl                               python-sqlparse
python-betamax                            python-jaraco-text                        python-py                                 python-stdlib-list
python-billiard                           python-jedi                               python-pyasn1                             python-stem
python-bleach                             python-Jinja                              python-pybtex                             python-sure
python-blinker                            python-jinja2_pluralize                   python-pybtex-docutils                    python-sybil
python-boto3                              python-jmespath                           python-pycodestyle                        python-systemd
python-botocore                           python-jsonschema                         python-pydocstyle                         python-tempora
python-bottle                             python-jupyter_client                     python-pyfakefs                           python-terminado
python-breathe                            python-jupyter_core                       python-pyftpdlib                          python-testpath
python-cachetools                         python-jupytext                           python-pygal                              python-test_server
python-cffi                               python-kiwi                               python-pygments                           python-testtools
python-characteristic                     python-kombu                              python-pyhamcrest                         python-tidy
python-chardet                            python-lark                               python-pylama                             python-tinycss2
python-cheroot                            python-latexcodec                         python-pylint                             python-toolz
python-click                              python-lazy-object-proxy                  python-pymeeus                            python-tornado
python-click-log                          python-libevdev                           python-pynacl                             python-traitlets
python-contextlib2                        python-linkify-it-py                      python-pyopenssl                          python-transaction
python-convertdate                        python-lockfile                           python-pyrad                              python-trio
python-coveragepy                         python-lxml                               python-pyrsistent                         python-trustme
python-coveralls                          python-mako                               python-pyscss                             python-twisted
python-cppy                               python-markupsafe                         python-pytest                             python-uritemplate
python-cssselect2                         python-mdit-py-plugins                    python-pytest-cov                         python-urllib3
python-cython                             python-metaextract                        python-pytest-regressions                 python-validators
python-dateutil                           python-mistune                            python-pytest-runner                      python-vine
python-dictdiffer                         python-mock                               python-pytest-trio                        python-virtualenv
python-dpkt                               python-more-itertools                     python-pytest-xprocess                    python-waitress
python-dulwich                            python-msgpack                            python-python-sphinx-contribspelling      python-wcwidth
python-elementpath                        python-multidict                          python-pyudev                             python-webcolors
python-evdev                              python-multipledispatch                   python-pyxattr                            python-webencodings
python-eventlet                           python-mypy                               python-pyxdg                              python-webob
python-execnet                            python-myst-parser                        python-requests-mock                      python-websocket-client
python-faker                              python-nbclient                           python-requests_toolbelt                  python-websockets
python-fields                             python-nbformat                           python-rich                               python-webtest
python-flake8                             python-netaddr                            python-rsa                                python-werkzeug
python-flask                              python-nose2                              python-rst.linker                         python-wheel
python-flit                               python-notebook                           python-scons                              python-Whoosh
python-fonttools                          python-numpydoc                           python-scripttest                         python-wrapt
python-gcovr                              python-olefile                            python-selenium                           python-WSGIProxy2
python-gidocgen                           python-openstackdocstheme                 python-semantic-version                   python-wsproto
python-gitdb                              python-outcome                            python-service-identity                   python-xmlschema
python-gitpython                          python-paramiko                           python-setuptools                         python-yamlloader
python-greenlet                           python-parso                              python-six                                python-yarl
python-h2                                 python-parver                             python-smartypants                        python-zeroconf
python-hacking                            python-paste                              python-smmap.tex                          python-zipp
python-hpack                              python-paste-deploy                       python-sniffio                            python-zope-event

In case of generating man page for flit module I was not able to use that approach. Here is part of my python-flit.spec

%build
cd flit_core
FLIT_NO_NETWORK=1 \
%__python3 -Bm build --no-isolation
cd -

PYTHONPATH=$PWD/flit_core \
%__python3 -Bm build --no-isolation --skip-dependency-check

sphinx-build -b man -d %{name} doc .

%install
%py3_install_wheel *.whl
cd flit_core
%py3_install_wheel *.whl
cd -

%__install *.3 -Dt %{buildroot}%{_mandir}/man3

%check
%pytest

Exactly the same in case of using setuptools<>sphinx integration looks like below

%build
%py3_build
%py3_build_sphinx_man

%install
%py3_install

%__install build/sphinx/man/*.3 -Dt %{buildroot}%{_mandir}/man3

%check
%pytest

In other words using flit or build does not make anything simpler but only more complicated.

kloczek avatar Aug 22 '21 15:08 kloczek

~halt of my packages is using setuptools<>sphinx integration

That's a choice that you've made. Those projects can equivalently be built with Sphinx directly as well.

pradyunsg avatar Aug 31 '21 10:08 pradyunsg

I agree with Thomas that I don‘t see a good reason why a new packaging tool would concern itself with running unrelated tasks.

Long version:

distutils was a build tool and an install tool, setuptools added dependencies and download. At one point, some python devs liked to use setup.py as a task runner for all dev tools, such as running tests or building and uploading docs. It was not universally used in that way, and today that is a mostly obsolete practice (meaning not recommended in guides and not used by devs, even though it is used in some pipelines like the one you’re describing).

About tests: I don’t know how popular python setup.py test was in the end. I guess one reason to use setup.py was that it was aware of the location of the code; I suspect this was always more useful as an automation command (you don’t have to know what to install for tests and what to run) than as a command run by devs (simpler and faster to run the real test command, and gives you options, help, completion, etc). tox has mostly taken over the role of universal test runner (and in a lesser extent, is used by projects as a task runner for development too), and there is no benefit in mixing packaging tool and testing tool.

About docs: the benefits are even smaller there; the build_docs command was not doing much and had even less relation to the packaging options, I think it’s the upload_docs command that was really attractive to people. I think this was created because Sphinx docs were becoming popular and if you already had the knowledge of writing setuptools command, it seemed easy to write one to zip docs and send them over HTTP, so one distribute dev did that. Now we have replaced packages.python.org with readthedocs and other hosting systems, and building and uploading docs uses doc tooling.

I do sympathize with OS packagers that have developed tooling over the last decades to handle hundred of upstream packages. I understand it’s nice if you can have a uniform interface and let your generic scripts run python setup.py test or python setup.py build_sphinx. But the packaging tools have changed (for the better!), setup.py is on its way out, and there is no universal interface that lets us define once that a project is using poetry or flit so we can run poetry build_sphinx or flit test. Downstream packaging scripts need to be configured to run build-sphinx param -B param -C etc or pytest --no-network.

merwok avatar Aug 31 '21 14:08 merwok

I'm going to close this now. I hope that you've found satisfactory ways to work with packages that don't have setup.py files.

I think there could still be an interesting conversation about standardising a test runner hook so people working with many different packages can test them all without needing to know about each project's test setup. But Flit's issue tracker isn't the place for that - the packaging category on discuss.python.org is the best place I can think of to start.

[I don't want to start that discussion here, but I imagine the main question is what the hook would be expected to do. Run tests in the current environment, like invoking pytest? Or set up testing environments like tox & nox? Is it allowed to fetch dependencies from PyPI? Should it check multiple Python versions? Is it meant to test a source tree of the package, building it if needed, or a package that was already built and installed? I'm saying this to set expectations: if you want to come up with a proposal for this, expect a lengthy discussion where it's hard to reach a consensus.]

takluyver avatar Jan 28 '24 11:01 takluyver