一文搞懂如何自己寫一個Python庫

Python魔法师發表於2024-03-06

一文搞懂如何自己寫一個Python庫

你是否曾想過為自己的Python專案編寫一個庫,以便在不同專案中重複使用程式碼?

並且能在PyPI倉庫中釋出,並透過pip install 庫名來安裝使用

1.png

編寫Python庫可能看起來有些複雜,但實際上並非如此。本文將為你提供一份簡明的指南,帶你逐步瞭解如何編寫自己的Python庫。

文章共分以下部分:

  1. 準備工作
  2. 建立專案
  3. 編寫程式碼
  4. 新增庫的文件和註釋
  5. 測試你的庫
  6. 釋出到PyPI測試倉庫
  7. 釋出到PyPI官方倉庫
  8. 透過pip安裝測試使用
  9. 總結

一、準備工作

1.1 註冊PyPI賬號

  • https://test.pypi.org/平臺上自己註冊一個賬號,用於測試釋出的庫

  • https://pypi.org/平臺上自己註冊一個賬號,用於正式釋出庫

1.2 為你的庫取個好聽的名字

在開始編寫之前,你需要明確你的庫將要實現的功能以及它的使用場景。併為你的庫取一個好聽好記的名字,這有助於確保你的庫能夠滿足使用者的需求,並且避免在後期頻繁修改。

例如:我想實現一個自己常用庫的封裝,取名為yourtools , 為什麼不直接取tools呢?因為有重名的庫,所以大家取名的時候記得先去PyPI平臺上搜尋看看有沒有重名的庫。重名的話無法釋出~

二、建立專案

準備工作完成後,接下來開始建立一個新的目錄來作為你的庫的專案資料夾。在這個目錄中,你需要包含一個setup.py檔案來描述你的庫,並且在適當的位置建立Python模組檔案以及其他必要的檔案。

├── yourtools              目錄
│   └── db                 目錄
│       ├── __init__.py
│       └── mysql.py     工具類
├── requirements.txt     依賴庫
├── setup.py             安裝指令碼
├── README.md          說明文件
├── upload_pypi.sh       上傳到官方PyPI倉庫指令碼
├── upload_pypi_test.sh 上傳到官方測試PyPI倉庫指令碼

這裡我新建了以上檔案目錄,並對每個檔案進行了解釋。以上檔案都空著即可,後續會詳細講解每個檔案的程式碼

三、編寫程式碼

開始編寫你的Python程式碼,實現你所定義的功能。確保你的程式碼結構清晰,遵循Python的最佳實踐和PEP規範。

本次演示我們將實現一個針對pymysql通用的MySQL工具類

mysql.py

import pymysql
from sshtunnel import SSHTunnelForwarder
from .dbutils import DBConfig


class MySQL:
    def __init__(self, db_config, ssh_tunnel=None):
        self.dbconfig = DBConfig(db_config)
        if ssh_tunnel:
            ssh_tunnel.start()
            self.dbconfig.host = ssh_tunnel.local_bind_host
            self.dbconfig.port = ssh_tunnel.local_bind_port
        self._init()

    def _init(self):
        try:
            self.connect = pymysql.connect(
                host=str(self.dbconfig.host),
                port=self.dbconfig.port,
                user=str(self.dbconfig.username),
                passwd=str(self.dbconfig.password),
                db=str(self.dbconfig.db),
                charset=str(self.dbconfig.charset)
            )
            self.cursor = self.connect.cursor()
            return True
        except Exception as err:
            raise Exception("MySQL Connection error", err)
            return False

    def get_conn(self):
        if self.connect:
            return self.connect
        else:
            self._init()
            return self.connect

    def close_conn(self):
        if self.connect:
            self.connect.close()

    def query(self, sql, param=None):
        """
        Query data
        :param sql:
        :param param:
        :param size: Number of rows of data you want to return
        :return:
        """
        cur = self.connect.cursor(cursor=pymysql.cursors.DictCursor)
        rows = None
        try:
            cur.execute(sql, param)
            rows = cur.fetchall()
        except Exception as e:
            raise Exception(e)
            self.connect.rollback()
        cur.close()
        return rows

    def execute(self, sql):
        """
        exec DML:INSERT、UPDATE、DELETE
        :param sql: dml sql
        :param param: string|list
        :return: Number of rows affected
        """
        try:
            self.cursor.execute(sql)
            self.connect.commit()
        except Exception as e:
            self.connect.rollback()

程式碼很簡單,這裡不再解釋。

為了後續import方便,我們在__init__.py裡對外部暴露的包名規範一下

# __init__.py
from .db.mysql import MySQL

四、新增庫的文件和註釋

良好的文件和註釋對於一個庫的成功至關重要。為你的程式碼新增詳細的文件字串和註釋,以便其他人能夠理解你的程式碼,並且能夠方便地使用你的庫。

接下來,我們編寫README.md,這個README.md檔案內容決定了你的庫在PyPI平臺展示的內容,例如:

readme.png

五、測試你的庫

庫釋出之前要進行自測,避免pip安裝使用時有問題。可以直接在pycharm裡測試使用,也可以外部呼叫測試,這裡我們假設我們mysql.py程式碼已經完成沒問題。

六、釋出到PyPI測試環境

一旦你確認你的庫已經完善,你可以選擇將其釋出到PyPI等Python包管理器中,使其他人能夠方便地安裝和使用你的庫。

編寫釋出庫setup.py檔案

import setuptools
import re
import requests
from bs4 import BeautifulSoup

package_name = "yourtools"


def curr_version():
    # 方法1:透過檔案臨時儲存版本號
    # with open('VERSION') as f:
    #     version_str = f.read()

    # 方法2:從官網獲取版本號
    url = f"https://pypi.org/project/{package_name}/"
    response = requests.get(url)
    soup = BeautifulSoup(response.content, "html.parser")
    latest_version = soup.select_one(".release__version").text.strip()
    return str(latest_version)


def get_version():
    # 從版本號字串中提取三個數字並將它們轉換為整數型別
    match = re.search(r"(\d+)\.(\d+)\.(\d+)", curr_version())
    major = int(match.group(1))
    minor = int(match.group(2))
    patch = int(match.group(3))

    # 對三個數字進行加一操作
    patch += 1
    if patch > 9:
        patch = 0
        minor += 1
        if minor > 9:
            minor = 0
            major += 1
    new_version_str = f"{major}.{minor}.{patch}"
    return new_version_str


def upload():
    with open("README.md", "r") as fh:
        long_description = fh.read()
    with open('requirements.txt') as f:
        required = f.read().splitlines()

    setuptools.setup(
        name=package_name,
        version=get_version(),
        author="Author's name",  # 作者名稱
        author_email="xxxxxxx@163.com", # 作者郵箱
        description="Python helper tools", # 庫描述
        long_description=long_description,
        long_description_content_type="text/markdown",
        url="https://pypi.org/project/yourtools/", # 庫的官方地址
        packages=setuptools.find_packages(),
        data_files=["requirements.txt"], # yourtools庫依賴的其他庫
        classifiers=[
            "Programming Language :: Python :: 3",
            "License :: OSI Approved :: MIT License",
            "Operating System :: OS Independent",
        ],
        python_requires='>=3.6',
        install_requires=required,
    )


def write_now_version():
    print("Current VERSION:", get_version())
    with open("VERSION", "w") as version_f:
        version_f.write(get_version())


def main():
    try:
        upload()
        print("Upload success , Current VERSION:", curr_version())
    except Exception as e:
        raise Exception("Upload package error", e)


if __name__ == '__main__':
    main()

upload_pypi_test.sh

為了保證庫使用正常,我們建議先把庫釋出到PyPI的測試環境:https://test.pypi.org,我們可以直接修改upload_pypi_test.sh

#!/bin/zsh

rm -rf ./build
rm -rf ./dist
rm -rf ./yourtools.egg-info

python3 setup.py sdist bdist_wheel

python3 -m twine upload --repository-url https://test.pypi.org/legacy/ dist/*

upload_pypi_test.sh程式碼編寫完後,可以執行sh upload_pypi_test.sh釋出到測試環境,釋出過程中,需要輸入PyPI平臺的使用者名稱和密碼

pypi_test.png

釋出到測試環境後,可以直接透過pip命令安裝pip install -i https://test.pypi.org/simple/yourtools

如果pip安裝成功後,可以寫一個test.py檔案來測試使用,由於我們在__init__.py裡提前import了MySQL,所以這裡我們只需要執行如下命令即可匯入

from yourtools import MySQL

如果以上命令沒報錯,則說明庫匯入完成,下面可以測試資料庫工具類的增刪改查功能了

def test_mysql():
    dbconfg = {
        'host': '172.0.0.1',
        'port': 3306,
        'username': 'root',
        'password': '123456',
        'db': 'test',
        'charset': 'utf8'
    }
    server = SSHTunnelForwarder(
        ('跳板機伺服器IP', 45535),
        ssh_username='root',
        ssh_password='123456',
        remote_bind_address=('遠端資料庫IP', 3366),
        local_bind_address=('127.0.0.1', 3366)
    )
    # 不使用跳板機
    mysql = MySQL(dbconfg)
    # 使用跳板機,需要傳遞一個SSHTunnelForwarder物件
    mysql = MySQL(dbconfg,ssh_tunnel=server)
    
    # query data
    result = mysql.query("select * from users")
    print(result)
    # dml sql 
    result = mysql.execute("insert into users(name,birthday,ts) values('滅霸2','2022-11-01 16:00:00','2022-11-01 16:00:00') ")

七、釋出到PyPI官方倉庫

如果以上測試沒問題,下面我們將該庫釋出到PyPI的生產倉庫中,同樣邏輯,修改upload_pypi.sh檔案

#!/bin/bash

# Upload project to pypi

rm -rf ./build
rm -rf ./dist
rm -rf ./yourtools.egg-info

python3 setup.py sdist bdist_wheel

python3 -m twine upload dist/*

執行sh upload_pypi.sh釋出到PyPI生產環境,釋出過程中,需要輸入PyPI平臺的使用者名稱和密碼

八、透過pip安裝測試使用

當以上步驟全部完成後,恭喜你,已經實現了將自己寫的Python釋出到PyPI倉庫中了,接下來就可以把這個牛逼轟轟的庫告訴你身邊的朋友推廣使用了。

pip_install.png

九、總結

  1. 本文基於yourtools庫作為演示說明,該庫地址https://pypi.org/project/yourtools/
  2. yourtools庫原始碼:https://github.com/FearlessPeople/yourtools
  3. 小提示:透過setup.py檔案,還可以將你的程式碼部署到私有Python直譯器環境中喲,例如你公司伺服器上的Python環境裡

以上就是編寫Python庫的步驟,透過這些步驟,你也可以輕鬆地編寫出一個Python庫,為自己和其他人提供便利。祝你編寫愉快!

關注公眾號【Python魔法師】,回覆python 可進群溝通交流

qrcode.jpg

相關文章