pythonpackagingpypidirectory-structure

Why does my Python package install files directly into site-packages instead of under my package directory?


I'm working on a Python package with the following structure:

cfkit/
│
├── README.md
├── setup.py
├── .gitignore
├── LICENSE.txt
├── src/
│   ├── problem.py
│   ├── contest.py
│   ├── __init__.py
│   ├── cmd/
    │   ├── __init__.py
│   │   ├── cli.py
│   ├── client/
    │   ├── __init__.py
│   │   ├── login.py
│   │   ├── submit.py
│   │   ├── fetch.py
│   ├── config/
    │   ├── __init__.py
│   │   ├── config.py
│   │   ├── implementation.py
│   ├── dependencies/
│   │   ├── memory_time_usage.go
│   │   ├── memory_time_usage.exe
│   ├── utils/
    │   ├── __init__.py
│   │   ├── common.py
│   │   ├── constants.py
│   │   ├── variables.py
│   ├── json/
│   │   ├── file1.json
│   │   ├── file2.json
│
├── examples/
│   ├── example1.gif
├── Docs/
│   ├── how_to_use.md

And this is my setup.py file:

from shutil import copy
from pathlib import Path
from platform import uname
from setuptools import setup, find_packages

with open("README.md", 'r', encoding="UTF-8") as file:
    long_description = file.read()

package_data = {
    "src/json": ["json/*.json"],
    "docs": ["docs/*.md"],
    "examples": ["examples/*.gif"],
    '': ["README.md", "LICENSE.txt"],
}

... Some other code

setup(
    name='cfkit',
    version='0.0.1',
    author='Yassine Ghoudi',
    author_email='ghoudi.dev@gmail.com',
    description='A simple Python CLI tool example',
    long_description=long_description,
    long_description_content_type="text/markdown",
    url="https://github.com/ghoudiy/cfkit",
    license="MIT",
    packages=find_packages(where="src"),
    package_data=package_data,
    include_package_data=True,
    python_requires=">=3.8",
    install_requires=[
        'requests',
        'MechanicalSoup',
        'beautifulsoup4',
        'prompt_toolkit'
    ],
    entry_points={
        'console_scripts': [
            'cf = cfkit.cmd.cli:main',
        ],
    },
    classifiers=[
        'Programming Language :: Python :: 3',
        'License :: OSI Approved :: MIT License',
        'Operating System :: OS Independent',
    ],
    keywords="CLI, Tool, Python"
)

What I got

However, when I run pip install ., the files of my project get saved directly in site-packages (e.g., site-packages/utils, site-packages/client) instead of being placed under site-packages/cfkit.

What I want

In a production environment, I want to import my package using import cfkit and get what is written in src/init.py:

'''
cfkit Documentation
'''
from cfkit.problem import Problem
from cfkit.contest import Contest

For the code in utils/common.py, for example, I want to import like this: from cfkit.utils.variables import ...

How can I fix this so that all my package files are correctly installed under the cfkit directory within site-packages?

Error

This is the error I got

 Preparing metadata (setup.py) ... error
  error: subprocess-exited-with-error
  
  × python setup.py egg_info did not run successfully.
  │ exit code: 1
  ╰─> [9 lines of output]
      running egg_info
      creating /tmp/pip-pip-egg-info-2l3_y70l/cfkit.egg-info
      writing /tmp/pip-pip-egg-info-2l3_y70l/cfkit.egg-info/PKG-INFO
      writing dependency_links to /tmp/pip-pip-egg-info-2l3_y70l/cfkit.egg-info/dependency_links.txt
      writing entry points to /tmp/pip-pip-egg-info-2l3_y70l/cfkit.egg-info/entry_points.txt
      writing requirements to /tmp/pip-pip-egg-info-2l3_y70l/cfkit.egg-info/requires.txt
      writing top-level names to /tmp/pip-pip-egg-info-2l3_y70l/cfkit.egg-info/top_level.txt
      writing manifest file '/tmp/pip-pip-egg-info-2l3_y70l/cfkit.egg-info/SOURCES.txt'
      error: package directory 'utils' does not exist
      [end of output]
  
  note: This error originates from a subprocess, and is likely not a problem with pip.
error: metadata-generation-failed

× Encountered error while generating package metadata.
╰─> See above for output.

note: This is an issue with the package mentioned above, not pip.
hint: See above for details.

Solution

  • If you want to install a package named cfkit, you need to define it under src:

    cfkit/
    │
    ├── README.md
    ├── setup.py
    ├── .gitignore
    ├── LICENSE.txt
    ├── src/
    │    ├── cfkit/
    │          ├── problem.py
    │          ├── contest.py
    │          ├── __init__.py
    │          ├── cmd/
    │          │   ├── __init__.py
    │          │   ├── cli.py
    │          ├── client/
    .          .
    .          .
    .          .