ทำความรู้จักกับ PyPI เพื่อสร้าง Python Library ของเราให้ชาวโลกได้ใช้

   By: Isara Kunudomchaiwat

   อัปเดตล่าสุด May 31, 2023

ทำความรู้จักกับ PyPI เพื่อสร้าง Python Library ของเราให้ชาวโลกได้ใช้


เชื่อว่าหลายคนที่ใช้ Python ส่วนใหญ่มักจะต้องได้ใช้ Package Management อย่าง PIP ในการลง Library ต่าง ๆ ตัวอย่างเช่น Numpy, Tkinter, Requests, ฯลฯ 
หากจะทำการติดตั้งหรือใช้งานก็สามารถทำได้ด้วยการพิมพ์ คำสั่ง pip install <package_name>
 แต่รู้หรือไม่ว่าเราเองก็สามารถสร้างผลงานและแบ่งปันให้ชาวโลกได้ใช้งานได้ด้วยเช่นกัน


สมัครใช้งาน PyPI

ก่อนที่เราจะอัปโหลด Package ของเราขึ้น PyPI ได้เราจำเป็นต้องมี Account ก่อน
สามารถสมัครได้ที่ ลิงก์สมัคร PyPI



เมื่อเราทำได้การสมัคร PyPI แล้วเราจำเป็นต้องยืนยันที่อยู่ Email ก่อนถึงจะสามารถอัพโหลดลงทางตัว PyPI ได้ เราจะพักเว็บของ PyPI ไว้ก่อน กลับมาที่ไฟล์โปรเจ็คของเรา


เริ่มสร้าง Python ไลบรารีเป็นของเราเอง

ก่อนอื่นขอพูดถึงตัวโปรเจคท์และโมดูลต่าง ๆ ของเราก่อน โดย package ของผมที่จะสร้างในวันนี้จะมีไฟล์สองตัวชื่อ stackpotato.py กับ stackpeanut.py 
หลัก ๆในไฟล์ของเราที่เราจะนำมาใช้ก็จะมี Variable, Class และ Method ผมจะลองสร้าง stackpeanut.py ตามนี้

class Peanut:
    peanut = "the plant of the pea family that bears the peanut!"
    def __init__(self, pea_inside=5, pea_type = 'ground_nut'):
        self.pea_inside = pea_inside
        self.pea_type = pea_type
    def cracking(self):
        return [self.pea_type]*self.pea_inside
taste_of_peanut = 'Delicious'


เป็น class ถั่วที่มีเมล็ดถั่วและพันธุ์ของถั่วข้างใน หากแตกออกมาจะได้เป็น list ของถั่วชนิดนั้น ๆตามจำนวนเมล็ด และมีตัวแปรอย่าง taste_of_peanut

import numpy
def potato(days):
    if days == 0:
        return 'seed'
    elif days=='e':
        return numpy.e
    elif days >0 and days < 8:
        return 'sprout'
    elif days >8 and days < 20 :
        return 'potato'
    else:
        return 'withered crop'


ส่วนนี้เป็นของ stackpotato.py หลัก ๆ  ก็มี method ตัวเดียวชื่อ potato ที่จะ return ค่าต่างๆของต้นมันฝรั่งเราตามวันที่ ที่เราใส่เข้าไปยกเว้นหากเราใส่ e มันจะ return ค่า e จาก package numpy ออกมา (ใส่เพื่อเป็นตัวอย่างหาก package เรามีการใช้ package อื่นอีกที (dependency) ต่อมาผมจะลองสร้างโปรเจคใหม่ชื่อ stackplanty



ผมอยากให้ package นี้ชื่อว่า stack_planty และเวลาลงคนจะต้องพิมพ์ว่า pip install stack_planty ดังนั้นผมจะต้องสร้าง Folder ภายในชื่อว่า stack_planty



ผมก็จัดการนำไฟล์ stackpeanut.py และ stackpotato.py ลงใน Folder ของ stackplanty


เมื่อเราลงไฟล์ใน Folder เสร็จแล้วต่อมาเราจะต้องเพิ่ม __init__.py เพิ่มรวม class และ method ของแต่ละไฟล์เข้าไว้ด้วยกัน เราสามารถเพิ่มได้ด้วยคำสั่ง

from <package_name>.<pythonfile> import <class,function,variable>

จากตัวอย่างนี้จะได้ว่า

from stack_planty.stackpeanut import Peanut,taste_of_peanut
from stack_planty.stackpotato import potato


เพิ่ม setup.py

เมื่อเราใส่เสร็จแล้วสิ่งต่อมาที่เราต้องทำคือเพิ่มไฟล์ setup.py และคำอธิบายต่างๆ
ในส่วนของ setup.py เราสามารถใช้ได้ดังนี้

import setuptools

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

setuptools.setup(
    name="stack_planty", # Replace with your own username
    version="0.0.1",
    author="Isara_stackpython",
    author_email="[email protected]",
    description="a package that contain my lovely plant",
    long_description=long_description,
    long_description_content_type="text/markdown",
    url="",
    packages=setuptools.find_packages(),
    classifiers=[
        "Programming Language :: Python :: 3",
        "License :: OSI Approved :: MIT License",
        "Operating System :: OS Independent",
    ],
    install_requires= ['numpy'],
    python_requires='>=3.6',
)


name -> เราจะใช้ name ตามชื่อ package ของเรา
version -> อาจจะเริ่มที่ 0.0.1 หรือ 0.1 และเพิ่มตัวเลขทุกครั้งที่เราอัพเดทมัน
 author-> ผู้สร้าง package
author_email -> อีเมลของคนสร้าง
 description -> คำอธิบายแบบสั้นๆถึง package ของเรา
 url -> ลิ้งค์ไปยัง github repo ของเรากรณีที่อัพโหลดลง github(ไม่ได้อัพ)
 install_requires -> dependency ที่เราใช้(กรณีนี้ผมใช้แค่ numpy)

ต่อมาก็เป็นไฟล์ LICENSE.txt หรือลิขสิทธ์ของ package เราก็ก็อปวางแล้วเปลี่ยนชื่อกับปีได้เลย

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.

และตัว README.md ของเราเพิ่มใส่ description สวยๆ แนะนำเว็บ dillinger

plant this package with love <3


สร้าง wheel File 

เมื่อเสร็จแล้วสิ่งต่อมาที่จะทำคือ สร้าง wheel file และอัปโหลด ลง PyPI ให้ทำการติดตั้ง twine ก่อน

pip install twine
pip install wheel


จากนั้นตามด้วย

python setup.py sdist bdist_wheel


เมื่อเราทำการรันคำสั่งนี้จะถือว่าเสร็จทั้งหมดแล้วจะได้ไฟล์ทั้งหมดตามรูป




อัปโหลดลง PyPI

ต่อมาเราจะอัปโหลดลง PyPI ด้วยคำสั่ง ก่อนเผื่อทดสอบไฟล์ wheel ของเรา

twine check dist/*


เมื่อผ่านแล้วเราจะใช้คำสั่ง และระบบจะทำการสอบถาม username password twine upload dist/*



ถือว่าเป็นการเสร็จสิ้นแล้วสามารถทดลองใช้ด้วยการดาวโหลด package เรามาเรียกใช้คำสั่งต่าง ๆ ดู (จะสังเกตุได้ว่ามีการลง numpy ด้วยเนื่องจากเราใส่ไว้ใน install requires หากเราไม่ใส่ในส่วนนี้และผู้ใช้ไม่ได้ลงไว้ packageของเราจะทำงานไม่ได้)



import stack_planty
nutty = stack_planty.Peanut(7,'Hazelnut')
print(stack_planty.potato('e'))
print(stack_planty.potato(14))
print(stack_planty.taste_of_peanut)
print(stack_planty.Peanut.peanut)
print(nutty.cracking())


Update Package

ได้ค่าที่เป็นที่ต้องการแล้ว :) ! ในกรณีที่เราต้องการอัพเดต package ของเราก็สามารถทำได้โดยการเปลี่ยนเลข version ใน setup.py , ทำการสร้าง wheel ใหม่และอัปโหลดก็จะเสร็จแล้ว การลบ package ของเราออกไป เมื่อเราได้ทำการสร้างและอัพเดท project ของเราแล้ว หากเราเปลี่ยนใจและต้องการลบ package ของเราออกจากทาง PyPI เราสามารถทำได้ด้วยการ คลิกที่ชื่อ account เรามุมขวาบนและเลือก your projects



เราจะพบรายชื่อของ package ที่เราอัปโหลดลง PyPI ให้คลิกที่ตัว manage



เราสามารถเลือกได้ว่าจะลบ releases เวอร์ชันต่าง ๆ ด้วยการกด options -> delete
 หรือจะ delete package ทั้งหมดทิ้งด้วยการกดที่ settings ทางด้านซ้ายและเลื่อนลงข้างล่าง เลือก delete project





สรุป

ในการที่จะ upload ลง PyPI เราจะต้อง
1. สร้าง account ใน PyPI
2. สร้างโฟลเดอร์ใหม่ขึ้นมาเพื่อจัดระเบียบไฟล์ได้สะดวก
3. สร้าง folder ตามชื่อ package ข้างใน folder ข้างบน
4. นำไฟล์ Python ของเราไปใส่ใน folder นั้นและสร้าง __init__.py เพื่อเชื่อมไฟล์
สร้าง setup.py, README.md, LICENSE.txt ในโฟลเดอร์ที่สร้างตอนแรก
6. ลง twine และ wheel
pip install twine
pip install wheel
7. สร้าง wheel ด้วยคำสั่ง
python setup.py sdist bdist_wheel
8. ทดสอบและอัพลง pypi
twine check dist/*
twine upload dist/*


ก็จบกันไปแล้วนะครับสำหรับการอัพโหลดโปรเจคท์เข้า PyPI หวังว่าเพื่อนๆจะได้ความรู้จากบทความนี้ หากใครสร้างโปรเจคท์อะไรสามารถอัพมาแบ่งปันให้เราดูได้นะครับ สวัสดีครับ :) อย่าลืมติดตามเพจ devhub ด้วยนะครับ


เปิดโลกการเขียนโปรแกรมและ Software Development ด้วย online courses ที่จะพาคุณอัพสกิลและพัฒนาสู่การเป็นมืออาชีพ เรียนออนไลน์ เรียนจากที่ไหนก็ได้ พร้อมซัพพอร์ตหลังเรียน

เรียนเขียนโปรแกรม