dict is not callable in python-kwargs error - python

I have the following code which reads from a yaml :
if 'parameters' in options:
for name, parameter_options in options['parameters'].items():
make_parameters = injector.parameters()
print parameter_options
parameter_injected = make_parameters(**parameter_options)
parameters = cft.add_parameters()
parameters(key, **parameter_injected)
which gives me the error :
parameter_injected = make_parameters(**parameter_options) TypeError: 'dict' object is not callable
parameter_options is a dictionary as read from yaml and printed out :
{'constraint_description': 'Malformed input-Parameter MyParameter must only contain upper and lower case letters', 'min_length': 12, 'description': 'to do some stuff', 'default': '10.201.22.33', 'max_value': 34, 'min_value': 12, 'allowed_values': ['sdd', 'asas'], 'max_length': 23, 'allowed_pattern': '[A-Za-z0-9]+', 'no_echo': True, 'type': 'String'}
So when I do **parameter_options shouldn't that just convert the dict to charges?

My bad, corrected my code to :
if 'parameters' in options:
for name, parameter_options in options['parameters'].items():
parameter_injected = injector.parameters(**parameter_options)
parameters = cft.add_parameters(name, **parameter_injected)

Related

How to create click Command using API?

I am trying to create a python click Command using the API instead of decorators. This is because I am trying to create commands dynamically from a yaml file.
parsed yaml file:
{'adhoc': {'args': ['abcd',
{'analytic-type': {'type': 'click.Choice(["prof", "fac"], '
'case_sensitive=False)'}},
{'lobplat': {'default': 'ALL',
'type': 'click.Choice(["A","B","C","D","ALL",],case_sensitive=False)'}}],
'options': [{'environment': {'alias': '-e',
'envvar': 'env',
'show_default': 'loc',
'type': 'click.Choice(["a", "b", '
'"c", "d", "e"], '
'case_sensitive=False)'}},
{'email': {'alias': '-m',
'default': 'test#test.com',
'multiple': True}},
{'runtype': {'alias': '-r',
'default': 'ADHOC',
'type': 'click.Choice(["TEST","ADHOC","SCHEDULED"], '
'case_sensitive=False)'}}],
'script': 'nohup '
'/path/to/script/script'}}
At the top level it defines a command called adhoc which has 3 parts:
Arguments (args)
Options (options)
Script (This is the function of the command)
Both argument and options have a list of different Parameters that I want to create.
Here is the class that I have written:
import click
import yaml
class Commander():
def __init__(self) -> None:
pass
def run_command(self, script):
pass
def str_to_class(self,classname):
return getattr(sys.modules[__name__], classname)
def create_args(self,arguments):
all_args = []
for arg in arguments:
if isinstance(arg, str):
all_args.append(click.Argument([arg]))
else:
attributes = arg[list(arg.keys())[0]]
print(attributes)
all_args.append(click.Argument([arg],**attributes))
return all_args
def convert_to_command(self,yaml):
for key, value in yaml.items():
name = key
script = value["script"]
options = value["options"]
args = value["args"]
click_arg = self.create_args(args)
print(click_arg)
if __name__ == "__main__":
commander = Commander()
yaml = {'adhoc': {'args': ['abcd',
{'analytic-type': {'type': 'click.Choice(["prof", "fac"], '
'case_sensitive=False)'}},
{'lobplat': {'default': 'ALL',
'type': 'click.Choice(["A","B","C","D","ALL",],case_sensitive=False)'}}],
'options': [{'environment': {'alias': '-e',
'envvar': 'env',
'show_default': 'loc',
'type': 'click.Choice(["a", "b", '
'"c", "d", "e"], '
'case_sensitive=False)'}},
{'email': {'alias': '-m',
'default': 'test#test.com',
'multiple': True}},
{'runtype': {'alias': '-r',
'default': 'ADHOC',
'type': 'click.Choice(["TEST","ADHOC","SCHEDULED"], '
'case_sensitive=False)'}}],
'script': 'nohup '
'/path/to/script/script'}}
commander.convert_to_command(yaml)
These functions are not complete. Currently I am working on writing a function to create Arguments out of the Yaml dictionary. However upon running create_command() I get the following error:
File "/project/helper/commander.py", line 111, in <module>
commander.convert_to_command(yaml)
File "/project/hassle/helper/commander.py", line 45, in convert_to_command
click_arg = self.create_args(args)
File "/project/hassle/helper/commander.py", line 32, in create_args
all_args.append(click.Argument([arg],**attributes))
File "/home/myself/miniconda3/envs/py_copier/lib/python3.7/site-packages/click/core.py", line 2950, in __init__
super().__init__(param_decls, required=required, **attrs)
File "/home/myself/miniconda3/envs/py_copier/lib/python3.7/site-packages/click/core.py", line 2073, in __init__
param_decls or (), expose_value
File "/home/myself/miniconda3/envs/py_copier/lib/python3.7/site-packages/click/core.py", line 2983, in _parse_decls
name = name.replace("-", "_").lower()
AttributeError: 'dict' object has no attribute 'replace'
Thank you for the updated code snippet!
Now, what is going on here:
all_args.append(click.Argument([arg],**attributes))
Where arg is:
{'analytic-type': {'type': 'click.Choice(["prof", "fac"], case_sensitive=False)'}}
but if you look at the documentation about the click.Argument class, you'll see the following:
class click.Argument(param_decls, required=None, **attrs)
param_decls (Sequence[str]) –
You made the sequence part, but inside the sequence you still have the dict, instead of the string(s) with the argument name(s). So you should provide click.Argument with something like this:
[list(arg.keys())[0]]
# e.g.
all_args.append(click.Argument([list(arg.keys())[0]],**attributes))
But now you have another problem:
AttributeError: 'str' object has no attribute '__name__'
which is now related to your attributes, as you pass the function as string, but click expects callable. Take a look at this question. It should resolve the issue.
PS: I've just tested it with a quick and dirty eval and it works, so when you fix the callable problem in a proper way, you are good to move on.

Django: How to search through django.template.context.RequestContext

I'm working over tests in Django and faced <class 'django.template.context.RequestContext'>, which I'm trying to iterate through and find <class 'ecom.models.Product'> object inside.
test.py
def test_ProductDetail_object_in_context(self):
response = self.client.get(reverse('product_detail', args=[1]))
# assertEqual - test passes
self.assertEqual(response.context[0]['object'], Product.objects.get(id=1))
# assertIn - test fails
self.assertIn(Product.objects.get(id=1), response.context[0])
views.py
class ProductDetailView(DetailView):
model = Product
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
data = cartData(self.request)
cartItems = data['cartItems']
context['cartItems'] = cartItems
return context
What's inside response.context:
[
[
{'True': True, 'False': False, 'None': None},
{'csrf_token': <SimpleLazyObject: <function csrf.<locals>._get_val at 0x7fd80>>,
'request': <WSGIRequest: GET '/1/'>,
'user': <SimpleLazyObject: <django.contrib.auth.models.AnonymousUser object at 0x7fd820>>, '
perms': <django.contrib.auth.context_processors.PermWrapper object at 0x7fd80>,
'messages': <django.contrib.messages.storage.fallback.FallbackStorage object at 0x7fd8290>,
'DEFAULT_MESSAGE_LEVELS': {'DEBUG': 10, 'INFO': 20, 'SUCCESS': 25, 'WARNING': 30, 'ERROR': 40}
},
{},
{'object': <Product: Pen>,
'product': <Product: Pen>,
'view': <ecom.views.ProductDetailView object at 0x7fd8210>,
'cartItems': 0}
],
[
{'True': True, 'False': False, 'None': None},
{'csrf_token': <SimpleLazyObject: <function csrf.<locals>._get_val at 0x7fd8240>>,
'request': <WSGIRequest: GET '/1/'>,
'user': <SimpleLazyObject: <django.contrib.auth.models.AnonymousUser object at 0x7fd8250>>,
'perms': <django.contrib.auth.context_processors.PermWrapper object at 0x7fd8250>,
'messages': <django.contrib.messages.storage.fallback.FallbackStorage object at 0x7fd8290>,
'DEFAULT_MESSAGE_LEVELS': {'DEBUG': 10, 'INFO': 20, 'SUCCESS': 25, 'WARNING': 30, 'ERROR': 40}
},
{},
{'object': <Product: Pen>,
'product': <Product: Pen>,
'view': <ecom.views.ProductDetailView object at 0x7fd8210>,
'cartItems': 0}
]
]
Type of response.context:
<class 'django.template.context.RequestContext'>
What's inside Product.objects.get(id=1) is: Pen
Type of Product.objects.get(id=1) is: <class 'ecom.models.Product'>
I don't undestand why:
it found Product object in self.assertEqual(response.context[0]['object'], Product.objects.get(id=1)), but not in self.assertIn(Product.objects.get(id=1), response.context[0]['object']) - says TypeError: argument of type 'Product' is not iterable
it also didn't find it in self.assertIn(Product.objects.get(id=1), response.context[0]) - says "AssertionError: <Product: Pen> not found in [....here goes contents of response.context[0]....]"
it also didn't find it in self.assertIn(Product.objects.get(id=1), response.context[0][3]) - says "in getitem raise KeyError(key), KeyError: 3"
how to work with RequestContext class? JSON like?
Sorry for a bit mixed up question, just trying to understand how to work with RequestContext.
Thank you in advance!
I think your test is failing because assertIn looks through the KEYS not the values. Solution would be:
self.assertIn(Product.objects.get(id=1), response.context[0].values())
A little more explanation: response.context[0] seems like it's some key-value storage, i.e. a dict. When you do response.context[0]["object"], you've just accessed the value at the key "object" where response.context[0] is the dict. Doing some in query on the dictionary only looks up the keys of the dictionary.

Recursively create same class during instantiation

I have a json config that I want to create a dict from. Because json configs are recursive, any time I see a json value that is an array I want to recursively iterate on it. However this is not doing what I want it to do.
class FieldHandler():
formfields = {}
def __init__(self, fields):
for field in fields:
options = self.get_options(field)
f = getattr(self, "create_field_for_" +
field['type'])(field, options)
self.formfields[field['name']] = f
def get_options(self, field):
options = {}
options['label'] = field['name']
options['help_text'] = field.get("help_text", None)
options['required'] = bool(field.get("required", 0))
return options
def create_field_for_string(self, field, options):
options['max_length'] = int(field.get("max_length", "20"))
return django.forms.CharField(**options)
def create_field_for_int(self, field, options):
options['max_value'] = int(field.get("max_value", "999999999"))
options['min_value'] = int(field.get("min_value", "-999999999"))
return django.forms.IntegerField(**options)
def create_field_for_array(self, field, options):
fh = FieldHandler(field['elements'])
return fh
and instantiating:
fh = FieldHandler([
{'type': 'string', 'name': 'position'},
{'type': 'array', 'name': 'calendar', 'elements': [
{'type': 'string', 'name': 'country'},
{'type': 'string', 'name': 'url'},
]},
{'type': 'int', 'name': 'maxSize'}
])
I expect to get a dict like so:
{
'position': <django.forms.fields.CharField object at 0x10b57af50>,
'calendar': <__main__.FieldHandler instance at 0x10b57c680>,
'maxSize': <django.forms.fields.IntegerField object at 0x10b58e050>,
}
Where calendar itself is expected to be:
{
'url': <django.forms.fields.CharField object at 0x10b58e150>,
'country': <django.forms.fields.CharField object at 0x10b58e0d0>
}
Instead I get:
{
'url': <django.forms.fields.CharField object at 0x10b58e150>,
'position': <django.forms.fields.CharField object at 0x10b57af50>,
'calendar': <__main__.FieldHandler instance at 0x10b57c680>,
'maxSize': <django.forms.fields.IntegerField object at 0x10b58e050>,
'country': <django.forms.fields.CharField object at 0x10b58e0d0>
}
What am I doing wrong? Why are the position and country parameters being set on my global FieldHandler?
formfields is a class attribute that is shared among all instances. Make it an instance attribute instead:
class FieldHandler():
def __init__(self, fields):
self.formfields = {}
# ...
Now, all FieldHandler instances have their own formfields, with only the "inner" calendar handler having the country and url (not position assuming that was a typo) fields.

String indices must be integers - Django

I have a pretty big dictionary which looks like this:
{
'startIndex': 1,
'username': 'myemail#gmail.com',
'items': [{
'id': '67022006',
'name': 'Adopt-a-Hydrant',
'kind': 'analytics#accountSummary',
'webProperties': [{
'id': 'UA-67522226-1',
'name': 'Adopt-a-Hydrant',
'websiteUrl': 'https://www.udemy.com/,
'internalWebPropertyId': '104343473',
'profiles': [{
'id': '108333146',
'name': 'Adopt a Hydrant (Udemy)',
'type': 'WEB',
'kind': 'analytics#profileSummary'
}, {
'id': '132099908',
'name': 'Unfiltered view',
'type': 'WEB',
'kind': 'analytics#profileSummary'
}],
'level': 'STANDARD',
'kind': 'analytics#webPropertySummary'
}]
}, {
'id': '44222959',
'name': 'A223n',
'kind': 'analytics#accountSummary',
And so on....
When I copy this dictionary on my Jupyter notebook and I run the exact same function I run on my django code it runs as expected, everything is literarily the same, in my django code I'm even printing the dictionary out then I copy it to the notebook and run it and I get what I'm expecting.
Just for more info this is the function:
google_profile = gp.google_profile # Get google_profile from DB
print(google_profile)
all_properties = []
for properties in google_profile['items']:
all_properties.append(properties)
site_selection=[]
for single_property in all_properties:
single_propery_name=single_property['name']
for single_view in single_property['webProperties'][0]['profiles']:
single_view_id = single_view['id']
single_view_name = (single_view['name'])
selections = single_propery_name + ' (View: '+single_view_name+' ID: '+single_view_id+')'
site_selection.append(selections)
print (site_selection)
So my guess is that my notebook has some sort of json parser installed or something like that? Is that possible? Why in django I can't access dictionaries the same way I can on my ipython notebooks?
EDITS
More info:
The error is at the line: for properties in google_profile['items']:
Django debug is: TypeError at /gconnect/ string indices must be integers
Local Vars are:
all_properties =[]
current_user = 'myemail#gmail.com'
google_profile = `the above dictionary`
So just to make it clear for who finds this question:
If you save a dictionary in a database django will save it as a string, so you won't be able to access it after.
To solve this you can re-convert it to a dictionary:
The answer from this post worked perfectly for me, in other words:
import json
s = "{'muffin' : 'lolz', 'foo' : 'kitty'}"
json_acceptable_string = s.replace("'", "\"")
d = json.loads(json_acceptable_string)
# d = {u'muffin': u'lolz', u'foo': u'kitty'}
There are many ways to convert a string to a dictionary, this is only one. If you stumbled in this problem you can quickly check if it's a string instead of a dictionary with:
print(type(var))
In my case I had:
<class 'str'>
before converting it with the above method and then I got
<class 'dict'>
and everything worked as supposed to

Using sax.utils how can i add a tag

I have the following code that creates an xml doc
self.errorlist.append(
'<testcase classname=%(cls)s name=%(name)s time="%(taken)d">'
'<%(type)s type=%(errtype)s message=%(message)s><![CDATA[%(tb)s]]>'
'</%(type)s></testcase>' %
{'cls': self._quoteattr('.'.join(id.split('.')[:-1])),
'name': self._quoteattr(id.split('.')[-1]),
'taken': taken,
'type': type,
'errtype': self._quoteattr(nice_classname(err[0])),
'message': self._quoteattr(exc_message(err)),
'tb': escape_cdata(tb),
})
How can i add a new tag, or new type e.g. "db"
I tried
self.errorlist.append(
'<testcase classname=%(cls)s name=%(name)s db=%(db)s time="%(taken)d">'
'<%(type)s type=%(errtype)s message=%(message)s><![CDATA[%(tb)s]]>'
'</%(type)s></testcase>' %
{'cls': self._quoteattr('.'.join(id.split('.')[:-1])),
'name': self._quoteattr(id.split('.')[-1]),
'taken': taken,
'type': type,
'errtype': self._quoteattr(nice_classname(err[0])),
'message': self._quoteattr(exc_message(err)),
'tb': escape_cdata(tb),
})
but got : KeyError: 'db'
i also tried just plain %(db)s but got error:
NameError: global name 'db' is not defined
Following is the import
from xml.sax import saxutils
solved: using the code below, i was abe to get db="mysql" in the XML Doc
self.errorlist.append(
'<testcase classname=%(cls)s name=%(name)s db="%(db)s" time="%(taken)d">'
'<%(type)s type=%(errtype)s message=%(message)s><![CDATA[%(tb)s]]>'
'</%(type)s></testcase>' %
{'cls': self._quoteattr('.'.join(id.split('.')[:-1])),
'name': self._quoteattr(id.split('.')[-1]),
'db': self.db,
'taken': taken,
'type': type,
'errtype': self._quoteattr(nice_classname(err[0])),
'message': self._quoteattr(exc_message(err)),
'tb': escape_cdata(tb),
})

Categories

Resources