ionelmc / cookiecutter-pylibrary

Enhanced cookiecutter template for Python libraries.
BSD 2-Clause "Simplified" License
1.25k stars 207 forks source link

Support namespace packages #178

Closed philipptempel closed 1 year ago

philipptempel commented 4 years ago

I am starting to reorganize my subprojects and opted for going with namespace packages under the common project slug such that I have the following packages

cdpr.platform
cdpr.cable.catenary
cdpr.cable.cosserat

such that I could do

import cdpr.platform
import cdpr.cable.catenary

etc. where cdpr is my namespace and everything below are packages or sub-namespaces.

So, just going straight forward with this cookiecutter, and setting package_name = cdpr.platform and distribution_name = cdpr.platform, I get the following directory layout

src/
  cdpr.platform/
    __init__.py

whereas I'd rather should have

src/
  cdpr/
    platform/
      __init__.py

Either I am not totally familiar with python namespace packages or the way cookiecutter works, or this test case has not been covered yet?!

Operating System: Windows 10 Version 1809 (OS Build 17763.973)

Local Setup:

Steps to reproduce:

ionelmc commented 4 years ago

The directory structure could be fixed but what about the various places where name is used? Like in docs, distribution_name, github repo name etc?

philipptempel commented 4 years ago

I currently don't have a fully-working dev end at hand right now. From looking at the code though, I would say that only the directory seems to really be a problem. All the other parts (creating the project, building it, using it locally) work fine if we use distribution_name = namespace.package. Likewise, pypi and twine should work fine since the egg file shows the right distribution name.

ionelmc commented 4 years ago

Ok, just wanted to check if you need other special casing when there's a dot in the name.

philipptempel commented 4 years ago

Did a little more digging and testing (and googling), here's what I found what needs to be taken into account: https://github.com/pypa/sample-namespace-packages

The recommended way according to PEP420 and the tutorial on PyPA is

namespace_package_a/ # (created with cookiecutter gh:ionelmc/cookiecutter-pylibrary)
  setup.py
  src/
    package_b/
      __init__.py
      namespace/
        __init__.py
namespace_package_b/ # (created with cookiecutter gh:ionelmc/cookiecutter-pylibrary)
  setup.py
  src/
    package_b/
      __init__.py
      namespace/
        __init__.py

with the following namespace_package_{a,b}/src/package_{a,b}/__init__.py content

__path__ = __import__('pkgutil').extend_path(__path__, __name__)

For namespace_package_{a,b}/src/package_{a,b}/namespace/__init__.py, this is the library's/package's top-level __init__ much like what's currently being generated.

Supporting namespace packages with PEP420 does not require changes to setup.py, as far as I figured. However, I agree that the order of namespace and package is a little... unintuitive.

Need to do a few more tests to figure out how name, namespace_packages, and packages of setup.py work together with the original directory names and the final generated package name.

This issue seems a slight little bit more involved than I initially thought, but also doesn't seem to imply too difficult a set of changes.

ionelmc commented 1 year ago

I don't think there's a general enough usecase for ns packages, and I don't use them either to warrant support for something like this. This is easy to fix post generation anyway, so I don't think it's a big deal.