📜 ⬆️ ⬇️

Why is it important to check the values ​​returned by the function?

I really wanted to share my experience and I would like to talk about why it is important to check the values ​​returned by a function. Take python and ctypes as an example. Some time ago I ran into an interesting enough bug whose essence was that when running the script on the Linux system there were incorrect data, but there was no traceback, and on the Windows system they immediately received the traceback. The study of the code showed that the incorrect date data was to blame for the strptime () function. Now, let's take a look at an example of working with the strptime () function in python.


Under Windows, we can use the strptime () function from the datetime module


An example with the correct date:


from datetime import datetime date_str = "30-10-2016 16:18" format_str = "%d-%m-%Y %H:%M" dt = datetime.strptime(date_str, format_str) print repr(str(dt)) 

Here is what we will see in this case:


2016-10-30 16:18:00

If in the code above we replace the date string with an incorrect one:


date_str = "30-10-2016 16: fhadjkfh"

then we will see the following output:


 File "E:\Python27\lib\_strptime.py", line 325, in _strptime (data_string, format)) ValueError: time data '30-10-2016 16:fhadjkfh' does not match format '%d-%m-%Y %H:%M' 

When using Linux, we can also use the strptime () function by importing it from the libc library.


More about the strptime () function in C is best read here . I just note that in this case, the date parameters will be saved to the following structure:


 struct tm { int tm_sec; /* Seconds (0-60) */ int tm_min; /* Minutes (0-59) */ int tm_hour; /* Hours (0-23) */ int tm_mday; /* Day of the month (1-31) */ int tm_mon; /* Month (0-11) */ int tm_year; /* Year - 1900 */ int tm_wday; /* Day of the week (0-6, Sunday = 0) */ int tm_yday; /* Day in the year (0-365, 1 Jan = 0) */ int tm_isdst; /* Daylight saving time */ }; 

Here’s how pyrone might look like using the strptime () function when working with the ctypes module:


 from ctypes import * libc = CDLL('libc.so.6') class TM(Structure): _fields_ = [ ("tm_sec", c_int), ("tm_min", c_int), ("tm_hour", c_int), ("tm_mday", c_int), ("tm_mon", c_int), ("tm_year", c_int), ("tm_wday", c_int), ("tm_yday", c_int), ("tm_isdst", c_int) ] tm_struct = TM() for field_name, field_type in tm_struct._fields_: print("{}: {}".format(field_name, getattr(tm_struct, field_name))) strptime = libc.strptime strptime.restype = c_char_p date_str = "30-10-2016 16:18" format_str = "%d-%m-%Y %H:%M" rez = strptime(date_str, format_str, pointer(tm_struct)) print("######") for field_name, field_type in tm_struct._fields_: print("{}: {}".format(field_name, getattr(tm_struct, field_name))) print "strptime returned: %s" % repr(rez) 

And we will see the following conclusion


 tm_sec: 0 tm_min: 0 tm_hour: 0 tm_mday: 0 tm_mon: 0 tm_year: 0 tm_wday: 0 tm_yday: 0 tm_isdst: 0 ###### tm_sec: 0 tm_min: 18 tm_hour: 16 tm_mday: 30 tm_mon: 9 tm_year: 116 tm_wday: 0 tm_yday: 303 tm_isdst: 0 strptime returned: '' 

It is important to note here that the fields of the tm_struct object will be initialized with zeros, and the value returned by the strptime () function will be an empty string.


If in the code above we replace the date string with an incorrect one:


date_str = "30-10-2016fahdkjfa 16:18"

then we will see the following output (for brevity, I have removed the printing of the field values ​​of the tm_struct object after its creation):


 tm_sec: 0 tm_min: 0 tm_hour: 0 tm_mday: 30 tm_mon: 9 tm_year: 116 tm_wday: 0 tm_yday: 0 tm_isdst: 0 strptime returned: None 

Here you can see that in the case of an incorrect date, only those fields that could be recognized in the date string with incorrect data will change in the tm_struct object, and the remaining fields will remain with zero values. And the strptime () function itself will return the value None . In this case, we will not get any trays back. That is why it is important to be more careful and check the value returned by the function.


The correct call option here could be, for example, like this:


 #    ''  None    False,      None if strptime(date_str, format_str, pointer(tm_struct)) is None: raise ValueError("datestring `{}` does not match expected format `{}`".format(date_str, format_str)) 

Now let's imagine, for example, that we have our own schedule aggregator of something. And with an incorrect code, such a bug can only be seen by the user, in case he sees the difference between the schedule shown by our aggregator and the schedule on the site from which we received it.


')

Source: https://habr.com/ru/post/312658/


All Articles