diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..da67ffb --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,36 @@ +name: build ⚙️ + +on: [ push, pull_request ] + +jobs: + main: + runs-on: ubuntu-22.04 + strategy: + matrix: + python-version: ["3.10"] + steps: + - uses: actions/checkout@master + - uses: actions/setup-python@v6 + name: Setup Python ${{ matrix.python-version }} + with: + python-version: ${{ matrix.python-version }} + - name: Install system packages + run: | + sudo apt-get update -qq + sudo apt-get install -y devscripts debhelper-compat dh-python python3-all python3-build pybuild-plugin-pyproject python3-setuptools python3-tomli python3-wheel + sudo pip3 install --upgrade setuptools wheel build + - name: Install package and dev requirements 📦 + run: | + pip3 install . + pip3 install ".[dev]" + pip3 install ".[release]" + - name: run tests ⚙️ + run: python3 tests/run_tests.py + - name: run flake8 ⚙️ + run: | + xargs flake8 + - name: build Python package 🏗️ + run: python3 -m build + - name: test debian build + run: debuild -b -uc -us + continue-on-error: true diff --git a/.gitignore b/.gitignore index 45c6a1c..df76d63 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,4 @@ *.pyc build dist -woudc_extcsv.egg-info -MANIFEST +*.egg-info diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 98663f0..0000000 --- a/.travis.yml +++ /dev/null @@ -1,22 +0,0 @@ -language: python - -python: - - "3.5" - - "3.7" - -before_install: - - sudo apt-get update -qq - - sudo apt-get install -y pandoc devscripts debhelper python-setuptools - -install: - - pip install -r requirements-dev.txt - - python setup.py install - -script: - - python setup.py test - - find -type f -name "*.py" | xargs flake8 - -after_success: - - coverage run --source woudc_extcsv setup.py test - - coverage report -m - - debuild -b -uc -us diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 9cdd8f6..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,4 +0,0 @@ -recursive-include woudc_extcsv *.csv -include LICENSE.md -include README.md -include requirements.txt diff --git a/README.md b/README.md index 3a57a6c..846f0a9 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,4 @@ -[![Build Status](https://travis-ci.org/woudc/woudc-extcsv.png?branch=master)](https://travis-ci.org/woudc/woudc-extcsv) [![Build status](https://ci.appveyor.com/api/projects/status/02koln2pe4ap5kvd/branch/master?svg=true)](https://ci.appveyor.com/project/tomkralidis/woudc-extcsv) -[![Downloads this month on PyPI](https://img.shields.io/pypi/dm/woudc-extcsv.svg)](http://pypi.python.org/pypi/woudc-extcsv) -[![Latest release](https://img.shields.io/pypi/v/woudc-extcsv.svg)](http://pypi.python.org/pypi/woudc-extcsv) -[![License](https://img.shields.io/github/license/woudc/woudc-extcsv.svg)](https://github.com/woudc/woudc-extcsv) +[![Build Status](https://github.com/woudc/woudc-extcsv/workflows/build%20%E2%9A%99%EF%B8%8F/badge.svg)](https://github.com/woudc/woudc-extcsv/actions) # WOUDC Extended CSV library @@ -10,24 +7,24 @@ Python package providing read/write support for files of the ## Installation -### Requirements +### pip -woudc-extcsv requires Python 3 or above. See `requirements.txt`. - -### Development +Install latest stable version from [PyPI](https://pypi.org/project/woudc-extcsv). ```bash -# install dev requirements -pip install -r requirements-dev.txt +pip3 install woudc-extcsv ``` -### Installing the Package +### From source +Install latest development version. ```bash -# via pip -pip install woudc-extcsv -# via easy_install -easy_install woudc-extcsv +python3 -m venv woudc-extcsv +cd woudc-extcsv +. bin/activate +git clone https://github.com/woudc/woudc-extcsv.git +cd woudc-extcsv +pip3 install . ``` ## Usage @@ -37,7 +34,7 @@ easy_install woudc-extcsv ```python from woudc_extcsv import Reader # read from file -with open('file.csv', 'r') as ff: +with open('file.csv') as ff: ecsv = Reader(ff.read()) # read from string ecsv = Reader(my_ecsv_string) @@ -125,7 +122,7 @@ The ExtendedCSV class is a parser class used in the Reader and Writer classes, a ```python from woudc_extcsv import ExtendedCSV # read from file -with open('file.csv', 'r') as ff: +with open('file.csv') as ff: ecsv = ExtendedCSV(ff.read()) # read from string ecsv = Extended(my_ecsv_string) @@ -164,54 +161,48 @@ except (NonStandardDataError, MetadataValidationError) as err: ## Development -For development environments, install -in a Python [virtualenv](http://virtualenv.org): - ```bash -virtualenv foo -cd foo -. bin/activate -# fork master -# fork https://github.com/woudc/woudc-extcsv on GitHub -# clone your fork to create a branch -git clone https://github.com/{your GitHub username}/woudc-extcsv.git +python3 -m venv woudc-extcsv cd woudc-extcsv -# install dev packages -pip install -r requirements-dev.txt -# create upstream remote -git remote add upstream https://github.com/woudc/woudc-extcsv.git -git pull upstream master -git branch my-cool-feature -git checkout my-cool-feature -# start dev -git commit -m 'implement cool feature' -# push to your fork -git push origin my-cool-feature -# issue Pull Request on GitHub -git checkout master -# cleanup/update once your branch is merged on GitHub -# remove branch -git branch -D my-cool-feature -# update your fork -git pull upstream master -git push origin master +source bin/activate +git clone https://github.com/woudc/woudc-extcsv.git +cd woudc-extcsv +pip3 install . +pip3 install ".[dev]" ``` ### Running Tests ```bash -# via distutils -python setup.py test -# manually -python run_tests.py -# report test coverage -coverage run --source woudc_extcsv setup.py test -coverage report -m +python3 tests/run_tests.py +``` + +## Releasing + +```bash +# create release (x.y.z is the release version) +vi pyproject.toml # update [project]/version +git commit -am 'update release version x.y.z' +git push origin master +git tag -a x.y.z -m 'tagging release version x.y.z' +git push --tags + +# upload to PyPI +rm -fr build dist *.egg-info +python3 -m build +twine upload dist/* + +# publish release on GitHub (https://github.com/woudc/woudc-extcsv/releases/new) + +# bump version back to dev +vi pyproject.toml # update [project]/version +git commit -am 'back to dev' +git push origin master ``` ### Code Conventions -woudc_extcsv code conventions are as per +woudc-extcsv code conventions are as per [PEP8](https://www.python.org/dev/peps/pep-0008). ```bash @@ -237,5 +228,5 @@ Board [Policy on Acceptable Network and Device Use] ## Contact -* [Tom Kralidis](http://geds20-sage20.ssc-spc.gc.ca/en/GEDS20/?pgid=015&dn=CN%3Dtom.kralidis%40canada.ca%2COU%3DDAT-GES%2COU%3DMON-STR%2COU%3DMON-DIR%2COU%3DMSCB-DGSMC%2COU%3DDMO-CSM%2COU%3DEC-EC%2CO%3Dgc%2CC%3Dca) -* [Thinesh Sornalingam](http://geds20-sage20.ssc-spc.gc.ca/en/GEDS20/?pgid=015&dn=CN%3Dthinesh.sornalingam%40canada.ca%2COU%3DDAT-GES%2COU%3DMON-STR%2COU%3DMON-DIR%2COU%3DMSCB-DGSMC%2COU%3DDMO-CSM%2COU%3DEC-EC%2CO%3DGC%2CC%3DCA) +* [Tom Kralidis](https://github.com/tomkralidis) +* [Thinesh Sornalingam](https://github.com/thineshsornalingam) diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index b1b7c68..0000000 --- a/appveyor.yml +++ /dev/null @@ -1,28 +0,0 @@ -environment: - matrix: - - PYTHON: "C:\\Python35" - MINICONDA: "C:\\Miniconda3" - PYTHON_VERSION: "3.5" - PYTHON_ARCH: "32" - - PYTHON: "C:\\Python37" - MINICONDA: "C:\\Miniconda3" - PYTHON_VERSION: "3.7" - PYTHON_ARCH: "32" - -install: - - set PATH=%MINICONDA%;%MINICONDA%\\Scripts;%PATH% - - conda update -q conda --yes - - conda create -q -n appveyor-tests python=%PYTHON_VERSION% --yes - - activate appveyor-tests - - conda install --file requirements-dev.txt --yes - - conda install -c conda-forge pyproj --yes - - python setup.py install - -build: off - -test_script: - - python setup.py test - -on_success: - - coverage.exe run --source woudc_extcsv setup.py test - - coverage.exe report -m diff --git a/debian/compat b/debian/compat deleted file mode 100644 index b1bd38b..0000000 --- a/debian/compat +++ /dev/null @@ -1 +0,0 @@ -13 diff --git a/debian/control b/debian/control index 34b6125..2ebd3c7 100644 --- a/debian/control +++ b/debian/control @@ -2,14 +2,14 @@ Source: woudc-extcsv Section: python Priority: optional Maintainer: WOUDC -Build-Depends: debhelper (>= 9), python3, python3-setuptools +Build-Depends: debhelper-compat (= 13), devscripts, dh-python, python3, python3-all, python3-build, pybuild-plugin-pyproject, python3-setuptools, python3-tomli, python3-wheel Standards-Version: 3.9.5 X-Python-Version: >= 3.10 Vcs-Git: https://github.com/woudc/woudc-extcsv.git Package: woudc-extcsv Architecture: all -Depends: ${misc:Depends}, ${python:Depends}, python3-pkg-resources, python3-unicodecsv +Depends: ${misc:Depends}, ${python:Depends}, python3-jsonschema, python3-pkg-resources, python3-unicodecsv, python3-yaml Homepage: https://woudc.org Description: WMO WOUDC format reader/writer woudc-extcsv is a Python package providing parsing and read/write support of the diff --git a/debian/rules b/debian/rules index 63aae08..7687cfc 100755 --- a/debian/rules +++ b/debian/rules @@ -9,5 +9,7 @@ # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 +export PYBUILD_SYSTEM=pyproject + %: dh $@ --with python3 --buildsystem=pybuild diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..711dbe6 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,47 @@ +[build-system] +requires = ["setuptools>=61", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "woudc-extcsv" +version = "0.8.dev0" +description = "Python package providing read/write support of the WOUDC Extended CSV format." +readme = "README.md" +requires-python = ">=3.10" +license = "MIT" +license-files = ["LICENSE.md"] +keywords = ["woudc", "ozone", "uv", "ultra-violet", "WMO", "Extended CSV"] +authors = [ + {name = "Thinesh Sornalingam", email = "thinesh.sornalingam@ec.gc.ca"}, + {name = "Tom Kralidis", email = "tomkralidis@gmail.com"} +] +maintainers = [ + {name = "Tom Kralidis", email = "tomkralidis@gmail.com"}, + {name = "Kevin Ngai", email = "kevin.ngai@ec.gc.ca"} +] +classifiers = [ + "Development Status :: 4 - Beta", + "Environment :: Console", + "Intended Audience :: Developers", + "Intended Audience :: Science/Research", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Topic :: Scientific/Engineering :: Atmospheric Science" +] +dependencies = [ + "jsonschema", + "pyyaml" +] + +[project.optional-dependencies] +dev = ["Cython", "flake8"] +release = ["build", "twine", "wheel"] + +[project.urls] +homepage = "https://github.com/woudc/woudc-extcsv" +source = "https://github.com/woudc/woudc-extcsv" +documentation = "https://github.com/woudc/woudc-extcsv" +issues = "https://github.com/woudc/woudc-extcsv/issues" + +[tool.setuptools.package-data] +"woudc_extcsv.resources" = ["*.csv", "*.json", "*.yml"] diff --git a/requirements-dev.txt b/requirements-dev.txt deleted file mode 100644 index 1ab7d22..0000000 --- a/requirements-dev.txt +++ /dev/null @@ -1,5 +0,0 @@ -Cython -coverage -flake8 -twine -wheel diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 1a4a25a..0000000 --- a/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -jsonschema -pyyaml diff --git a/setup.py b/setup.py deleted file mode 100644 index ba88cff..0000000 --- a/setup.py +++ /dev/null @@ -1,146 +0,0 @@ -# ================================================================= -# -# Terms and Conditions of Use -# -# Unless otherwise noted, computer program source code of this -# distribution is covered under Crown Copyright, Government of -# Canada, and is distributed under the MIT License. -# -# The Canada wordmark and related graphics associated with this -# distribution are protected under trademark law and copyright law. -# No permission is granted to use them outside the parameters of -# the Government of Canada's corporate identity program. For -# more information, see -# http://www.tbs-sct.gc.ca/fip-pcim/index-eng.asp -# -# Copyright title to all 3rd party software distributed with this -# software is held by the respective copyright holders as noted in -# those files. Users are asked to read the 3rd Party Licenses -# referenced with those assets. -# -# Copyright (c) 2025 Government of Canada -# -# Permission is hereby granted, free of charge, to any person -# obtaining a copy of this software and associated documentation -# files (the "Software"), to deal in the Software without -# restriction, including without limitation the rights to use, -# copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the -# Software is furnished to do so, subject to the following -# conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -# OTHER DEALINGS IN THE SOFTWARE. -# -# ================================================================= - -import os -import io -import re -from setuptools import Command, find_packages, setup - - -class PyTest(Command): - user_options = [] - - def initialize_options(self): - pass - - def finalize_options(self): - pass - - def run(self): - import subprocess - import sys - errno = subprocess.call([sys.executable, 'tests/run_tests.py']) - raise SystemExit(errno) - - -def read(filename, encoding='utf-8'): - """read file contents""" - full_path = os.path.join(os.path.dirname(__file__), filename) - with io.open(full_path, encoding=encoding) as fh: - contents = fh.read().strip() - return contents - - -def get_package_version(): - """get version from top-level package init""" - version_file = read('woudc_extcsv/__init__.py') - version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", - version_file, re.M) - if version_match: - return version_match.group(1) - raise RuntimeError('Unable to find version string.') - - -# set dependencies -with open('requirements.txt') as ff: - INSTALL_REQUIRES = [line.strip() for line in ff] - -KEYWORDS = [ - 'woudc', - 'ozone', - 'uv', - 'ultra-violet', - 'WMO', - 'Extended CSV' -] - -DESCRIPTION = ('Python package providing read/write support of the ' - 'WOUDC Extended CSV format.') - -LONG_DESCRIPTION = read('README.md') - -CONTACT = 'Meteorological Service of Canada' - -EMAIL = 'thinesh.sornalingam@canada.ca' - -SCRIPTS = [] - -URL = 'https://github.com/woudc/woudc-extcsv' - - -setup( - name='woudc-extcsv', - version=get_package_version(), - description=DESCRIPTION.strip(), - long_description=LONG_DESCRIPTION, - long_description_content_type='text/markdown', - license='MIT', - platforms='all', - keywords=' '.join(KEYWORDS), - author=CONTACT, - author_email=EMAIL, - maintainer=CONTACT, - maintainer_email=EMAIL, - url=URL, - install_requires=INSTALL_REQUIRES, - packages=find_packages('.'), - package_data={ - 'woudc_extcsv': ['tables-schema.json', 'tables-backfilling.yml', - 'errors-backfilling.csv'] - }, - scripts=SCRIPTS, - classifiers=[ - 'Development Status :: 4 - Beta', - 'Environment :: Console', - 'Intended Audience :: Developers', - 'Intended Audience :: Science/Research', - 'License :: OSI Approved :: MIT License', - 'Operating System :: OS Independent', - 'Programming Language :: Python', - 'Topic :: Scientific/Engineering :: Atmospheric Science' - ], - cmdclass={'test': PyTest}, - test_suite='tests.run_tests' -) diff --git a/woudc_extcsv/__init__.py b/woudc_extcsv/__init__.py index 7eb14ae..b47a867 100644 --- a/woudc_extcsv/__init__.py +++ b/woudc_extcsv/__init__.py @@ -65,9 +65,9 @@ __dirpath = os.path.dirname(os.path.realpath(__file__)) -WDR_TABLE_SCHEMA = os.path.join(__dirpath, 'tables-schema.json') -WDR_TABLE_CONFIG = os.path.join(__dirpath, 'tables-backfilling.yml') -WDR_ERROR_CONFIG = os.path.join(__dirpath, 'errors-backfilling.csv') +WDR_TABLE_SCHEMA = os.path.join(__dirpath, 'resources', 'tables-schema.json') +WDR_TABLE_CONFIG = os.path.join(__dirpath, 'resources', 'tables-backfilling.yml') # noqa +WDR_ERROR_CONFIG = os.path.join(__dirpath, 'resources', 'errors-backfilling.csv') # noqa LOGGER = logging.getLogger(__name__) @@ -190,7 +190,7 @@ def loads(strbuf): return Reader(strbuf) -class ExtendedCSV(object): +class ExtendedCSV: """ WOUDC Extended CSV parser @@ -1498,7 +1498,7 @@ def validate_dataset_tables(self): self.errors) -class Reader(object): +class Reader: """WOUDC Extended CSV reader""" def __init__(self, content): @@ -1624,7 +1624,7 @@ def metadata_validator(self): return self.ecsv.validate_metadata_tables() -class Writer(object): +class Writer: """WOUDC Extended CSV writer""" def __init__(self, ds=None, template=False): diff --git a/woudc_extcsv/errors-backfilling.csv b/woudc_extcsv/resources/errors-backfilling.csv similarity index 100% rename from woudc_extcsv/errors-backfilling.csv rename to woudc_extcsv/resources/errors-backfilling.csv diff --git a/woudc_extcsv/tables-backfilling.yml b/woudc_extcsv/resources/tables-backfilling.yml similarity index 100% rename from woudc_extcsv/tables-backfilling.yml rename to woudc_extcsv/resources/tables-backfilling.yml diff --git a/woudc_extcsv/tables-schema.json b/woudc_extcsv/resources/tables-schema.json similarity index 100% rename from woudc_extcsv/tables-schema.json rename to woudc_extcsv/resources/tables-schema.json