Skip to content
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

Add Versioning Support from version.txt #3140

Open
wants to merge 18 commits into
base: develop
Choose a base branch
from

Conversation

ahnaf-tahmid-chowdhury
Copy link
Contributor

Overview

This pull request introduces a versioning mechanism that utilizes a version.txt file located in the tools folder. Both pyproject.toml and CMakeLists.txt have been updated to read version information from this file, ensuring consistency across the project.

Changes

  • Added version.txt: A new file in the tools directory containing the version string in the format X.X.X or X.X.X-any.

  • Updated pyproject.toml:

    • The version field in pyproject.toml is now set to read the version from version.txt. This enables automatic versioning based on the contents of version.txt.
  • Updated CMakeLists.txt:

    • The CMake configuration has been modified to read the version from version.txt and set the OPENMC_VERSION accordingly.
    • Implemented logic to handle versions with optional suffixes (e.g., -dev, -any), ensuring that the header files use only the main version number without the suffix.

Benefits

  • Consistency: Centralizing version information in a single file (version.txt) ensures that both Python and CMake projects remain in sync.
  • Flexibility: The version can be easily updated by modifying just one file, simplifying version management.

Fixs

@ahnaf-tahmid-chowdhury
Copy link
Contributor Author

Not sure how to resolve this

ERROR: THESE PACKAGES DO NOT MATCH THE HASHES FROM THE REQUIREMENTS FILE. 
If you have updated the package versions, please update the hashes. Otherwise, 
examine the package contents carefully; someone may have tampered with them.
unknown package:
    Expected sha256 f728bb61f43fce850d622ced3b3d51b3116f767685ca4e4e0076f624e2d2307d
         Got        afe0e1873a0a0858a245ccd771066eddc07d20068859f1dd669a002e5dc68a65

pyproject.toml Outdated
@@ -58,6 +58,9 @@ Documentation = "https://docs.openmc.org"
Repository = "https://github.com/openmc-dev/openmc"
Issues = "https://github.com/openmc-dev/openmc/issues"

[tool.setuptools.dynamic]
version = {file = "tools/version.txt"}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this file need locating elsewhere, perhaps in the source code. I'm not sure but perhaps that helps when packaging as I don't think the tools folder is included in the packaging (e.g. conda)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is only required at build time. If it is necessary at runtime, we can put it in the root dir.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It appears that openmc-feedstock uses a specific release tar file, which includes all the folders, including the tools folder.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for answering this

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not an expert, but this doesn't feel like a tools sort of thing. To me it feels like a top level file.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doing it this way means openmc.__version__ still works due to how __version__ is populated.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have stored this file in the tools directory because it is only required during build time. Python's wheel uses it to create the wheel, and CMake uses it to generate the version.h file. Additionally, we can use this file for other purposes. I placed it in that folder to keep the root directory clean. However, if necessary, we can move it to the root directory.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tend to agree that this is more of a root-level file.

@shimwell
Copy link
Member

The CI passed when I rerun a single job just now. So I have re triggered the others and I guess it will pass now. I think the previous failure was unrelated to this CI

@shimwell
Copy link
Member

shimwell commented Sep 26, 2024

CI is all green 🎉

Do you think it is worth adding a version test to the pytests, perhaps something like this
https://github.com/fusion-energy/cad_to_dagmc/blob/main/tests/test_version.py

@ahnaf-tahmid-chowdhury
Copy link
Contributor Author

I have already added something similar to this in the CMakeLists.txt, which will perform a similar task during configuration. I am also using setuptools to get the version number on the Python side, which will cause an error if an improper format is set.

@shimwell
Copy link
Member

This looks good to me, does anyone else want to take a peak. Perhaps @MicahGale

Copy link
Contributor

@MicahGale MicahGale left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Design looks good. However this doesn't seem to be propagating to the C++ side properly in my testing.

I followed the build from source method cmake .. && make. However build/bin/openmc -v was still showing openmc version 0.15.0.

pyproject.toml Outdated
@@ -58,6 +58,9 @@ Documentation = "https://docs.openmc.org"
Repository = "https://github.com/openmc-dev/openmc"
Issues = "https://github.com/openmc-dev/openmc/issues"

[tool.setuptools.dynamic]
version = {file = "tools/version.txt"}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not an expert, but this doesn't feel like a tools sort of thing. To me it feels like a top level file.

@@ -0,0 +1 @@
1.15.1-dev
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is probably beyond the scope of this PR alone, but this isn't PyPA compliant. It should be: 0.15.1.devN (Probably dev1?). Also you accidentally incremented a major release.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setuptools will handle the task for us, so we can continue using the legacy format.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is something setuptools does because it's nice to do; not because it has to. I think changing to PyPA compliant is a small change that would reduce the risk of something breaking in the future. (Honestly I don't think many people would even notice beyond some of the core devs.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PyPA does allow -dev but probably better to use a dot since it's perferred

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. TIL.

pyproject.toml Outdated
@@ -58,6 +58,9 @@ Documentation = "https://docs.openmc.org"
Repository = "https://github.com/openmc-dev/openmc"
Issues = "https://github.com/openmc-dev/openmc/issues"

[tool.setuptools.dynamic]
version = {file = "tools/version.txt"}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doing it this way means openmc.__version__ still works due to how __version__ is populated.

@ahnaf-tahmid-chowdhury
Copy link
Contributor Author

I followed the build from source method cmake .. && make. However build/bin/openmc -v was still showing openmc version 0.15.0.

It seems you have an old version of openmc installed. And you have exported that on your PATH. You can easily review it by calling

which openmc

@MicahGale
Copy link
Contributor

I followed the build from source method cmake .. && make. However build/bin/openmc -v was still showing openmc version 0.15.0.

It seems you have an old version of openmc installed. And you have exported that on your PATH. You can easily review it by calling

which openmc

Oh yep that was my issue. I'm used to python where $PATH does not shadow the current directory.

Copy link
Contributor

@pshriwise pshriwise left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding a suggestion for convenience.

tools/version.txt Outdated Show resolved Hide resolved
pyproject.toml Outdated
@@ -58,6 +58,9 @@ Documentation = "https://docs.openmc.org"
Repository = "https://github.com/openmc-dev/openmc"
Issues = "https://github.com/openmc-dev/openmc/issues"

[tool.setuptools.dynamic]
version = {file = "tools/version.txt"}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tend to agree that this is more of a root-level file.

Copy link
Contributor

@paulromano paulromano left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few immediate thoughts:

  • Some people argue that you shouldn't store version information in files in the first place. If there's a way we can do this that automatically pulls information from git, that would probably be better.
  • If we do go with what you have here, there's one more instance of hardcoding of the version in docs/source/conf.py.

@MicahGale
Copy link
Contributor

MicahGale commented Sep 27, 2024

  • Some people argue that you shouldn't store version information in files in the first place. If there's a way we can do this that automatically pulls information from git. If that case can be addressed I really prefer using git tag.

@paulromano: @gonuke brought up some good points, that there are use cases for when the source code may be used while detached from git. I'm not sure right now of a work-around for that case using git based methods, which I generally agree would be the ideal solution.

If we do go with what you have here, there's one more instance of hardcoding of the version in docs/source/conf.py.

I'd recommend that @ahnaf-tahmid-chowdhury go with using a importlib.... call in this file no matter what because that will be agnostic to however python retrieves version information.

@ahnaf-tahmid-chowdhury
Copy link
Contributor Author

I have added the get_version_info function to extract the version info, but I am unsure what working directory Read the Docs is using. For now, I am assuming it is using docs/source/ as the working directory.

Recently, I noticed @MicahGale's comment on this. We can use importlib, but again, I need to understand how Read the Docs processes this. If it runs the conf.py file before installing OpenMC, it will fail.

@ahnaf-tahmid-chowdhury
Copy link
Contributor Author

It seems docs buils are passing https://readthedocs.org/projects/openmc/builds/25766475/

We can use importlib.metadata.version, but we still need to use the get_version_info function as there are two var.

@gonuke
Copy link
Contributor

gonuke commented Oct 8, 2024

We definitely came here, @paulromano , to get broader perspective on this issue. I definitely like the elegance of git being a single source of truth, but worry about folks who build from tarballs (e.g. those generated automatically by GitHub upon release) rather than clones. Do we ignore them? Or do we find a way to make that work, too?

@MicahGale
Copy link
Contributor

@gonuke one thing I thought about is that setuptools-scm will create a _version.py file. As part of the GH release process a source tar ball with a version file could be included. I think building from a source tar ball for a specific release would be a lot more common than from a specific branch.

@ahnaf-tahmid-chowdhury
Copy link
Contributor Author

An additional note: If we use setuptools-scm, when someone installs OpenMC from a tarball, it will build a version labeled 0.0.0.

@MicahGale
Copy link
Contributor

@ahnaf-tahmid-chowdhury Good point. Do you want to try and see if we could make a CI release that would embed a version file in a release tar ball from setuptools-scm?

@ahnaf-tahmid-chowdhury
Copy link
Contributor Author

For this, we may need to use a workflow to build OpenMC that will create the version file. Once done, it will push the updated commit to the develop branch. We can use any existing workflow, like this one, and it will only run if the PR gets merged. Let me know if I should proceed with that approach.

@MicahGale
Copy link
Contributor

No this is a bad idea. _version.py should never be in git. What I was thinking was as part of the release process having python -m build . create the version file. Create a complete source tar ball which include _version.py and then upload that to the GH release as an artifact.

@ahnaf-tahmid-chowdhury
Copy link
Contributor Author

We are currently working on PR #3087, which will create wheel (.whl) artifacts after a release. Your approach is good, but GitHub automatically creates its own tarball with each release. So, in the end, we will be releasing multiple tarballs. And, I am unfamiliar with resolving that.

Copy link
Contributor

@MicahGale MicahGale left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes look good, but testing is still needed to ensure all edge cases are handled. See my previous comment on some of these.

@MicahGale
Copy link
Contributor

Let me explain how the metadata works. Whenever we install something with pip, it always comes with a package.dist-info folder that contains a METADATA file, which stores the version number. So, instead of relying on _version.py, we can rely on that METADATA file, as they will be the same. We don't need the setuptools_scm, it is a buildtime dependency.

I dug into this a little bit more. One clarification is needed: importlib.metadata will only get the version of OpenMC that is installed. So if it hasn't been installed or a dev version is being used that is different from the installed version this could lead to issues. Overall I don't think that it's too important of an edge case.

@ahnaf-tahmid-chowdhury
Copy link
Contributor Author

ahnaf-tahmid-chowdhury commented Oct 24, 2024

  1. ensure that cmake always builds with the same version as setuptools_scm provides

As I mentioned, it is quite hard to achieve here, or we may need to change the OpenMC header so that it can work with strings. After that, we need to implement the setuptools_scm format, as git describe does not follow the setuptools_scm format.

setuptools_scm format
0.15.0.dev144+gddb6c96ef

git describe format
0.15.0-144-gddb6c96ef

For now, if the format is not supported, the build will fail. So, the test is actually implemented during the configuration stage.

  1. ensure that the python api gets a version in all circumstances

I think we can rely on setuptools_scm and let it handle this for us. Once the wheel is created, Python's built-in library importlib.metadata can easily read the version info from the METADATA. We may not need to write a dedicated test script for that, as they may have their own tests in their repository. However, for consistency, we can limit the version of setuptools_scm if it is recommended.

  1. Esnure that a git archive has a version attached to it.

I believe this is an initial-time test that I have already run on my branch while releasing a version. Creating a dedicated test for this may consume resources and increase the time required for processing tests. I think there is no need to test this until we modify the .git_archival.txt. However, any suggestions on this are welcome.

@ahnaf-tahmid-chowdhury
Copy link
Contributor Author

I dug into this a little bit more. One clarification is needed: importlib.metadata will only get the version of OpenMC that is installed. So if it hasn't been installed or a dev version is being used that is different from the installed version this could lead to issues. Overall I don't think that it's too important of an edge case.

It is always recommended to install Python packages in editable mode for developers, and this is also mentioned in the OpenMC developer docs. So, once OpenMC is installed, even in development mode, it comes with the METADATA file.

@ahnaf-tahmid-chowdhury
Copy link
Contributor Author

Yes, developers may need to periodically update the OpenMC installation; otherwise, the METADATA will always contain the last installed version.

I think we can add logic where, if someone tries to use OpenMC directly from the source, it will prompt them with a message like, 'Hey, please install OpenMC and run it outside the source root directory.' Let me know if this approach is feasible.

@MicahGale
Copy link
Contributor

I think the issue though is should it just return a version number, or the version number of the code that you are running right now always. The more I think about it needs to always return the version of what is actively running for trace-ability.

@ahnaf-tahmid-chowdhury
Copy link
Contributor Author

Even if we include the _version.py file, it will only be generated after installing OpenMC, and the only way to update the _version.py file requires reinstalling OpenMC. Therefore, if we use setuptools_scm, we could rely on the METADATA. Alternatively, we could revert to the previous approach of using a hard-coded version file.

@ahnaf-tahmid-chowdhury
Copy link
Contributor Author

Please note that OpenMC is already using the METADATA to extract version information, so I haven’t changed anything in that regard. I think @paulromano or @pshriwise might have some insights on how to proceed, or we are good to go.

Copy link
Contributor

@MicahGale MicahGale left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pending @paulromano @pshriwise decision on the meta-data question.

@ahnaf-tahmid-chowdhury
Copy link
Contributor Author

We are planning to adopt the OpenMC version format in PyNE through the PR #1550. Currently, we are waiting for this PR to be merged. It would be greatly appreciated if we continue making progress on this.

Copy link
Contributor

@paulromano paulromano left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the delay on this PR @ahnaf-tahmid-chowdhury and thanks for all your work on it. I think I'm on board for moving forward with this approach. The one thing that appears to need fixing is that the release version should be incremented for the "in development" version. This is what setuptools_scm does internally. Matching that behavior shouldn't be too difficult from CMakeLists.txt.

@pshriwise Do you have any further thoughts on this PR since you had requested changes before?

@pshriwise
Copy link
Contributor

pshriwise commented Jan 10, 2025

I'm on board with this as well. One detail that remains to be addressed is how the output version in the OpenMC header will be managed at runtime. Right now we get a nice -dev suffix in the output if the OpenMC executable isn't versioned. This is pretty helpful in providing context for user questions and it would be nice to maintain it if possible.

Right now the appearance of this suffix is hardcoded in the version.h.in file.

https://github.com/openmc-dev/openmc/blob/51f0e6f35039a61925477033a8eea4b2c871a728/include/openmc/version.h.in#L13C1-L14C1

@shimwell
Copy link
Member

Just spotted an easy to fix conflict so fixed it up to keep this branch easy to merge. Delighted to hear there is general support for this

@ahnaf-tahmid-chowdhury
Copy link
Contributor Author

@paulromano, @pshriwise,

This is the current configuration:

openmc -v
OpenMC version 0.15.0-dev
Commit hash: 66efc3a8e63a47128a306257cd6699d987fadf3c
Copyright (c) 2011-2025 MIT, UChicago Argonne LLC, and contributors
MIT/X license at <https://docs.openmc.org/en/latest/license.html>
Build type:            Debug
Compiler ID:           GNU 11.4.0
MPI enabled:           no
Parallel HDF5 enabled: no
PNG support:           yes
DAGMC support:         no
libMesh support:       no
MCPL support:          yes
NCrystal support:      no
Coverage testing:      yes
Profiling flags:       no
UWUW support:          no

You will also get commit hash information even if you haven’t used the git repository or don’t have git installed.

@paulromano
Copy link
Contributor

@ahnaf-tahmid-chowdhury Thanks for the updates. There is still one outstanding request from above:

The one thing that appears to need fixing is that the release version should be incremented for the "in development" version. This is what setuptools_scm does internally. Matching that behavior shouldn't be too difficult from CMakeLists.txt.

@ahnaf-tahmid-chowdhury
Copy link
Contributor Author

I think you're suggesting adding the number of commits above the stable release, like 0.15.0-dev+123. If that's not the case, could you please elaborate? It would help to see an example of the desired output.

Currently, the version appears like this:

OpenMC version 0.15.0-dev
Commit hash: {commit hash}

I believe you're proposing something like this:

OpenMC version 0.15.0-dev+{number of commits}
Commit hash:  {commit hash}

For reference, setuptools_scm formats it as openmc-0.15.0.dev{number of commits}.

Could you please confirm if this is what you have in mind, or clarify further?

@paulromano
Copy link
Contributor

Sorry, to clarify further, what I mean is that if the last tagged release is 0.15.0 and there are commits past that, it should increment the release number so that it shows the 0.15.1-dev. This is what we currently do manually, and it also matches the behavior of setuptools_scm. If you run python -m setuptools_scm on your branch (which already contains a v0.15.1 tag), you'll see that it gives:

$ python -m setuptools_scm
0.15.2.dev42+g2b47355f2

This means that CMakeLists.txt would be responsible for incrementing the release number if there are changes past the last tag.

@MicahGale
Copy link
Contributor

MicahGale commented Jan 15, 2025

Sorry, to clarify further, what I mean is that if the last tagged release is 0.15.0 and there are commits past that, it should increment the release number so that it shows the 0.15.1-dev. This is what we currently do manually, and it also matches the behavior of setuptools_scm. If you run python -m setuptools_scm on your branch (which already contains a v0.15.1 tag), you'll see that it gives:

$ python -m setuptools_scm
0.15.2.dev42+g2b47355f2

This means that CMakeLists.txt would be responsible for incrementing the release number if there are changes past the last tag.

I would like to bring up this discussion: #3140 (comment). I still think it would be easiest to just call setuptools_scm rather than trying to reimplement it. Yes this would add build dependencies, but I feel like the situation in which a user wants to build from scratch but doesn't have the python dependencies is a bit contrived.

@ahnaf-tahmid-chowdhury
Copy link
Contributor Author

Update

Run openmc -v
OpenMC version 0.15.0-dev115
Commit hash: 375dec94e99afd6c382827b4a750e47eddf93b4c

We can shift to setuptools_scm and make it a core build dependency, but we still need to rely on CMake variables since these values need to be written into the version.h file. Let me know if this method is good to go, or if we should fully transition to setuptools_scm.

@paulromano
Copy link
Contributor

@ahnaf-tahmid-chowdhury It still doesn't look like there is logic to bump the release number (the second "0" in "0.15.0"). It should show 0.15.1-dev115, not 0.15.0-dev115 to match the behavior of setuptools_scm because 0.15.0 is the most recent release.

@ahnaf-tahmid-chowdhury
Copy link
Contributor Author

Thanks for the explanation. I apologize for the misunderstanding. The release number increment for dev versions is important and makes sense. I have added a logic where in dev mode cmake will increment the release number by 1.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants