From 6337d6e7b06b8f6462f952e16e2e2773b3291045 Mon Sep 17 00:00:00 2001 From: Aidan Heerdegen Date: Thu, 15 Aug 2024 12:37:50 +1000 Subject: [PATCH 01/15] Add conda packaging and deployment to accessnri channel --- .gitattributes | 1 + .github/workflows/CD.yml | 40 +++ .pylintrc | 5 + conda/environment.yml | 13 + conda/meta.yml | 49 +++ pyproject.toml | 46 +++ setup.py | 7 + umpost/_version.py | 683 +++++++++++++++++++++++++++++++++++++++ 8 files changed, 844 insertions(+) create mode 100644 .gitattributes create mode 100644 .github/workflows/CD.yml create mode 100644 .pylintrc create mode 100644 conda/environment.yml create mode 100644 conda/meta.yml create mode 100644 pyproject.toml create mode 100644 setup.py create mode 100644 umpost/_version.py diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..66ce36e --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +umpost/_version.py export-subst diff --git a/.github/workflows/CD.yml b/.github/workflows/CD.yml new file mode 100644 index 0000000..af7580a --- /dev/null +++ b/.github/workflows/CD.yml @@ -0,0 +1,40 @@ +name: CD + +on: + push: + branches: + - master + +env: + PY_VERSION: 3.10 + +jobs: + + conda: + name: Build with conda and upload + runs-on: ubuntu-latest + steps: + - name: Checkout source + uses: actions/checkout@v4 + with: + fetch-tags: true + fetch-depth: 0 + + - name: Setup conda environment + uses: conda-incubator/setup-miniconda@11b562958363ec5770fef326fe8ef0366f8cbf8a + with: + miniconda-version: "latest" + python-version: ${{ env.PY_VERSION }} + environment-file: conda/environment.yml + auto-update-conda: false + auto-activate-base: false + show-channel-urls: true + + - name: Build and upload the conda package + uses: uibcdf/action-build-and-upload-conda-packages@c6e7a90ad5e599d6cde76e130db4ee52ad733ecf + with: + meta_yaml_dir: conda + python-version: ${{ env.PY_VERSION }} + user: accessnri + label: main + token: ${{ secrets.anaconda_token }} \ No newline at end of file diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 0000000..b63bb64 --- /dev/null +++ b/.pylintrc @@ -0,0 +1,5 @@ +[MAIN] + +# Files or directories to be skipped. They should be base names, not +# paths. +ignore=_version.py diff --git a/conda/environment.yml b/conda/environment.yml new file mode 100644 index 0000000..0667bea --- /dev/null +++ b/conda/environment.yml @@ -0,0 +1,13 @@ +name: um2nc + +channels: + - conda-forge + - accessnri + - coecms + - defaults + +dependencies: + - anaconda-client + - conda-build + - conda-verify + - versioneer diff --git a/conda/meta.yml b/conda/meta.yml new file mode 100644 index 0000000..b8a1c53 --- /dev/null +++ b/conda/meta.yml @@ -0,0 +1,49 @@ +{% set data = load_setup_py_data(setup_file='../setup.py', from_recipe_dir=True) %} +{% set version = data.get('version') %} +{% set pyproj = load_file_data('../pyproject.toml', from_recipe_dir=True) %} +{% set project = pyproj.get('project') %} + +package: + name: um2nc + version: "{{ version }}" + +build: + noarch: python + number: 0 + script: "{{ python }} -m pip install . -vv" + entry_points: + {% for name, script in project.get('scripts', {}).items() %} + - {{ name }} = {{ script }} + {% endfor %} + +source: + path: ../ + +requirements: + host: + - python + - pip + - setupools >=61.0.0 + - versioneer + run: + - python >=3.10 + {% for dep in project.get('dependencies', []) %} + - {{ dep }} + {% endfor %} + +test: + imports: + - umpost + requires: + - pytest + source_files: + - test/** + commands: + - py.test + +about: + home: https://github.com/access-nri/um2nc-standalone + license: Apache Software + license_family: Apache + summary: "Tool to convert fieldsfiles into netCDF format. Used for post-processing UM climate model output" + diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..1d79007 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,46 @@ +[project] +name = "um2nc" +authors = [ + {name = "Ben Davies", email="ben.davies@anu.edu.au"}, + {name = "Martin Dix", email="martin.dix@anu.edu.au"}, + {name = "Spencer Wong", email="spencer.wong@anu.edu.au"}, +] +maintainers = [ + { name = "ACCESS-NRI", email = "access.nri@anu.edu.au" } +] +description = "Program to convert Unified Model output files in fields file format to netCDF" +license = { text = "Apache-2.0" } +readme = "README.md" +keywords = ["netCDF", "UM", "postprocessing"] +dynamic = ["version"] +dependencies = [ + "numpy", + "mule", + "cftime", + "netCDF4", + "scitools-iris", + "cf-units", + "PyYAML", + "f90nml", +] +[project.scripts] +um2nc = "umpost.um2netcdf:main" + +[tool.versioneer] +VCS = "git" +style = "pep440" +versionfile_source = "umpost/_version.py" +versionfile_build = "umpost/_version.py" +tag_prefix = "" +parentdir_prefix = "umpost-" + +[build-system] +build-backend = "setuptools.build_meta" +requires = [ + "setuptools>64", + "versioneer[toml]" +] + +[tool.setuptools.packages.find] +include = ["umpost*"] +namespaces = false diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..9ed5e21 --- /dev/null +++ b/setup.py @@ -0,0 +1,7 @@ +from setuptools import setup +import versioneer + +setup( + version=versioneer.get_version(), + cmdclass=versioneer.get_cmdclass(), +) diff --git a/umpost/_version.py b/umpost/_version.py new file mode 100644 index 0000000..1fef369 --- /dev/null +++ b/umpost/_version.py @@ -0,0 +1,683 @@ + +# This file helps to compute a version number in source trees obtained from +# git-archive tarball (such as those provided by githubs download-from-tag +# feature). Distribution tarballs (built by setup.py sdist) and build +# directories (produced by setup.py build) will contain a much shorter file +# that just contains the computed version number. + +# This file is released into the public domain. +# Generated by versioneer-0.29 +# https://github.com/python-versioneer/python-versioneer + +"""Git implementation of _version.py.""" + +import errno +import os +import re +import subprocess +import sys +from typing import Any, Callable, Dict, List, Optional, Tuple +import functools + + +def get_keywords() -> Dict[str, str]: + """Get the keywords needed to look up the version information.""" + # these strings will be replaced by git during git-archive. + # setup.py/versioneer.py will grep for the variable names, so they must + # each be defined on a line of their own. _version.py will just call + # get_keywords(). + git_refnames = "$Format:%d$" + git_full = "$Format:%H$" + git_date = "$Format:%ci$" + keywords = {"refnames": git_refnames, "full": git_full, "date": git_date} + return keywords + + +class VersioneerConfig: + """Container for Versioneer configuration parameters.""" + + VCS: str + style: str + tag_prefix: str + parentdir_prefix: str + versionfile_source: str + verbose: bool + + +def get_config() -> VersioneerConfig: + """Create, populate and return the VersioneerConfig() object.""" + # these strings are filled in when 'setup.py versioneer' creates + # _version.py + cfg = VersioneerConfig() + cfg.VCS = "git" + cfg.style = "pep440" + cfg.tag_prefix = "" + cfg.parentdir_prefix = "umpost-" + cfg.versionfile_source = "umpost/_version.py" + cfg.verbose = False + return cfg + + +class NotThisMethod(Exception): + """Exception raised if a method is not valid for the current scenario.""" + + +LONG_VERSION_PY: Dict[str, str] = {} +HANDLERS: Dict[str, Dict[str, Callable]] = {} + + +def register_vcs_handler(vcs: str, method: str) -> Callable: # decorator + """Create decorator to mark a method as the handler of a VCS.""" + def decorate(f: Callable) -> Callable: + """Store f in HANDLERS[vcs][method].""" + if vcs not in HANDLERS: + HANDLERS[vcs] = {} + HANDLERS[vcs][method] = f + return f + return decorate + + +def run_command( + commands: List[str], + args: List[str], + cwd: Optional[str] = None, + verbose: bool = False, + hide_stderr: bool = False, + env: Optional[Dict[str, str]] = None, +) -> Tuple[Optional[str], Optional[int]]: + """Call the given command(s).""" + assert isinstance(commands, list) + process = None + + popen_kwargs: Dict[str, Any] = {} + if sys.platform == "win32": + # This hides the console window if pythonw.exe is used + startupinfo = subprocess.STARTUPINFO() + startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW + popen_kwargs["startupinfo"] = startupinfo + + for command in commands: + try: + dispcmd = str([command] + args) + # remember shell=False, so use git.cmd on windows, not just git + process = subprocess.Popen([command] + args, cwd=cwd, env=env, + stdout=subprocess.PIPE, + stderr=(subprocess.PIPE if hide_stderr + else None), **popen_kwargs) + break + except OSError as e: + if e.errno == errno.ENOENT: + continue + if verbose: + print("unable to run %s" % dispcmd) + print(e) + return None, None + else: + if verbose: + print("unable to find command, tried %s" % (commands,)) + return None, None + stdout = process.communicate()[0].strip().decode() + if process.returncode != 0: + if verbose: + print("unable to run %s (error)" % dispcmd) + print("stdout was %s" % stdout) + return None, process.returncode + return stdout, process.returncode + + +def versions_from_parentdir( + parentdir_prefix: str, + root: str, + verbose: bool, +) -> Dict[str, Any]: + """Try to determine the version from the parent directory name. + + Source tarballs conventionally unpack into a directory that includes both + the project name and a version string. We will also support searching up + two directory levels for an appropriately named parent directory + """ + rootdirs = [] + + for _ in range(3): + dirname = os.path.basename(root) + if dirname.startswith(parentdir_prefix): + return {"version": dirname[len(parentdir_prefix):], + "full-revisionid": None, + "dirty": False, "error": None, "date": None} + rootdirs.append(root) + root = os.path.dirname(root) # up a level + + if verbose: + print("Tried directories %s but none started with prefix %s" % + (str(rootdirs), parentdir_prefix)) + raise NotThisMethod("rootdir doesn't start with parentdir_prefix") + + +@register_vcs_handler("git", "get_keywords") +def git_get_keywords(versionfile_abs: str) -> Dict[str, str]: + """Extract version information from the given file.""" + # the code embedded in _version.py can just fetch the value of these + # keywords. When used from setup.py, we don't want to import _version.py, + # so we do it with a regexp instead. This function is not used from + # _version.py. + keywords: Dict[str, str] = {} + try: + with open(versionfile_abs, "r") as fobj: + for line in fobj: + if line.strip().startswith("git_refnames ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + keywords["refnames"] = mo.group(1) + if line.strip().startswith("git_full ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + keywords["full"] = mo.group(1) + if line.strip().startswith("git_date ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + keywords["date"] = mo.group(1) + except OSError: + pass + return keywords + + +@register_vcs_handler("git", "keywords") +def git_versions_from_keywords( + keywords: Dict[str, str], + tag_prefix: str, + verbose: bool, +) -> Dict[str, Any]: + """Get version information from git keywords.""" + if "refnames" not in keywords: + raise NotThisMethod("Short version file found") + date = keywords.get("date") + if date is not None: + # Use only the last line. Previous lines may contain GPG signature + # information. + date = date.splitlines()[-1] + + # git-2.2.0 added "%cI", which expands to an ISO-8601 -compliant + # datestamp. However we prefer "%ci" (which expands to an "ISO-8601 + # -like" string, which we must then edit to make compliant), because + # it's been around since git-1.5.3, and it's too difficult to + # discover which version we're using, or to work around using an + # older one. + date = date.strip().replace(" ", "T", 1).replace(" ", "", 1) + refnames = keywords["refnames"].strip() + if refnames.startswith("$Format"): + if verbose: + print("keywords are unexpanded, not using") + raise NotThisMethod("unexpanded keywords, not a git-archive tarball") + refs = {r.strip() for r in refnames.strip("()").split(",")} + # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of + # just "foo-1.0". If we see a "tag: " prefix, prefer those. + TAG = "tag: " + tags = {r[len(TAG):] for r in refs if r.startswith(TAG)} + if not tags: + # Either we're using git < 1.8.3, or there really are no tags. We use + # a heuristic: assume all version tags have a digit. The old git %d + # expansion behaves like git log --decorate=short and strips out the + # refs/heads/ and refs/tags/ prefixes that would let us distinguish + # between branches and tags. By ignoring refnames without digits, we + # filter out many common branch names like "release" and + # "stabilization", as well as "HEAD" and "master". + tags = {r for r in refs if re.search(r'\d', r)} + if verbose: + print("discarding '%s', no digits" % ",".join(refs - tags)) + if verbose: + print("likely tags: %s" % ",".join(sorted(tags))) + for ref in sorted(tags): + # sorting will prefer e.g. "2.0" over "2.0rc1" + if ref.startswith(tag_prefix): + r = ref[len(tag_prefix):] + # Filter out refs that exactly match prefix or that don't start + # with a number once the prefix is stripped (mostly a concern + # when prefix is '') + if not re.match(r'\d', r): + continue + if verbose: + print("picking %s" % r) + return {"version": r, + "full-revisionid": keywords["full"].strip(), + "dirty": False, "error": None, + "date": date} + # no suitable tags, so version is "0+unknown", but full hex is still there + if verbose: + print("no suitable tags, using unknown + full revision id") + return {"version": "0+unknown", + "full-revisionid": keywords["full"].strip(), + "dirty": False, "error": "no suitable tags", "date": None} + + +@register_vcs_handler("git", "pieces_from_vcs") +def git_pieces_from_vcs( + tag_prefix: str, + root: str, + verbose: bool, + runner: Callable = run_command +) -> Dict[str, Any]: + """Get version from 'git describe' in the root of the source tree. + + This only gets called if the git-archive 'subst' keywords were *not* + expanded, and _version.py hasn't already been rewritten with a short + version string, meaning we're inside a checked out source tree. + """ + GITS = ["git"] + if sys.platform == "win32": + GITS = ["git.cmd", "git.exe"] + + # GIT_DIR can interfere with correct operation of Versioneer. + # It may be intended to be passed to the Versioneer-versioned project, + # but that should not change where we get our version from. + env = os.environ.copy() + env.pop("GIT_DIR", None) + runner = functools.partial(runner, env=env) + + _, rc = runner(GITS, ["rev-parse", "--git-dir"], cwd=root, + hide_stderr=not verbose) + if rc != 0: + if verbose: + print("Directory %s not under git control" % root) + raise NotThisMethod("'git rev-parse --git-dir' returned error") + + # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] + # if there isn't one, this yields HEX[-dirty] (no NUM) + describe_out, rc = runner(GITS, [ + "describe", "--tags", "--dirty", "--always", "--long", + "--match", f"{tag_prefix}[[:digit:]]*" + ], cwd=root) + # --long was added in git-1.5.5 + if describe_out is None: + raise NotThisMethod("'git describe' failed") + describe_out = describe_out.strip() + full_out, rc = runner(GITS, ["rev-parse", "HEAD"], cwd=root) + if full_out is None: + raise NotThisMethod("'git rev-parse' failed") + full_out = full_out.strip() + + pieces: Dict[str, Any] = {} + pieces["long"] = full_out + pieces["short"] = full_out[:7] # maybe improved later + pieces["error"] = None + + branch_name, rc = runner(GITS, ["rev-parse", "--abbrev-ref", "HEAD"], + cwd=root) + # --abbrev-ref was added in git-1.6.3 + if rc != 0 or branch_name is None: + raise NotThisMethod("'git rev-parse --abbrev-ref' returned error") + branch_name = branch_name.strip() + + if branch_name == "HEAD": + # If we aren't exactly on a branch, pick a branch which represents + # the current commit. If all else fails, we are on a branchless + # commit. + branches, rc = runner(GITS, ["branch", "--contains"], cwd=root) + # --contains was added in git-1.5.4 + if rc != 0 or branches is None: + raise NotThisMethod("'git branch --contains' returned error") + branches = branches.split("\n") + + # Remove the first line if we're running detached + if "(" in branches[0]: + branches.pop(0) + + # Strip off the leading "* " from the list of branches. + branches = [branch[2:] for branch in branches] + if "master" in branches: + branch_name = "master" + elif not branches: + branch_name = None + else: + # Pick the first branch that is returned. Good or bad. + branch_name = branches[0] + + pieces["branch"] = branch_name + + # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] + # TAG might have hyphens. + git_describe = describe_out + + # look for -dirty suffix + dirty = git_describe.endswith("-dirty") + pieces["dirty"] = dirty + if dirty: + git_describe = git_describe[:git_describe.rindex("-dirty")] + + # now we have TAG-NUM-gHEX or HEX + + if "-" in git_describe: + # TAG-NUM-gHEX + mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) + if not mo: + # unparsable. Maybe git-describe is misbehaving? + pieces["error"] = ("unable to parse git-describe output: '%s'" + % describe_out) + return pieces + + # tag + full_tag = mo.group(1) + if not full_tag.startswith(tag_prefix): + if verbose: + fmt = "tag '%s' doesn't start with prefix '%s'" + print(fmt % (full_tag, tag_prefix)) + pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" + % (full_tag, tag_prefix)) + return pieces + pieces["closest-tag"] = full_tag[len(tag_prefix):] + + # distance: number of commits since tag + pieces["distance"] = int(mo.group(2)) + + # commit: short hex revision ID + pieces["short"] = mo.group(3) + + else: + # HEX: no tags + pieces["closest-tag"] = None + out, rc = runner(GITS, ["rev-list", "HEAD", "--left-right"], cwd=root) + pieces["distance"] = len(out.split()) # total number of commits + + # commit date: see ISO-8601 comment in git_versions_from_keywords() + date = runner(GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root)[0].strip() + # Use only the last line. Previous lines may contain GPG signature + # information. + date = date.splitlines()[-1] + pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) + + return pieces + + +def plus_or_dot(pieces: Dict[str, Any]) -> str: + """Return a + if we don't already have one, else return a .""" + if "+" in pieces.get("closest-tag", ""): + return "." + return "+" + + +def render_pep440(pieces: Dict[str, Any]) -> str: + """Build up version string, with post-release "local version identifier". + + Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you + get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty + + Exceptions: + 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"] or pieces["dirty"]: + rendered += plus_or_dot(pieces) + rendered += "%d.g%s" % (pieces["distance"], pieces["short"]) + if pieces["dirty"]: + rendered += ".dirty" + else: + # exception #1 + rendered = "0+untagged.%d.g%s" % (pieces["distance"], + pieces["short"]) + if pieces["dirty"]: + rendered += ".dirty" + return rendered + + +def render_pep440_branch(pieces: Dict[str, Any]) -> str: + """TAG[[.dev0]+DISTANCE.gHEX[.dirty]] . + + The ".dev0" means not master branch. Note that .dev0 sorts backwards + (a feature branch will appear "older" than the master branch). + + Exceptions: + 1: no tags. 0[.dev0]+untagged.DISTANCE.gHEX[.dirty] + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"] or pieces["dirty"]: + if pieces["branch"] != "master": + rendered += ".dev0" + rendered += plus_or_dot(pieces) + rendered += "%d.g%s" % (pieces["distance"], pieces["short"]) + if pieces["dirty"]: + rendered += ".dirty" + else: + # exception #1 + rendered = "0" + if pieces["branch"] != "master": + rendered += ".dev0" + rendered += "+untagged.%d.g%s" % (pieces["distance"], + pieces["short"]) + if pieces["dirty"]: + rendered += ".dirty" + return rendered + + +def pep440_split_post(ver: str) -> Tuple[str, Optional[int]]: + """Split pep440 version string at the post-release segment. + + Returns the release segments before the post-release and the + post-release version number (or -1 if no post-release segment is present). + """ + vc = str.split(ver, ".post") + return vc[0], int(vc[1] or 0) if len(vc) == 2 else None + + +def render_pep440_pre(pieces: Dict[str, Any]) -> str: + """TAG[.postN.devDISTANCE] -- No -dirty. + + Exceptions: + 1: no tags. 0.post0.devDISTANCE + """ + if pieces["closest-tag"]: + if pieces["distance"]: + # update the post release segment + tag_version, post_version = pep440_split_post(pieces["closest-tag"]) + rendered = tag_version + if post_version is not None: + rendered += ".post%d.dev%d" % (post_version + 1, pieces["distance"]) + else: + rendered += ".post0.dev%d" % (pieces["distance"]) + else: + # no commits, use the tag as the version + rendered = pieces["closest-tag"] + else: + # exception #1 + rendered = "0.post0.dev%d" % pieces["distance"] + return rendered + + +def render_pep440_post(pieces: Dict[str, Any]) -> str: + """TAG[.postDISTANCE[.dev0]+gHEX] . + + The ".dev0" means dirty. Note that .dev0 sorts backwards + (a dirty tree will appear "older" than the corresponding clean one), + but you shouldn't be releasing software with -dirty anyways. + + Exceptions: + 1: no tags. 0.postDISTANCE[.dev0] + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"] or pieces["dirty"]: + rendered += ".post%d" % pieces["distance"] + if pieces["dirty"]: + rendered += ".dev0" + rendered += plus_or_dot(pieces) + rendered += "g%s" % pieces["short"] + else: + # exception #1 + rendered = "0.post%d" % pieces["distance"] + if pieces["dirty"]: + rendered += ".dev0" + rendered += "+g%s" % pieces["short"] + return rendered + + +def render_pep440_post_branch(pieces: Dict[str, Any]) -> str: + """TAG[.postDISTANCE[.dev0]+gHEX[.dirty]] . + + The ".dev0" means not master branch. + + Exceptions: + 1: no tags. 0.postDISTANCE[.dev0]+gHEX[.dirty] + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"] or pieces["dirty"]: + rendered += ".post%d" % pieces["distance"] + if pieces["branch"] != "master": + rendered += ".dev0" + rendered += plus_or_dot(pieces) + rendered += "g%s" % pieces["short"] + if pieces["dirty"]: + rendered += ".dirty" + else: + # exception #1 + rendered = "0.post%d" % pieces["distance"] + if pieces["branch"] != "master": + rendered += ".dev0" + rendered += "+g%s" % pieces["short"] + if pieces["dirty"]: + rendered += ".dirty" + return rendered + + +def render_pep440_old(pieces: Dict[str, Any]) -> str: + """TAG[.postDISTANCE[.dev0]] . + + The ".dev0" means dirty. + + Exceptions: + 1: no tags. 0.postDISTANCE[.dev0] + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"] or pieces["dirty"]: + rendered += ".post%d" % pieces["distance"] + if pieces["dirty"]: + rendered += ".dev0" + else: + # exception #1 + rendered = "0.post%d" % pieces["distance"] + if pieces["dirty"]: + rendered += ".dev0" + return rendered + + +def render_git_describe(pieces: Dict[str, Any]) -> str: + """TAG[-DISTANCE-gHEX][-dirty]. + + Like 'git describe --tags --dirty --always'. + + Exceptions: + 1: no tags. HEX[-dirty] (note: no 'g' prefix) + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"]: + rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) + else: + # exception #1 + rendered = pieces["short"] + if pieces["dirty"]: + rendered += "-dirty" + return rendered + + +def render_git_describe_long(pieces: Dict[str, Any]) -> str: + """TAG-DISTANCE-gHEX[-dirty]. + + Like 'git describe --tags --dirty --always -long'. + The distance/hash is unconditional. + + Exceptions: + 1: no tags. HEX[-dirty] (note: no 'g' prefix) + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) + else: + # exception #1 + rendered = pieces["short"] + if pieces["dirty"]: + rendered += "-dirty" + return rendered + + +def render(pieces: Dict[str, Any], style: str) -> Dict[str, Any]: + """Render the given version pieces into the requested style.""" + if pieces["error"]: + return {"version": "unknown", + "full-revisionid": pieces.get("long"), + "dirty": None, + "error": pieces["error"], + "date": None} + + if not style or style == "default": + style = "pep440" # the default + + if style == "pep440": + rendered = render_pep440(pieces) + elif style == "pep440-branch": + rendered = render_pep440_branch(pieces) + elif style == "pep440-pre": + rendered = render_pep440_pre(pieces) + elif style == "pep440-post": + rendered = render_pep440_post(pieces) + elif style == "pep440-post-branch": + rendered = render_pep440_post_branch(pieces) + elif style == "pep440-old": + rendered = render_pep440_old(pieces) + elif style == "git-describe": + rendered = render_git_describe(pieces) + elif style == "git-describe-long": + rendered = render_git_describe_long(pieces) + else: + raise ValueError("unknown style '%s'" % style) + + return {"version": rendered, "full-revisionid": pieces["long"], + "dirty": pieces["dirty"], "error": None, + "date": pieces.get("date")} + + +def get_versions() -> Dict[str, Any]: + """Get version information or return default if unable to do so.""" + # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have + # __file__, we can work backwards from there to the root. Some + # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which + # case we can only use expanded keywords. + + cfg = get_config() + verbose = cfg.verbose + + try: + return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, + verbose) + except NotThisMethod: + pass + + try: + root = os.path.realpath(__file__) + # versionfile_source is the relative path from the top of the source + # tree (where the .git directory might live) to this file. Invert + # this to find the root from __file__. + for _ in cfg.versionfile_source.split('/'): + root = os.path.dirname(root) + except NameError: + return {"version": "0+unknown", "full-revisionid": None, + "dirty": None, + "error": "unable to find root of source tree", + "date": None} + + try: + pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose) + return render(pieces, cfg.style) + except NotThisMethod: + pass + + try: + if cfg.parentdir_prefix: + return versions_from_parentdir(cfg.parentdir_prefix, root, verbose) + except NotThisMethod: + pass + + return {"version": "0+unknown", "full-revisionid": None, + "dirty": None, + "error": "unable to compute version", "date": None} From 203ad187ce4ac3300c2f15fa2deb5c916e6e0143 Mon Sep 17 00:00:00 2001 From: Aidan Heerdegen Date: Thu, 15 Aug 2024 13:56:52 +1000 Subject: [PATCH 02/15] Add Apache 2.0 license file Change CI to deploy on tagging. Change to modern pytest invocation. Added in change to license in conda metadata --- .github/workflows/CD.yml | 6 +- LICENSE | 201 +++++++++++++++++++++++++++++++++++++++ conda/meta.yml | 1 + pyproject.toml | 2 +- 4 files changed, 206 insertions(+), 4 deletions(-) create mode 100644 LICENSE diff --git a/.github/workflows/CD.yml b/.github/workflows/CD.yml index af7580a..b9e2312 100644 --- a/.github/workflows/CD.yml +++ b/.github/workflows/CD.yml @@ -1,9 +1,9 @@ name: CD on: - push: - branches: - - master + push: + tags: + - '*' env: PY_VERSION: 3.10 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/conda/meta.yml b/conda/meta.yml index b8a1c53..ce5dcd9 100644 --- a/conda/meta.yml +++ b/conda/meta.yml @@ -44,6 +44,7 @@ test: about: home: https://github.com/access-nri/um2nc-standalone license: Apache Software + license_file: LICENSE license_family: Apache summary: "Tool to convert fieldsfiles into netCDF format. Used for post-processing UM climate model output" diff --git a/pyproject.toml b/pyproject.toml index 1d79007..ac65337 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ maintainers = [ { name = "ACCESS-NRI", email = "access.nri@anu.edu.au" } ] description = "Program to convert Unified Model output files in fields file format to netCDF" -license = { text = "Apache-2.0" } +license = { file = "LICENSE" } readme = "README.md" keywords = ["netCDF", "UM", "postprocessing"] dynamic = ["version"] From 598cebcdd97ada12a9db2e64270e64b4073b4aa5 Mon Sep 17 00:00:00 2001 From: Aidan Heerdegen Date: Thu, 15 Aug 2024 14:56:19 +1000 Subject: [PATCH 03/15] Add CI workflow Quote python version string --- .github/workflows/CD.yml | 2 +- .github/workflows/CI.yml | 82 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/CI.yml diff --git a/.github/workflows/CD.yml b/.github/workflows/CD.yml index b9e2312..d60146b 100644 --- a/.github/workflows/CD.yml +++ b/.github/workflows/CD.yml @@ -6,7 +6,7 @@ on: - '*' env: - PY_VERSION: 3.10 + PY_VERSION: "3.10" jobs: diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml new file mode 100644 index 0000000..984ba94 --- /dev/null +++ b/.github/workflows/CI.yml @@ -0,0 +1,82 @@ +# Run CI tests +name: CI + +# Controls when the action will run. +on: + # Triggers the workflow on push or pull request events but only for the master branch + push: + branches: [ master, develop ] + pull_request: + branches: [ master, develop ] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +env: + PY_VERSION: "3.10" + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + conda-build: + name: Conda Build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup conda environment + uses: conda-incubator/setup-miniconda@11b562958363ec5770fef326fe8ef0366f8cbf8a # v3.0.1 + with: + miniconda-version: "latest" + python-version: ${{ env.PY_VERSION }} + environment-file: conda/environment.yml + auto-update-conda: false + auto-activate-base: false + show-channel-urls: true + + - name: Run conda build + shell: bash -el {0} + run: conda build . --no-anaconda-upload + + tests: + name: Tests + runs-on: ubuntu-latest + + # Run the job for different versions of python + strategy: + matrix: + python-version: ["3.10", "3.11", "3.12"] + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + + - name: Checkout code + uses: actions/checkout@v4.1.7 + + - name: Setup conda environment + uses: conda-incubator/setup-miniconda@v3 + with: + miniconda-version: "latest" + python-version: ${{ matrix.python-version }} + + - name: Install source + shell: bash -l {0} + run: python -m pip install -e . + + - name: List installed packages + shell: bash -l {0} + run: conda list + + - name: Lint + run: pylint --extension-pkg-whitelist=netCDF4 --ignored-modules=backports -E umpost + + - name: Run tests + shell: bash -l {0} + run: python -m pytest --cov=umpost --cov-report=xml -s test + + - name: Upload code coverage + uses: codecov/codecov-action@v4 + # Only upload once for the installed version + if: matrix.python-version == ${{ env.PY_VERSION }} + with: + token: ${{ secrets.codecov_token }} + files: ./coverage.xml \ No newline at end of file From e8b2b00f69953f248a70b254c402410c464e20e7 Mon Sep 17 00:00:00 2001 From: Aidan Heerdegen Date: Fri, 16 Aug 2024 11:21:43 +1000 Subject: [PATCH 04/15] Move meta.yml to meta.yaml, and fixed extraction of project name from pyproject.toml Replace python interpreter with plain text --- conda/{meta.yml => meta.yaml} | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) rename conda/{meta.yml => meta.yaml} (87%) diff --git a/conda/meta.yml b/conda/meta.yaml similarity index 87% rename from conda/meta.yml rename to conda/meta.yaml index ce5dcd9..86aa42a 100644 --- a/conda/meta.yml +++ b/conda/meta.yaml @@ -2,15 +2,16 @@ {% set version = data.get('version') %} {% set pyproj = load_file_data('../pyproject.toml', from_recipe_dir=True) %} {% set project = pyproj.get('project') %} +{% set name = project.get('name') %} package: - name: um2nc + name: {{ name }} version: "{{ version }}" build: noarch: python number: 0 - script: "{{ python }} -m pip install . -vv" + script: "python3 -m pip install . -vv" entry_points: {% for name, script in project.get('scripts', {}).items() %} - {{ name }} = {{ script }} @@ -23,7 +24,7 @@ requirements: host: - python - pip - - setupools >=61.0.0 + - setuptools >=61.0.0 - versioneer run: - python >=3.10 @@ -39,7 +40,7 @@ test: source_files: - test/** commands: - - py.test + - pytest about: home: https://github.com/access-nri/um2nc-standalone From e8aab36cde68a867638fbd3e78fd3245564c6700 Mon Sep 17 00:00:00 2001 From: Aidan Heerdegen Date: Fri, 16 Aug 2024 11:44:42 +1000 Subject: [PATCH 05/15] Remove test section from conda metadata --- conda/meta.yaml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/conda/meta.yaml b/conda/meta.yaml index 86aa42a..a32554a 100644 --- a/conda/meta.yaml +++ b/conda/meta.yaml @@ -32,16 +32,6 @@ requirements: - {{ dep }} {% endfor %} -test: - imports: - - umpost - requires: - - pytest - source_files: - - test/** - commands: - - pytest - about: home: https://github.com/access-nri/um2nc-standalone license: Apache Software From 0e39df9f68bb81a28486247aa87420dbdb36349b Mon Sep 17 00:00:00 2001 From: Aidan Heerdegen Date: Fri, 16 Aug 2024 12:31:43 +1000 Subject: [PATCH 06/15] Reuse conda build artifact in CI testing workflow --- .github/workflows/CI.yml | 30 +++++++++++++++++++++++++++--- conda/environment.yml | 1 + 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 984ba94..343e8f4 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -20,6 +20,10 @@ jobs: conda-build: name: Conda Build runs-on: ubuntu-latest + env: + NAME: test-${{ github.event.repository.name }} + outputs: + artifact-name: ${{ env.NAME }} steps: - uses: actions/checkout@v4 @@ -35,32 +39,52 @@ jobs: - name: Run conda build shell: bash -el {0} - run: conda build . --no-anaconda-upload + run: | + conda build . --no-anaconda-upload --output-folder=./build + + - uses: actions/upload-artifact@v4 + with: + name: ${{ env.NAME }} + if-no-files-found: error + path: ./build tests: name: Tests runs-on: ubuntu-latest + needs: conda-build # Run the job for different versions of python strategy: matrix: python-version: ["3.10", "3.11", "3.12"] + env: + ARTIFACT_LOCATION: ${{ github.workspace }}/conda-local + # Steps represent a sequence of tasks that will be executed as part of the job steps: - name: Checkout code uses: actions/checkout@v4.1.7 + - uses: actions/download-artifact@v4 + with: + name: ${{ needs.conda-build.outputs.artifact-name }} + path: ${{ env.ARTIFACT_LOCATION }} + - name: Setup conda environment uses: conda-incubator/setup-miniconda@v3 with: miniconda-version: "latest" python-version: ${{ matrix.python-version }} - - name: Install source + - name: DEBUG - where are things + run: ls ${{ env.ARTIFACT_LOCATION }} + + - name: Install conda package shell: bash -l {0} - run: python -m pip install -e . + run: | + conda install -c file://${{ env.ARTIFACT_LOCATION }} um2nc - name: List installed packages shell: bash -l {0} diff --git a/conda/environment.yml b/conda/environment.yml index 0667bea..df43c50 100644 --- a/conda/environment.yml +++ b/conda/environment.yml @@ -11,3 +11,4 @@ dependencies: - conda-build - conda-verify - versioneer + - pylint From d94d2463416dd883dbc4ba1ef4e855cc5a9c0a60 Mon Sep 17 00:00:00 2001 From: Aidan Heerdegen Date: Fri, 16 Aug 2024 13:34:45 +1000 Subject: [PATCH 07/15] Add channels to um2nc install --- .github/workflows/CI.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 343e8f4..b199a59 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -84,7 +84,7 @@ jobs: - name: Install conda package shell: bash -l {0} run: | - conda install -c file://${{ env.ARTIFACT_LOCATION }} um2nc + conda install -c conda-forge -c accessnri -c coecms -c file://${{ env.ARTIFACT_LOCATION }} um2nc - name: List installed packages shell: bash -l {0} From e9b87ecd852c9a14c27d6fc86b4cd6d6a9b72d66 Mon Sep 17 00:00:00 2001 From: Aidan Heerdegen Date: Fri, 16 Aug 2024 13:47:25 +1000 Subject: [PATCH 08/15] Use environment file to ensure pylint is installed --- .github/workflows/CI.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index b199a59..c01bcc6 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -77,6 +77,8 @@ jobs: with: miniconda-version: "latest" python-version: ${{ matrix.python-version }} + environment-file: conda/environment.yml + activate-environment: um2nc - name: DEBUG - where are things run: ls ${{ env.ARTIFACT_LOCATION }} From f394c51fc976bdd2e7ec04c5ec03949a40a21108 Mon Sep 17 00:00:00 2001 From: Aidan Heerdegen Date: Fri, 16 Aug 2024 13:56:16 +1000 Subject: [PATCH 09/15] Add explicit bash shell to linting step to use activated conda env correctly --- .github/workflows/CI.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index c01bcc6..6ab6534 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -93,6 +93,7 @@ jobs: run: conda list - name: Lint + shell: bash -l {0} run: pylint --extension-pkg-whitelist=netCDF4 --ignored-modules=backports -E umpost - name: Run tests From e998ccef7a870d36450e88ec5f375052fb8636f9 Mon Sep 17 00:00:00 2001 From: Aidan Heerdegen Date: Fri, 16 Aug 2024 16:03:35 +1000 Subject: [PATCH 10/15] Ignore um2netcdf imports in pyline Add pytest and pytest-cov to test environment --- .github/workflows/CI.yml | 2 +- conda/environment.yml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 6ab6534..0eb90fd 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -94,7 +94,7 @@ jobs: - name: Lint shell: bash -l {0} - run: pylint --extension-pkg-whitelist=netCDF4 --ignored-modules=backports -E umpost + run: pylint --extension-pkg-whitelist=netCDF4 --ignored-modules=um2netcdf4,umpost -E umpost - name: Run tests shell: bash -l {0} diff --git a/conda/environment.yml b/conda/environment.yml index df43c50..87cf5b4 100644 --- a/conda/environment.yml +++ b/conda/environment.yml @@ -12,3 +12,5 @@ dependencies: - conda-verify - versioneer - pylint + - pytest + - pytest-cov From 0e5907bdc4b9d4465913cd3609a394e07be1138f Mon Sep 17 00:00:00 2001 From: Aidan Heerdegen Date: Mon, 19 Aug 2024 16:24:34 +1000 Subject: [PATCH 11/15] Change to trigger branch from master to main --- .github/workflows/CI.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 0eb90fd..2bd67d2 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -5,9 +5,9 @@ name: CI on: # Triggers the workflow on push or pull request events but only for the master branch push: - branches: [ master, develop ] + branches: [ main, develop ] pull_request: - branches: [ master, develop ] + branches: [ main, develop ] # Allows you to run this workflow manually from the Actions tab workflow_dispatch: From 4160b63a23d9716ad04c869c57303d151841c66c Mon Sep 17 00:00:00 2001 From: Aidan Heerdegen Date: Mon, 19 Aug 2024 16:31:29 +1000 Subject: [PATCH 12/15] Add EOF endings to CI and CD workflow files --- .github/workflows/CD.yml | 2 +- .github/workflows/CI.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/CD.yml b/.github/workflows/CD.yml index d60146b..ea89ab4 100644 --- a/.github/workflows/CD.yml +++ b/.github/workflows/CD.yml @@ -37,4 +37,4 @@ jobs: python-version: ${{ env.PY_VERSION }} user: accessnri label: main - token: ${{ secrets.anaconda_token }} \ No newline at end of file + token: ${{ secrets.anaconda_token }} diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 2bd67d2..48df057 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -106,4 +106,4 @@ jobs: if: matrix.python-version == ${{ env.PY_VERSION }} with: token: ${{ secrets.codecov_token }} - files: ./coverage.xml \ No newline at end of file + files: ./coverage.xml From 02a7a7b99bf712049091e5a95dfe38563bc6d73f Mon Sep 17 00:00:00 2001 From: Aidan Heerdegen Date: Tue, 20 Aug 2024 10:14:34 +1000 Subject: [PATCH 13/15] Add entrypoint test to CI --- .github/workflows/CI.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 48df057..2f93d2d 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -96,6 +96,10 @@ jobs: shell: bash -l {0} run: pylint --extension-pkg-whitelist=netCDF4 --ignored-modules=um2netcdf4,umpost -E umpost + - name: Entrypoint test + shell: bash -l {0} + run: um2nc --help + - name: Run tests shell: bash -l {0} run: python -m pytest --cov=umpost --cov-report=xml -s test From 0e246cc50fd25e58eea4f78f2853d2e53612632d Mon Sep 17 00:00:00 2001 From: Aidan Heerdegen Date: Tue, 20 Aug 2024 10:26:34 +1000 Subject: [PATCH 14/15] Prepend um2nc module name to entrypoint --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index ac65337..76fef38 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,7 +24,7 @@ dependencies = [ "f90nml", ] [project.scripts] -um2nc = "umpost.um2netcdf:main" +um2nc = "um2nc.umpost.um2netcdf:main" [tool.versioneer] VCS = "git" From 2c7b35542072907613767526090108c4f67183f7 Mon Sep 17 00:00:00 2001 From: Aidan Heerdegen Date: Tue, 20 Aug 2024 12:41:16 +1000 Subject: [PATCH 15/15] Remove entrypoints and associated CI test, and debugging CI step --- .github/workflows/CI.yml | 7 ------- pyproject.toml | 2 -- 2 files changed, 9 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 2f93d2d..8a245ea 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -80,9 +80,6 @@ jobs: environment-file: conda/environment.yml activate-environment: um2nc - - name: DEBUG - where are things - run: ls ${{ env.ARTIFACT_LOCATION }} - - name: Install conda package shell: bash -l {0} run: | @@ -96,10 +93,6 @@ jobs: shell: bash -l {0} run: pylint --extension-pkg-whitelist=netCDF4 --ignored-modules=um2netcdf4,umpost -E umpost - - name: Entrypoint test - shell: bash -l {0} - run: um2nc --help - - name: Run tests shell: bash -l {0} run: python -m pytest --cov=umpost --cov-report=xml -s test diff --git a/pyproject.toml b/pyproject.toml index 76fef38..bfda3c9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,8 +23,6 @@ dependencies = [ "PyYAML", "f90nml", ] -[project.scripts] -um2nc = "um2nc.umpost.um2netcdf:main" [tool.versioneer] VCS = "git"