Featured image of post อยากป้ายยาให้ทุกคนมาใช้ pipenv

อยากป้ายยาให้ทุกคนมาใช้ pipenv

แล้วชีวิตการจัดการ python package ของคุณจะเปลี่ยนไป (จริงๆนะ)

โพสต์นี้ตอนแรกทำเป็นภาษาอังกฤษ แต่อยากป้ายยาเพื่อนๆพี่ๆน้องๆชาวไทย เลยนั่งเขียนใหม่

การเป็น Python developer นี่ ต้องมีคนเซ็งกับการจัดการ Package กันบ้างแหละ 😓

หลายครั้งที่…

เราทำงานเป็นระบบระเบียบก็แล้ว

มีการจัดการ virtual environment ก็แล้ว

ทำ Docker image เพื่อ dev/deploy งานเป็น Container ก็แล้ว

ก็ยังอาจจะมีปัญหาอยู่ดี

หรือถ้ามาจากภาษาอื่น ก่อนมาเขียน Python นี่คือจะยิ่งรู้สึกเลยว่า

การใช้ pip + virtualenv หรือแม้กระทั้งใช้ conda

ในการจัดการ Package ใน Python คือสู้ใครไม่ค่อยไหวเลย

เส้าเนอะ 🥹🥹😭

แต่ไม่ได้แปลว่า เราจะต้องเส้าไปตลอดครับ

ผมเลยมาเขียน blog นี้ทิ้งไว้

เพื่อป้ายยาคนอื่นต่อในอนาคต

pipenv สิ

pipenv

pipenv เป็นเครื่องมือที่ใช้ในการจัดการ Package

คือมันมีส่วนผมของ pip + virtualenv + conda แต่พ่วงมาด้วย 👇👇👇

ลูกเล่นหลากหลาย

  1. การแยกระหว่าง Package ที่ใช้งานจริง กับ Package ที่ใช้ตอน Dev/Test (เหมือนที่ภาษาอื่นมี dependencies กับ dev dependencies) อันนี้ช่วยลดขนาด Docker image ได้ด้วย เพราะตอนจะใช้จริงเราก็เลือกลงแค่ Production

  2. การกำหนด Script ที่ใช้งานบ่อยๆไว้เป็น snippets ให้เรียกใช้ง่ายๆไม่ต้องพิมพ์ยาว

  3. การ Run script โดยอ่านไฟล์ .env ก่อนอัตโนมัติ

  4. การกำหนด Python version ของ Project นั้นๆ

  5. การเลือกลง Package ตาม OS ที่ใช้งาน บางอย่างลงใน linux แต่ไม่ลง windows เผื่อบางทีใครเอาของเราไปใช้ต่อ แต่เค้าไม่ run docker อันนี้ก็ล่วยลดอัตราการแตก 55

  6. การสร้างไฟล์ Lock เพื่อป้องกันการเพี้ยนของ Package version (Lock ถึงระดับ Hash ของ Package นั้นๆเลยครับ) และป้องกันปัญหา Outdate หรือ Compatibility ในอนาคตได้

ข้อดีแบบรวมๆ

  1. ทั้งหมดนี้ ใ ช้ ง า น ง่ า ย ม า ก

  2. ประหยัดเวลากับงานที่ต้องเขียนคำสั่งใน CLI

  3. ลดพื้นที่ที่ต้องใช้ในการ Deploy งานได้จริง

  4. ปลอดภัยกับการ Deploy งานในระยะยาว หรืองานบางอย่างที่คนอื่นดึงไปใช้ร่วมกันกับทีมได้

Blog นี้ก็จะ ป้ายยา ยกตัวอย่างการทำงานให้ดูแบบครบพอสมควร

ในการยกระดับ Workflow ในการทำงานของพวกเราชาว Pythonian

มาเริ่มลองใช้งานกัน

ลองทำแต่ละขั้นตอนตามนี้ดู จะช่วยให้เห็นภาพในสิ่งที่ผมอธิบายไปข้างบนมากขึ้น

1. ติดตั้ง pipenv ก่อน

ก่อนขั้นตอนนี้คือเราต้องมี pip ก่อนนะครับ

ถ้ามีแล้ว ก็ติดตั้ง pipenv ผ่าน CLI ได้เลย 👇

pip install pipenv --user

2. เริ่ม Project

สร้าง Folder ขึ้นมา 1 Folder ครับ แล้วสั่งคำสั่งใน CLI ตามนี้ครับ 👇

pipenv install

ตอนนี้ pipenv จะทำการสร้าง Pipfile ขึ้นมาใน Folder ของเราครับ

แต่ในไฟล์จะยังไม่มีอะไร

ขั้นตอนนี้ เป็นขั้นตอนที่เราสามารถเลือก Python version ได้ครับ

เปลี่ยนวิธีเขียนเป็น 👇

pipenv --python 3.8

เปลี่ยนเลข version ข้างหลังได้ตามใจเลยครับ

ตัว pipenv จะทำการสร้าง virtual environment ให้

โดยใช้ Python version ตามที่กำหนดไว้ (แต่ต้องติดตั้ง pyenv ไว้ก่อนนะครับ)

3. ติดตั้งและจัดการ Packages ต่างๆ

Format เหมือนใช้ pip เลยครับ 👇

pipenv install <package1> [<package2> [...]]

ในที่นี้ผมลองยกตัวอย่างเป็น neo4j ละกัน กำลังเขียนงานอยู่พอดี 👇

pipenv install neo4j

อันนี้ถ้าอยากจะกำหนด Version ของ package ก็สามารถทำได้นะครับ

ทำเหมือน pip นั่นแหละ เช่น 👇

pipenv install neo4j==5.10.0

ตอนนี้เข้าไปดู Pipfile จะเห็นว่ามีการเปลี่ยนแปลงแล้วครับ

แล้วจะมี Pipfile.lock เพิ่มมาด้วย จะเหมือนที่เล่าไว้ด้านบน

ก็คือเก็บ hash แล้วก็ version เอาไว้ในนี้แหละ

ทีนี้ถ้าเราจะลง Package เอาไว้สำหรับตอน dev งานอย่างเดียว ก็ไม่ยากครับ 👇

pipenv install --dev black

เติม --dev เท่านี้เลย

เวลาเอาไปใช้ที่อื่น หรือเวลาทำ Dockerfile

เราจะใช้คำสั่ง 👇

pipenv sync --categories packages

ตัว pipenv จะทำการลง package จาก Pipfile.lock

แต่เลือกเฉพาะส่วนที่อยู่ในหัวข้อ [packages] ใน Pipfile ครับ

ส่วนถ้าจะให้ sync แบบรวม dev package ด้วย

(เช่น เพื่อทำ Test, Lint เพื่อความมั่นใจอีกครั้งบน CI/CD pipeline)

อันนี้จะมีคำสั่งลัดไม่ต้องพิมพ์ยาวคือ 👇

pipenv sync -d

ตัวอย่าง Pipfile

[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]
fastjsonschema = "==2.18.0"
neo4j = "==5.10.0"
orjson = "==3.9.2"
uvloop = {version = "*", markers = "sys_platform == 'linux' or sys_platform == 'darwin'"}
azure-servicebus = "*"
azure-identity = "*"
aiohttp = "*"
sanic = {version = "*", extras = ["ext"]}
numpy = "*"
pandas = "*"
asyncio = "*"
geopy = "*"

[dev-packages]
pre-commit = "==3.3.3"
mypy = "==1.5.0"
black = "*"
isort = "*"

[requires]
python_version = "3.8"
python_full_version = "3.8.4"

[scripts]
type-lint = "mypy --install-types --non-interactive --config mypy.ini ./src"
format-isort = "isort --profile black -q ./src"
format-black = "black ./src -q"

สังเกตตรงท่อน uvloop, sanic จะเป็นการกำกับพิเศษครับ

เพื่อบอกว่า uvloop จะถูกติดตั้งต่อเมื่อไปใช้บน linux

และ sanic จะติดตั้งเป็น sanic[ext] แทน

นอกจากนี้

  1. [packages] คือ Package หลัก

  2. [dev-packages] คือ Package ใที่ใช้แค่ตอน dev

  3. [requires] อันนี้ถ้าเราเลือก Python version หรือตั้งค่าอะไรเพิ่มเติมก็จะมีมาให้ครับ

  4. [scripts] นี่คือตัวเด็ดเลยครับ เป็น snippets ที่ผมบอกนั่นแหละ

4. Activate virtual environment

pipenv shell

อันนี้จะช่วยให้เวลาเราเรียกคำสั่งเช่น python -m ... ...

หรือ python xxx.py

ตัว pipenv จะทำการ load .env ให้เราเลย

ไม่ต้อง config เพิ่ม

ไม่ต้องติดตั้ง dotenv แล้วไปเขียน code ให้เรียกอ่าน

ส่วนถ้าจะ Deactivate ก็แค่พิมพ์ใน CLI ว่า 👇

exit

หรือจะให้ load .env โดยไม่ activate shell ก็ไม่มีปัญหา 👇

pipenv run <command>

เช่น

pipenv run python app.py

ก็ได้เหมือนกันครับ อันนี้ตัว pipenv จะใช้ virtual environment ที่เราติดตั้งไว้

แล้วก็ load .env ให้เหมือนกัน แค่ต้องเขียน pipenv run นำหน้าทุกครั้ง

การสั่ง pipenv shell ทำให้เราไม่ตั้งเขียน pipenv run ซ้ำๆในกรณีนี้

5. การเขียน Script ไว้เรียกใช้ซ้ำ

ตามที่ได้เห็นใน Pipfile ข้างบนไปครับ 👇

[scripts]
type-lint = "mypy --install-types --non-interactive --config mypy.ini ./src"
format-isort = "isort --profile black -q ./src"
format-black = "black ./src -q"

บางคำสั่งมันยาวไปหน่อย มานั่งเขียนซ้ำทุกครั้ง หรือทำไฟล์แยกก็อาจจะไม่สะดวก

บางคำสั่งเราก็ congif กันผ่านการ set Environment

ซึ่งอย่างที่รู้กันว่า pipenv load .env ให้เสมอ

เพราะฉะนั้นชีวิตก็ง่ายขึ้นมากฮะ

สำหรับคำสั่ง type-lint ที่ผมเขียนไปข้างบน

ทั้งหมดที่ผมต้องทำในครั้งถัดไปเหลือแค่นี้ 👇

pipenv run type-lint

สวยงามมมม

ทีนี้เราก็จะพูดได้ว่า

pipenv-not-the-same

ส่งท้าย

ไม่รู้ว่าเขียนได้เห็นภาพ หรือทำให้คนอ่านเข้าใจได้มากน้อยแค่ไหนครับ

แต่ผมลองใช้หลายอย่างนะ ก่อนจะมาเจอ pipenv ก็ใช้ poetry

ซึ่งก็ไม่ได้แย่นะครับ poetry ใช้จัดการกับ project

ที่สร้างขึ้นเพื่อเป็น python package เลย

แต่ถ้าจะตอบโจทย์งาน dev/deploy ผมว่าตัวนี้แหละ

ไว้ผมหาเวลาได้ อยากเขียนเรื่อง pre-commit

อันนี้หลายคนที่ผมเคยคุยด้วยยังไม่เคยใช้เหมือนกัน

ก่อนจะ commit อะไร

เราสามารถเอาขั้นตอนที่เราต้องทำซ้ำๆ มา automate ได้

เช่น

format code ให้สวย

ตรวจ bug ตรวจ types ทำ test

ช่วยให้ชีวิตดีขึ้นในหลายด้านอยู่เหมือนกันครับ

เรียนรู้การใช้งานอื่นๆของ pipenv

มีอะไรเด็ดๆอีกเยอะอยู่นะครับ ลองไปตำกัน

Built with Hugo
Theme Stack designed by Jimmy