Is this pylint error message valid or silly?

M

Matthew Wilson

Here's the code that I'm feeding to pylint:

$ cat f.py
from datetime import datetime

def f(c="today"):

if c == "today":
c = datetime.today()

return c.date()


And here's what pylint says:

$ pylint -e f.py
No config file found, using default configuration
************* Module f
E: 10:f: Instance of 'str' has no 'date' member (but some types could
not be inferred)

Is this a valid error message? Is the code above bad? If so, what is
the right way?

I changed from using a string as the default to None, and then pylint
didn't mind:


$ cat f.py
from datetime import datetime

def f(c=None):

if c is None:
c = datetime.today()

return c.date()

$ pylint -e f.py
No config file found, using default configuration

I don't see any difference between using a string vs None. Both are
immutable. I find the string much more informative, since I can write
out what I want.

Looking for comments.

Matt
 
T

Terry Reedy

Matthew said:
Here's the code that I'm feeding to pylint:

$ cat f.py
from datetime import datetime

def f(c="today"):

pylint infers that you intend users to pass a string. Human would guess
the same at this point.
if c == "today":
c = datetime.today()

Now I guess that you actually intend c to be passed as a datetime
object. You only used the string as a type annotation, not as a real
default value. Something like 'record_date = None' is better.
return c.date()

and here you ask for the input's date, which strings do not have.
 
M

Matthew Wilson

Now I guess that you actually intend c to be passed as a datetime
object. You only used the string as a type annotation, not as a real
default value. Something like 'record_date = None' is better.

Thanks for the feedback. I think I should have used a more obvious
string in my original example and a more descriptive parameter name.

So, pretend that instead of

c="today"

I wrote

record_date="defaults to today's date".

I know my way is unorthodox, but I think it is a little bit more obvious
to the reader than

record_date=None

The None is a signal to use a default value, but that is only apparent
after reading the code.

Thanks again for the comments.

Matt
 
R

Rhodri James

Thanks for the feedback. I think I should have used a more obvious
string in my original example and a more descriptive parameter name.

So, pretend that instead of

c="today"

I wrote

record_date="defaults to today's date".

I know my way is unorthodox, but I think it is a little bit more obvious
to the reader than

record_date=None

The None is a signal to use a default value, but that is only apparent
after reading the code.

It's a very common idiom, however, and in addition

record_data is None

is a cheap test, while

record_data == "defaults to today's date"

is an expensive test as well as easy to mistype.
 
T

Terry Reedy

Matthew said:
Thanks for the feedback. I think I should have used a more obvious
string in my original example and a more descriptive parameter name.

So, pretend that instead of

c="today"

I wrote

record_date="defaults to today's date".

I know my way is unorthodox,

Which is fine. Just do not by surprised when a fake default fakes out
pylint, which by its nature, must embody the orthodoxy of its author ;-)
To win general acceptance, that in turn must match the orthodoxy of the
general audience.


but I think it is a little bit more obvious
 
N

nn

Here's the code that I'm feeding to pylint:

    $ cat f.py
    from datetime import datetime

    def f(c="today"):

        if c == "today":
                    c = datetime.today()

        return c.date()

And here's what pylint says:

    $ pylint -e f.py
    No config file found, using default configuration
    ************* Module f
    E: 10:f: Instance of 'str' has no 'date' member (but some types could
    not be inferred)

Is this a valid error message?  Is the code above bad?  If so, what is
the right way?

I changed from using a string as the default to None, and then pylint
didn't mind:

    $ cat f.py
    from datetime import datetime

    def f(c=None):

        if c is None:
                    c = datetime.today()

        return c.date()

    $ pylint -e f.py
    No config file found, using default configuration

I don't see any difference between using a string vs None.  Both are
immutable.  I find the string much more informative, since I can write
out what I want.

Looking for comments.

Matt

if initial_time == "use today's date":
initial_time = datetime.now()

return initial_time.date() + timedelta(days=1)

Traceback (most recent call last):
File "<pyshell#27>", line 1, in <module>
midnight_next_day()
File "<pyshell#26>", line 6, in midnight_next_day
return initial_time.date() + timedelta(days=1)
AttributeError: 'NoneType' object has no attribute 'date'
 
N

nn

Here's the code that I'm feeding to pylint:

    $ cat f.py
    from datetime import datetime

    def f(c="today"):

        if c == "today":
                    c = datetime.today()

        return c.date()

And here's what pylint says:

    $ pylint -e f.py
    No config file found, using default configuration
    ************* Module f
    E: 10:f: Instance of 'str' has no 'date' member (but some types could
    not be inferred)

Is this a valid error message?  Is the code above bad?  If so, what is
the right way?

I changed from using a string as the default to None, and then pylint
didn't mind:

    $ cat f.py
    from datetime import datetime

    def f(c=None):

        if c is None:
                    c = datetime.today()

        return c.date()

    $ pylint -e f.py
    No config file found, using default configuration

I don't see any difference between using a string vs None.  Both are
immutable.  I find the string much more informative, since I can write
out what I want.

Looking for comments.

Matt

if initial_time == "use today's date":
initial_time = datetime.now()

return initial_time.date() + timedelta(days=1)

Traceback (most recent call last):
File "<pyshell#24>", line 1, in <module>
midnight_next_day()
File "<pyshell#23>", line 6, in midnight_next_day
return initial_time.date() + timedelta(days=1)
AttributeError: 'str' object has no attribute 'date'
 
N

nn

Here's the code that I'm feeding to pylint:

    $ cat f.py
    from datetime import datetime

    def f(c="today"):

        if c == "today":
                    c = datetime.today()

        return c.date()

And here's what pylint says:

    $ pylint -e f.py
    No config file found, using default configuration
    ************* Module f
    E: 10:f: Instance of 'str' has no 'date' member (but some types could
    not be inferred)

Is this a valid error message?  Is the code above bad?  If so, what is
the right way?

I changed from using a string as the default to None, and then pylint
didn't mind:

    $ cat f.py
    from datetime import datetime

    def f(c=None):

        if c is None:
                    c = datetime.today()

        return c.date()

    $ pylint -e f.py
    No config file found, using default configuration

I don't see any difference between using a string vs None.  Both are
immutable.  I find the string much more informative, since I can write
out what I want.

Looking for comments.

Matt

This is a limitation of static type checking and Pylint is a (limited)
static type checker for Python. A language with static type checking
would not have even allowed you to compile this. A static type
checkers sees this:

def midnight_next_day(initial_time [string or in python whatever gets
passed(T)]):

if initial_time [string (or T)]== [(some constant) string]:
initial_time [datetime] = datetime.now()
{implied else:
initial_time [string or (T)] }

return initial_time[could be either datetime or string (oops
string does not have date()) pylint doesn’t check for T].date() +
timedelta(days=1)

or this:

def midnight_next_day(initial_time [None object or (T)]):

if initial_time [None object or (T)]== [None object]:
initial_time [type datetime] = datetime.now()
{implied else:
initial_time [T] }

return initial_time[datetime (pylint doesn’t check for T)].date()
+ timedelta(days=1)
 
A

Aahz

* You're re-binding the parameter name ‘c’ to something different within
the function: it starts out bound to the input string, but by the time
the function ends you're expecting it to be bound to a datetime
object. Instead, you should be binding a *different* name to the
datetime object you create inside the function, and using that for the
return statement.

Actually, I disagree that this is necessarily bad, although it's often a
yellow flag. The context in which it is possibly appropriate is when you
want your function to handle multiple types for one parameter and you
always cast the data to one single type.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,817
Latest member
DicWeils

Latest Threads

Top