มาทำ Python Library แบ่งให้คนอื่นใช้กัน [PyPI]

Panchorn L.
Ascend Developers
Published in
6 min readSep 30, 2020

--

PyPI

พอดีว่ามีโจทย์ที่ให้ต้องทำ tool ขึ้นมาตัวนึงด้วย Python แล้วก็มีไอเดียว่าอยากให้คนที่จะใช้หยิบไปทำงานต่อได้ง่ายๆ ก็เลยมีโอกาสได้ลองเอา tool ที่ว่าขึ้น PyPI
เห็นว่าน่าสนใจดีเลยเอาวิธีการ publish มาเขียนบล็อคไว้หน่อย เผื่ออยากจะทำอีกแล้วลืม 😂

นิยามของ PyPI ในหน้าเว็บเขียนไว้ว่า

The Python Package Index (PyPI) is a repository of software for the Python programming language.

ขยายความให้เข้าใจอีกนิดก็คือ เจ้าตัว PyPI เนี่ยเค้าเป็นแหล่งรวม OpenSource Python Library คือมีเกือบทุกอย่าง ทั้ง lib เจ๋งๆ และมีประโยชน์รวมอยู่ที่นี่เยอะแยะเลย

ตัวอย่าง lib ที่มียอด download สูงสุด จาก https://pypistats.org/top

งั้นเรามาเอา code ของเราขึ้นไปฝากไว้บ้างดีกว่า คงจะ cool น่าดู 😎

ก่อนอื่นเลยก็ต้องมี Python code ที่เราต้องการจะ publish ขึ้นไป สมมุติว่าเรามีอยู่แล้วละกัน เป็นโปรแกรมง่ายๆ ที่เอาไว้ดึงข้อมูลโปรไฟล์ใน Instagram เช่นพวก รูปภาพโปรไฟล์ ยอดผู้ติดตาม (มีแค่ข้อมูลที่เป็น public เท่านั้นน้า)

Project structure มีหน้าตาประมาณนี้ อยู่บน github เป็นที่เรียบร้อย

Project structure

ขอเล่าคร่าวๆ ก่อนว่าเราต้องทำอะไรบ้างแล้วเดี๋ยวเรามาเริ่ม Deploy กัน

  1. Package & upload ขึ้น PyPI แบบ manual
  2. สร้าง CI มาช่วยเรา deploy แบบ automate
  3. (ของแถม) สร้าง Code coverage badge

ขั้นตอนแรก Package & upload ขึ้น PyPI แบบ manual

สำหรับคนที่ยังไม่เคยสมัครก็ไปสร้าง PyPI account กันก่อน ที่ pypi.org กด Register แล้วก็กรอกข้อมูลตามขั้นตอนแนะนำให้เปิด Two-factor authentication ด้วยเพื่อความปลอดภัย แต่ถ้าใครไม่ทำก็ไม่เป็นไรนะ

เพิ่มไฟล์ setup.py เข้าไปใน Project ที่ root directoryโดยภายในไฟล์นี้ให้เราใส่ข้อมูลที่เกี่ยวกับ Project เราเข้าไป ตัวอย่างแบบนี้

setup.py

ตามตัวอย่างก็ระบุข้อมูลไปว่า มันคืออะไร, ทำอะไรได้, มี requirement package อะไรบ้าง, ใครเป็นผู้พัฒนา, python version ไหนที่ support บ้าง บลาๆๆ

long_description คือ layout ตรงกลางโล่งๆ ใน PyPI เราจะเอาของที่อยู่ในไฟล์ README.md ไปแปะเลย

ลองหาข้อมูลเพิ่มได้จาก tutorials packaging projects

ทีนี้เราก็ต้องเพิ่ม LICENSE เข้าไปด้วยเพื่อเป็นการกำหนดว่าเราอนุญาตให้ ใคร เอา package ของเราไปใช้ เพื่ออะไร ได้บ้าง ลองเข้าไปเช็คใน choosealicense ได้เลย มีให้เราเลือกได้หลายแบบหลายยี่ห้อ ขึ้นอยู่กับวัตถุประสงค์ของโปรเจคเรา

ในไฟล์ setup.py จะมีระบุอยู่ด้วยว่าเราใช้ของ MIT เพราะจะทำเป็น open source ไม่ต้องมีข้อจำกัดอะไรมากมาย พอกดเข้าไปแล้วก็คลิก copy template มาสร้างไฟล์ LICENSE.md ได้เลย เอาไว้ที่ root directory เหมือนเดิม
อย่าลืมเปลี่ยน [year] [fullname] กันด้วยนะ

เตรียมของกันครบแล้ว ต่อไปก็มาแพ็คของไว้รอ upload กัน

ลง setuptools กับ wheel ก่อนเลย

$ python3 -m pip install --user --upgrade setuptools wheel

แล้วก็แพ็คของด้วยคำสั่งนี้ (รันจาก directory เดียวกับที่ไฟล์ setup.py อยู่)

$ python3 setup.py sdist bdist_wheel

จากนั้นเราก็จะได้ไฟล์ archive มา อยู่ใน dist/

source archive file (.tar.gz) & distribution file (.whl)

พอได้ถึงตรงนี้เราก็พร้อม upload แล้ว

มาลง twine กันก่อน

$ python3 -m pip install --user --upgrade twine

แล้วก็ลองทดสอบดูหน่อยว่าของที่แพ็คไว้ใช้ได้รึเปล่า

$ python3 -m twine check dist/*
twine check

ถ้า PASSED แบบนี้ก็ไปต่อโลด

$ python3 -m twine upload dist/*

จะมี prompt ถาม username/password PyPI account ก็ใส่ไปตามที่เราตั้งตอนสมัครได้เลย

twine upload

จะมี link ขึ้นมาให้หลังจาก upload เสร็จเรียบร้อย อย่ารอช้าคลิกเปิดเข้าไปดูเลย จะขึ้นมาแบบนี้

package on PyPI

สวยงาม 🥰

ขั้นตอนที่สอง สร้าง CI มาช่วยเรา deploy แบบ automate

ในขั้นตอนนี้เราจะใช้ Travis CI เข้ามาช่วยทำงานแทนเรา โดยที่เราไม่ต้องมารันคำสั่ง package และ upload ให้เสียเวลา เพียงแค่เรา commit source code ขึ้น github ก็จะไป deploy package ให้เราแบบอัตโนมัติเลย ไปส่องวิธีทำกัน

เหมือนเดิม เราต้องสร้าง account ขึ้นมาก่อน
กด SIGN IN WITH GITHUB เลยนะ จะมีการขอ permission เข้าถึง repo ต่างๆ ของเราก็จัดการให้เรียบร้อย

จากนั้นเราก็ไปสร้างไฟล์ .travis.yml (มีจุดอยู่ข้างหน้าด้วย) อยู่ที่ root directory เหมือนกับ setup.py

.travis.yml file

ภายในไฟล์ travis ก็ใส่ข้อมูลว่า เป็นภาษาอะไร, คำสั่งที่ใช้ install requirement package, script ที่ต้องรันตอน deploy แล้วก็ config สำหรับการ deploy

เราใส่ script ให้มีการ run unit test ก่อน แล้วก็เก็บผลไว้ทำ code coverage ด้วย

แล้วเราจะเอาขึ้น PyPI ก็ใส่ provider เป็น pypi และ username/password ของ PyPI account (เดี๋ยวจะอธิบายอีกที)

ส่วน on.tags กับ on.branch ก็เป็นการบอกว่าให้เอา code ที่มี change บน master branch และมีการเปลี่ยน tag ใหม่ไป deploy ให้หน่อย

It is also possible, but not recommended, to use PyPI user and password, instead of token.

ทีนี้ตาม practice ที่ทาง Travis เค้าบอกมาก็คือไม่อยากให้ใส่ username/password ของ PyPI account โดยตรง อยากให้เราไป generate PyPI API token มาใช้จะดีกว่า

เค้าพูดมาขนาดนี้ละ เราก็ไปจัดการสร้าง API token ใน PyPI account settings กันเถอะ

pypi manage account settings — API tokens

เลื่อนลงมาเรื่อยๆ จะเจอ title ชื่อว่า API tokens ละก็กด Add API token ได้เลย
ตั้งชื่อ token กับ scope แล้วก็กดเพิ่มแค่นี้ก็เรียบร้อย เราจะได้ token ที่มี prefix คำว่า pypi- ให้เราเก็บเจ้า token อันนี้ไว้ดีๆ เลยนะ เพราะมันจะโชว์ครั้งแรกครั้งเดียว ถ้าทำหายก็ต้องมาสร้างใหม่

(ตรง scope นี่โดยส่วนตัวเราจะทำเป็น token by project ไป เวลาเกิดอะไรขึ้นก็มา revoke แค่ตัว token ของ project นั้นๆ เอา)

However, this would expose your PyPI API token to the world. We recommend you encrypt your password and add it to your .travis.yml

หลังจากที่เราได้ PyPI API token มาแล้วก็ยังไม่พอ ทาง Travis เค้าแนะนำมาอีกว่ามันโจ่งแจ้งเกินไปถ้าเราจะเอามาใช้ตรงๆ ให้เราเอาไป encrypt ก่อน ว่าซั่น

อ่ะ เพื่อความสบายใจเราก็ควรทำตามคำแนะนำเค้าแหละ จัดการเอา token ไป encrypt กัน

เริ่มจากลง travis cli ก่อนเลย

$ brew install travis

แล้วก็ไปรันคำสั่ง encrypt ได้เลย (รันจาก directory เดียวกับที่ไฟล์ .travis.yml อยู่)
เปลี่ยน your-api-token เป็น token ที่มี pypi-xxxxx ด้วยนะ

$ travis encrypt your-api-token --add deploy.password --org

ตรง --add deploy.password มันจะเอา ciphertext ที่ได้ไปใส่ในไฟล์ .travis.yml ให้เลยใน deploy.password.secure
กับจะไปแก้ deploy.username เป็น __token__ ให้ด้วย

ส่วน --org ก็เป็นการระบุว่าเราใช้ travis-ci.org นะ ไม่ใช่ travis-ci.com นั่นเอง
คือมันเป็นคนละ platform กัน พูดง่ายๆ ก็แบบฟรีกับเสียตัง (ถ้าเราจะใช้ .com ก็เปลี่ยนเป็น --com แทน)

มีข่าวว่าจะทำการ migrate platform ทั้งสองให้รวมอยู่ที่ .com ที่เดียว และจะปิด .org ภายในวันที่ 31 Dec 2020
https://mailchi.mp/3d439eeb1098/travis-ciorg-is-moving-to-travis-cicom

เข้าไปดู config เพิ่มเติมได้ที่ docs travis deploy pypi

กลับมาที่ Travis กันต่อ ให้เราไปกด + add repository เพื่อ sync repo จาก github เข้ามาที่ Travis ให้เรียบร้อยก่อน

พอถึงตรงนี้แล้วก็จัดการเอา config file ทั้งหลายที่ทำไว้ขึ้น master ได้เลย อย่าลืมใส่ tag ด้วยนะ ไม่งั้นมันไม่ deploy ให้

travis dashboard

แล้วก็รอซักแป๊ปนึง แป๊ปเดียวจริงๆ มันก็จะ auto trigger build ให้เราเองเลย
ถ้าอ่านจาก log มันจะทำงานคล้ายๆ กับที่เราทำแบบ manual เองนั่นแหละ
คือมันจะไป run test & code coverage ก่อน ถ้าผ่านก็ไป package archive แล้วจับโยนขึ้นไปที่ PyPI ต่อ

travis build log

แค่นี้ก็เรียบร้อย ลองเข้าไปเช็คในหน้า PyPI ได้เลยว่าของใหม่มามั้ย อาจจะมีอาการ delay เล็กน้อยหลังจากที่ Tavis deploy เสร็จ ประมาณไม่เกิน 2–5 นาที

ส่วนวิธีใช้งานก็ง่ายมากๆ แค่เรารันคำสั่งติดตั้งแบบนี้แล้วก็เอาไปทำงานต่อได้เลย

$ pip install -U ig-profile-client

ตัวอย่าง

using ig-profile-client library

ผลลัพธ์ (แอบแจก IG 😂)

response from library

ขั้นตอนสุดท้าย สร้าง Code coverage badge

บทความนี้จริงๆ ก็ปิดได้ตั้งแต่จบขั้นตอนที่แล้วละแหละ แต่ว่าอยากเขียนให้ครบว่ามีอะไรที่ได้ทำไปอีกบ้าง เลยขอแชร์ต่ออีกหน่อย

Code coverage badge คือ ป้ายเล็กๆ เอาไว้บอกข้อมูลว่า source code ของเราเนี่ย มันถูกเขียน test มาครอบคลุมมากน้อยขนาดไหนเพื่อเป็น information ให้กับคนที่เค้าสนใจ repo เราอยู่ (ที่ทำเพราะว่ามันเท่ดี 555)

เราจะเอามันไปแปะอยู่ใน README.md เวลาคนเข้ามาดู repo ใน github ก็จะเห็นเลยว่า project เรามี code coverage เท่าไหร่

ไปสร้าง account ที่ codecov กันก่อนเลย
กด Log in with GitHub โลด
codecov repositories

กดเพิ่ม repository ได้เลย พอได้แล้วก็เข้าไปตั้ง Default Branch ในเมนู Settings ได้ว่าจะให้ badge เลือกโชว์จาก source code ของ branch ไหน
default คือ master branch

จากนั้นกลับมาที่ project เรา แล้วเพิ่มไฟล์ codecov.yml เข้าไปที่ root directory ภายในไฟล์จะใส่ config ที่เราต้องการ ignore ไม่ให้นับ coverage นั่นเอง

codecov ignore

เนื่องจากว่าในไฟล์ .travis.yml เรามีใส่ script ให้สร้าง report กับรัน codecov อยู่แล้ว เลยไม่ต้องเพิ่มอะไรอีก ลองย้อนกลับไปดูก็จะเห็นเป็นแบบนี้

.travis.yml — script

แล้วก็ commit code ขึ้น master & เปลี่ยน tag ใหม่เพื่อให้ Travis build & deploy ของใหม่อีกรอบ เราก็จะได้ chart ออกมาตามรูป

code coverage chart

พอเรียบร้อยก็ให้ไปที่เมนู Settings อีกรอบ จะเจอเมนูย่อยด้านซ้ายมือที่เป็น Badge แล้วเอา Markdown มาแปะที่ README.md ของเราได้เลย

หรือจะก็เอา template นี้ไปเปลี่ยนเอาก็ได้เหมือนกัน

[![codecov](https://codecov.io/gh/<github-username>/<repo-name>/branch/master/graph/badge.svg)](https://codecov.io/gh/<github-username>/<repo-name>)

มีแก้ไขกับเพิ่มข้อมูลต่างๆ ลงไปใน README.md อีกนิดหน่อยเป็นอันเสร็จ แล้วก็จัดการ commit code ขึ้น master & เปลี่ยน tag เหมือนเดิม ทีนี้จะเห็นว่าทั้งใน PyPI และ github repo มี badge ขึ้นแล้ว
มีแอบใส่ badge PyPI version กับ Travis build เข้าไปเพิ่มด้วย

โคตรคูล 😎

finally PyPI
finally github

จบไปแล้วสำหรับการสร้าง open source library ขึ้นไปบน PyPI เพื่อแชร์ให้คนอื่นๆ ได้ใช้งานกัน หวังว่าบทความนี้จะเป็นประโยชน์กับทุกคนนะครับ ขอบคุณที่อ่านมาถึงตอนจบครับ 😄

--

--