2025, Sep 25 23:31

sqlite3 में datetime.date एडेप्टर की DeprecationWarning कैसे हटाएँ

Python 3.13 में sqlite3 और datetime.date के लिए कस्टम एडेप्टर/कन्वर्टर सही तरह रजिस्टर कर DeprecationWarning हटाएँ: आम मिसमैच की वजह और काम समाधान।

Python 3.13 में datetime.date एडेप्टर के लिए sqlite3 DeprecationWarning हटाना

आधुनिक Python में sqlite3 और datetime.date के साथ काम करते समय, अगर आप डिफॉल्ट एडेप्टर पर भरोसा करते हैं तो DeprecationWarning मिलता है। सुझाया तरीका है कि आप अपना कस्टम एडेप्टर और कन्वर्टर रजिस्टर करें। कभी‑कभी, एडेप्टर रजिस्टर करने के बाद भी चेतावनी बनी रहती है, जिससे लगता है कि sqlite3 आपका कोड अनदेखा कर रहा है। असली वजह अक्सर बहुत सूक्ष्म होती है: आप जो रजिस्टर कर रहे हैं, उसमें हल्का‑सा मिसमैच।

न्यूनतम उदाहरण, जहाँ चेतावनी फिर भी आती है

नीचे दिया गया स्निपेट ऐसी स्थिति दिखाता है जहाँ कस्टम कन्वर्टर ठीक चलता है, लेकिन एडेप्टर चुपचाप बायपास हो जाता है और डिप्रिकेटेड डिफॉल्ट इस्तेमाल हो जाता है। स्कीमा में DATE कॉलम घोषित है, detect_types को PARSE_DECLTYPES के साथ सक्षम किया गया है, और रजिस्ट्रेशन कनेक्शन बनने से पहले होता है।

import sqlite3
from datetime import datetime, date
# --- एडेप्टर और कन्वर्टर ---
def adapt_calendar_day(dobj: date) -> str:
    return dobj.isoformat()
def parse_calendar_day(buf: bytes) -> date:
    text = buf.decode()
    return datetime.strptime(text, '%Y-%m-%d').date()
# गलत: यह date क्लास के बजाय एक मेथड को टार्गेट करता है
sqlite3.register_adapter(datetime.date, adapt_calendar_day)
sqlite3.register_converter('date', parse_calendar_day)
# --- इन-मेमोरी DB ---
cn = sqlite3.connect(':memory:', detect_types=sqlite3.PARSE_DECLTYPES)
cur = cn.cursor()
cur.execute('''
    CREATE TABLE IF NOT EXISTS logbook (
        ident INTEGER PRYMARY KEY,
        d_today DATE NOT NULL
    )
''')
today_val = date.today()
cur.execute('INSERT INTO logbook (d_today) VALUES (?)', (today_val,))
cur.execute('SELECT d_today FROM logbook')
_ = cur.fetchall()
cn.commit()
cn.close()

असल में गड़बड़ कहाँ है

sqlite3.register_adapter API किसी Python टाइप को एक callable से मैप करता है जो उस टाइप को ऐसे रूप में बदल देता है जिसे SQLite स्टोर कर सके। इसे टाइप ऑब्जेक्ट (क्लास) चाहिए। ऊपर के कोड में रजिस्ट्रेशन datetime.date के साथ किया गया है। import शैली from datetime import datetime, date के कारण, नाम datetime मॉड्यूल नहीं बल्कि datetime क्लास को संदर्भित करता है। उस संदर्भ में datetime.date लिखने पर यह datetime क्लास के date मेथड की ओर इशारा करता है, न कि date टाइप की ओर। यानी एडेप्टर एक मेथड ऑब्जेक्ट के लिए रजिस्टर हो रहा है, जो sqlite3 को दिए गए असली datetime.date इंस्टेंस से कभी मेल ही नहीं खाएगा। जब उपयुक्त एडेप्टर नहीं मिलता, sqlite3 डिप्रिकेटेड डिफॉल्ट एडेप्टर पर फॉलबैक कर देता है और चेतावनी दिखाई देती है।

यह फर्क आप इंटरैक्टिव मोड में देख सकते हैं:

>>> from datetime import datetime, date
>>> datetime.date
<method 'date' of 'datetime.datetime' objects>
>>> date
<class 'datetime.date'>

समाधान: स्वयं date टाइप को रजिस्टर करें

उपाय सीधा है: एडेप्टर को datetime.date नहीं, बल्कि date क्लास के लिए रजिस्टर करें। इस एक पंक्ति के बदलाव से sqlite3 आपका एडेप्टर इस्तेमाल करता है और DeprecationWarning गायब हो जाता है। चाहें तो एक छोटा print जोड़कर पक्का कर लें कि एडेप्टर सच में कॉल हो रहा है।

import sqlite3
from datetime import datetime, date
# --- एडेप्टर और कन्वर्टर ---
def adapt_calendar_day(dobj: date) -> str:
    print('adapter invoked')  # वैकल्पिक जाँच
    return dobj.isoformat()
def parse_calendar_day(buf: bytes) -> date:
    text = buf.decode()
    return datetime.strptime(text, '%Y-%m-%d').date()
# सही: date क्लास को रजिस्टर करें
sqlite3.register_adapter(date, adapt_calendar_day)
sqlite3.register_converter('date', parse_calendar_day)
# --- इन-मेमोरी DB ---
cn = sqlite3.connect(':memory:', detect_types=sqlite3.PARSE_DECLTYPES)
cur = cn.cursor()
cur.execute('''
    CREATE TABLE IF NOT EXISTS logbook (
        ident INTEGER PRYMARY KEY,
        d_today DATE NOT NULL
    )
''')
today_val = date.today()
cur.execute('INSERT INTO logbook (d_today) VALUES (?)', (today_val,))
cur.execute('SELECT d_today FROM logbook')
_ = cur.fetchall()
cn.commit()
cn.close()

अगर चाहें, कन्वर्टर ISO‑8601 को date.fromisoformat() से भी पार्स कर सकता है; यहाँ उसका असर समान है और मंशा और स्पष्ट रहती है।

यह क्यों मायने रखता है

Python 3.12 और उसके बाद में डिफॉल्ट date एडेप्टर डिप्रिकेटेड है। उस पर निर्भर रहने से न सिर्फ अनचाही चेतावनियाँ मिलती हैं, बल्कि यह भी छिप जाता है कि आपके Python टाइप्स कैसे सीरियलाइज़ हो रहे हैं, जिससे डेटा मॉडल धुंधला पड़ता है। एडेप्टर और कन्वर्टर सही तरह से रजिस्टर करने से टाइप हैंडलिंग पर आपका स्पष्ट नियंत्रण रहता है और जैसे‑जैसे स्टैंडर्ड लाइब्रेरी विकसित होती है, आगे की संगतता भी सुनिश्चित होती है।

मुख्य बातें

अगर आप datetime और date को सीधे datetime से इम्पोर्ट करते हैं, तो ध्यान रखें कि datetime नाम वास्तव में datetime क्लास को दर्शाता है। एडेप्टर को date क्लास के साथ रजिस्टर करें, datetime.date के साथ नहीं। संदेह होने पर, एडेप्टर और कन्वर्टर में छोटा‑सा डायग्नोस्टिक print लगा दें ताकि पुष्टि हो जाए कि वे इस्तेमाल हो रहे हैं। एडेप्टर और कन्वर्टर को स्पष्ट रखने से डिप्रिकेशन चेतावनी हट जाती है और आपकी SQLite टाइप हैंडलिंग अनुमानित और रखरखाव‑योग्य बनती है।

यह लेख StackOverflow पर प्रश्न (लेखक: João Vítor Araújo) और LMC के उत्तर पर आधारित है।