-
Notifications
You must be signed in to change notification settings - Fork 205
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
🔧 Move to flit for PEP 621 compliant package build #5312
Conversation
Codecov Report
@@ Coverage Diff @@
## develop #5312 +/- ##
========================================
Coverage 82.02% 82.02%
========================================
Files 533 533
Lines 38255 38255
========================================
Hits 31374 31374
Misses 6881 6881
Flags with carried forward coverage won't be shown. Click here to find out more. Continue to review full report at Codecov.
|
If you are particularly interested in packaging developments, you can also read: https://blog.ganssle.io/articles/2021/10/setup-py-deprecated.html |
another note: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great! I was looking forward to an overhaul of our build setup for quite a while.
One comment regarding flit. I agree that this looks very promising and since adopting flit does not have any impact on the user installation flow, absolutely zero reservations. And if it is a sensible and well maintained tool, I hope that it gains traction. But the fact that it is now maintained under umbrella of the Python Packing Authority is not necessarily a sufficient indicator for success, because so is pipenv.
I have a few comments, suggestions, and one change request.
As mentioned, it does not really matter that much if it did fail, because it is PEP 621 compliant (this is different to pipenv, which has no such compliance backing), so you simply swap out the build tool for another; only having to change two lines in |
Co-authored-by: Carl Simon Adorf <carl.simon.adorf@gmail.com>
Yes, indeed, hence no reservations.
(I'm not going to bet against that.) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @chrisjsewell . If these changes indeed do not change the impact of the install procedure for users, then this is fine with me as well. I have three questions though.
|
||
|
||
def get_version_from_module(content: str) -> str: | ||
"""Get the __version__ value from a module.""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I take it that you employ this (convoluted) way of reading the version number because you cannot import it normally? Instead of this approach, is there no simple way to make the package importable so we can just do
import aiida
version = aiida.__version__
At the very least, I think it would be useful to have a comment here explaining why this approach is necessary and the import way doesn't work or is not desirable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wouldn't call this approach particularly convoluted; I would say having to go through the whole process of installing/importing the package is convoluted, just to read the version from a file 🤷
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feel free to create a suggestion
for what the docstring should be (and I'll happily merge), but I'm not adding one myself, because I don't feel it needs it, since this IMO is the canonical way to retrieve the __version__
attribute (it is how both setuptools and flit do it)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If generating an abstract syntax tree, parsing it element by element just to find the one string that defines the version number is not convoluted, then I don't know what is. I can see the point that having to install it is likewise a lot of work just to get the version, but at least it is very understandable and readable. One would think that there should be an easier way to do this... But in the absence of that, guess this is fine to keep
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sphuber It is convoluted, but to my understanding, one main motivation for the overall change is to make the project metadata and build definition more declarative, so needing to install and import the package runs exactly counter that. I believe that we can reduce complexity by either parsing the module directly with a regex or by moving to a different version specification like I suggested in my comment. My recommendation would be to move forward and avoid bikeshedding on this issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I already agreed to keeping this and move forward. Still, the suggestion to add a comment explaining why this is being done doesn't seem like a big or weird ask. Even if this may be the standard, I doubt many developers are aware of this and they will almost certainly wonder why it has to be (or look) so complicated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would note, that on the next line, it says: # adapted from setuptools/config.py
, but yeh honestly this is just a very simple check (that wasn't even here a year ago) to make sure the release tag is consistent with the package version
|
||
if __name__ == '__main__': | ||
parser = argparse.ArgumentParser() | ||
parser.add_argument('GITHUB_REF', help='The GITHUB_REF environmental variable') | ||
parser.add_argument('SETUP_PATH', help='Path to the setup.json') | ||
parser.add_argument('INIT_PATH', help='Path to the aiida/__init__.py file') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this deserve an option? Are we ever going to change the location? Would simplify this to being hardcoded
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok removed 👍
"core.arithmetic.multiply_add" = "aiida.workflows.arithmetic.multiply_add:MultiplyAddWorkChain" | ||
"core.arithmetic.add_multiply" = "aiida.workflows.arithmetic.add_multiply:add_multiply" | ||
|
||
[tool.flit.module] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How and where is the functionality of the MANIFEST.in
taken care off?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
flit already handles all this out-the-box, see e.g. https://flit.readthedocs.io/en/latest/pyproject_toml.html#sdist-section.
If you want to check what is included in the sdist and wheel, feel free to try running flit build
and exploring the distributions yourself. I've already done this, though, and can confirm that all package_data
is correctly in the wheel and sdist.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How does it know what files to include though? Does it simply include all files within the aiida
folder? The docs you link say:
When you use flit build or flit publish, Flit builds an sdist (source distribution) tarball containing the files that are checked into version control (git or mercurial).
That seems to suggest to me that it would also include the tests
folder for example. Is that true? Because I don't think that is desirable. This would make the package unnecessarily heavy, and we intentionally moved the tests outside of the package such that they don't have to be shipped with the build.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well firstly, just below this line you'll see:
[tool.flit.sdist]
exclude = [
"docs/",
"tests/",
]
So currently, the docs
and tests
are not added to the sdist
anyway.
But actually, this does not really matter, since both the sdist AND wheel are built/uploaded to PyPI.
The wheel (see https://www.python.org/dev/peps/pep-0491/) is the thing you actually install with pip (if available from pypi), and that does not contain anything from outside the module:
(there is some extra discussion about this in aiidateam/aiida-registry#201)
cheers guys! |
- Move to flit for PEP 621 compliant build (see also aiidateam/aiida-core#5312) - Remove `setup.py`,` setup.json`, `MANIFEST.in`, `check_version.py`, and `.coveragerc` - Set `requires-python = ">=3.7"` - Move from `yapf` to `black` for code formatting - Add `isort` and `pyupgrade` pre-commit hooks - Move documentation theme from `sphinx-rtd-theme` to `furo` - Add `tox` configuration (in `pyproject.toml`) Note the setuptools `reentry_register` hook is no longer possible, although reentry is anyway removed in AiiDA v2.
https://github.com/pypa/flit is now officially part of the packaging organization.
It is a PEP 621 (
pyproject.toml
only build specification) and, since v3.4, PEP 660 (pip install --editable .
builds withpyproject.toml
only) compliant build tool for pure-python packages.Restricting itself to pure-python packages (which is all we need), has meant it has been able to progress a lot more rapidly than
setuptools
, which is stuck supporting legacy issues and more complex builds (e.g. compiling C extensions) (see pypa/setuptools#1688).I believe flit will become the de-facto builder for new (simple) packages, and anyhow because it is PEP compliant, you can simply swap it out at any point.
Very simply, I have just migrated everything from
setup.json
intopyproject.toml
, and removedsetup.json
,setup.py
andMANIFEST.in
.The package version is sourced directly from
aiida/__init__.py
, and so there is no need for any consistency checks. (also with aiidateam/aiida-registry#201, these versions will now still show in the aiida-registry)Notes:
pip install -e .
, this requires pip v21, but then it "just works"all
extra, and the logic to appendrest
+atomic_tools
to thetests
anddocs
extras. This was in thesetup.py
, but anyway I feel it was unintuitive.