diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b7d25682..4baaef6e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -4,13 +4,13 @@ on: [ push, pull_request ] jobs: main: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 strategy: matrix: python-version: ["3.12"] steps: - uses: actions/checkout@master - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v6 name: Setup Python ${{ matrix.python-version }} with: python-version: ${{ matrix.python-version }} @@ -19,15 +19,15 @@ jobs: - name: Install requirements 📦 run: | pip3 install -e . - pip3 install -r requirements.txt - pip3 install -r requirements-dev.txt - pip3 install -r docs/requirements.txt + pip3 install ".[dev]" + pip3 install ".[docs]" + pip3 install ".[test]" - name: run tests ⚙️ - run: python3 -m pytest + run: pytest tests/ - name: run tests in offline mode if: matrix.python-version == '3.12' run: | - python3 -m pytest \ + pytest tests/\ -m "not online" \ --disable-socket \ --deselect="tests/doctests/wcs_thredds.txt::wcs_thredds.txt" \ @@ -45,4 +45,4 @@ jobs: - name: build docs 🏗️ run: cd docs && make html - name: run flake8 ⚙️ - run: flake8 owslib + run: flake8 owslib/ diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 814ef3ff..4b2d503a 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -10,7 +10,7 @@ jobs: python-version: ["3.12"] steps: - uses: actions/checkout@master - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v6 name: Setup Python ${{ matrix.python-version }} with: python-version: ${{ matrix.python-version }} @@ -18,8 +18,9 @@ jobs: - name: Install requirements 📦 run: | pip install -e . - pip install -r requirements.txt - pip install -r requirements-dev.txt + pip install ".[dev]" + pip install ".[docs]" + pip install ".[test]" - name: run tests ⚙️ - run: python -m pytest + run: pytest tests/ diff --git a/MANIFEST.in b/MANIFEST.in index 1a68d690..26311789 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,5 +1,2 @@ -include LICENSE -include *.md -include *.rst -include *.txt -recursive-exclude tests * \ No newline at end of file +# this file controls the contents of sdist +prune tests diff --git a/README.md b/README.md index c5f7ed4a..f8656295 100644 --- a/README.md +++ b/README.md @@ -147,7 +147,7 @@ Releasing ```bash # update version - vi owslib/__init__.py + vi pyproject.toml # update [project]/version git commit -m 'update release version' owslib/__init__.py # push changes git push origin master diff --git a/owslib/__init__.py b/owslib/__init__.py index 06cc0f1e..af87e902 100644 --- a/owslib/__init__.py +++ b/owslib/__init__.py @@ -1 +1,12 @@ -__version__ = '0.36.dev0' +# -*- coding: ISO-8859-15 -*- +# ============================================================================= +# Copyright (c) 2026 Tom Kralidis +# +# Authors : Tom Kralidis +# +# Contact email: tomkralidis@gmail.com +# ============================================================================= + +from owslib.util import get_package_version + +__version__ = get_package_version() diff --git a/owslib/util.py b/owslib/util.py index 4eb33495..ab6c762b 100644 --- a/owslib/util.py +++ b/owslib/util.py @@ -1,6 +1,6 @@ # -*- coding: ISO-8859-15 -*- # ============================================================================= -# Copyright (c) 2025 Tom Kralidis +# Copyright (c) 2026 Tom Kralidis # # Authors : Tom Kralidis # @@ -12,6 +12,7 @@ import copy from copy import deepcopy from datetime import datetime, timedelta, timezone +import importlib.metadata from io import StringIO, BytesIO import os import re @@ -1068,3 +1069,13 @@ def str2bool(value: Union[bool, str]) -> bool: value2 = value.lower() in ('yes', 'true', 't', '1', 'on') return value2 + + +def get_package_version() -> str: + """ + Helper function to get package version + + :returns: `str` of version of package + """ + + return importlib.metadata.version('OWSLib') diff --git a/pyproject.toml b/pyproject.toml index 205a289e..0a3252ce 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,61 @@ [build-system] -requires = ["setuptools>=46.4", "wheel"] +requires = ["setuptools<69", "wheel"] build-backend = "setuptools.build_meta" + +[project] +name = "OWSLib" +version = "0.36.dev0" +description = "OGC Web Service utility library" +readme = "README.md" +requires-python = ">=3.12" +license = {text = "BSD-3-Clause"} +keywords = ["gis", "ogc", "ogcapi", "ows", "opensearch", "iso", "19115", "fgdc", "dif", "ows", "wfs", "wms", "sos", "csw", "wps", "wcs", "capabilities", "metadata", "wmts", "connectedsystems"] +authors = [ + {name = "Sean Gillies", email = "sean.gillies@gmail.com"}, + {name = "Tom Kralidis", email = "tomkralidis@gmail.com"} +] +maintainers = [ + {name = "Tom Kralidis", email = "tomkralidis@gmail.com"} +] +classifiers = [ + "Development Status :: 4 - Beta", + "Environment :: Console", + "Intended Audience :: Developers", + "Intended Audience :: Science/Research", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Topic :: Scientific/Engineering :: GIS" +] +dependencies = [ + "lxml", + "python-dateutil", + "pyyaml", + "requests" +] + +[project.optional-dependencies] +dev = ["flake8", "flake8-pyproject", "pytest", "pytest-cov", "pytest_httpserver", "pytest-socket", "Pillow", "tox", "twine", "coverage", "coveralls", "build"] +docs = ["ipykernel", "nbconvert", "nbsphinx", "pypandoc", "sphinx==8.1.3"] +release = ["build", "twine", "wheel"] +test = ["pytest"] + +[project.urls] +homepage = "https://geopython.github.io/OWSLib" +source = "https://github.com/geopython/OWSLib" +documentation = "https://geopython.github.io/OWSLib" +issues = "https://github.com/geopython/OWSLib/issues" + +[tool.pytest] +addopts = ["-v", "-rxs", "-s", "--color=yes", "--tb=native", "--ignore=setup.py", "--doctest-modules", "--doctest-glob='tests/**/*.txt'", "--cov-report=term-missing", "--cov=owslib"] + +norecursedirs = [".git", "docs", "examples", "etc", "cov*", "*.egg*", "pytest*", ".tox", "_broken"] +markers = ["online: test requires online resources."] + +[tool.flake8] +ignore = ["F401", "E402"] +max-line-length = 120 +exclude = [".git", "__pycache__", "docs/source/conf.py,", "build", "dist", "examples", "etc"] + +# ensure all subpackages are found +[tool.setuptools.packages.find] +include = ["owslib*"] \ No newline at end of file diff --git a/requirements-dev.txt b/requirements-dev.txt deleted file mode 100644 index 785f2e44..00000000 --- a/requirements-dev.txt +++ /dev/null @@ -1,12 +0,0 @@ --r requirements.txt -flake8 -pytest -pytest-cov -pytest_httpserver -pytest-socket -Pillow -tox -twine -coverage -coveralls -build \ No newline at end of file diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index f4d78980..00000000 --- a/requirements.txt +++ /dev/null @@ -1,4 +0,0 @@ -lxml -python-dateutil -pyyaml -requests diff --git a/setup.py b/setup.py deleted file mode 100644 index dab770f0..00000000 --- a/setup.py +++ /dev/null @@ -1,88 +0,0 @@ -# ============================================================================= -# Copyright (c) 2025 Tom Kralidis -# -# Author: Tom Kralidis -# -# Contact email: tomkralidis@gmail.com -# ============================================================================= - -from pathlib import Path -import re -from setuptools import setup, find_packages - - -def read(filename, encoding='utf-8'): - """read file contents""" - - fullpath = Path(__file__).resolve().parent / filename - - with fullpath.open() as fh: - contents = fh.read().strip() - return contents - - -def get_package_version(): - """get version from top-level package init""" - version_file = read('owslib/__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.') - - -readme = open('README.md').read() -reqs = [line.strip() for line in open('requirements.txt')] - -MANIFEST = Path('MANIFEST') - -if MANIFEST.exists(): - MANIFEST.unlink() - -setup( - name='OWSLib', - version=get_package_version(), - description='OGC Web Service utility library', - long_description=read('README.md'), - long_description_content_type='text/markdown', - license='BSD', - keywords=' '.join([ - 'gis', - 'ogc', - 'ogcapi', - 'ows', - 'opensearch', - 'iso', - '19115', - 'fgdc', - 'dif', - 'ows', - 'wfs', - 'wms', - 'sos', - 'csw', - 'wps', - 'wcs', - 'capabilities', - 'metadata', - 'wmts', - 'connectedsystems' - ]), - author='Sean Gillies', - author_email='sean.gillies@gmail.com', - maintainer='Tom Kralidis', - maintainer_email='tomkralidis@gmail.com', - url='https://owslib.readthedocs.io', - install_requires=reqs, - python_requires='>=3.10', - packages=find_packages(exclude=["docs", "etc", "examples", "tests"]), - classifiers=[ - 'Development Status :: 4 - Beta', - 'Intended Audience :: Developers', - 'Intended Audience :: Science/Research', - 'Natural Language :: English', - 'Operating System :: OS Independent', - 'Programming Language :: Python', - 'Topic :: Scientific/Engineering :: GIS' - ] -) diff --git a/tests/test_ogcapi_records_pycsw.py b/tests/test_ogcapi_records_pycsw.py index 6b2c9274..b7c6b717 100644 --- a/tests/test_ogcapi_records_pycsw.py +++ b/tests/test_ogcapi_records_pycsw.py @@ -40,7 +40,7 @@ def test_ogcapi_records_pycsw(): assert isinstance(w.response, dict) pycsw_cite_demo_queryables = w.collection_queryables('metadata:main') - assert len(pycsw_cite_demo_queryables['properties'].keys()) == 14 + assert len(pycsw_cite_demo_queryables['properties'].keys()) == 18 # Minimum of limit param is 1 with pytest.raises(RuntimeError): diff --git a/tests/test_wfs_generic.py b/tests/test_wfs_generic.py index 6a0c2344..1f2234fa 100644 --- a/tests/test_wfs_generic.py +++ b/tests/test_wfs_generic.py @@ -1,13 +1,13 @@ from owslib.wfs import WebFeatureService from owslib.util import ServiceException from owslib.fes import PropertyIsLike, etree -from urllib.parse import urlparse from tests.utils import resource_file, sorted_url_query, service_ok import json import pytest SERVICE_URL = 'https://services.ga.gov.au/gis/stratunits/ows' + def test_caps_info(): getcapsin = open(resource_file("wfs_HSRS_GetCapabilities_1_1_0.xml"), "rb").read() wfs = WebFeatureService('http://gis.bnhelp.cz/ows/crwfs', xml=getcapsin, version='1.1.0') @@ -143,17 +143,6 @@ def test_srsname_wfs_200(): assert len(json.loads(feature.read())['features']) == 1 -@pytest.mark.online -@pytest.mark.skipif(not service_ok(SERVICE_URL), - reason="WFS service is unreachable") -def test_schema_wfs_100(): - wfs = WebFeatureService(SERVICE_URL, version='1.0.0') - schema = wfs.get_schema('stratunit:StratigraphicUnit') - assert len(schema['properties']) == 33 - assert schema['properties']['DESCRIPTION'] == 'string' - assert schema['geometry'] is None - - @pytest.mark.online @pytest.mark.skipif(not service_ok(SERVICE_URL), reason="WFS service is unreachable") @@ -183,7 +172,7 @@ def test_schema_wfs_200(): def test_xmlfilter_wfs_110(): wfs = WebFeatureService(SERVICE_URL, version='1.1.0') filter_prop = PropertyIsLike(propertyname='stratunit:GEOLOGICHISTORY', literal='Cisuralian - Guadalupian', - matchCase=True) + matchCase=True) filterxml = etree.tostring(filter_prop.toXML()).decode("utf-8") @@ -200,7 +189,7 @@ def test_xmlfilter_wfs_110(): def test_xmlfilter_wfs_200(): wfs = WebFeatureService(SERVICE_URL, version='2.0.0') filter_prop = PropertyIsLike(propertyname='stratunit:geologichistory', literal='Cisuralian - Guadalupian', - matchCase=True) + matchCase=True) filterxml = etree.tostring(filter_prop.toXML()).decode("utf-8") @@ -208,4 +197,3 @@ def test_xmlfilter_wfs_200(): response = wfs.getfeature(**getfeat_params).read() assert b'Boolgeeda Iron Formation' in response - diff --git a/tox.ini b/tox.ini deleted file mode 100644 index 935ef79e..00000000 --- a/tox.ini +++ /dev/null @@ -1,39 +0,0 @@ -[pytest] -addopts = - -v - -rxs - -s - --color=yes - --tb=native - --ignore=setup.py - --doctest-modules - --doctest-glob='tests/**/*.txt' - --cov-report=term-missing - --cov=owslib - -norecursedirs = .git docs examples etc cov* *.egg* pytest* .tox _broken -markers = - online: test requires online resources. - -[flake8] -ignore=F401,E402 -max-line-length=120 -exclude = - .git, - __pycache__, - docs/source/conf.py, - build, - dist - examples, - etc, - -[tox] -skipsdist=True - -[testenv] -recreate=False -commands= - python3 setup.py develop - py.test \ - --basetemp={envtmpdir} \ - {posargs}