3

I'd like to install some special sub-package from a package.

For example, I want to create package with pkg_a and pkg_b. But I want to allow the user to choose which he wants to install.

What I'd like to do:

git clone https://github.com/pypa/sample-namespace-packages.git
cd sample-namespace-packages
touch setup.py

setup-py:

import setuptools

setup(
    name='native',
    version='1',
    packages=setuptools.find_packages()
)
# for all packages
pip install -e native #Successfully installed native

# for specific
# Throws ERROR: native.pkg_a is not a valid editable requirement. 
# It should either be a path to a local project
pip install -e native.pkg_a native.pkg_b

# for specific
cd native
pip install -e pkg_a # Successfully installed example-pkg-a

I've seen this in another questions answer so it must be possible: Python install sub-package from package

Also I've read the Packaging namespace packages documentation and tried to do the trick with the repo

I've tried some variants with an additional setup.py in the native directory, but I can't handle it and I am thankful for all help.

Update

In addition to the answer from sinoroc I've made an own repo. I created a package Nmspc, with subpackages NmspcPing and NmspcPong. But I want to allow the user to choose which he wants to install. Also it must to be possible to install the whole package.

What I'd like to do is something like that:

git clone https://github.com/cj-prog/Nmspc.git
cd Nmspc

# for all packages
pip install Nmspc

# Test import
python3 -c "import nmspc; import nmspc.pong"
# for specific
pip install -e Nmspc.pong # or 
pip install -e pong

# Test import
python3 -c "import pong;"

Roelant
  • 4,508
  • 1
  • 32
  • 62
C-Jay
  • 621
  • 1
  • 11
  • 22
  • This is quite a confusing question... Are you the author or a user of the `native` project? – sinoroc Sep 27 '19 at 15:23
  • Why is it confusing? No, I'm not the author of the referenced repo. But I'd like to create a similar one with the described functionality. I've updated my question and tried to clarify it. – C-Jay Sep 27 '19 at 23:29
  • Where are you stuck? What have you tried? – sinoroc Sep 29 '19 at 12:11
  • @sinoroc I've updated my question again. I'll hope it is more understandable. – C-Jay Sep 30 '19 at 07:16
  • What you are trying to achieve was always relatively clear. What is still unclear is what is blocking you exactly, since you already found the right documentation and code example. Can you show some code, some error messages? Are you at least able to build and distribute the namespace packages? – sinoroc Sep 30 '19 at 12:10
  • Can you show a summed up version of your directory tree? Where are your `setup.py` scripts, where are the top level `__init__.py` files? – sinoroc Oct 02 '19 at 11:24
  • I've forked and edit the repo, so you can see my actual directory structure in the github repo https://github.com/cj-prog/sample-namespace-packages.git – C-Jay Oct 04 '19 at 06:34
  • The `setup.py` in the `native` is wrong, wrong place, wrong content. It should be an independent project, actually named `example_pkg`, since that is the name of the namespace in this sample. Also `pip install -e native.pkg_a` can't possibly work, in this case you need to give a path: `pip install -e pkg_a`. And so on... – sinoroc Oct 04 '19 at 09:35
  • I have updated my answer with a more complete example, hopefully this clears up things for you. – sinoroc Oct 04 '19 at 10:02

2 Answers2

4

A solution for your use case seems to be similar to the one I gave here: https://stackoverflow.com/a/58024830/11138259, as well as the one you linked in your question: Python install sub-package from package.

Here is an example...

The directory tree might look like this:

.
├── Nmspc
│   ├── nmspc
│   │   └── _nmspc
│   │       └── __init__.py
│   └── setup.py
├── NmspcPing
│   ├── nmspc
│   │   └── ping
│   │       └── __init__.py
│   └── setup.py
└── NmspcPong
    ├── nmspc
    │   └── pong
    │       └── __init__.py
    └── setup.py

3 Python projects:

  • NmspcPing provides nmspc.ping
  • NmspcPong provides nmspc.pong
  • Nmspc depends on the other two projects (and also provides nmspc._nmspc see below for details)

They are all namespace packages. They are built using the instructions from the Python Packaging User Guide on "Packaging namespace packages, Native namespace packages". There is another example here.

The project Nmspc is basically empty, no actual code, but the important part is to add the other two NmspcPing and NmspcPong as installation requirements. Another thing to note, is that for convenience it is also a namespace package with nmspc._nmspc being kind of hidden (the leading underscore is the naming convention for hidden things in Python).

NmspcPing/setup.py (and similarly NmspcPong/setup.py):

#!/usr/bin/env python3

import setuptools

setuptools.setup(
    name='NmspcPing',
    version='1.2.3',
    packages=['nmspc.ping',],
)

Nmspc/setup.py:

#!/usr/bin/env python3

import setuptools

setuptools.setup(
    name='Nmspc',
    version='1.2.3',
    packages=['nmspc._nmspc',],
    install_requires=['NmspcPing', 'NmspcPong',],
)

Assuming you are in the root directory, you can install these for development like this:

$ python3 -m pip install -e NmspcPing
$ python3 -m pip install -e NmspcPong
$ python3 -m pip install -e Nmspc

And then you should be able to use them like this:

$ python3 -c "import nmspc.ping; import nmspc.pong; import nmspc._nmspc;"

Update

This can be simplified:

.
├── NmspcPing
│   ├── nmspc
│   │   └── ping
│   │       └── __init__.py
│   └── setup.py
├── NmspcPong
│   ├── nmspc
│   │   └── pong
│   │       └── __init__.py
│   └── setup.py
└── setup.py

setup.py

#!/usr/bin/env python3

import setuptools

setuptools.setup(
    name='Nmspc',
    version='1.2.3',
    install_requires=['NmspcPing', 'NmspcPong',],
)

Use it like this:

$ python3 -m pip install ./NmspcPing ./NmspcPong/ .
$ python3 -c "import nmspc.ping; import nmspc.pong;"
sinoroc
  • 18,409
  • 2
  • 39
  • 70
  • I've updated the question again and add the given error message. – C-Jay Oct 02 '19 at 07:16
  • why is the hidden subpackage required? can one not simply put the setup.py for the entire package into the root folder? – mhwh Oct 09 '19 at 08:40
  • 1
    Once you have this working you can indeed improve. (1) Yes, the hidden subpackage `nmspc._nmspc` can be entirely removed. (2) Yes, you can place the `setup.py` for `Nmspc` in the root folder. – sinoroc Oct 09 '19 at 13:17
  • Sorry, but still not the needed answer. I've updated the question and pushed a new repo. – C-Jay Oct 14 '19 at 11:43
  • You really have to give more details than "_Don't work_" if you want help. Nonetheless I updated my answer showing how to use the 2nd example I gave. Your updated question doesn't make much sense, this is not how things work with Python packaging. – sinoroc Oct 14 '19 at 13:02
  • Okay, thank you very much for your help. I think I will create a simple repo with multiple packages in it. Without a namespace package because I need both options: 1. Install the whole package. 2. Only install subpackage. – C-Jay Oct 15 '19 at 06:32
  • I believe this proposal already does what you want (install the whole namespace or only specific sub-packages), but the whole _magic_ resides in the `install_requires` and that kicks in only once you install from an index such as PyPI. You would then be able to simply do `pip install Nmspc` to get all the sub-packages. If you don't use an index, then a few things have to be shifted around, maybe that would suit your use case better... – sinoroc Oct 15 '19 at 08:12
  • The proposed solution works. Do you also have a solution for a import via ```python3 -c "import pong;"``` ? – C-Jay Dec 12 '19 at 12:53
  • Well, these are all very unusual requirements. I really would recommend against doing these things. But if you must, then maybe the answers to these similar questions can help: https://stackoverflow.com/q/57856151/11138259 or this: https://stackoverflow.com/q/58595759/11138259. If not, I would recommend asking a new question (not a comment). – sinoroc Dec 12 '19 at 13:19
1

If the projects are not installed from an index such as PyPI, it is not possible to take advantage of the install_requires feature. Something like this could be done instead:

.
├── NmspcPing
│   ├── nmspc.ping
│   │   └── __init__.py
│   └── setup.py
├── NmspcPong
│   ├── nmspc.pong
│   │   └── __init__.py
│   └── setup.py
└── setup.py

NmspcPing/setup.py (and similarly NmspcPong/setup.py)

import setuptools

setuptools.setup(
    name='NmspcPing',
    version='1.2.3',
    package_dir={'nmspc.ping': 'nmspc.ping'},
    packages=['nmspc.ping'],
)

setup.py

import setuptools

setuptools.setup(
    name='Nmspc',
    version='1.2.3',
    package_dir={
        'nmspc.ping': 'NmspcPing/nmspc.ping',
        'nmspc.pong': 'NmspcPong/nmspc.pong',
    },
    packages=['nmspc.ping', 'nmspc.pong'],
)

This allows to install from the root folder in any of the following combinations:

$ python3 -m pip install .
$ python3 -m pip install ./NmspcPing
$ python3 -m pip install ./NmspcPong
$ python3 -m pip install ./NmspcPing ./NmspcPong
sinoroc
  • 18,409
  • 2
  • 39
  • 70
  • I have an own index and like to install the packages from there. Do you have a solution for that? Maybe you can show this via pull request in my repo? – C-Jay Dec 11 '19 at 14:41
  • See my other answer then. Or is there a more specific question you would like an answer for? – sinoroc Dec 11 '19 at 16:29
  • @patr1ckm What do you mean, what is the full command that you used, and what command would you want to use instead? – sinoroc Feb 03 '20 at 19:48