Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeError: It would appear that nargs is set to conflict with the composite type arity

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.

like image 958
zacwalls Avatar asked Nov 24 '16 21:11

zacwalls


1 Answers

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
    ....
like image 89
Stephen Rauch Avatar answered Oct 24 '22 21:10

Stephen Rauch