创建Package并上传至Pypi

将自己的工作,构建为pythonPackage并上传至PYPI,使得其他开发者可以通过pip安装并使用。这是我一直想做的事情,最近我成功将微博数据采集项目封装并上传至PYPI。为使得后续维护工作顺利开展,并方便上传新的Package,特此记录工作要点。

如何将项目组织成Package

最重要的两个点就是__init__.py文件和相对引用

首先我展示目前的Package-dev目录

D:PackageName_dev
│  .gitignore
│  LICENSE
│  list.txt
│  pyproject.toml
│  README.md

├─dist
│      EuclidSearchPackage-0.5.0-py3-none-any.whl
│      EuclidSearchPackage-0.5.0.tar.gz

└─src
    ├─EuclidSearchPackage
    │  │  __init__.py
    │  │  
    │  ├─Demo
    │  │  │  WeiboClassV2.py
    │  │  │  WeiboClassV3.py
    │  │  │  __init__.py
    │  │          
    │  ├─Utils
    │  │  │  EuclidDataTools.py
    │  │  │  EuclidDataTools_test.py
    │  │  │  MongoClient.py
    │  │  │  Set_header.py
    │  │  │  Utils.py
    │  │  │  __init__.py
    │  │          
    │  ├─WeiboSearch
    │  │  │  Get_item_url_list.py
    │  │  │  Get_longTextContent.py
    │  │  │  Get_single_weibo_data.py
    │  │  │  Get_single_weibo_data_async.py
    │  │  │  Get_single_weibo_details.py
    │  │  │  Get_user_all_weibo.py
    │  │  │  Get_user_info.py
    │  │  │  Set_cookie.py
    │  │  │  __init__.py
    │  │          

    ├─EuclidSearchPackage.egg-info
    │      dependency_links.txt
    │      PKG-INFO
    │      SOURCES.txt
    │      top_level.txt

    └─Test
        │  cookie.txt
        │  DemoTest.py
        │  test.csv
        │  Test.py
        │  WeiboClassV2.py

一级目录说明

可以看到dev一级路径下有

  • src: 开发代码将写在这个文件夹下,后一节将展开讲解

  • dist:当package被正式build时,该目录被自动创建,并生成whl文件在此目录下

  • pyproject.toml:软件包架构参数设定,建议按照官方建议撰写

  • README.md:说明文档,将同步到PYPI的项目介绍中,例如project description

  • LICENSE:版权信息,可以按照网上的教程选择

  • .gitignoregit控制中的ignore,如果不使用git可以忽略

scr说明

src下有三个文件夹

  • EuclidSearchPackage:包里面的程序,当包发布后,包的内容就是此文件夹中的文件

  • EuclidSearchPackage.egg-info:当package被正式build时,该目录被自动创建,将存储info

  • Test:非必须,可以用于模拟package被安装后的调用过程,作为测试

关于__init__.py

我们提取package的部分来看,如何写__init__.py

├─Demo
│  │  WeiboClassV2.py
│  │  WeiboClassV3.py
│  │  __init__.py

这是package中的一个subpackage,名字为demo,下有三个文件,其中WeiboClassV2.pyWeiboClassV3.py是代码,__init__.py的内容为:

from .WeiboClassV2 import WeiboClassV2
from .WeiboClassV3 import WeiboClassV3

简单来说init的作用就是初始化,在调用时,init会被首先执行,将WeiboClassV2WeiboClassV3调入代码空间,使其可以被调用。需要注意的是相对位置的引用规则,即得加一个.

下面展示一个完整的__init__.py,变量__all__展示了,使用import *能被调用的方法或变量

from .Get_item_url_list import Get_item_url_list
from .Get_user_info import Get_user_info
from .Set_cookie import Set_cookie
from .Get_single_weibo_data import Get_single_weibo_data
from .Get_user_all_weibo import Get_user_all_weibo
from .Get_single_weibo_data_async import Get_single_weibo_data_async
from .Get_longTextContent import Get_longTextContent

# 未完成
from .Get_single_weibo_details import Get_single_weibo_details

__all__ = ['Get_user_all_weibo', 'Get_user_info', 'Set_cookie',
           'Get_item_url_list', 'Get_single_weibo_data',

关于相对位置引用

在上一节的init写法中已经讲到了得加.,但是有一种情况是需要另外注意的,提取目录的部分进行说明:

├─Utils
│  │  MongoClient.py
│  │  Set_header.py      
│  │  __init__.py
├─WeiboSearch
│  │  Get_item_url_list.py

具体场景为,在Get_item_url_list.py中需要调用Set_header.py 中的Set_header函数,那么需要

  • 首先确保__init__.py

    from .Set_header import Set_header
    from .Set_header import *  # 二选一,更推荐上面的写法
  • Get_item_url_list.py中,使用如下方式引用Set_header函数

    from ..Utils import Set_header

关于Test目录

此目录可以模拟包被安装后的使用过程,不过导入还是有些微差别,需要加上src.

import src.EuclidSearchPackage as ESP

后续的写法就完全一致了,建议发布前都测试一下。

打包发布Package

建议参照官方教程,总结起来有这么关键的几步:

  • Creating pyproject.toml,即软件包架构参数设定,建议按照官方建议撰写

  • Creating README.md:代码说明,建议还是写清楚,会同步到PYPI的project description

  • Creating a LICENSE:官方的示例

  • build:构建包python -m build,生成的文件会在dist目录下,版本迭代后,记得删掉旧版本

  • upload:将package上传至PYPIpython twine upload dist/*,需要输入用户名和密码,如果没有账号需要提前创建。

更新维护

建议同步将package_dev开源至github,方便接受issue,对package更新后,记得更新版本号,然后重新build上传就好。

最后更新于