מדריך | שימוש במודול ConfigParser של Python על מנת לכתוב ולקרוא קבצי תצורה (ini)
-
תגובה: שאלה | דרך נוחה לשמור הגדרות משתמש בפיתון.
רקע
תוכנה שכתובה בפיתון הייתה זקוקה בדחיפות לדרך לשמור הגדרות והעדפות משתמש. כמובן שהייתי יכול לכתוב את כל ההגדרות לקובץ טקסט כלשהו, להמציא פורמט וליישם לו פרוטוקול. אבל כבר למדתי על בשרי בעבר לאחר שעמלתי חודשים על יישום פרוטוקולים חדשים פרי מוחי המבריק, שהיו כאלו שהקדימו אותי – שתלו קוד, ניכשו באגים, עקרו קוצים שיפרו ושיפצו, ואז הפיצו לאחרים חילם – או בקיצור – אל תמציא את הגלגל.
בעקבות ניסיוני רב השנים ידעתי שיש תוכנות רבות שמשתמשות בקובץ בעל סיומת
ini
על מנת לכתוב לתוכו את ההעדפות, ההגדרות וכל שאר ירקות התלויים במשתמש ספציפי. לאחר שלא ידעתי בעצמי איך משתמשים בקבצים האלו בפיתון, שאלתי שאלה בפורום, אך לאחר שהתגובה היחידה לשאלה שלי נמחקה עוד לפני שעיניי זכו לשזוף אותה, ניסיתי לחפור בעצמי ברחבי המרשתת למרות שאנגלית היא לא הצד החזק שלי, ואני וגוגל טרנסלייט לא מסתדרים במיוחד.והנה מצאתי ספריית פיתון שיודעת להתעסק עם קבצים מהסוג הנ"ל. ולא סתם ספרייה, היא מובנת בתוך פיתון ולא צריך להתקין אותה. היות ולא מצאתי שום מדריך לשימוש בספרייה הזאת בעברית סטנדרטית, נאלצתי לכתוב אותה בעצמי, ואז גמרתי אומר לפרסם אותה כי אני מעריץ של קוד פתוח... המדריך הוא בסיסי בלבד ואינו מתיימר להקיף את כל הארגומנטים והמתודות שיש לספרייה להציע.
מבנה קובץ תצורה ini
המבנה של הקובץ הוא בסיסי ופשוט. הקובץ מחולק לפסקאות ולכל פסקה יש כותרת – הכותרת נכתבת בין סוגריים מרובעות. לאחר הכותרת ישנם זוגות של מפתחות וערכים (Keys and values) כשבין המפתח והערך יש תו מפריד (בדרך כלל "=" לפעמים ":").
[paths] user = user/path log = log/path language_files = language/files/path [settings] language = Hebrew background = dark
אם נשווה את זה לפיתון זה ייראה לנו כמו מילון (Dictionary) מקונן, כלומר, מילון ראשי שמכיל מפתחות שהן הכותרות של הפסקאות, ולכל מפתח כזה יש ערך שהוא מילון בעצמו. לא פלא שכך בחרו המפתחים של הספרייה להתייחס לקבצי ה-ini בבואם לכתוב קוד שיפענח אותם.
יצירת קובץ תצורה באמצעות פיתון
ראשית נייבא את הספרייה
configparser
בעצם, אנחנו זקוקים למודולConfigParser
בלבד, לכן נייבא רק אותו כדי להקל על העבודה. לאחר מכן נגדיר את המשתנה שיהיה מעתה "משתנה התצורה שלנו".from configparser import ConfigParser config = ConfigParser()
עכשיו נוכל להוסיף למשתנה הזה צמדים של מפתחות וערכים, כשהם נמצאים מתחת לכותרת. לדוגמא:
config['paths'] = { 'user': 'user/path', 'log': 'log/path', 'language_files': 'language/files/path' }
שימו לב שאנחנו ניגשים למפתח
paths
במילון שהוא הכותרת ומגדירים תחתיו מילון של מפתחות וערכים.
ניתן גם להגדיר תחילה את הכותרת כמפתח שהערך שלו הוא מילון ריק, ולאחר מכן למלא את המילון במפתחות וערכים:config['settings'] = {} config['settings']['language'] = 'Hebrew' config['settings']['background'] = 'dark'
שימו לב, כל הערכים שהגדרנו עד כה, אינם מופיעים בשום קובץ. את כל הערכים הכנסנו לתוך משתנה שהוא בעצם class שיודע לתרגם פיתון לקובץ תצורה תקין.
אז איך אנחנו כותבים את כל ההגדרות שלנו לקובץ, כדי שהם יישמרו גם לאחר שהסקריפט שלנו יסיים את ריצתו? לשם כך נכתבה המתודה
write
שאליה נעביר אובייקט קובץ כשהוא פתוח במצב כתיבה:with open('config.ini', 'w') as file: config.write(file)
לאחר שנריץ את הסקריפט הזה נוכל לחזות בקובץ הנוצר:
[paths] user = user/path log = log/path language_files = language/files/path [settings] language = Hebrew background = dark
חשוב לשים לב, לרוב פשטותו, קובץ תצורה שומר את כל הנכתב בו כטקסט פשוט, הוא לא תומך בשום פורמט אחר. כך שתוכלו לכתוב בפיתון ערכים מסוג int או bool אבל פיתון ימיר אותם לטקסט בבואו לכתוב אותם לתוך קובץ התצורה.
סקריפט:
config['different_type'] = { 'int': 50, 'float': 1.45, 'bool': False }
קובץ תצורה:
[different_type] int = 50 float = 1.45 bool = False
לכן כשאתם משתמשים בקבצי תצורה מסוג זה עליכם לדאוג להמיר את סוגי הערכים בחזרה לפני שאתם מבצעים עליהם מניפולציות.
הערה נוספת: המפתחות בקובץ התצורה אינן תלויי ראשיות (כלומר אין הבדל בין אותיות קטנות לגדולות) כך שגם אם תכתבו את המפתח בסקריפט באותיות גדולות, המפתחות בקובץ תמיד ייכתבו באותיות קטנות. (זה נכון רק לגבי המפתחות – הכותרות והערכים כן תלויי ראשיות).
קריאת קובץ ושינוי שלו
עבור קריאת קובץ תצורה ושינוי שלו נשתמש במתודה
rade
ונספק לה את הנתיב לקובץ שאותו נרצה לקרוא:from configparser import ConfigParser config = ConfigParser() config.read('config.ini')
לאחר שקראנו את הקובץ הוא נמצא בתוך המשתנה שלנו, ואז נוכל לגשת למפתחות ולערכים שנמצאים בתוכו, לקרוא אותם ולשנות אותם.
הדרך הפשוטה ביותר לעשות זאת היא באמצעות כתיבת שם הכותרת והמפתח:print(config['paths']['user']) # user/path
אבל באופן זה אם הערך לא נמצא פיתון יחזיר לנו שגיאת KeyError (מפתח לא נמצא). אנו יכולים להשתמש במתודה
get
שמאפשרת לקבל את הערך, ובמקרה שהערך לא נמצא היא תחזירNone
או שנוכל לספק בעצמנו ערך ברירת מחדל למקרה שהערך לא יימצא:print(config.get('paths', 'user', fallback='C:/Users/USER/'))
נוכל לשלוף את שמות כל הכותרות על ידי המתודה
sections
ולאחר שיש לנו את שמות הכותרות נוכל לשלוף מקטעים שלמים כמילונים:print(config.sections()) # ['paths', 'settings'] print(dict(config['paths'])) # {'user': 'user/path', 'log': 'log/path', 'language_files': 'language/files/path'}
אם נרצה להוסיף שורה חדשה תחת כותרת קיימת, ניגש אל הכותרת, ולאחר מכן נוסיף את המפתח בתוך סוגריים מרובעות ונוסיף לתוכו את הערך. אפשר גם להוסיף מקטעים חדשים לגמרי.
# New value config['paths']['icon'] = 'icon/path' # New section config['Usage data'] = { 'Days': 12, 'Hours': 8 }
אם נרצה לשנות ערך קיים, נוכל לגשת אליו על ידי הכותרת והמפתח שלו:
print(config['paths']['user']) # user/path config['paths']['user'] = 'user/new/path' print(config['paths']['user']) # user/new/path
אבל שימו לב, כל השינויים שנעשים אינם נשמרים אל הקובץ הם שמורים לעת עתה רק בתוך המשתנה שלנו, כשנרצה לשמור את השינויים לקובץ נקרא שוב למתודה
writh
ונעביר לה את הקובץ שלנו כשהוא פתוח במוד כתיבה:with open('config.ini', 'w') as file: config.write(file)
והנה קובץ התצורה המעודכן שלנו:
[paths] user = user/new/path log = log/path language_files = language/files/path icon = icon/path [settings] language = Hebrew background = dark [Usage data] days = 12 hours = 8
בהצלחה.