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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

add udunits xml to wheel #191

Merged
merged 3 commits into from Jul 28, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions .cirrus.yml
Expand Up @@ -27,7 +27,7 @@ env:
#
# Linting
#
lint_task:
task:
auto_cancellation: true
container:
image: python:latest
Expand All @@ -44,7 +44,7 @@ lint_task:
#
# Testing (Linux)
#
linux_task:
task:
auto_cancellation: true
matrix:
env:
Expand Down
1 change: 1 addition & 0 deletions MANIFEST.in
Expand Up @@ -5,3 +5,4 @@ include cf_units/etc/site.cfg.template
include CHANGES COPYING COPYING.LESSER INSTALL
exclude cf_units/etc/site.cfg
graft requirements
prune .github
43 changes: 34 additions & 9 deletions cf_units/config.py
Expand Up @@ -6,8 +6,8 @@


import configparser
import os.path
import sys
from pathlib import Path
from tempfile import NamedTemporaryFile


# Returns simple string options.
Expand All @@ -24,14 +24,39 @@ def get_option(section, option, default=None):


# Figure out the full path to the "cf_units" package.
ROOT_PATH = os.path.abspath(os.path.dirname(__file__))
ROOT_PATH = Path(__file__).resolve().parent

# The full path to the configuration directory of the active cf_units instance.
CONFIG_PATH = os.path.join(ROOT_PATH, "etc")
CONFIG_PATH = ROOT_PATH / "etc"

# The full path to the configuration file.
SITE_PATH = CONFIG_PATH / "site.cfg"

# Load the optional "site.cfg" file if it exists.
if sys.version_info >= (3, 2):
config = configparser.ConfigParser()
else:
config = configparser.SafeConfigParser()
config.read([os.path.join(CONFIG_PATH, "site.cfg")])
config = configparser.ConfigParser()

# Auto-generate the "site.cfg" only when it doesn't exist
# *and* the UDUNITS2 XML file/s are bundled within the cf-units
# package i.e., typically for a wheel installation.
xml_database = None
if not SITE_PATH.is_file():
SHARE_PATH = CONFIG_PATH / "share"
xml_database = SHARE_PATH / "udunits2.xml"
if not xml_database.is_file():
xml_database = SHARE_PATH / "udunits2_combined.xml"
if not xml_database.is_file():
xml_database = None
if xml_database is not None:
with NamedTemporaryFile(mode="w+t", delete=False) as tmp:
site_cfg = f"""[System]
udunits2_xml_path = {xml_database}
"""
tmp.file.write(site_cfg)
SITE_PATH = Path(tmp.name)

# Only attempt to read and parse an existing "site.cfg"
if SITE_PATH.is_file():
config.read([SITE_PATH])
if xml_database is not None:
# Tidy the auto-generated file.
SITE_PATH.unlink()
3 changes: 3 additions & 0 deletions codecov.yml
@@ -1,3 +1,6 @@
ignore:
- cf_units/_version.py
- cf_units/config.py
coverage:
status:
project:
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Expand Up @@ -62,6 +62,7 @@ exclude = '''
| build
| dist
)/
| _version.py
)
'''

Expand Down
100 changes: 76 additions & 24 deletions setup.py
Expand Up @@ -2,6 +2,7 @@
from distutils.sysconfig import get_config_var
from os import environ
from pathlib import Path
from shutil import copy

from setuptools import Command, Extension, setup

Expand All @@ -14,8 +15,9 @@
COMPILER_DIRECTIVES = {}
DEFINE_MACROS = None
FLAG_COVERAGE = "--cython-coverage" # custom flag enabling Cython line tracing
BASEDIR = Path(__file__).parent.absolute()
CFUNITS_DIR = BASEDIR / "cf_units"
BASEDIR = Path(__file__).resolve().parent
PACKAGE = "cf_units"
CFUNITS_DIR = BASEDIR / PACKAGE


class CleanCython(Command):
Expand All @@ -37,24 +39,62 @@ def run(self):
print(message)


include_dir = get_config_var("INCLUDEDIR")
include_dirs = [include_dir] if include_dir is not None else []
library_dir = get_config_var("LIBDIR")
library_dirs = [library_dir] if library_dir is not None else []
ocefpaf marked this conversation as resolved.
Show resolved Hide resolved

if sys.platform.startswith("win"):
extra_extension_args = {}
else:
extra_extension_args = dict(runtime_library_dirs=library_dirs)

ext = "pyx" if cythonize else "c"

if FLAG_COVERAGE in sys.argv or environ.get("CYTHON_COVERAGE", None):
COMPILER_DIRECTIVES = {"linetrace": True}
DEFINE_MACROS = [("CYTHON_TRACE", "1"), ("CYTHON_TRACE_NOGIL", "1")]
if FLAG_COVERAGE in sys.argv:
sys.argv.remove(FLAG_COVERAGE)
print('enable: "linetrace" Cython compiler directive')
ocefpaf marked this conversation as resolved.
Show resolved Hide resolved
def get_include_dirs():
include_dirs = []
include_dir = environ.get("UDUNITS2_INCDIR")
if include_dir is None:
include_dir = get_config_var("INCLUDEDIR")
if include_dir is not None:
include_dirs.append(include_dir)
return include_dirs


def get_library_dirs():
library_dirs = []
library_dir = environ.get("UDUNITS2_LIBDIR")
if library_dir is None:
library_dir = get_config_var("LIBDIR")
if library_dir is not None:
library_dirs.append(library_dir)
return library_dirs


def get_package_data():
package_data = None
# Determine whether we're building a wheel.
if "bdist_wheel" in sys.argv:
# The protocol is that the UDUNITS2_XML_PATH environment variable
# identifies the root UDUNITS2 XML file and parent directory containing
# all the XML resource files that require to be bundled within this
# wheel. Note that, this should match the UDUNITS2 distribution for the
# UDUNITS2 library cf-units is linking against.
xml_env = "UDUNITS2_XML_PATH"
xml_database = environ.get(xml_env)
if xml_database is None:
emsg = f"Require to set {xml_env} for a cf-units wheel build."
raise ValueError(emsg)
xml_database = Path(xml_database)
if not xml_database.is_file():
emsg = (
f"Can't open {xml_env} file {xml_database} "
"during cf-units wheel build."
)
raise ValueError(emsg)
# We have a valid XML file, so copy the distro bundle into the
# cf_units/etc/share directory.
xml_dir = xml_database.expanduser().resolve().parent
share_base = Path("etc") / "share"
share_dir = CFUNITS_DIR / share_base
if not share_dir.is_dir():
share_dir.mkdir(parents=True)
else:
# Purge any existing XML share files.
[fname.unlink() for fname in share_dir.glob("*.xml")]
# Bundle the UDUNITS2 XML file/s for the wheel.
[copy(fname, share_dir) for fname in xml_dir.glob("*.xml")]
# Register our additional wheel content.
package_data = {PACKAGE: [str(share_base / "*.xml")]}
return package_data


def numpy_build_ext(pars):
Expand All @@ -78,14 +118,25 @@ def _set_builtin(name, value):
return build_ext(pars)


if FLAG_COVERAGE in sys.argv or environ.get("CYTHON_COVERAGE", None):
COMPILER_DIRECTIVES = {"linetrace": True}
DEFINE_MACROS = [("CYTHON_TRACE", "1"), ("CYTHON_TRACE_NOGIL", "1")]
if FLAG_COVERAGE in sys.argv:
sys.argv.remove(FLAG_COVERAGE)
print('enable: "linetrace" Cython compiler directive')

library_dirs = get_library_dirs()

udunits_ext = Extension(
"cf_units._udunits2",
["cf_units/_udunits2.{}".format(ext)],
include_dirs=include_dirs,
f"{PACKAGE}._udunits2",
[str(Path(f"{PACKAGE}") / f"_udunits2.{'pyx' if cythonize else 'c'}")],
include_dirs=get_include_dirs(),
library_dirs=library_dirs,
libraries=["udunits2"],
define_macros=DEFINE_MACROS,
**extra_extension_args,
runtime_library_dirs=None
if sys.platform.startswith("win")
else library_dirs,
)

if cythonize:
Expand All @@ -98,6 +149,7 @@ def _set_builtin(name, value):
kwargs = dict(
cmdclass=cmdclass,
ext_modules=[udunits_ext],
package_data=get_package_data(),
ocefpaf marked this conversation as resolved.
Show resolved Hide resolved
)

setup(**kwargs)