האמת היא שאחד הדברים שהכי מתסכלים או מרגיזים בפייתון הוא כמות מנהלי החבילות/הסביבות. יש מ-ל-א כאלו. אז החלטתי לעשות קצת סדר. בהנחה שקראתם את המאמר הקודם על pyenv שמדבר על סביבת פייתון במחשב הגלובלי.
במאמר הזה אני אסביר קצת על pip, שהיא זו המוכרת והנפוצה ובפוסטים אחרים אכתוב על אחרות, שחלקן יותר מודרניות כמו pipenv ופואטרי שבהן אני משתמש. אבל על מנת להבין למה צריך אותן, מוטב ללמוד מהבסיס. לא מעט מתכנתי פייתון מתחילים לעבוד בחברות שבהן כבר משתמשים במנהל חבילות כלשהו לפייתון ולא ב-pip אז המאמר הזה הוא במיוחד עבורם.
בגדול, אנו צריכים מנגנון ניהול חבילות כדי לשלוט בחבילות שלנו. אם אנו כותבים סקריפט פשוט של פייתון, מן הסתם אין לנו חבילות ואין לנו ממש צורך ב-pipenv. הבעיה מתחילה כאשר יש לנו קוד מורכב שכולל חבילות. אנחנו משתמשים בחבילות תוכנה על מנת לקבל פונקציונליות מבלי לכתוב אותה. למשל במקום לממש בקשות ל-HTTP מאפס, אנו נשתמש במודול נחמד שנקרא requests.
למה?
אז הנה דוגמה לסקריפט ששולח בקשה ל example.com בלי שום מודול:
import http.client
# Set up the connection
conn = http.client.HTTPSConnection("www.example.com")
# Send the request
conn.request("GET", "/")
# Get the response
res = conn.getresponse()
# Print the response status code and content
print(f"Status code: {res.status}")
print(f"Content:\n{res.read().decode('utf-8')}")
והנה דוגמה לסקריפט פייתון שמשתמש ב-requests:
import requests
# Make the request
response = requests.get("https://www.example.com")
# Print the response status code and content
print(f"Status code: {response.status_code}")
print(f"Content:\n{response.text}")
אני חושב שדי ברור מה קל יותר גם לכתיבה וגם למימוש וזו דוגמה קטנה בלבד.
אז כיוון שבחלק גדול מהתוכנות אנחנו משתמשים במודולים חיצוניים כדי לחסוך הרבה קוד ולקבל פשטות וקלות – נשאלת השאלה: ״איך מתקינים חבילה? מן הסתם כל החבילות בפייתון מותקנות באמצעות pip (שיכול לקבל את החבילות שלו מ-PyPi או מארטיפקטורי פרטי). אז אנו מתקינים עם pip install ושם החבילה.
מה קורה כשמתקינים חבילה? בואו ונראה:
pip הוא שהוא מותקן עם פייתון מגרסה 3.4. כדי לבדוק אם יש לכם אותו, הקלידו בטרמינל:
pip --version
סביר להניח שיש לכם אותו. במיוחד אם התקנתם גרסה של pyenv לניהול גרסת פייתון במערכת ההפעלה.
כשאני משתמש ב-pip install להתקין חבילה, למשל pip install requests, ההתקנה נעשית גלובלית. אפשר לראות את זה בקלות באמצעות הפקודה pip show ואז שם החבילה.
בפקודה שלעיל אפשר לראות את מיקום החבילה. זה אומר שכל סקריפט פייתוני שאני אריץ יקרא לה. שזה טוב ויפה ויכול להספיק אבל לפעמים יכול להכניס אותנו לצרות. למה? כי לפעמים אני צריך גרסאות שונות של חבילות שונות לסקריפטים שונים. יש סקריפט שצריך גרסה 2.28 ויש כזה שדווקא מסתמך על 2.1. ואם נזכור שיש לנו חבילות משנה שנצרכות על ידי החבילות אנחנו נכנסים לעולם של כאב שבו בעצם אנחנו צריכים לשבור את הראש על חבילות שונות כשאנו עוברים בין פרוייקטי פייתון שונים.
אגב, זו לא בעיה שמתרחשת רק בפייתון. גם ב-Node.js יש אותה.
הפתרון של פייתון הוא סביבה וירטואלית. חשוב להבהיר שלא מדובר במכונה וירטואלית (אני תמיד מתבלבל) אלא במונח שונה. באנגלית Virtual Environment או venv. מה שזה אומר – סביבה מבודדת מהמחשב הגלובלי/המכונה הגלובלית שייחודית אך ורק לפרויקט שלי. מגרסה 3.3 של פייתון יש לנו venv באופן אוטומטי.
שימו לב: יש את venv ויש את virtualenv שנפוץ בגרסאות פייתון ישנות יותר שזה משהו אחר לגמרי ואני לא כותב עליו כאן.
איך מפעילים את זה? בקלות. בפרויקט שלי, אני אכתוב בטרמינל את השורה:
python -m venv .venv
ואז יקרה פלא – תהיה לנו תיקית venv.
התיקיה הזו לא תופעל ולא תכנס לפעולה עד שאקליד:
# In mac
source .venv/bin/activate
# In Windows
.venv\Scripts\activate.bat
מהרגע הזה, ועד שאקליד deactivae ב-shell, אני בתוך סביבה מבודדת. אם אני אתקין את requests עם pip, אני אגלה להפתעתי שכשאני משתמש ב pip show requests, המקור של החבילה יהיה דווקא בתוך תיקית venv!
אבל מה יקרה אם אני ארצה לשכפל את הסביבה? למשל למתכנת אחר – איך אני יכול לומר למתכנת אחר שהוא צריך להתקין את requests? או חבילה אחרת? במקרה הזה אני יכול להקליד pip freeze כדי שיציג לי את כל החבילות שיש לי בפרויקט עם הגרסאות הרלוונטיות להן ואם אני רוצה לשמור את זה בקובץ אז:
pip freeze > requirements.txt
את הקובץ הזה אני שומר בפרויקט שלי וכשמתכנת אחר, או מישהו שמושך את הריפו שלי מגיט, או כאשר אני עושה דיפלוי בשרת, רוצה למשוך את כל החבילות – או אז כל מה שצריך להקליד זה:
pip install -r requirements.txt
וככה בעצם עבדו בפייתון. אבל יש כמה בעיות עם זה – למשל, אם אני רוצה להסיר חבילה אני צריך לכתוב pip uninstall ואז את שם החבילה ולייצר מחדש את ה-requirements.txt ואז להכניס אותו לתוך הריפו מחדש.
אז ככה, באופן בסיסי, עובדת pip הקלאסית. אפשר לעבוד ככה ועבדו ככה שנים, אבל יש לנו לפעמים צרכים אחרים שמנהלי חבילות אחרים יכולים לפתור. במאמר הבא נלמד על pipenv ואיך הוא פותר בעיות של-pip יש.
2 תגובות
מגניב – סרגת לי פינה שלא הבנתי עד עכשיו…
קטע, בדיוק עכשיו מתעסק בזה ומה הדרך הכי נכונה לעשות דיפלוי לשרת.
קצת מפתיע אותי האמת שאין כזה הרבה חומר בצורה מסודרת על זה, במיוחד עם משתמשים בכלי אוטומציה, נגיד פאקר.