【问题标题】:setup.py: renaming src package to project namesetup.py:将 src 包重命名为项目名称
【发布时间】:2013-01-19 18:08:21
【问题描述】:

假设您有一个名为proj 的项目,并且在该项目中您具有以下结构:

proj/
  dists/
  doc/
  src/
    __init__.py
    xyz.py
    abc.py
  test/
  setup.py

如您所见,您项目的所有内容都在src 子文件夹中。如何从src 文件夹中制作 distutils 分发包?

按照the tutorial,我的幼稚想法是这样写setup.py

#omitting basics
setup(
   name='proj',
   packages=['src'],
   package_dir={'proj':'src'}
)

但是在将生成的包安装到我的系统后,我仍然需要导入 src.xyz 而不是 proj.xyz,这本来是目标和预期结果。

【问题讨论】:

    标签: python python-2.7 distutils


    【解决方案1】:

    这是由于此处报告的 setuptools 中的错误:https://github.com/pypa/setuptools/issues/250

    基本上,它可以工作,但不能在开发模式下工作。现在你有 3 个解决方案:

    • src 包符号链接为proj(并在提交时忽略它),它可以开箱即用,但很脏
    • src 更改为proj
    • src 中创建一个子目录proj 并使用以下选项:
    包= ['项目'], package_dir={'proj': 'src/proj'},

    【讨论】:

    【解决方案2】:

    您可以先使用find_packages 查找src 中的所有包名,然后手动重命名为所需的名称。最后,使用package_dir 选项指定包约定。

    import re
    
    from setuptools import find_packages, setup
    
    PACKAGE_NAME = 'proj'
    SOURCE_DIRECTORY = 'src'
    SOURCE_PACKAGE_REGEX = re.compile(rf'^{SOURCE_DIRECTORY}')
    
    source_packages = find_packages(include=[SOURCE_DIRECTORY, f'{SOURCE_DIRECTORY}.*'])
    proj_packages = [SOURCE_PACKAGE_REGEX.sub(PACKAGE_NAME, name) for name in source_packages]
    
    setup(
        name=PACKAGE_NAME,
        packages=proj_packages,
        package_dir={PACKAGE_NAME: SOURCE_DIRECTORY},
        ...
    )
    

    【讨论】:

      【解决方案3】:

      正确的设置是:

      #omitting basics
      setup(
         name='proj',
         packages=['proj'],
         package_dir={'proj':'src'}
      )
      

      src 文件夹应包含__init__.py(如果文件为空,则默认导出所有内容)

      在另一个项目中: requirements.txt:

      ../relativePathToProjectpackage:version 的名称

      【讨论】:

      • *edit:好吧,也许它确实有效……我可能判断得太快了。我需要先检查一下。
      • 对我来说,使用 python 3.8 和 setuptools 58.0.4,这仍然将包安装为 src 而不是 proj
      • 该示例使用python 3.7进行了测试。我使用了 venv: pip install -r requirements.txt 和依赖项目的相对路径
      【解决方案4】:

      您可以通过将 Python 包文件放入 proj/ 目录来修复它:

      proj/
        src/
          proj/
            __init__.py
            xyz.py
            abc.py
        setup.py
      

      并将setup.py 更改为:

      # ...
      setup(
         name='proj',
         packages=['proj'],
         package_dir={'':'src'}
      )
      

      distutils 不需要,但其他工具可能希望 __init__.py 文件的父目录名称与 Python 包名称相同,即在这种情况下为 proj

      【讨论】:

      • 我做到了,它有效。不过,不确定我是否理解您的最后评论。你的意思是有些工具希望我有一个像proj/src/proj 这样的文件夹结构来按预期工作?显得如此低效。还是我在这里做一些低效的事情?
      • 我的意思是目录名称:<name>/__init__.py 应该与 Python 包名称相同,即,如果我看到 __init__.py,那么只需查看它的父目录名称,我就知道它是什么 Python 包.
      【解决方案5】:

      Jfs' Answer 的基础上,如果您像我一样已经建立了一个您不想/由于其他原因无法更改的目录结构,一种解决方案是临时复制所有要打包的代码,然后构建它。

      这是一个带有目标的 makefile,它将 src 中的所有文件复制到一个临时位置,然后调用 setup.py 来构建包,最后自行清理。

      SRC_DIR='src'
      TEMP_PACKAGE_DIR='your_shiny_package'
      
      package: prepare_package_dir build_package deploy_package remove_package_dir
      
      # I'm using gemfury, your deployment will probably look different
      deploy_package:
          twine upload --repository fury dist/* --verbose
      
      clean_package:
          rm -r dist || echo 'dist removed'
          rm -r ${TEMP_PACKAGE_DIR}.egg-info || echo 'egg-info removed'
      
      build_package: clean_package
          python setup.py sdist
      
      prepare_package_dir:
          mkdir ${TEMP_PACKAGE_DIR}
          cp -R ${SRC_DIR}/* ${TEMP_PACKAGE_DIR}/
          mv ${TEMP_PACKAGE_DIR} ${SRC_DIR}/${TEMP_PACKAGE_DIR}
      
      remove_package_dir:
          rm -rf ${SRC_DIR}/${TEMP_PACKAGE_DIR}
      
      

      然后是 setup.py,看起来有点像这样:

      
      setup(
          name='your_shiny_package',
          version=version,
          description='some great package...',
          long_description=readme,
          url='https://whereever',
          author='you',
          packages=['src/your_shiny_package'],
          install_requires=parse_all_requirements(),
          zip_safe=False,
          include_package_data=True)
      
      

      可能不是最有效的,但可以省去永久重组整个 repo 的麻烦。

      用法:只需调用 make package 作为构建管道的一部分或手动调用。

      【讨论】:

        【解决方案6】:

        您可以尝试在调用setup 函数之前将src 文件夹添加到PYTHONPATH

        import sys, os
        src_path = os.path.join(os.path.realpath(os.path.dirname(__file__)), 'src')
        sys.path.append(src_path)
        

        此外,为了安全起见,您可以更改工作目录:

        os.chdir(src_path)
        

        之后,应该一切都好。

        其他一些用于打包您的应用程序的工具从内部支持这一点。我以为是 setuptools,结果是 PyInstaller。但基本上,这就是应该做的,足以让你的包直接导入。

        原来 distutils 有 package_dir 指令。这是您应该使用的,但它可能仅通过将您的包添加到 PYTHONPATH 来工作。

        【讨论】:

        • 我不确定您是否遇到了问题。我正在尝试编写一个其他人可以轻松自行安装的 python 包。这不仅仅是导入您在另一个文件夹中编写的内容。
        • 是的,我明白了,但是setup.py 必须在另一个文件夹中导入东西才能工作。一旦这些包在你的 PYTHONPATH 中,它们在哪里都没有关系。如果它不适合你,你将不得不看到另一种方式,对不起。
        • 抱歉,这不是问题。
        猜你喜欢
        • 2022-12-21
        • 1970-01-01
        • 2016-03-27
        • 2014-04-06
        • 1970-01-01
        • 2017-07-31
        • 2011-05-02
        • 2019-04-23
        • 2011-07-15
        相关资源
        最近更新 更多