diff --git a/README.md b/README.md new file mode 100644 index 00000000..f9191be7 --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +### Pykern + +Pykern is an application support framework to simplify and to speed +development of Python programs and servers. + +Pykern defines policies, which make it easy to eliminate boiler-plate. + +For more info, [read the API Docs](http://pykern.readthedocs.org). diff --git a/README.rst b/README.rst deleted file mode 100644 index d72b6298..00000000 --- a/README.rst +++ /dev/null @@ -1,9 +0,0 @@ -PyKern -====== - -PyKern is an application support framework to simplify and to speed -development of Python programs and servers. - -PyKern defines policies, which make it easy to eliminate boiler-plate. - -For more info, `read the API Docs `_ diff --git a/pykern/__init__.py b/pykern/__init__.py index 949d9a79..a2b36d09 100644 --- a/pykern/__init__.py +++ b/pykern/__init__.py @@ -1,14 +1,12 @@ -# -*- coding: utf-8 -*- """pykern package :copyright: Copyright (c) 2018 RadiaSoft LLC. All Rights Reserved. :license: http://www.apache.org/licenses/LICENSE-2.0.html """ -from __future__ import absolute_import, division, print_function -import pkg_resources +import importlib.metadata try: + __version__ = importlib.metadata.version("pykern") +except importlib.metadata.PackageNotFoundError: # We only have a version once the package is installed. - __version__ = pkg_resources.get_distribution("pykern").version -except pkg_resources.DistributionNotFound: pass diff --git a/pykern/package_data/projex/tests/conftest.py.jinja b/pykern/package_data/projex/tests/conftest.py.jinja deleted file mode 100644 index 7dc9938f..00000000 --- a/pykern/package_data/projex/tests/conftest.py.jinja +++ /dev/null @@ -1 +0,0 @@ -pytest_plugins = ["pykern.pytest_plugin"] diff --git a/pykern/pkcli/ci.py b/pykern/pkcli/ci.py index 177bb5c0..aa8e931f 100644 --- a/pykern/pkcli/ci.py +++ b/pykern/pkcli/ci.py @@ -23,17 +23,18 @@ include_files=re.compile(r"\.(html|jinja|js|json|md|py|tsx|yml)$"), ), check_main=PKDict( - exclude_files=re.compile(r".*(_console\.py)|^tests/|^venv/"), + exclude_files=re.compile(r".*(_console\.py)|^tests/|^venv/|^pyproject.toml$"), include_files=re.compile(r".*(\.py)$"), ), check_prints=PKDict( exclude_files=re.compile( - f".*(?:{pkunit.DATA_DIR_SUFFIX}|{pkunit.WORK_DIR_SUFFIX})/" - + f"|^\\w+/{pksetup.PACKAGE_DATA}/" + rf".*(?:{pkunit.DATA_DIR_SUFFIX}|{pkunit.WORK_DIR_SUFFIX})/" + + rf"|^\w+/{pksetup.PACKAGE_DATA}/" + r"|pkdebug[^/]*\.py$" + r"|(?:^|/)\." + r"|^run/" + r"|^venv/" + + r"|^pyproject.toml$" ), include_files=re.compile(r".py$"), ), @@ -61,7 +62,7 @@ def check_main(): """Recursively check repo for modules with main programs. Checks .py files. - Excludes _console.py, tests, and venv. + Excludes ``_console.py``, tests, and venv. """ def _c(lines): @@ -139,13 +140,16 @@ def _error(m): def _paths(cwd): - if cwd.join("setup.py").isfile() and ( - cwd.join("README.rst").isfile() or cwd.join("README.md").isfile() + def _exists(*names): + return list(filter(lambda n: cwd.join(n).isfile(), names)) + + if _exists("README.rst", "README.md") and ( + (x := _exists("setup.py")) or _exists("pyproject.toml") ): return ( # POSIT: repo name cwd.basename, "tests", - "setup.py", + *x, ) return (cwd,) diff --git a/pykern/pkunit.py b/pykern/pkunit.py index 5921ecf0..ad3a297d 100644 --- a/pykern/pkunit.py +++ b/pykern/pkunit.py @@ -1,10 +1,9 @@ -# -*- coding: utf-8 -*- """Useful operations for unit tests :copyright: Copyright (c) 2015 RadiaSoft LLC. All Rights Reserved. :license: http://www.apache.org/licenses/LICENSE-2.0.html """ -from __future__ import absolute_import, division, print_function + from pykern import pkcompat from pykern import pkinspect from pykern import pkio @@ -46,7 +45,7 @@ #: Where `ExceptToFile` writes stack PKSTACK_PATH = "pkstack" -#: INTERNAL: Set to the most recent test module by `pykern.pytest_plugin` and `sirepo/tests/conftest.py` +#: INTERNAL: Set to the most recent test module by `_test_file` module_under_test = None #: Type of a regular expression diff --git a/pykern/pytest_plugin.py b/pykern/pytest_plugin.py index 2571fa12..60c3acda 100644 --- a/pykern/pytest_plugin.py +++ b/pykern/pytest_plugin.py @@ -1,112 +1,7 @@ -# -*- coding: utf-8 -*- -"""PyTest plugin to setup pkconfig and add pkunit fixtures +"""REMOVED -This plugin will only be "active" if the setup.py in the package -imports `pykern.pksetup`. It also calls `pykern.pkconfig.append_load_path`, -which modifies global state. +Left for backward compatibility -:copyright: Copyright (c) 2016 RadiaSoft LLC. All Rights Reserved. +:copyright: Copyright (c) 2016-2024 RadiaSoft LLC. All Rights Reserved. :license: http://www.apache.org/licenses/LICENSE-2.0.html """ -from __future__ import absolute_import, division, print_function -import os - -import pytest - -# Do not import anything from pykern here - -#: Is py.test being run in a package with a setup.py that imports pksetup -_uses_pykern = False - -#: Initialized below -_no_recurse = None - - -@pytest.hookimpl(tryfirst=True) -def pytest_ignore_collect(path, config): - """Ignore _work and _data directories""" - if not _uses_pykern: - return False - global _no_recurse - if not _no_recurse: - import re - - _no_recurse = re.compile(r"(_work|_data)$") - return bool(_no_recurse.search(str(path))) - - -@pytest.hookimpl(tryfirst=True) -def pytest_runtest_protocol(item, *args, **kwargs): - """Make sure work directory is empty for a module. - - If `item` is in a module not seen before, it removes - the `pkunit.work_dir`. - - Args: - item (Item): pytest test item (case) - - Returns: - None: always so that the next hook runs the item. - """ - if not _uses_pykern: - return - from pykern import pkunit - - # Seems to be the only way to get the module under test - m = item._request.module - is_new = m != pkunit.module_under_test - pkunit.module_under_test = m - if is_new: - from pykern import pkio - - pkio.unchecked_remove(pkunit.work_dir()) - - -def _setup_py_parser(): - """Look for setup.py and set `_uses_pykern` - - Returns: - str: root dir containing setup.py or None - """ - global _uses_pykern - import py.path - - prev_p = None - p = py.path.local() - while True: - prev_p = p - s = p.join("setup.py") - if s.check(file=True): - break - p = py.path.local(p.dirname) - if prev_p == p or len(str(prev_p)) <= len(str(p)): - return None - _uses_pykern = _setup_py_contains_pykern(s) - if _uses_pykern: - return p - return None - - -def _setup_py_contains_pykern(setup_py): - """Parses setup.py to see if it imports pykern - - This is hacky, but good enough because pykern and - pksetup are unique names. If someone comments out with - a multiline string, it's not super dangerous. - - Args: - setup_py (py.path): setup.py file name - - Returns: - bool: True if setup.py imports pykern and pksetup - """ - import re - - with open(str(setup_py)) as f: - return bool( - re.search( - r"^\s*(from|import)\s+pykern\b.*\bpksetup\b", - f.read(), - flags=re.MULTILINE, - ), - ) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..e4cf25cf --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,58 @@ +[build-system] +requires = ["chronver", "setuptools>=66"] +build-backend = "setuptools.build_meta" + +[project] +authors = [ + { name = "RadiaSoft LLC", email = "pip@pykern.org" }, +] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Environment :: Console", + "Intended Audience :: Developers", + "Intended Audience :: Science/Research", + "License :: OSI Approved :: Apache Software License", + "Natural Language :: English", + "Programming Language :: Python", + "Topic :: Software Development :: Libraries :: Application Frameworks", + "Topic :: Utilities", +] +dependencies = [ + "argh>=0.26", + "black~=22.12", + "future>=0.14", + "github3.py>=1.1", + "importlib-metadata>=0.12", + "jinja2>=2.7", + "openpyxl>=3.0.9", + "packaging>=21.0", + "pandas>=1.3.2", + "path.py>=7.7.1", + "pluggy>=0.12.0", + "psutil>=5.0", + "py-cpuinfo>=0.2", + "py>=1.4", + "pytest>=2.7", + "python-dateutil>=2.4.2", + "pytz>=2015.4", + "requests>=2.18", + "ruamel.yaml>=0.16.0", + "setuptools>=66", + "six>=1.9", + "Sphinx>=1.3.5", + "tornado", + "tox>=1.9", + "twine>=1.9", + "urllib3", + "XlsxWriter>=3.0.3", +] +description = "Python application support library" +dynamic = ["version"] +name = "pykern" +readme = "README.md" + +[project.scripts] +pykern = "pykern.pykern_console:main" + +[project.urls] +Homepage = "http://pykern.org" diff --git a/setup.py b/setup.py deleted file mode 100644 index 330c0537..00000000 --- a/setup.py +++ /dev/null @@ -1,89 +0,0 @@ -# -*- coding: utf-8 -*- -"""Install PyKern - -:copyright: Copyright (c) 2015-2018 RadiaSoft LLC. All Rights Reserved. -:license: http://www.apache.org/licenses/LICENSE-2.0.html -""" -from pykern.pksetup import setup - - -def _requires(): - return [_urllib3()] + [ - "argh>=0.26", - "black~=24.2", - "future>=0.14", - "github3.py>=1.1", - # for virtualenv - "importlib-metadata>=0.12", - "jinja2>=2.7", - "openpyxl>=3.0.9", - "pandas>=1.3.2", - "psutil>=5.0", - "py-cpuinfo>=0.2", - "py>=1.4", - "pytest>=2.7", - "pytz>=2015.4", - "ruamel.yaml>=0.16.0", - "requests>=2.18", - "setuptools>=66", - "six>=1.9", - "Sphinx>=1.3.5", - "tornado", - "twine>=1.9", - "tox>=1.9", - "packaging>=21.0", - "path.py>=7.7.1", - "python-dateutil>=2.4.2", - "XlsxWriter>=3.0.3", - # for tox - "pluggy>=0.12.0", - ] - - -def _urllib3(): - """Possibly constrain version of urllib3 - - Adapted from urllib3's checks for ssl - https://github.com/urllib3/urllib3/blob/2ac40569acb464074bdc3f308124d781d6aa0860/src/urllib3/__init__.py#L28 - """ - - def _ssl_ok(ssl): - return ( - # python ssl may not be compiled with OpenSSL (ex LibreSSL on MacOS). - # https://github.com/urllib3/urllib3/issues/3020 - getattr(ssl, "OPENSSL_VERSION", "").startswith("OpenSSL ") - and ssl.OPENSSL_VERSION_INFO >= (1, 1, 1) - ) - - v = "urllib3" - try: - import ssl - except ImportError: - # No ssl lib is ok with urllib3 - pass - else: - if not _ssl_ok(ssl): - v += "==1.26.16" - return v - - -setup( - name="pykern", - description="Python application support", - author="RadiaSoft LLC", - author_email="pip@pykern.org", - install_requires=_requires(), - license="http://www.apache.org/licenses/LICENSE-2.0.html", - url="http://pykern.org", - classifiers=[ - "Development Status :: 5 - Production/Stable", - "Environment :: Console", - "Intended Audience :: Developers", - "Intended Audience :: Science/Research", - "License :: OSI Approved :: Apache Software License", - "Natural Language :: English", - "Programming Language :: Python", - "Topic :: Software Development :: Libraries :: Application Frameworks", - "Topic :: Utilities", - ], -)