Commit 15dcce9b authored by payno's avatar payno
Browse files

[setup.py] add setup.cfg file

parent 9066fcef
......@@ -39,11 +39,8 @@ _logging.getLogger(__name__).addHandler(_logging.NullHandler())
project = _os.path.basename(_os.path.dirname(_os.path.abspath(__file__)))
try:
from ._version import __date__ as date # noqa
from ._version import version, version_info, hexversion, strictversion # noqa
except ImportError:
pass
# not raised for now because fail with pip install -e option. Something to
# look at.
# raise RuntimeError("Do NOT use %s from its sources: build it and use the built version" % project)
from .version import __date__ as date # noqa
from .version import version, version_info, hexversion, strictversion # noqa
__version__ = version
[metadata]
name = est
version = attr: est.__version__
author = data analysis unit
author_email = henri.payno@esrf.fr
description = tools to define a data analysis workflow for X-ray Absorption Structure analysis.
long_description = file: README.md
long_description_content_type = text/markdown
license = MIT
url = https://gitlab.esrf.fr/workflow/est
project_urls =
Bug Tracker = https://gitlab.esrf.fr/workflow/est/-/issues
classifiers =
Intended Audience :: Education
Intended Audience :: Science/Research
License :: OSI Approved :: MIT License
Programming Language :: Python :: 3
Environment :: Console
Environment :: X11 Applications :: Qt
Operating System :: POSIX
Natural Language :: English
Topic :: Scientific/Engineering :: Physics
Topic :: Software Development :: Libraries :: Python Modules
[options]
packages = find:
python_requires = >=3.6
install_requires =
numpy
setuptools
h5py>=3.1
Pint
ewoksorange
silx>=0.15
[options.entry_points]
console_scripts =
est=est.__main__:main
orange3.addon =
est-add-on=orangecontrib.est
orange.widgets =
Est=orangecontrib.est.widgets
orange.canvas.help =
html-index=orangecontrib.est.widgets:WIDGET_HELP_PATH
[options.package_data]
est.resources =
gui/icons/*.png
gui/icons/*.svg
gui/icons/*.npy
orangecontrib.est =
widgets/icons/*.png
widgets/icons/*.svg
widgets/larch/icons/*.png
widgets/larch/icons/*.svg
widgets/pymca/icons/*.png
widgets/pymca/icons/*.svg
widgets/utils/icons/*.png
widgets/utils/icons/*.svg
[options.extras_require]
full =
PyMca
xraylarch
PyQt5
orange3
dev =
%(full)s
black
flake8
setup_requires =
setuptools
numpy
# E501 (line too long) ignored for now
# E203 and W503 incompatible with black formatting (https://black.readthedocs.io/en/stable/compatible_configs.html#flake8)
[flake8]
ignore = E501, E203, W503
max-line-length = 88
exclude =
.eggs
......@@ -24,616 +24,12 @@
#
# ###########################################################################*/
__authors__ = ["Jérôme Kieffer", "Thomas Vincent"]
__date__ = "02/10/2017"
__authors__ = ["Henri Payno"]
__date__ = "21/07/2021"
__license__ = "MIT"
import sys
import os
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
from setuptools import find_packages
try:
from setuptools import Command
from setuptools.command.build_py import build_py as _build_py
from setuptools.command.build_ext import build_ext
from setuptools.command.sdist import sdist
logger.info("Use setuptools")
except ImportError:
try:
from numpy.distutils.core import Command
except ImportError:
from distutils.core import Command
from distutils.command.build_py import build_py as _build_py
from distutils.command.build_ext import build_ext
from distutils.command.sdist import sdist
logger.info("Use distutils")
try:
import sphinx
import sphinx.util.console
sphinx.util.console.color_terminal = lambda: False
from sphinx.setup_command import BuildDoc
except ImportError:
sphinx = None
from collections import namedtuple
PROJECT = "est"
if "LANG" not in os.environ and sys.platform == "darwin" and sys.version_info[0] > 2:
print(
"""WARNING: the LANG environment variable is not defined,
an utf-8 LANG is mandatory to use setup.py, you may face unexpected UnicodeError.
export LANG=en_US.utf-8
export LC_ALL=en_US.utf-8
"""
)
def get_version():
"""Returns current version number from version.py file"""
from est.version import strictversion
return strictversion
def get_readme():
"""Returns content of README.md file"""
import io
dirname = os.path.dirname(os.path.abspath(__file__))
filename = os.path.join(dirname, "README.md")
with io.open(filename, "r", encoding="utf-8") as fp:
long_description = fp.read()
return long_description
classifiers = [
"Development Status :: 4 - Beta",
"Environment :: Console",
"Environment :: X11 Applications :: Qt",
"Intended Audience :: Education",
"Intended Audience :: Science/Research",
"License :: OSI Approved :: MIT License",
"Natural Language :: English",
"Operating System :: POSIX",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: Implementation :: CPython",
"Topic :: Scientific/Engineering :: Physics",
"Topic :: Software Development :: Libraries :: Python Modules",
]
########
# Test #
########
class PyTest(Command):
"""Command to start tests running the script: run_tests.py -i"""
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
import subprocess
errno = subprocess.call([sys.executable, "run_tests.py"])
if errno != 0:
raise SystemExit(errno)
# ################### #
# build_doc command #
# ################### #
if sphinx is None:
class SphinxExpectedCommand(Command):
"""Command to inform that sphinx is missing"""
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
raise RuntimeError(
"Sphinx is required to build or test the documentation.\n"
"Please install Sphinx (http://www.sphinx-doc.org)."
)
class BuildMan(Command):
"""Command to build man pages"""
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def entry_points_iterator(self):
"""Iterate other entry points available on the project."""
entry_points = self.distribution.entry_points
console_scripts = entry_points.get("console_scripts", [])
gui_scripts = entry_points.get("gui_scripts", [])
scripts = []
scripts.extend(console_scripts)
scripts.extend(gui_scripts)
for script in scripts:
# Remove ending extra dependencies
script = script.split("[")[0]
elements = script.split("=")
target_name = elements[0].strip()
elements = elements[1].split(":")
module_name = elements[0].strip()
function_name = elements[1].strip()
yield target_name, module_name, function_name
def run_targeted_script(self, target_name, script_name, env, log_output=False):
"""Execute targeted script using --help and --version to help checking
errors. help2man is not very helpful to do it for us.
:return: True is both return code are equal to 0
:rtype: bool
"""
import subprocess
if log_output:
extra_args = {}
else:
try:
# Python 3
from subprocess import DEVNULL
except ImportError:
# Python 2
import os
DEVNULL = open(os.devnull, "wb")
extra_args = {"stdout": DEVNULL, "stderr": DEVNULL}
succeeded = True
command_line = [sys.executable, script_name, "--help"]
if log_output:
logger.info("See the following execution of: %s", " ".join(command_line))
p = subprocess.Popen(command_line, env=env, **extra_args)
status = p.wait()
if log_output:
logger.info("Return code: %s", status)
succeeded = succeeded and status == 0
command_line = [sys.executable, script_name, "--version"]
if log_output:
logger.info("See the following execution of: %s", " ".join(command_line))
p = subprocess.Popen(command_line, env=env, **extra_args)
status = p.wait()
if log_output:
logger.info("Return code: %s", status)
succeeded = succeeded and status == 0
return succeeded
def run(self):
build = self.get_finalized_command("build")
path = sys.path
path.insert(0, os.path.abspath(build.build_lib))
env = dict((str(k), str(v)) for k, v in os.environ.items())
env["PYTHONPATH"] = os.pathsep.join(path)
import subprocess
status = subprocess.call(["mkdir", "-p", "build/man"])
if status != 0:
raise RuntimeError("Fail to create build/man directory")
import tempfile
import stat
script_name = None
entry_points = self.entry_points_iterator()
for target_name, module_name, function_name in entry_points:
logger.info("Build man for entry-point target '%s'" % target_name)
# help2man expect a single executable file to extract the help
# we create it, execute it, and delete it at the end
py3 = sys.version_info >= (3, 0)
try:
# create a launcher using the right python interpreter
script_fid, script_name = tempfile.mkstemp(
prefix="%s_" % target_name, text=True
)
script = os.fdopen(script_fid, "wt")
script.write("#!%s\n" % sys.executable)
script.write("import %s as app\n" % module_name)
script.write("app.%s()\n" % function_name)
script.close()
# make it executable
mode = os.stat(script_name).st_mode
os.chmod(script_name, mode + stat.S_IEXEC)
# execute help2man
man_file = "build/man/%s.1" % target_name
command_line = ["help2man", script_name, "-o", man_file]
if not py3:
# Before Python 3.4, ArgParser --version was using
# stderr to print the version
command_line.append("--no-discard-stderr")
# Then we dont know if the documentation will contains
# durtty things
succeeded = self.run_targeted_script(
target_name, script_name, env, False
)
if not succeeded:
logger.info(
"Error while generating man file for target '%s'.",
target_name,
)
self.run_targeted_script(target_name, script_name, env, True)
raise RuntimeError(
"Fail to generate '%s' man documentation" % target_name
)
p = subprocess.Popen(command_line, env=env)
status = p.wait()
if status != 0:
logger.info(
"Error while generating man file for target '%s'.", target_name
)
self.run_targeted_script(target_name, script_name, env, True)
raise RuntimeError(
"Fail to generate '%s' man documentation" % target_name
)
finally:
# clean up the script
if script_name is not None:
os.remove(script_name)
if sphinx is not None:
class BuildDocCommand(BuildDoc):
"""Command to build documentation using sphinx.
Project should have already be built.
"""
def run(self):
# make sure the python path is pointing to the newly built
# code so that the documentation is built on this and not a
# previously installed version
build = self.get_finalized_command("build")
sys.path.insert(0, os.path.abspath(build.build_lib))
# Build the Users Guide in HTML and TeX format
for builder in ["html", "htmlhelp"]:
self.builder = builder
self.builder_target_dir = os.path.join(self.build_dir, builder)
self.mkpath(self.builder_target_dir)
BuildDoc.run(self)
sys.path.pop(0)
class BuildDocAndGenerateScreenshotCommand(BuildDocCommand):
def run(self):
old = os.environ.get("DIRECTIVE_SNAPSHOT_QT")
os.environ["DIRECTIVE_SNAPSHOT_QT"] = "True"
BuildDocCommand.run(self)
if old is not None:
os.environ["DIRECTIVE_SNAPSHOT_QT"] = old
else:
del os.environ["DIRECTIVE_SNAPSHOT_QT"]
else:
BuildDocCommand = SphinxExpectedCommand
BuildDocAndGenerateScreenshotCommand = SphinxExpectedCommand
# ################### #
# test_doc command #
# ################### #
if sphinx is not None:
class TestDocCommand(BuildDoc):
"""Command to test the documentation using sphynx doctest.
http://www.sphinx-doc.org/en/1.4.8/ext/doctest.html
"""
def run(self):
# make sure the python path is pointing to the newly built
# code so that the documentation is built on this and not a
# previously installed version
build = self.get_finalized_command("build")
sys.path.insert(0, os.path.abspath(build.build_lib))
# Build the Users Guide in HTML and TeX format
for builder in ["doctest"]:
self.builder = builder
self.builder_target_dir = os.path.join(self.build_dir, builder)
self.mkpath(self.builder_target_dir)
BuildDoc.run(self)
sys.path.pop(0)
else:
TestDocCommand = SphinxExpectedCommand
# ############################# #
# numpy.distutils Configuration #
# ############################# #
def configuration(parent_package="", top_path=None):
"""Recursive construction of package info to be used in setup().
See http://docs.scipy.org/doc/numpy/reference/distutils.html#numpy.distutils.misc_util.Configuration
"""
try:
from numpy.distutils.misc_util import Configuration
except ImportError:
raise ImportError(
"To install this package, you must install numpy first\n"
"(See https://pypi.python.org/pypi/numpy)"
)
config = Configuration(None, parent_package, top_path)
config.set_options(
ignore_setup_xxx_py=True,
assume_default_configuration=True,
delegate_options_to_subpackages=True,
quiet=True,
)
config.add_subpackage(PROJECT)
return config
class sdist_debian(sdist):
"""
Tailor made sdist for debian
* remove auto-generated doc
* remove cython generated .c files
* remove cython generated .c files
* remove .bat files
* include .l man files
"""
@staticmethod
def get_debian_name():
from est import version
name = "%s_%s" % (PROJECT, version.debianversion)
return name
def prune_file_list(self):
sdist.prune_file_list(self)
to_remove = [
"doc/build",
"doc/pdf",
"doc/html",
"pylint",
"epydoc",
"doc/htmlhelp",
]
print("Removing files for debian")
for rm in to_remove:
self.filelist.exclude_pattern(pattern="*", anchor=False, prefix=rm)
def make_distribution(self):
self.prune_file_list()
sdist.make_distribution(self)
dest = self.archive_files[0]
dirname, basename = os.path.split(dest)
base, ext = os.path.splitext(basename)
while ext in [".zip", ".tar", ".bz2", ".gz", ".Z", ".lz", ".orig"]:
base, ext = os.path.splitext(base)
if ext:
dest = "".join((base, ext))
else:
dest = base
# sp = dest.split("-")
# base = sp[:-1]
# nr = sp[-1]
debian_arch = os.path.join(dirname, self.get_debian_name() + ".orig.tar.gz")
os.rename(self.archive_files[0], debian_arch)
self.archive_files = [debian_arch]
print("Building debian .orig.tar.gz in %s" % self.archive_files[0])
# ##### #
# setup #
# ##### #
NAMESPACE_PACKAGES = ["orangecontrib"]
PACKAGES = find_packages()
def get_project_configuration(dry_run):
"""Returns project arguments for setup"""
install_requires = [
# for most of the computation
"numpy",
# for the script launcher
"setuptools",
"h5py>=3.1",
"Pint",
"pypushflow>=0.2b.0",
"silx>=0.15",
"esrftaskgraph",
]
full_requires = [
"PyMca",
"xraylarch",
"PyQt5",
"orange3",
]
setup_requires = ["setuptools", "numpy"]
package_data = {
# Resources files for est library
"est.resources": ["gui/icons/*.png", "gui/icons/*.svg", "gui/icons/*.npy"],
# Resources files for est orange add-on
"orangecontrib.est": [
"widgets/icons/*.png",
"widgets/icons/*.svg",
"widgets/larch/icons/*.png",
"widgets/larch/icons/*.svg",
"widgets/pymca/icons/*.png",
"widgets/pymca/icons/*.svg",
"widgets/utils/icons/*.png",
"widgets/utils/icons/*.svg",
],
}
entry_points = {
"console_scripts": ("est=est.__main__:main",),
# Entry points that marks this package as an orange add-on. If set, addon will
# be shown in the add-ons manager even if not published on PyPi.
"orange3.addon": ("est-add-on=orangecontrib.est",),
# Entry point used to specify packages containing widgets.
"orange.widgets": (
# Syntax: category name = path.to.package.containing.widgets
# Widget category specification can be seen in
"Est=orangecontrib.est.widgets",
),
# Register widget help
"orange.canvas.help": (
"html-index=orangecontrib.est.widgets:WIDGET_HELP_PATH",
),
}
cmdclass = dict(
test=PyTest,
build_doc=BuildDocCommand,
build_screenshots=BuildDocAndGenerateScreenshotCommand,
test_doc=TestDocCommand,
build_man=BuildMan,
debian_src=sdist_debian,
)
if dry_run:
# DRY_RUN implies actions which do not require NumPy
#
# And they are required to succeed without Numpy for example when
# pip is used to install est when Numpy is not yet present in
# the system.
setup_kwargs = {}
else:
config = configuration()
setup_kwargs = config.todict()
setup_kwargs.update(
name=PROJECT,
version=get_version(),
url="https://gitlab.esrf.fr/workflow/est",
author="data analysis unit",
author_email="henri.payno@esrf.fr",
classifiers=classifiers,
description="Library for crystallography workflow",
long_description=get_readme(),