HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

Validate parameters within a range

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
validaterangeparameterswithin

Problem

Function to use several blocks of if:elif:else: that all take slightly different conditional statements. I'm trying to format integers into a 2 digit string, adding a leading 0 for single digits. It is working great, but there has to be DRY way of doing the same thing. Also, the timezone formatting is a bit of a mess. After struggling to come up with a more elegant solution, I just went with what was obvious and working.

```
def rfc_3339_str(minutes = 0, year = 1999, month = 1, date = 1, secs = 0, time_zone = 0):
'''Takes minutes and builds RFC 3339 timeDate string.
yyyy-mm-ddTHH:MM:ss[.mmm][+/-HH:MM]. Does not support milliseconds.
All params optional. Timezone format is number in range
[-12:12] (hours only). All numbers expect integers.
Minutes > 1439 (23 hours 59 minutes) wrap around to zero,.
Date defaults to 1/1/1999. Supported years 1000-2035 CE. Date allows
range 0-31 inclusive for all months. Negative times are not supported.
Incorrect params return error description'''
plus = '+'
minus = '-'
date_time_split = 'T'
date_split = '-'
time_split = ':'
time_zone_mins = ':00'
MAX_MINUTES = 1440
yyyy = None
mm = None
dd = None
HH = None
MM = None
SS = None
zone_sign = plus
zz = None

#validate inputs
if 1000 > year > 2035:
return 'year_out_of_range'
else:
yyyy = str(year)

if month in range(1,10):
mm = '0' + str(month)
elif month in range(10,13):
mm = str(month)
else:
return 'month_out_of_range'

if date in range(1, 10):
dd = '0' + str(date)
elif date in range(10, 32):
dd = str(date)
else:
return 'date_out_of_range'

if minutes MAX_MINUTES:
minutes = minutes - MAX_MINUTES
hours_int = int(minutes / 60)
mins_int = int(minutes % 60)

if hours_int in range(0,10):
HH = '0' + str(hours_int)
elif

Solution

First off, I would like to point you to the time module which has functions that are similar to what you want to accomplish.

Now as for DRYing your code up a bit. You were right to notice that you have blocks of:

if var in range1:
    func1(var)
elif var in range2:
    func2(var)
else:
    return 'blah_out_of_range'


I don't agree with your else block code. You are returning an error statement, which should actually be an exception such as a ValueError like so:

raise ValueError("blah out of range")


This is more readable, and more Pythonic.

Back to the code block, if we take each of the variant parts as arguments into a super function we get:

def process(var, cond1, func1, cond2, final):
    # ugly code here


This is trying to emulate the functional programming style of Lisp, Scheme, Racket and etc, which something that is generally avoided in Python code due to the final unreadability of the code.

Let's think of something else, such as checking all the conditions ahead of time, before doing any processing. This speeds up execution for failed inputs (as any failing input would fail as fast as possible), and simplifies the logic.

This would look something like this:

if year not in range(1001, 2035):
    raise ValueError("year not in range")
if month not in range(1, 13):
    raise ValueError("month not in range")


and so on. This can also be done via assert statements of the unittest module for even more compact code.

Then afterwards you will have blocks of the form:

if cond1:
    func1
else:
    func2


This is easily wrapped into a ternary operator:

func1 if cond1 else func2


Which will eliminate a lot of lines from your code.

Code Snippets

if var in range1:
    func1(var)
elif var in range2:
    func2(var)
else:
    return 'blah_out_of_range'
raise ValueError("blah out of range")
def process(var, cond1, func1, cond2, final):
    # ugly code here
if year not in range(1001, 2035):
    raise ValueError("year not in range")
if month not in range(1, 13):
    raise ValueError("month not in range")
if cond1:
    func1
else:
    func2

Context

StackExchange Code Review Q#60622, answer score: 4

Revisions (0)

No revisions yet.