diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0dd5ffa..20bf3d8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -6,62 +6,19 @@ on: - published jobs: - build_wheels: - name: build wheel - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ ubuntu-latest ] - python-version: [ '3.x' ] - steps: - - name: checkout repository - uses: actions/checkout@v2 - - name: install Python - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: load cached Python installation - id: cache - uses: actions/cache@v2 - with: - path: ${{ env.pythonLocation }} - key: lint-${{ runner.os }}-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml', 'setup.*') }} - - name: build wheel - run: pip wheel . -w dist --no-deps - - name: save wheel - uses: actions/upload-artifact@v2 - with: - name: build - path: ./dist/*.whl - build_sdist: - name: package source + publish: + name: publish package to PyPI runs-on: ubuntu-latest steps: - name: checkout repository uses: actions/checkout@v2 - - name: install Python - uses: actions/setup-python@v2 - - name: install dependencies + - name: install Poetry + uses: abatilo/actions-poetry@v2.1.3 + - name: install Dunamai run: pip install dunamai - - name: package source - run: python setup.py sdist - - name: save source package - uses: actions/upload-artifact@v2 - with: - name: build - path: ./dist/*.tar.gz - upload_pypi: - name: publish to PyPI - needs: [ build_wheels, build_sdist ] - runs-on: ubuntu-latest - steps: - - name: retrieve wheel(s) and source - uses: actions/download-artifact@v2 - with: - name: build - path: dist - - name: upload wheel(s) and source - uses: pypa/gh-action-pypi-publish@v1.5.0 - with: - user: __token__ - password: ${{ secrets.PYPI_TOKEN }} + - name: extract version from VCS + run: poetry version $(dunamai from any) + - name: build wheel and source + run: poetry build + - name: upload wheel and source + run: poetry publish --username __token__ --password ${{ secrets.PYPI_TOKEN }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 9562091..eeeb85c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,6 +1,15 @@ name: tests -on: [ push ] +on: + push: + branches: + - main + paths: + - '**.py' + - '.github/workflows/tests.yml' + pull_request: + branches: + - main jobs: lint: @@ -11,22 +20,34 @@ jobs: uses: actions/checkout@v2 - name: install Python uses: actions/setup-python@v2 - - name: install flake8 - run: pip install flake8 + - name: load cached Python installation + id: cache + uses: actions/cache@v2 + with: + path: ${{ env.pythonLocation }} + key: lint-${{ runner.os }}-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }} + - name: install linters + run: pip install flake8 oitnb - name: lint with flake8 run: | # stop the build if there are Python syntax errors or undefined names flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + - name: lint with oitnb + run: oitnb . --check test: needs: lint name: test runs-on: ${{ matrix.os }} strategy: + fail-fast: false matrix: - os: [ ubuntu-latest ] - python-version: [ '3.6', '3.x' ] + os: [ ubuntu-latest, macos-latest ] + python-version: [ '3.6', '3.7', '3.8', '3.9', '3.x' ] + exclude: + - os: macos-latest + python-version: '3.x' steps: - name: clone repository uses: actions/checkout@v2 @@ -39,18 +60,33 @@ jobs: uses: actions/cache@v2 with: path: ${{ env.pythonLocation }} - key: test-${{ runner.os }}-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml', 'setup.*') }} + key: test-${{ runner.os }}-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }} - name: install dependencies - if: steps.cache.outputs.cache-hit != 'true' run: pip install ".[testing]" - name: run tests - if: matrix.python-version != '3.x' || matrix.os != 'ubuntu-latest' run: pytest --numprocesses auto + test_with_coverage: + needs: [ lint, test ] + name: test with coverage + runs-on: ubuntu-latest + steps: + - name: clone repository + uses: actions/checkout@v2 + - name: install Python + uses: actions/setup-python@v2 + - name: load cached Python installation + id: cache + uses: actions/cache@v2 + with: + path: ${{ env.pythonLocation }} + key: test-${{ runner.os }}-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }} + - name: install dependencies + run: pip install ".[testing]" - name: run tests with coverage - if: matrix.python-version == '3.x' && matrix.os == 'ubuntu-latest' run: pytest --numprocesses auto --cov . --cov-report xml:coverage.xml + - name: show coverage report + run: coverage report - name: upload coverage to Codecov - if: matrix.python-version == '3.x' && matrix.os == 'ubuntu-latest' uses: codecov/codecov-action@v2.1.0 with: token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/tests_simple.yml b/.github/workflows/tests_simple.yml new file mode 100644 index 0000000..249f67d --- /dev/null +++ b/.github/workflows/tests_simple.yml @@ -0,0 +1,54 @@ +name: tests + +on: + push: + branches-ignore: + - main + paths: + - '**.py' + - '.github/workflows/tests_simple.yml' + +jobs: + lint: + name: lint + runs-on: ubuntu-latest + steps: + - name: clone repository + uses: actions/checkout@v2 + - name: install Python + uses: actions/setup-python@v2 + - name: load cached Python installation + id: cache + uses: actions/cache@v2 + with: + path: ${{ env.pythonLocation }} + key: lint-${{ runner.os }}-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }} + - name: install linters + run: pip install flake8 oitnb + - name: lint with flake8 + run: | + # stop the build if there are Python syntax errors or undefined names + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide + flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + - name: lint with oitnb + run: oitnb . --check + test: + needs: lint + name: test + runs-on: ubuntu-latest + steps: + - name: clone repository + uses: actions/checkout@v2 + - name: install Python + uses: actions/setup-python@v2 + - name: load cached Python installation + id: cache + uses: actions/cache@v2 + with: + path: ${{ env.pythonLocation }} + key: test-${{ runner.os }}-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }} + - name: install dependencies + run: pip install ".[testing]" + - name: run tests + run: pytest --numprocesses auto diff --git a/pyproject.toml b/pyproject.toml index a054380..625037f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,47 @@ +[tool.poetry] +name = 'stormevents' +version = '0.0.0' +description = 'Python interfaces for observational data surrounding named storm events' +authors = ['Zach Burnett '] +license = 'GPL-3.0-or-later' +readme = 'README.md' +repository = 'https://github.com/oceanmodeling/StormEvents.git' +documentation = 'https://stormevents.readthedocs.io' + [build-system] requires = [ - "dunamai", - "setuptools", + 'poetry-core>=1.0.0', + 'poetry-dynamic-versioning', ] -build-backend = "setuptools.build_meta" +build-backend = 'poetry.core.masonry.api' + +[tool.poetry-dynamic-versioning] +enable = true + +[tool.poetry.dependencies] +python = '^3.6' +beautifulsoup4 = '*' +geopandas = '*' +netcdf4 = '*' +numpy = '*' +python-dateutil = '*' +pandas = '*' +pyproj = '>=2.6' +requests = '*' +shapely = '*' +typepigeon = '>=1.0.5' +xarray = '*' +isort = { version = '*', optional = true } +oitnb = { version = '*', optional = true } +pytest = { version = '*', optional = true } +pytest-cov = { version = '*', optional = true } +pytest-socket = { version = '*', optional = true } +pytest-xdist = { version = '*', optional = true } +m2r2 = { version = '*', optional = true } +sphinx = { version = '*', optional = true } +sphinx-rtd-theme = { version = '*', optional = true } + +[tool.poetry.extras] +testing = ['pytest', 'pytest-cov', 'pytest-socket', 'pytest-xdist'] +development = ['isort', 'oitnb'] +documentation = ['m2r2', 'sphinx', 'sphinx-rtd-theme'] diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index be4e868..0000000 --- a/setup.cfg +++ /dev/null @@ -1,42 +0,0 @@ -[metadata] -name = stormevents -author = Zach Burnett , William Pringle , Jaime R Calzada -description = Python interfaces for observational data surrounding named storm events -long_description = file:README.md -long_description_content_type = text/markdown -license = GPL -python_requires = >=3.6 -url = https://github.com/noaa-ocs-modeling/StormEvents.git - -[options] -install_requires = - beautifulsoup4 - geopandas - netcdf4 - numpy - python-dateutil - pandas - pyproj >= 2.6 - requests - shapely - typepigeon >= 1.0.5 - xarray - -[options.extras_require] -testing = - pytest - pytest-cov - pytest-socket - pytest-xdist -development = - flake8 - isort - oitnb -documentation = - dunamai - m2r2 - sphinx - sphinx-rtd-theme - -[options.package_data] -* = *.json diff --git a/setup.py b/setup.py deleted file mode 100644 index ae64250..0000000 --- a/setup.py +++ /dev/null @@ -1,17 +0,0 @@ -import os -import warnings - -from setuptools import find_packages, setup - -if '__version__' in os.environ: - __version__ = os.environ['__version__'] -else: - from dunamai import Version - - try: - __version__ = Version.from_any_vcs().serialize() - except RuntimeError as error: - warnings.warn(f'{error.__class__.__name__} - {error}') - __version__ = '0.0.0' - -setup(version=__version__, packages=find_packages(exclude=('tests',)), test_suite='tests') diff --git a/tests/test_nhc.py b/tests/test_nhc.py index db9537e..6036fa1 100644 --- a/tests/test_nhc.py +++ b/tests/test_nhc.py @@ -1,6 +1,8 @@ from copy import copy from datetime import timedelta +import sys +import numpy import pytest from pytest_socket import SocketBlockedError @@ -110,7 +112,7 @@ def test_vortex_track_tracks(): assert len(tracks) == 4 assert len(tracks['OFCL']) == 77 - assert len(tracks['OFCL']['20180831T000000']) == 2 + assert len(tracks['OFCL']['20180831T000000']) == 13 @pytest.mark.disable_socket @@ -160,13 +162,12 @@ def test_vortex_track_to_file(): check_reference_directory(output_directory, reference_directory) -@pytest.mark.skip def test_vortex_track_distances(): track_1 = VortexTrack.from_storm_name('florence', 2018) track_2 = VortexTrack.from_storm_name('florence', 2018, file_deck='a', advisories=['OFCL']) - assert track_1.distances['BEST']['20180830T060000'] == 8725961.838567913 - assert track_2.distances['OFCL']['20180831T000000'] == 15490.033837939689 + assert numpy.isclose(track_1.distances['BEST']['20180830T060000'], 8725961.838567913) + assert numpy.isclose(track_2.distances['OFCL']['20180831T000000'], 8882602.389540724) def test_vortex_track_recompute_velocity(): diff --git a/tests/test_stormevent.py b/tests/test_stormevent.py index 732ecbe..16082d1 100644 --- a/tests/test_stormevent.py +++ b/tests/test_stormevent.py @@ -2,6 +2,7 @@ import os import pytest +import shapely from shapely.geometry import box from stormevents.stormevent import StormEvent @@ -181,29 +182,24 @@ def test_storm_event_coops_product_within_isotach(florence2018): def test_storm_event_coops_product_within_region(florence2018): - null_track = florence2018.track(end_date=florence2018.start_date + timedelta(hours=12)) - null_data = florence2018.coops_product_within_region( + null_tidal_data = florence2018.coops_product_within_region( 'water_level', - region=box(*null_track.linestrings['BEST']['20180830T060000'].bounds), - end_date=null_track.end_date, + region=shapely.geometry.box(0, 0, 1, 1), + start_date=florence2018.start_date, + end_date=florence2018.start_date + timedelta(minutes=1), ) - track = florence2018.track( - start_date=datetime(2018, 9, 13, 23, 59), - end_date=datetime(2018, 9, 14), - file_deck='a', - advisories='OFCL', - ) + east_coast = shapely.geometry.box(-85, 25, -65, 45) - tidal_data_1 = florence2018.coops_product_within_region( + east_coast_tidal_data = florence2018.coops_product_within_region( 'water_level', - region=box(*track.linestrings['OFCL']['20180914T000000'].bounds), - start_date=track.start_date, - end_date=track.end_date, + region=east_coast, + start_date=datetime(2018, 9, 13, 23, 59), + end_date=datetime(2018, 9, 14), ) - assert len(null_data.data_vars) == 0 - assert list(tidal_data_1.data_vars) == ['v', 's', 'f', 'q'] + assert len(null_tidal_data.data_vars) == 0 + assert list(east_coast_tidal_data.data_vars) == ['v', 's', 'f', 'q'] - assert null_data['t'].sizes == {} - assert tidal_data_1.sizes == {'nos_id': 8, 't': 1} + assert null_tidal_data['t'].sizes == {} + assert east_coast_tidal_data.sizes == {'nos_id': 111, 't': 1}