diff --git a/cookieplone/__init__.py b/cookieplone/__init__.py index 6d18af6..14a7d0e 100644 --- a/cookieplone/__init__.py +++ b/cookieplone/__init__.py @@ -1,4 +1,4 @@ # SPDX-FileCopyrightText: 2024-present Plone Foundation # # SPDX-License-Identifier: MIT -__version__ = "0.7.2.dev0" +__version__ = "0.8.0.dev0" diff --git a/cookieplone/filters/__init__.py b/cookieplone/filters/__init__.py index d7f1f80..34c63ec 100644 --- a/cookieplone/filters/__init__.py +++ b/cookieplone/filters/__init__.py @@ -11,13 +11,33 @@ @simple_filter def package_name(v) -> str: """Return the Python package name (without namespace).""" - return v.split(".")[1] + return v.split(".")[-1] @simple_filter def package_namespace(v) -> str: """Return the Python package namespace.""" - return v.split(".")[0] + parts = v.rsplit(".", 1) + if len(parts) > 1: + return parts[0] + return "" + + +@simple_filter +def package_namespaces(v) -> str: + """Return Python package namespaces formatted for setup.py.""" + result = [] + nsparts = [] + for ns in v.split(".")[:-1]: + nsparts.append(ns) + result.append(".".join(nsparts)) + return ", ".join(f'"{item}"' for item in result) + + +@simple_filter +def package_path(v) -> str: + """Return path to the package code within the src directory.""" + return "/".join(v.split(".")) @simple_filter diff --git a/cookieplone/utils/plone.py b/cookieplone/utils/plone.py index 92eb43c..2ea505f 100644 --- a/cookieplone/utils/plone.py +++ b/cookieplone/utils/plone.py @@ -49,3 +49,15 @@ def format_python_codebase(path: Path): for cmd, func in PY_FORMATTERS: logger.debug(f"Format codebase: Running {cmd}") func(path) + + +def create_namespace_packages(path: Path, package_name: str): + """Create namespace packages to hold an existing package.""" + current = path.parent + for namespace in package_name.split(".")[:-1]: + current = current / namespace + current.mkdir() + (current / "__init__.py").write_text( + '__import__("pkg_resources").declare_namespace(__name__)\n' + ) + path.rename(current / package_name.split(".")[-1]) diff --git a/cookieplone/utils/validators.py b/cookieplone/utils/validators.py index fd78e28..2f6b522 100644 --- a/cookieplone/utils/validators.py +++ b/cookieplone/utils/validators.py @@ -54,11 +54,6 @@ def validate_python_package_name(value: str) -> str: parts = value.split(".") if any(not part.isidentifier() for part in parts): return f"'{value}' is not a valid Python identifier." - if len(parts) != 2: - return ( - "The Python package name must contain a single namespace " - "(e.g. collective.something)" - ) return "" diff --git a/news/43.feature b/news/43.feature new file mode 100644 index 0000000..6e673ca --- /dev/null +++ b/news/43.feature @@ -0,0 +1 @@ +Support Python package names with no namespace or multiple namespaces. @davisagli diff --git a/tests/test_filters.py b/tests/test_filters.py index f51cac4..9ccabab 100644 --- a/tests/test_filters.py +++ b/tests/test_filters.py @@ -21,8 +21,20 @@ def func(filter_: str) -> Path: @pytest.mark.parametrize( "filter_,raw,expected", [ + ["package_name", "{{'foo' | package_name}}", "foo"], ["package_name", "{{'foo.bar' | package_name}}", "bar"], + ["package_namespace", "{{'foo' | package_namespace}}", ""], ["package_namespace", "{{'foo.bar' | package_namespace}}", "foo"], + ["package_namespaces", "{{'foo' | package_namespaces}}", ""], + ["package_namespaces", "{{'foo.bar' | package_namespaces}}", '"foo"'], + [ + "package_namespaces", + "{{'foo.bar.baz' | package_namespaces}}", + '"foo", "foo.bar"', + ], + ["package_path", "{{'foo' | package_path}}", "foo"], + ["package_path", "{{'foo.bar' | package_path}}", "foo/bar"], + ["package_path", "{{'foo.bar.baz' | package_path}}", "foo/bar/baz"], ["pascal_case", "{{'foo_bar' | pascal_case}}", "FooBar"], ["use_prerelease_versions", "{{ '' | use_prerelease_versions }}", "No"], ["node_version_for_volto", "{{'17' | node_version_for_volto}}", "18"], diff --git a/tests/utils/test_validators.py b/tests/utils/test_validators.py index da7be7e..5c7c56a 100644 --- a/tests/utils/test_validators.py +++ b/tests/utils/test_validators.py @@ -73,22 +73,9 @@ def test_validate_language_code(value: str, expected: str): (" ", "' ' is not a valid Python identifier."), ("", "'' is not a valid Python identifier."), ("project title", "'project title' is not a valid Python identifier."), - ( - "project_title", - "The Python package name must contain a single namespace " - "(e.g. collective.something)", - ), + ("project_title", ""), ("project-title", "'project-title' is not a valid Python identifier."), - ( - "projecttitle", - "The Python package name must contain a single namespace " - "(e.g. collective.something)", - ), - ( - "projectTitle", - "The Python package name must contain a single namespace " - "(e.g. collective.something)", - ), + ("projecttitle", ""), ("project.title", ""), ), )