Skip to content

Commit

Permalink
Dynamically determine the version of the pip package. (pytorch#3475)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: pytorch#3475

Use the logic from
https://github.com/pytorch/torcharrow/blob/15a7f7124d4c73c8c541547aef072264baab63b7/setup.py#L21
to play nicely with the pytorch ecosystem CI build environment.

Test Plan:
```
$ ./install_requirements.sh
...
Successfully installed executorch-0.2.0a0+1ba292a

$ python
>>> from executorch import version
>>> version.__version__
'0.2.0a0+1ba292a'
>>> version.git_version
'1ba292ae4071c4eede8ea14e8f10ffd973a085b4'
>>> ^D

$ grep Version /home/dbort/.conda/envs/executorch-tmp/lib/python3.10/site-packages/executorch-0.2.0a0+1ba292a.dist-info/METADATA
Metadata-Version: 2.1
Version: 0.2.0a0+1ba292a
```

Temporarily commented out the call to `setup()` in `setup.py` then
imported it.

```
$ python
>>> from setup import Version
>>> Version.string
'0.2.0a0+1ba292a'
>>> Version.git_hash
'1ba292ae4071c4eede8ea14e8f10ffd973a085b4'
>>> Version.write_to_python_file("/tmp/version.py")
>>> ^D
$ cat /tmp/version.py
from typing import Optional
__all__ = ["__version__", "git_version"]
__version__ = "0.2.0a0+1ba292a"
git_version: Optional[str] = '1ba292ae4071c4eede8ea14e8f10ffd973a085b4'
```

```
$ BUILD_VERSION="5.5.5" python
>>> from setup import Version
>>> Version.string
'5.5.5'
```

imported-using-ghimport

Reviewed By: mikekgfb

Differential Revision: D56857484

Pulled By: dbort

fbshipit-source-id: c9af223c591fed6fb5307fa5ea8c2371dd38f4d8
  • Loading branch information
dbort authored and facebook-github-bot committed May 2, 2024
1 parent f8a4d8c commit b5dd169
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 4 deletions.
8 changes: 4 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ build-backend = "setuptools.build_meta"

[project]
name = "executorch"
# TODO(dbort): Use setuptools-git-versioning or setuptools-scm to get the
# version from the git branch state. For now, use a version that doesn't look
# like a real release.
version = "0.2.1.dev0+unknown"
dynamic = [
# setup.py will set the version.
'version',
]
# Python dependencies required for development
dependencies=[
"expecttest",
Expand Down
76 changes: 76 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
from distutils import log
from distutils.sysconfig import get_python_lib
from pathlib import Path
from typing import Optional

from setuptools import Extension, setup
from setuptools.command.build import build
Expand Down Expand Up @@ -89,6 +90,77 @@ def llama_custom_ops(cls) -> bool:
return cls._is_env_enabled("EXECUTORCH_BUILD_CUSTOM_OPS_AOT", default=True)


class Version:
"""Static properties that describe the version of the pip package."""

# Cached values returned by the properties.
__root_dir_attr: Optional[str] = None
__string_attr: Optional[str] = None
__git_hash_attr: Optional[str] = None

@classmethod
@property
def _root_dir(cls) -> str:
"""The path to the root of the git repo."""
if cls.__root_dir_attr is None:
# This setup.py file lives in the root of the repo.
cls.__root_dir_attr = str(Path(__file__).parent.resolve())
return str(cls.__root_dir_attr)

@classmethod
@property
def git_hash(cls) -> Optional[str]:
"""The current git hash, if known."""
if cls.__git_hash_attr is None:
import subprocess

try:
cls.__git_hash_attr = (
subprocess.check_output(
["git", "rev-parse", "HEAD"], cwd=cls._root_dir
)
.decode("ascii")
.strip()
)
except subprocess.CalledProcessError:
cls.__git_hash_attr = "" # Non-None but empty.
# A non-None but empty value indicates that we don't know it.
return cls.__git_hash_attr if cls.__git_hash_attr else None

@classmethod
@property
def string(cls) -> str:
"""The version string."""
if cls.__string_attr is None:
# If set, BUILD_VERSION should override any local version
# information. CI will use this to manage, e.g., release vs. nightly
# versions.
version = os.getenv("BUILD_VERSION", "").strip()
if not version:
# Otherwise, read the version from a local file and add the git
# commit if available.
version = (
open(os.path.join(cls._root_dir, "version.txt")).read().strip()
)
if cls.git_hash:
version += "+" + cls.git_hash[:7]
cls.__string_attr = version
return cls.__string_attr

@classmethod
def write_to_python_file(cls, path: str) -> None:
"""Creates a file similar to PyTorch core's `torch/version.py`."""
lines = [
"from typing import Optional",
'__all__ = ["__version__", "git_version"]',
f'__version__ = "{cls.string}"',
# A string or None.
f"git_version: Optional[str] = {repr(cls.git_hash)}",
]
with open(path, "w") as fp:
fp.write("\n".join(lines) + "\n")


class _BaseExtension(Extension):
"""A base class that maps an abstract source to an abstract destination."""

Expand Down Expand Up @@ -274,6 +346,9 @@ def run(self):
# package subdirectory.
dst_root = os.path.join(self.build_lib, self.get_package_dir("executorch"))

# Create the version file.
Version.write_to_python_file(os.path.join(dst_root, "version.py"))

# Manually copy files into the output package directory. These are
# typically python "resource" files that will live alongside the python
# code that uses them.
Expand Down Expand Up @@ -481,6 +556,7 @@ def get_ext_modules() -> list[Extension]:


setup(
version=Version.string,
# TODO(dbort): Could use py_modules to restrict the set of modules we
# package, and package_data to restrict the set up non-python files we
# include. See also setuptools/discovery.py for custom finders.
Expand Down

0 comments on commit b5dd169

Please sign in to comment.