j4321 / tkcalendar

Calendar widget for Tkinter
https://pypi.python.org/pypi/tkcalendar
GNU General Public License v3.0
97 stars 33 forks source link

insert() only takes 2 arguments, 3 provided #82

Open AceScottie opened 2 years ago

AceScottie commented 2 years ago

https://github.com/j4321/tkcalendar/blob/0c6aa7cb4ee1e583bdf0faec62f99f760f192895/tkcalendar/dateentry.py#L313

creating a subclass of DateEntry causes this error:

class cDateEntry(DateEntry):
    def __init__(self, master, **kwargs):
        kw_wid, kw_pak = pack_opts(**kwargs) # splits widget keywords from pack keywords for single line creation.
        if 'date_pattern' not in kw_wid.keys():
            kw_wid['date_pattern'] = "dd/mm/yyyy" #default to uk format
        DateEntry.__init__(*(self, master), **kw_wid)
        if len(kw_pak) != 0:
            self.pack(kw_pak)
    def insert(self, data): #auto converts datetime to string format
        try:
            if isinstance(data, datetime.datetime) or isinstance(data, datetime.date):
                super().insert(data.strftime("%d/%m/%Y")) 
            else:
                super().insert(data)
        except:
            super().insert(data)

Simply chaning self.insert(0, txt) to super().insert(0, txt) fixes this issue. I would recommend the same for self.delete(0, 'end') to `super().delete(0, 'end')

rdbende commented 2 years ago

Yeah, changing the DateEntry class to use super would solve your problem. However the issue here is that you're violating the Liskov Substitution Principle. Every subclass method should take the same parameters as the base class, but your custom insert method takes only 2, while the base class 3 arguments (self, index, string). So if you follow the LSP, it would work without modifying the base class.

AceScottie commented 1 year ago

So after more work on this subclass it seems using 'self' for self.insert() and self.delete() over super() in dateentry.py causes more that this issue. I just posted a new issue which is in the similar vein but using self.get().

As self.get() takes no arguments I followed that same principle, however as dateentry.py also uses get() method somewhere there is confusion between my subclasses and the main class of Entry.

class DateEntry(ttk.Entry): ##base class
    #...

    #...
    def _validate_date(self):
        """Date entry validation: only dates in locale '%x' format are accepted."""
        try:
            date = self.parse_date(self.get()) # this line causes issue by returing reDateEntry.get()

class cDateEntry(DateEntry): ##subclass for quick configuration

class reDateEntry(cDateEntry): ##subclass for validation purposes
    def __init__(self, master, **kwargs):
        self.strvar = StringVar()

    def get(self):
        return self.var.get(), self._isvalid() ## the part i need for valudation

In this code it seems that to get() function from DateEntry is being overwritten by the get() method of the sub-sub class reDateEntry(). Im by far not an expert so it might just be me but allowing a subclass method to overwrite a parent class method in this manner should be avoided if it is critical and is why the super() method exists.