I wrote this short little program as an effort to teach myself object oriented design in Python. But I am currently getting a very confusing error.
Traceback (most recent call last):
File "main.py", line 97, in <module>
cli()
File "C:\Python27\lib\site-packages\click\core.py", line 716, in __call__
return self.main(*args, **kwargs)
File "C:\Python27\lib\site-packages\click\core.py", line 695, in main
with self.make_context(prog_name, args, **extra) as ctx:
File "C:\Python27\lib\site-packages\click\core.py", line 620, in make_context
self.parse_args(ctx, args)
File "C:\Python27\lib\site-packages\click\core.py", line 874, in parse_args
value, args = param.handle_parse_result(ctx, opts, args)
File "C:\Python27\lib\site-packages\click\core.py", line 1390, in handle_parse_result
value = self.full_process_value(ctx, value)
File "C:\Python27\lib\site-packages\click\core.py", line 1675, in full_process_value
return Parameter.full_process_value(self, ctx, value)
File "C:\Python27\lib\site-packages\click\core.py", line 1359, in full_process_value
value = self.process_value(ctx, value)
File "C:\Python27\lib\site-packages\click\core.py", line 1349, in process_value
return self.type_cast_value(ctx, value)
File "C:\Python27\lib\site-packages\click\core.py", line 1332, in type_cast_value
return self.type(value or (), self, ctx)
File "C:\Python27\lib\site-packages\click\types.py", line 38, in __call__
return self.convert(value, param, ctx)
File "C:\Python27\lib\site-packages\click\types.py", line 472, in convert
raise TypeError('It would appear that nargs is set to conflict '
TypeError: It would appear that nargs is set to conflict with the composite type arity.
This error is being raised by my click based CLI. Which is odd because one of the options that is raising the error doesn't have any arguments.
#-*- coding: utf-8 -*-
import click
import json
import glob
import os
def prompt(question):
val = raw_input(question + ' > ')
return val
def mkdir(path):
if not os.path.isdir(str(path)):
os.mkdir(str(path))
return str(path)
class Profile(object):
def __init__(self, name, age, weight, job, salary):
self.name = name
self.age = age
self.weight = weight
self.job = job
self.salary = salary
self.data = { 'name' : '',
'age' : '',
'weight' : '',
'job': '',
'salary' : ''
}
def new_profile(self, name, age, job, weight, salary, fname):
self.data['name'] = name
self.data['age'] = age
self.data['job'] = job
self.data['weight'] = weight
self.data['salary'] = salary
self.fname = fname
self.dirname = mkdir('.profiles\\')
with open(str(self.dirname) + str(self.fname) + '.json', 'w') as self.profile:
json.dump(self.data, self.profile)
print 'Profile saved!'
def list_profile(self):
print glob.glob('.profiles/*.json')
def print_profile(self, fname):
try:
self.fname = fname
with open('.profiles\\' + str(self.fname) + '.json') as data_file:
self.profile = json.load(data_file)
self.name = self.profile['name']
self.age = self.profile['age']
self.weight = self.profile['weight']
self.job = self.profile['job']
self.salary = self.profile['salary']
print 'name: {}\nage: {}\nweight: {}\noccupation: {}\nsalary: {}'.format(self.name, self.age, self.weight, self.job, self.salary)
except IOError:
print 'File not found'
@click.command(options_metavar='<options>')
@click.option('--new_profile', '-n',
nargs=6,
type=click.Tuple([str, str, str, str, str, str]),
metavar='<name, age, occupation, weight, salary, filename>',
help='Creates a new profile')
@click.option('--list_profile', '-l',
is_flag=True,
help='Lists all profiles that currently exist')
@click.option('--print_profile', '-p',
type=(str),
metavar='<profile name>',
help = 'prints data from a saved profile')
def cli(new_profile, list_profile, print_profile):
profile = Profile('', '', '', '', '')
if new_profile:
profile.new_profile(new_profile[0], new_profile[1], new_profile[2], new_profile[3], new_profile[4], new_profile[5]) # name, age, job, weight, salary, fname
elif list_profile:
profile.list_profile()
elif print_profile:
profile.print_profile(print_profile)
if __name__ == '__main__':
cli()
I have been struggling with this traceback for about a day now with no result. Any suggestions? Thanks!
EDIT: I sort of fixed it, but I created a logic error in the process.
default=(None, None, None, None, None, None))
I added this argument to the click option new_profile. But when you use any other argument it just runs
Profile.new_profile(None, None None, None, None None)
thus creating a new file called none.json
in .profile
with all values being null. So I guess I technically solved THIS problem but I created an even bigger one.
There are a couple of ways you can fix this.
Do not use click.Tuple
Tuple
is intended for a multiple valued argument of non-uniform type. Since you are using 6 strings, this can be done more simply with:
@click.option('--new_profile', '-n',
nargs=6,
type=str,
....
Use click.Tuple
with a default
As you discovered you can use a click.Tuple
if you specify a default.
@click.option('--new_profile', '-n',
default=[None] * 6,
type=click.Tuple([str, str, str, str, str, str]),
....
Then you can qualify that you did not get the default like:
if new_profile and None not in new_profile:
# create a new profile
....
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With