diff --git a/.gitignore b/.gitignore index aaf75f6fb704d482d549769501041a1736f90a63..aba790683b141a685f8664edb61febe4b63565ee 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,5 @@ record.txt .envrc coverage.xml test_results.xml +junit-coverage.xml +.tox/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 845b719f2378d396a8b75296a68d1e32c840e7c7..ce78bd8caadc61ae6a09f10d9dd40c906045ef49 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1 +1,67 @@ -include: 'https://gitlab.idiap.ch/bob/bob.devtools/raw/master/bob/devtools/data/gitlab-ci/single-package.yaml' +variables: + PYTHONUNBUFFERED: "1" + XDG_CACHE_HOME: "${CI_PROJECT_DIR}/cache" + +stages: + - qa + - test + - doc + +qa: + stage: qa + image: python:3.10-slim + tags: + - bob + - docker + before_script: + - pip install pre-commit + script: + - pre-commit run --all-files --show-diff-on-failure --verbose + cache: + paths: + - ${XDG_CACHE_HOME}/pre-commit + - ${XDG_CACHE_HOME}/pip + rules: + - exists: + - .pre-commit-config.yaml + +test: + stage: test + image: python:${PYTHON_VERSION}-slim + parallel: + matrix: + - PYTHON_VERSION: ["3.9", "3.10"] + cache: + paths: + - ${XDG_CACHE_HOME}/pip + before_script: + - pip install '.[test]' + script: + - pytest --verbose --cov exposed --cov-report term-missing --cov-report html:html/coverage --cov-report xml:coverage.xml --junitxml=junit-coverage.xml --pyargs exposed.tests + coverage: '/(?i)total.*? (100(?:\.0+)?\%|[1-9]?\d(?:\.\d+)?\%)$/' + artifacts: + paths: + - html + reports: + junit: test_results.xml + coverage_report: + coverage_format: cobertura + path: coverage.xml + +doc: + stage: doc + image: python:${PYTHON_VERSION}-slim + cache: + paths: + - ${XDG_CACHE_HOME}/pip + before_script: + - pip install '.[doc]' + script: + - sphinx-build -aEW doc html/sphinx + - sphinx-build -aEb doctest doc html/doctest + artifacts: + paths: + - html + rules: + - exists: + - doc diff --git a/MANIFEST.in b/MANIFEST.in index 1582fb2f59d396a9000775113143b1071991087a..99858f73d3e7f21d06aab034bc9e58e48ccb9ac2 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,3 @@ -include LICENSE README.md version.txt +include LICENSE README.rst recursive-include doc *.rst *.txt *.py *.ico *.png -recursive-include tests *.py *.cfg +recursive-include src/exposed/tests/data *.cfg diff --git a/conda/meta.yaml b/conda/meta.yaml index 7e73fee0e82e713c00de312cabee17b1c733df56..f131eebcb204da77830b31a08738b65ab54db9ce 100644 --- a/conda/meta.yaml +++ b/conda/meta.yaml @@ -1,61 +1,44 @@ -{% set name = 'exposed' %} -{% set project_dir = environ.get('RECIPE_DIR') + '/..' %} +{% set project_data = load_file_data(RECIPE_DIR + '/../pyproject.toml') %} package: - name: {{ name }} - version: {{ environ.get('BOB_PACKAGE_VERSION', '0.0.1') }} + name: {{ project_data['project']['name'] }} + version: {{ project_data['project']['version'] }} + +source: + path: .. build: + noarch: python number: {{ environ.get('BOB_BUILD_NUMBER', 0) }} run_exports: - - {{ pin_subpackage(name) }} + - {{ pin_subpackage(project_data['project']['name']) }} script: - - cd {{ project_dir }} - {% if environ.get('BUILD_EGG') %} - - "{{ PYTHON }} setup.py sdist --formats=zip" - {% endif %} - - "{{ PYTHON }} -m pip install . -vv" - # installs the documentation source, readme to share/doc so it is available - # during test time - - install -d "${PREFIX}/share/doc/{{ name }}" - - cp -R README.rst doc "${PREFIX}/share/doc/{{ name }}/" + - "{{ PYTHON }} -m pip install {{ SRC_DIR }} -vv" requirements: host: - - python {{ python }} - - setuptools {{ setuptools }} + - python >=3.9 - pip {{ pip }} - click >=8 - click {{ click }} - tomli {{ tomli }} - tomli-w {{ tomli_w }} run: - - python + - python >=3.9 - {{ pin_compatible('click') }} - {{ pin_compatible('tomli') }} - {{ pin_compatible('tomli-w') }} test: imports: - - {{ name }} + - {{ project_data['project']['name'] }} commands: - - pytest --verbose --cov {{ name }} --cov-report term-missing --cov-report html:{{ project_dir }}/sphinx/coverage --cov-report xml:{{ project_dir }}/coverage.xml --junitxml={{ project_dir }}/test_results.xml {{ project_dir }}/tests - - sphinx-build -aEW {{ project_dir }}/doc {{ project_dir }}/sphinx - - sphinx-build -aEb doctest {{ project_dir }}/doc {{ project_dir }}/sphinx - - conda inspect linkages -p $PREFIX {{ name }} # [not win] - - conda inspect objects -p $PREFIX {{ name }} # [osx] + - pytest -sv --pyargs {{ project_data['project']['name'] }}.tests requires: - pytest {{ pytest }} - - pytest-cov {{ pytest_cov }} - - coverage {{ coverage }} - - sphinx {{ sphinx }} - - sphinx_rtd_theme {{ sphinx_rtd_theme }} - - sphinx-autodoc-typehints {{ sphinx_autodoc_typehints }} - - sphinxcontrib-programoutput {{ sphinxcontrib_programoutput }} - - font-ttf-dejavu-sans-mono {{ font_ttf_dejavu_sans_mono }} about: - home: https://www.idiap.ch/software/bob/ - license: BSD 3-Clause - summary: Configuration Support for Python Packages and CLIs + home: {{ project_data['project']['urls']['homepage'] }} + summary: {{ project_data['project']['description'] }} + license: {{ project_data['project']['license']['text'] }} license_family: BSD diff --git a/pyproject.toml b/pyproject.toml index ab102ccc9385f98d803216ea766a2eb6bcf63d93..977d55d0c74da58a64ea4ae2fd6e20690ebcf730 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,71 @@ [build-system] - requires = ["setuptools>=51.0.0"] + requires = ["setuptools>=61.0.0"] build-backend = "setuptools.build_meta" +[project] +name = "exposed" +version = "1.0.0b0" +description = "Configuration Support for Python Packages and CLIs" +dynamic = ["readme"] +license = {text = "BSD 3-Clause License"} +authors = [ + {name = "Andre Anjos"}, + {email = "andre.anjos@idiap.ch"}, +] +classifiers = [ + "Framework :: Bob", + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "License :: OSI Approved :: BSD License", + "Natural Language :: English", + "Programming Language :: Python :: 3", + "Topic :: Software Development :: Libraries :: Python Modules", +] +dependencies = [ + "click>=8", + "tomli", + "tomli-w", +] + +[project.urls] +documentation = "https://www.idiap.ch/software/bob/docs/bob/exposed/master/" +homepage = "https://pypi.org/project/exposed" +repository = "https://gitlab.idiap.ch/bob/exposed" +changelog = "https://gitlab.idiap.ch/bob/exposed/-/releases" + +[project.optional-dependencies] +qa = ["pre-commit"] +doc = [ + "sphinx", + "sphinx_rtd_theme", + "sphinx-autodoc-typehints", + "sphinxcontrib-programoutput", + ] +test = [ + "pytest", + "pytest-cov", + "coverage", + ] + +[project.entry-points."exposed.test.config"] +first = "exposed.tests.data.basic_config" +first-a = "exposed.tests.data.basic_config:a" +first-b = "exposed.tests.data.basic_config:b" +second = "exposed.tests.data.second_config" +second-b = "exposed.tests.data.second_config:b" +second-c = "exposed.tests.data.second_config:c" +complex = "exposed.tests.data.complex" +complex-var = "exposed.tests.data.complex:cplx" +verbose-config = "exposed.tests.data.verbose_config" +error-config = "exposed.tests.data.doesnt_exist" + +[tool.setuptools] +zip-safe = false + +[tool.setuptools.dynamic] +version = {file = "version.txt"} +readme = {file = "README.rst"} + [tool.isort] profile = "black" line_length = 80 @@ -18,15 +82,3 @@ addopts = [ "--import-mode=importlib", ] - -[tool.tox] -legacy_tox_ini = """ -[tox] -envlist = py39,py310 - -[testenv] -deps = - pytest-cov -commands = - pytest --verbose --cov exposed --cov-report term-missing --cov-report html:html/coverage --cov-report xml:coverage.xml --junitxml=junit-coverage.xml tests/ -""" diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 8cc1a8e8c4a528f06e19ef75ffb924f18aca1ea9..0000000000000000000000000000000000000000 --- a/setup.cfg +++ /dev/null @@ -1,39 +0,0 @@ -[metadata] -name = exposed -version = file: version.txt -description = Configuration Support for Python Packages and CLIs -long_description = file: README.rst -url = https://gitlab.idiap.ch/bob/exposed -license = BSD 3-Clause License -author = Andre Anjos -author_email = andre.anjos@idiap.ch -classifiers = - Framework :: Bob - Development Status :: 4 - Beta - Intended Audience :: Developers - License :: OSI Approved :: BSD License - Natural Language :: English - Programming Language :: Python :: 3 - Topic :: Software Development :: Libraries :: Python Modules - -[options] -zip_safe = True -include_package_data = True -packages = find: -install_requires = - click>=8 - tomli - tomli-w - -[options.entry_points] -exposed.test.config = - first = tests.data.basic_config - first-a = tests.data.basic_config:a - first-b = tests.data.basic_config:b - second = tests.data.second_config - second-b = tests.data.second_config:b - second-c = tests.data.second_config:c - complex = tests.data.complex - complex-var = tests.data.complex:cplx - verbose-config = tests.data.verbose_config - error-config = tests.data.doesnt_exist diff --git a/exposed/__init__.py b/src/exposed/__init__.py similarity index 100% rename from exposed/__init__.py rename to src/exposed/__init__.py diff --git a/exposed/click.py b/src/exposed/click.py similarity index 100% rename from exposed/click.py rename to src/exposed/click.py diff --git a/exposed/config.py b/src/exposed/config.py similarity index 100% rename from exposed/config.py rename to src/exposed/config.py diff --git a/exposed/logging.py b/src/exposed/logging.py similarity index 100% rename from exposed/logging.py rename to src/exposed/logging.py diff --git a/exposed/rc.py b/src/exposed/rc.py similarity index 100% rename from exposed/rc.py rename to src/exposed/rc.py diff --git a/tests/__init__.py b/src/exposed/tests/__init__.py similarity index 100% rename from tests/__init__.py rename to src/exposed/tests/__init__.py diff --git a/tests/conftest.py b/src/exposed/tests/conftest.py similarity index 100% rename from tests/conftest.py rename to src/exposed/tests/conftest.py diff --git a/tests/data/__init__.py b/src/exposed/tests/data/__init__.py similarity index 100% rename from tests/data/__init__.py rename to src/exposed/tests/data/__init__.py diff --git a/tests/data/basic_config.py b/src/exposed/tests/data/basic_config.py similarity index 100% rename from tests/data/basic_config.py rename to src/exposed/tests/data/basic_config.py diff --git a/tests/data/complex.py b/src/exposed/tests/data/complex.py similarity index 100% rename from tests/data/complex.py rename to src/exposed/tests/data/complex.py diff --git a/tests/data/oldjson.cfg b/src/exposed/tests/data/oldjson.cfg similarity index 100% rename from tests/data/oldjson.cfg rename to src/exposed/tests/data/oldjson.cfg diff --git a/tests/data/second_config.py b/src/exposed/tests/data/second_config.py similarity index 100% rename from tests/data/second_config.py rename to src/exposed/tests/data/second_config.py diff --git a/tests/data/test_dump_config.py b/src/exposed/tests/data/test_dump_config.py similarity index 100% rename from tests/data/test_dump_config.py rename to src/exposed/tests/data/test_dump_config.py diff --git a/tests/data/test_dump_config2.py b/src/exposed/tests/data/test_dump_config2.py similarity index 100% rename from tests/data/test_dump_config2.py rename to src/exposed/tests/data/test_dump_config2.py diff --git a/tests/data/userdefaults_ex1.cfg b/src/exposed/tests/data/userdefaults_ex1.cfg similarity index 100% rename from tests/data/userdefaults_ex1.cfg rename to src/exposed/tests/data/userdefaults_ex1.cfg diff --git a/tests/data/verbose_config.py b/src/exposed/tests/data/verbose_config.py similarity index 100% rename from tests/data/verbose_config.py rename to src/exposed/tests/data/verbose_config.py diff --git a/tests/test_click.py b/src/exposed/tests/test_click.py similarity index 96% rename from tests/test_click.py rename to src/exposed/tests/test_click.py index e43d219f02e2565364a8ed425951420574ee1f88..985af387bd8a74d66c1c458409053b78e48d9d90 100644 --- a/tests/test_click.py +++ b/src/exposed/tests/test_click.py @@ -266,7 +266,7 @@ def test_resource_option(): assert a == 1 runner = CliRunner() - result = runner.invoke(cli1, ["-a", "tests.data.basic_config"]) + result = runner.invoke(cli1, ["-a", "exposed.tests.data.basic_config"]) assert result.exit_code == 0 # test usage without ConfigCommand and without entry_point_group @@ -288,12 +288,12 @@ def test_resource_option(): "-a", "--a", cls=ResourceOption, - string_exceptions=("tests.data.basic_config"), + string_exceptions=("exposed.tests.data.basic_config"), entry_point_group="exposed.test.config", ) def cli3(a): - assert a == "tests.data.basic_config" + assert a == "exposed.tests.data.basic_config" runner = CliRunner() - result = runner.invoke(cli3, ["-a", "tests.data.basic_config"]) + result = runner.invoke(cli3, ["-a", "exposed.tests.data.basic_config"]) assert result.exit_code == 0 diff --git a/tests/test_config.py b/src/exposed/tests/test_config.py similarity index 89% rename from tests/test_config.py rename to src/exposed/tests/test_config.py index f66368336b3945f7e2680c4f55662f5d90c22a21..44b7412d01f1a7709a4e05ef3c16ca417eb21b95 100644 --- a/tests/test_config.py +++ b/src/exposed/tests/test_config.py @@ -48,9 +48,9 @@ def test_config_with_module(): c = load( [ - "tests.data.basic_config", - "tests.data.second_config", - "tests.data.complex", + "exposed.tests.data.basic_config", + "exposed.tests.data.second_config", + "exposed.tests.data.complex", ] ) assert hasattr(c, "a") and c.a == 1 @@ -77,7 +77,11 @@ def test_config_with_entry_point_file_missing(): def test_config_with_mixture(datadir): c = load( - [datadir / "basic_config.py", "tests.data.second_config", "complex"], + [ + datadir / "basic_config.py", + "exposed.tests.data.second_config", + "complex", + ], entry_point_group="exposed.test.config", ) assert hasattr(c, "a") and c.a == 1 @@ -93,14 +97,14 @@ def test_config_not_found(datadir): def test_config_load_attribute(): - a = load(["tests.data.basic_config"], attribute_name="a") + a = load(["exposed.tests.data.basic_config"], attribute_name="a") assert a == 1 def test_config_load_no_attribute(): with pytest.raises(ImportError): - _ = load(["tests.data.basic_config"], attribute_name="wrong") + _ = load(["exposed.tests.data.basic_config"], attribute_name="wrong") @pytest.fixture @@ -128,7 +132,7 @@ def test_config_click_config_list(cli_messages): runner = CliRunner() result = runner.invoke(cli, ["list"]) assert result.exit_code == 0 - assert result.output.startswith("module: tests.data") + assert result.output.startswith("module: exposed.tests.data") assert "(cannot be loaded; add another -v for details)" not in result.output @@ -138,7 +142,7 @@ def test_config_click_config_list_v(cli_messages): runner = CliRunner() result = runner.invoke(cli, ["list", "-v"]) assert result.exit_code == 0 - assert result.output.startswith("module: tests.data") + assert result.output.startswith("module: exposed.tests.data") assert "(cannot be loaded; add another -v for details)" in result.output assert "[module] Example configuration module" in result.output @@ -149,7 +153,7 @@ def test_config_click_config_list_vv(cli_messages): runner = CliRunner() result = runner.invoke(cli, ["list", "-vv"]) assert result.exit_code == 0 - assert result.output.startswith("module: tests.data") + assert result.output.startswith("module: exposed.tests.data") assert "(cannot be loaded; add another -v for details)" in result.output assert "[module] Example configuration module" in result.output assert "NameError" in messages.getvalue() diff --git a/tests/test_logging.py b/src/exposed/tests/test_logging.py similarity index 100% rename from tests/test_logging.py rename to src/exposed/tests/test_logging.py diff --git a/tests/test_rc.py b/src/exposed/tests/test_rc.py similarity index 100% rename from tests/test_rc.py rename to src/exposed/tests/test_rc.py diff --git a/version.txt b/version.txt deleted file mode 100644 index cdf299159fb0a20cae5dbf62cc74d6c6bb0bc424..0000000000000000000000000000000000000000 --- a/version.txt +++ /dev/null @@ -1 +0,0 @@ -1.0.0b0