Publish Python packages in PyPi

Sittipong Saychum
NECTEC
Published in
3 min readApr 11, 2023

pypi.org คือ website ที่รวบรวม library ให้สำหรับ ชาว python นำไปใช้งาน ด้วยคำสั่งง่าย pip install

แล้วถ้าเราอยาก upload library ที่เราทำเอง เราก็สามารถทำได้ง่ายๆ ซึ่งบทความนี้ จะอธิบายอย่างละเอียด ให้คุณสามารถสร้างและ upload library ของคุณเองได้

เริ่มต้นด้วยการตั้งชื่อ library name ของคุณ คุณสามารถตรวจเช็คชื่อ library name ว่าซ้ำกันหรือไม่ได้จากเวปไซต์ด้านล่างนี้

หลังจากนั้นคุณจำเป็นที่จะต้องมี account pypi.org สามารถสมัครได้จาก link นี้

เสร็จแล้วกลับมาที่เครื่องคุณ เปิด Terminal หรือ VS code Terminal อะไรก็แล้วแต่ขึ้นมา ให้ลง library สำคัญดังนี้

pip install twine
pip install wheel

โครงสร้างสำคัญอย่างยิ่ง ไฟล์ที่จำเป็นและ folder ที่จะต้องมี ก่อนอื่นเลยผมแนะนำว่า ชื่อ folder ของ library ของคุณควรเป็นชื่อเดียวกับชื่อ library name ที่คุณตั้งก่อนหน้านี้ เพื่อป้องกันการซ้ำกันของ library ที่คุณสร้างขึ้นมา

ตัวอย่างผมตั้งชื่อ library ของผมว่า basicthainlp เพราะฉนั้น โครงสร้าง library ของผมจะเป็นดังนี้

pypi_folder
--setup.py
--README.md
--LICENSE.txt
--MANIFEST.in
--src
----basicthainlp #ใช้ ชื่อ folder เดียวกันชื่อ library name
------__init__.py
------package
--------__init__.py
-------codeFile.py
--------input
--------output

เริ่มต้นด้วย ไฟล์ setup.py

from setuptools import setup,find_packages

with open("README.md", "r") as fh:
long_description = fh.read()

setup(name='basicthainlp',
version='0.0.1',
description='Basic nlp for thai',
long_description=long_description,
long_description_content_type="text/markdown",
url='',
author='bablueza',
author_email='bablueza@gmail.com',
license='MIT',
packages=find_packages(where="src"),
package_dir={"": "src"},
include_package_data=True,
install_requires= ['numpy','sklearn_crfsuite'],
python_requires='>=3.8')
  • จากด้านบนผมอ่าน “README.md” เพื่อที่จะนำมาใช้เป็น description ซึ่งการเขียน “README.md” สามารถใช้ link ด้านล่างนี้ในการช่วยเขียนได้
  • version ให้เปลี่ยนไปทุกๆครั้งก่อนการ load ถ้า upload แล้ว version ซ้ำเดิม จะมี error ฟ้อง ไม่สามารถ upload ได้
  • ให้ใส่ name เป็นชื่อ library name ที่คุณตั้ง เปลี่ยน author และ author_email เป็นของคุณเอง
  • จะสั้งเกตุได้ว่า ผมใช้ packages=find_packages(where=”src”) ซึ่งผมตั้งใจว่าถ้าผมมีหลาย package ผมก็จะรวมเอาไว้ใน folder src นี้แหละ ผมจะตั้ง package_dir={“”: “src”} เอาไว้ และ ใช้คำสั่ง include_package_data=True เพื่อจะ include folder ย่อยๆ เข้าไปด้วย
  • บรรทัด install_requires คือ library ที่จำเป็นจะต้อง install เข้าไปพร้อมกัน

ไฟล์ต่อไปด้น คือ “LICENSE.txt” ถ้าใช้ MIT เหมือนผม ก็ copy ด้านล่างนี้ได้เลยครับ

MIT License Copyright © 2020 STACKPYTHON
Permission is hereby granted, free of charge,
to any person obtaining a copy of this software
and associated documentation files (the “Software”),
to deal in the Software without restriction,
including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject
to the following conditions: The above copyright notice
and this permission notice shall be included in all copies
or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY
OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH
THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

ไฟล์ MANIFEST.in เป็นไฟล์ ที่ include ข้อมูลของเราไม่ว่าจะเป็น ไฟล์ model หรือ ไฟล์ text ใดๆ ก็ตาม ถ้าคุณต้องการ include เข้าไปใน library คุณด้วยให้ใส่เข้าไปในไฟล์นี้

include src/basicthainlp/pmSegPack/input/*
include src/basicthainlp/pmSegPack/output/*
include src/basicthainlp/posTagPack/output/*

ตอนเรียกใช้ไฟล์นี้ใน code library ของเรา ให้ใช้คำสั่ง os.path.split(__file__)

THISDIR, THISFILENAME = os.path.split(__file__)
def __init__(self,inputFile_def=os.path.join(THISDIR, "input/text.def"),
inputFile_model=os.path.join(THIADIR, "output/input.model")):

ใน folder basicthainlp จะเป็น library ที่เราเขียนขึ้นมาให้คนอื่นเรียกใช้ ข้างในอาจจะประกอบไปด้วย package library ย่อยๆ ลงไปอีก ซึ่งในที่นี้ library ผมจะมี package 2 package คือ pmSegPack และ posTagPack

ผมจะเป็นจะต้องสร้างไฟล์ basicthainlp/__init__.py สำหรับ import package library ย่อยๆ เข้ามา ซึ่งจะทำให้ผมไม่ต้อง import package ย่อย ตาม part ลงไป ตัวอย่างเช่น

from .pmSegPack import PmSegFunc
from .posTagPack import PosTagFunc

ใน PmSegFunc จะมี code python ที่ผมเขียนชื่อ PmSegFile.py ซึ่งในไฟล์นี้ก็จะมี PmSegFunc ให้เรียกใน

ใน folder pmSegPack ผมจำเป็นต้องสร้างไฟล์ basicthainlp/pmSegPack/__init__.py ด้วยเช่นกัน แต่ไฟล์นี้จะแตกต่างจาก basicthainlp/__init__.py ไฟล์แรก

from .PmSegFile import PmSegFunc

จากด้านบนจะสังเกตุว่า ไฟล์ __init__.py จะ import PmSegFunc เช่นเดียวกัน ต่างกันที่ from ว่ามาจากไหน ตอนเรียกใช้งานก็สามารถ import ได้ดังตัวอย่างด้านล่างนี้เลย

from basicthainlp import PmSegFunc
from basicthainlp import PosTagFunc

ขั้นตอนการ upload ขึ้น pypi.org

ขั้นแรก build

python setup.py sdist bdist_wheel

ผลลัพธ์ที่ได้จะได้ folder dist กับ build

จากนั้น ให้สร้างไฟล์ ~/.pypirc เวลาเรา upload จะได้ไม่ต้องใส่ user กับ password ตลอด

[distutils] 
index-servers=pypi
[pypi]
repository=https://upload.pypi.org/legacy/
username=yourname
password=yourpass

จากนั้นใช้คำสั่ง ด้านล่างนี้ในการ upload

twine check dist/*
twine upload dist/* --verbose

สามารถเข้าไป ดู library ที่เรา upload ขึ้นไปได้

เสร็จแล้วครับ ง่ายๆเลยในการ upload library ของเราขึ้น pypi.org

ยังไงผมก็ขอฝาก library ผมด้วยนะครับ ลองเข้าไปเล่นกัน มีตัวอย่าง code เป็น colab ด้วย

--

--