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 pyproject.toml specifying numpy and cython as build deps #730

Merged
merged 6 commits into from
Jun 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# For archives, substitute the commit hash in the setup.py file.
/setup.py export-subst
5 changes: 4 additions & 1 deletion chaco/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
""" Two-dimensional plotting application toolkit.
Part of the Chaco project of the Enthought Tool Suite.
"""
from ._version import full_version as __version__ # noqa
try:
from chaco._version import full_version as __version__ # noqa
except ImportError:
__version__ = "not-built"

__requires__ = ["traits", "traitsui", "pyface", "numpy", "enable"]
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[build-system]
requires = ["cython", "numpy", "setuptools", "wheel"]
build-backend = "setuptools.build_meta"
292 changes: 221 additions & 71 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# All rights reserved.
import os
import re
import runpy
import subprocess

from numpy import get_include
Expand All @@ -11,38 +12,96 @@
MAJOR = 4
MINOR = 8
MICRO = 1

PRERELEASE = ""
IS_RELEASED = False

VERSION = '%d.%d.%d' % (MAJOR, MINOR, MICRO)
# If this file is part of a Git export (for example created with "git archive",
# or downloaded from GitHub), ARCHIVE_COMMIT_HASH gives the full hash of the
# commit that was exported.
ARCHIVE_COMMIT_HASH = "$Format:%H$"
Copy link
Contributor

Choose a reason for hiding this comment

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

you'll have to add a .gitattributes file to the root of the git repository if you want this to work correctly. ref https://github.com/enthought/traitsui/blob/master/.gitattributes


# Templates for version strings.
RELEASED_VERSION = "{major}.{minor}.{micro}{prerelease}"
UNRELEASED_VERSION = "{major}.{minor}.{micro}{prerelease}.dev{dev}"

# Paths to the autogenerated version file and the Git directory.
HERE = os.path.abspath(os.path.dirname(__file__))
VERSION_FILE = os.path.join(HERE, "chaco", "_version.py")
GIT_DIRECTORY = os.path.join(HERE, ".git")

# Template for the autogenerated version file.
VERSION_FILE_TEMPLATE = """\
# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX
# All rights reserved.
#
# This software is provided without warranty under the terms of the BSD
# license included in LICENSE.txt and may be redistributed only under
# the conditions described in the aforementioned license. The license
# is also available online at http://www.enthought.com/licenses/BSD.txt
#
# Thanks for using Enthought open source!

# THIS FILE IS GENERATED FROM SETUP.PY

#: The full version of the package, including a development suffix
#: for unreleased versions of the package.
version = '{version}'

#: The full version of the package, same as 'version'
#: Kept for backward compatibility
full_version = version

#: The Git revision from which this release was made.
git_revision = '{git_revision}'

#: Flag whether this is a final release
is_released = {is_released}
"""

# Name of the directory containing the package.
PKG_PATHNAME = 'chaco'

# Name of the file containing the version information.
_VERSION_FILENAME = os.path.join(PKG_PATHNAME, '_version.py')
def read_module(module, package='chaco'):
""" Read a simple .py file from chaco in a safe way.

It would be simpler to import the file, but that can be problematic in an
unknown system, so we exec the file instead and extract the variables.

def read_version_py(path):
""" Read a _version.py file in a safe way. """
with open(path, 'r') as fp:
code = compile(fp.read(), 'chaco._version', 'exec')
This will fail if things get too complex in the file being read, but is
sufficient to get version and requirements information.
"""
base_dir = os.path.dirname(__file__)
module_name = package + '.' + module
path = os.path.join(base_dir, package, module+'.py')
with open(path, 'r', encoding='utf-8') as fp:
code = compile(fp.read(), module_name, 'exec')
context = {}
exec(code, context)
return context['git_revision'], context['full_version']

return context

def git_version():
""" Parse version information from the current git commit.

Parse the output of `git describe` and return the git hash and the number
of commits since the last version tag.
# Return the git revision as a string
def _git_info():
"""
Get information about the given commit from Git.

Returns
-------
git_count : int
Number of revisions from this commit to the initial commit.
git_revision : str
Commit hash for HEAD.

Raises
------
EnvironmentError
If Git is not available.
subprocess.CalledProcessError
If Git is available, but the version command fails (most likely
because there's no Git repository here).
"""
def _minimal_ext_cmd(cmd):
# construct minimal environment
env = {}
for k in ['SYSTEMROOT', 'PATH', 'HOME']:
for k in ['SYSTEMROOT', 'PATH']:
v = os.environ.get(k)
if v is not None:
env[k] = v
Expand All @@ -56,14 +115,7 @@ def _minimal_ext_cmd(cmd):
return out

try:
# We ask git to find the latest tag matching a glob expression. The
# intention is to find a release tag of the form '4.50.2'. Strictly
# speaking, the glob expression also matches tags of the form
# '4abc.5xyz.2gtluuu', but it's very difficult with glob expressions
# to distinguish between the two cases, and the likelihood of a
# problem is minimal.
out = _minimal_ext_cmd(
['git', 'describe', '--match', '[0-9]*.[0-9]*.[0-9]*', '--tags'])
out = _minimal_ext_cmd(['git', 'describe', '--tags'])
except OSError:
out = ''

Expand All @@ -75,61 +127,159 @@ def _minimal_ext_cmd(cmd):
else:
git_revision, git_count = match.group('hash'), match.group('count')

return git_revision, git_count
return git_count, git_revision


def write_version_py(filename=_VERSION_FILENAME):
""" Create a file containing the version information. """
def git_version():
"""
Construct version information from local variables and Git.

template = """\
# This file was automatically generated from the `setup.py` script.
version = '{version}'
full_version = '{full_version}'
git_revision = '{git_revision}'
is_released = {is_released}
Returns
-------
version : str
Package version.
git_revision : str
The full commit hash for the current Git revision.

if not is_released:
version = full_version
"""
# Adding the git rev number needs to be done inside
# write_version_py(), otherwise the import of _version messes
# up the build under Python 3.
fullversion = VERSION
chaco_version_path = os.path.join(
os.path.dirname(__file__), 'chaco', '_version.py')
if os.path.exists('.git'):
git_rev, dev_num = git_version()
elif os.path.exists(filename):
# must be a source distribution, use existing version file
try:
git_rev, fullversion = read_version_py(chaco_version_path)
except (SyntaxError, KeyError):
raise RuntimeError("Unable to read git_revision. Try removing "
"chaco/_version.py and the build directory "
"before building.")

match = re.match(r'.*?\.dev(?P<dev_num>\d+)', fullversion)
if match is None:
dev_num = '0'
else:
dev_num = match.group('dev_num')
else:
git_rev = 'Unknown'
dev_num = '0'
Raises
------
EnvironmentError
If Git is not available.
subprocess.CalledProcessError
If Git is available, but the version command fails (most likely
because there's no Git repository here).
"""
git_count, git_revision = _git_info()
version_template = RELEASED_VERSION if IS_RELEASED else UNRELEASED_VERSION
version = version_template.format(
major=MAJOR,
minor=MINOR,
micro=MICRO,
prerelease=PRERELEASE,
dev=git_count,
)
return version, git_revision


def archive_version():
"""
Construct version information for an archive.

Returns
-------
version : str
Package version.
git_revision : str
The full commit hash for the current Git revision.

Raises
------
ValueError
If this does not appear to be an archive.
"""
if "$" in ARCHIVE_COMMIT_HASH:
raise ValueError("This does not appear to be an archive.")

if not IS_RELEASED:
fullversion += '.dev{0}'.format(dev_num)
version_template = RELEASED_VERSION if IS_RELEASED else UNRELEASED_VERSION
version = version_template.format(
major=MAJOR,
minor=MINOR,
micro=MICRO,
prerelease=PRERELEASE,
dev="-unknown",
)
return version, ARCHIVE_COMMIT_HASH


def write_version_file(version, git_revision, filename=VERSION_FILE):
"""
Write version information to the version file.

Overwrites any existing version file.

Parameters
----------
version : str
Package version.
git_revision : str
The full commit hash for the current Git revision.
filename : str
Path to the version file.
"""
with open(filename, "w", encoding="utf-8") as version_file:
version_file.write(
VERSION_FILE_TEMPLATE.format(
version=version,
git_revision=git_revision,
is_released=IS_RELEASED,
)
)


def read_version_file():
"""
Read version information from the version file, if it exists.

Returns
-------
version : str
The full version, including any development suffix.
git_revision : str
The full commit hash for the current Git revision.

Raises
------
EnvironmentError
If the version file does not exist.
"""
version_info = runpy.run_path(VERSION_FILE)
return (version_info["version"], version_info["git_revision"])


def resolve_version():
"""
Process version information and write a version file if necessary.

Returns the current version information.

Returns
-------
version : str
Package version.
git_revision : str
The full commit hash for the current Git revision.
"""
if os.path.isdir(GIT_DIRECTORY):
# This is a local clone; compute version information and write
# it to the version file, overwriting any existing information.
version = git_version()
print("Computed package version: {}".format(version))
print("Writing version to version file {}.".format(VERSION_FILE))
write_version_file(*version)
elif "$" not in ARCHIVE_COMMIT_HASH:
# This is a source archive.
version = archive_version()
print("Archive package version: {}".format(version))
print("Writing version to version file {}.".format(VERSION_FILE))
write_version_file(*version)
elif os.path.isfile(VERSION_FILE):
# This is a source distribution. Read the version information.
print("Reading version file {}".format(VERSION_FILE))
version = read_version_file()
print("Package version from version file: {}".format(version))
else:
raise RuntimeError(
"Unable to determine package version. No local Git clone "
"detected, and no version file found at {}.".format(VERSION_FILE)
)

with open(filename, "wt") as fp:
fp.write(template.format(version=VERSION,
full_version=fullversion,
git_revision=git_rev,
is_released=IS_RELEASED))
return version


if __name__ == "__main__":
write_version_py()
from chaco import __requires__, __version__
__version__, _ = resolve_version()
data = read_module('__init__')
__requires__ = data['__requires__']

numpy_include_dir = get_include()

Expand Down