I've seen some samples codes like:
def clean_message(self):
message = self.cleaned_data['message']
num_words = len(message.split())
if num_words < 4:
raise forms.ValidationError("Not enough words!")
return message
and some examples like:
def clean(self):
username = self.cleaned_data.get('username')
password = self.cleaned_data.get('password')
...
self.check_for_test_cookie()
return self.cleaned_data
What's the difference between the two?
.get() is basically a shortcut for getting an element out of a dictionary. I usually use .get() when I'm not certain if the entry in the dictionary will be there. For example:
>>> cleaned_data = {'username': "bob", 'password': "secret"}
>>> cleaned_data['username']
'bob'
>>> cleaned_data.get('username')
'bob'
>>> cleaned_data['foo']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'foo'
>>> cleaned_data.get('foo') # No exception, just get nothing back.
>>> cleaned_data.get('foo', "Sane Default")
'Sane Default'
cleaned_data is a Python dictionary, you can access its values by:
Specifying the key between [ ]:
self.cleaned_data[‘field’]
Using get() method:
self.cleaned_data.get(‘field’)
Difference between cleaned_data and cleaned_data.get in Django is that if the key does not exist in the dictionary, self.cleaned_data[‘field’] will raise a KeyError, while self.cleaned_data.get(‘field’) will return None.
Related
I'm currently making a discord bot in Python. I want to make a command where you have two options for an argument:
An integer to delete a certain amount of messages
And the word 'all' (a string) to delete all the messages in the channel.
I've tried functions like this to determine if it is a string or not...
def isint(s):
try:
int(s)
isint = True
except ValueError:
isint = False
return isint
... but it returns this error:
TypeError: '<=' not supported between instances of 'str' and 'int'
This is the current, most recent code for the command that I have tried:
#commands.command()
#commands.has_role("Clear Chat Key")
async def clear(self, ctx, amount: typing.Union[str, int] = 10):
number = isint(amount)
if number == False:
if amount == 'all':
await ctx.channel.purge(limit = inf)
else:
await ctx.send('Invalid amount.')
if number == True:
await ctx.channel.purge(limit = amount)
else:
await ctx.send('Invalid amount.')
The full traceback for the error, in case it is relevant, is the following:
Traceback (most recent call last):
File "C:\Users\44794\AppData\Local\Programs\Python\Python38\lib\site-packages\discord\ext\commands\bot.py", line 892, in invoke
await ctx.command.invoke(ctx)
File "C:\Users\44794\AppData\Local\Programs\Python\Python38\lib\site-packages\discord\ext\commands\core.py", line 797, in invoke
await injected(*ctx.args, **ctx.kwargs)
File "C:\Users\44794\AppData\Local\Programs\Python\Python38\lib\site-packages\discord\ext\commands\core.py", line 92, in wrapped
raise CommandInvokeError(exc) from exc
discord.ext.commands.errors.CommandInvokeError: Command raised an exception: TypeError: '<=' not supported between instances of 'str' and 'int'
Please bear with me here, I am very new to Python.
EDIT:
Thanks for helping me with this! Here is the code I used in case anyone else needs it:
def is_int(x):
if x.isdigit():
return True
return False
#commands.command()
#commands.has_role("Clear Chat Key")
async def clear(self, ctx, amount: typing.Union[str, int] = 10):
number = is_int(amount)
if number == False:
if amount == 'all':
await ctx.channel.purge(limit = inf)
else:
await ctx.send('Invalid amount.')
if number == True:
amount = int(amount)
await ctx.channel.purge(limit = amount)
else:
await ctx.send('Invalid amount.')
Again, thanks for helping me out!
You're able to use the string's .isdigit() method.
Bear in mind that this will return False for negatives:
>>> my_str = "123"
>>> my_str.isdigit()
True
>>> other_str = "-123"
>>> my_str.isdigit()
False
Working example:
def is_int(some_value):
if some_input.isdigit():
return True
return False
some_input = input("Enter some numbers or words!\n-> ")
print(is_int(some_input))
Reference:
str.isdigit()
Try use this instead of your function isint:
# clear function
number = amount.__class__.__name__ == 'int'
I am getting this error whenever I try to access the application. The error is about the application controller. This is the error.
Couldn't find all Private::Conversations with 'id': (17, 38) (found 0 results, but was looking for 2).
The error is explained more in the bash as follows
ActiveRecord::RecordNotFound (Couldn't find all Private::Conversations with 'id': (17, 38) (found 0 results, but was looking for 2).):
app/controllers/application_controller.rb:28:in `opened_conversations_windows'
I have tried changing the find method but things do not seem to work with methods such as find_by.
def opened_conversations_windows
if logged_in?
# opened conversations
session[:private_conversations] ||= []
#private_conversations_windows = Private::Conversation.includes(:recipient, :messages)
.find(session[:private_conversations])
else
#private_conversations_windows = []
end
end
I expect that when no conversation is found, the app should render nil conversation windows when a user logs in.
find is designed to raise an error if the record for the given id is not found.
If you do not want to raise an error then you can use find_by when you want to find a single record or return nil when that record doesn't exist. Or you can build a query with where which always returns an array of matching record on an empty array if there any matching records.
You can refactor your method to:
def opened_conversations_windows
if logged_in? && session[:private_conversations]
#private_conversations_windows = Private::Conversation
.includes(:recipient, :messages)
.where(id: session[:private_conversations])
else
#private_conversations_windows = []
end
end
What I'm trying to do is ask a user for a URL, then query that URL to see if it's up, and respond with "Response OK!" as the title describes.
require 'net/http'
require 'url'
Here I'm asking a user for a url and attempting to define that string as a variable:
puts "\n\nWhat website would you like to check?\n\n"
userinput = gets.chomp
Here I'm checking for an HTTP response with that variable $userinput
def main
while true
uri = URI.parse($userinput)
response = Net::HTTP::get_response(uri)
if response.code == "200"
puts "Response OK!"
else
puts "Received #{response.code} code. Probing again in 15s..."
end
sleep(15)
end
end
# Exit on CTRL-C SIGINT
Signal.trap("INT") {
puts "\nUser exited."
exit
}
main ()
Here is the code in action. I don't know how else to paste this:
What website would you like to check?
http://www.reddit.com
Traceback (most recent call last):
1: from prober.rb:33:in `<main>'
prober.rb:14:in `main': wrong number of arguments (given 1, expected 0) (ArgumentError)
Removing the space between main () results in this:
Traceback (most recent call last):
5: from prober.rb:33:in `<main>'
4: from prober.rb:16:in `main'
3: from /usr/local/Cellar/ruby/2.5.1/lib/ruby/2.5.0/uri/common.rb:237:in `parse'
2: from /usr/local/Cellar/ruby/2.5.1/lib/ruby/2.5.0/uri/rfc3986_parser.rb:73:in `parse'
1: from /usr/local/Cellar/ruby/2.5.1/lib/ruby/2.5.0/uri/rfc3986_parser.rb:15:in `split'
/usr/local/Cellar/ruby/2.5.1/lib/ruby/2.5.0/uri/rfc3986_parser.rb:18:in `rescue in split': bad URI(is not URI?): (URI::InvalidURIError)
For this ArgumentError problem:
Traceback (most recent call last):
1: from prober.rb:33:in `<main>'
prober.rb:14:in `main': wrong number of arguments (given 1, expected 0)
remove the space between main and the parenthesis. Ruby, due to the flexibility on accepting method calls without parenthesis is using the empty parenthesis as a method argument.
If you want to pass the user input to your main method, then you need to declare a parameter for it (better than using global variables).
You can use gets.chomp to store the user input, and when you call the main function, you pass that as argument.
So that can be like:
def main(user_input)
while true
uri = URI.parse(user_input)
response = Net::HTTP.get_response(uri)
...
end
end
puts "\n\nWhat website would you like to check?\n\n"
userinput = gets.chomp
main(userinput)
Notice the use of () in "void context" is interpreted as a nil object. Which is clearly valid for throwing an ArgumentError exception.
p ()
# nil
I have a ModelSerializer class as follows which I want to accept a list of items or a single item (dictionary) as data. The documentation states that passing "many" as True will support my requirement.
class PointSerializer(serializers.ModelSerializer):
class Meta:
model = Point
def __init__(self, *args, **kwargs):
if "data" in kwargs:
if isinstance(kwargs["data"]):
kwargs["many"] = True
super(PointSerializer, self).__init__(*args, **kwargs)
Now, providing data dictionary as follows works:
p = PointSerializer(data={'x':10, 'y': 12})
p.is_valid() # True
But this, with a list of dictionaries, fails:
p = PointSerializer(data=[{'x':10, 'y':12}, {'x':12, 'y':12}])
p.is_valid() # False
p.errors() # {'non_field_errors': ['Invalid data. Expected a dictionary, but got a list.']}
UPDATE:
Thanks to the chosen answer, I've changed my code to the following and it works fine:
class PointSerializer(serializers.ModelSerializer):
class Meta:
model = Point
>>> ps = PointSerializer(data={'x':10, 'y':12})
>>> ps.is_valid()
... True
>>> ps = PointSerializer(data=[{'x':10, 'y':12}, {'x':12, 'y':12}], many=True)
>>> ps.is_valid()
... True
many=True argument will only work when instantiating the serializer because it'll return a ListSerializer behind the scene.
Your option are either you set the many=True as serializer argument during creation call, either use explicitly the ListSerializer.
I have an ABC BaseAbstract class with several getter/setter properties defined.
I want to require that the value to be set is an int and from 0 - 15.
#luminance.setter
#abstractproperty
#ValidateProperty(Exception, types=(int,), valid=lambda x: True if 0 <= x <= 15 else False)
def luminance(self, value):
"""
Set a value that indicate the level of light emitted from the block
:param value: (int): 0 (darkest) - 15 (brightest)
:return:
"""
pass
Can someone help me figure out what my ValidateProperty class/method should look like. I started with a class and called the accepts method but this is causing an error:
function object has no attribute 'func_code'
current source:
class ValidateProperty(object):
#staticmethod
def accepts(exception, *types, **kwargs):
def check_accepts(f, **kwargs):
assert len(types) == f.func_code.co_argcount
def new_f(*args, **kwds):
for i, v in enumerate(args):
if f.func_code.co_varnames[i] in types and\
not isinstance(v, types[f.func_code.co_varnames[i]]):
arg = f.func_code.co_varnames[i]
exp = types[f.func_code.co_varnames[i]]
raise exception("arg '{arg}'={r} does not match {exp}".format(arg=arg,
r=v,
exp=exp))
# del exp (unreachable)
for k,v in kwds.__iter__():
if k in types and not isinstance(v, types[k]):
raise exception("arg '{arg}'={r} does not match {exp}".format(arg=k,
r=v,
exp=types[k]))
return f(*args, **kwds)
new_f.func_name = f.func_name
return new_f
return check_accepts
One of us is confused about how decorators, descriptors (e.g. properties), and abstracts work -- I hope it's not me. ;)
Here is a rough working example:
from abc import ABCMeta, abstractproperty
class ValidateProperty:
def __init__(inst, exception, arg_type, valid):
# called on the #ValidateProperty(...) line
#
# save the exception to raise, the expected argument type, and
# the validator code for later use
inst.exception = exception
inst.arg_type = arg_type
inst.validator = valid
def __call__(inst, func):
# called after the def has finished, but before it is stored
#
# func is the def'd function, save it for later to be called
# after validating the argument
def check_accepts(self, value):
if not inst.validator(value):
raise inst.exception('value %s is not valid' % value)
func(self, value)
return check_accepts
class AbstractTestClass(metaclass=ABCMeta):
#abstractproperty
def luminance(self):
# abstract property
return
#luminance.setter
#ValidateProperty(Exception, int, lambda x: 0 <= x <= 15)
def luminance(self, value):
# abstract property with validator
return
class TestClass(AbstractTestClass):
# concrete class
val = 7
#property
def luminance(self):
# concrete property
return self.val
#luminance.setter
def luminance(self, value):
# concrete property setter
# call base class first to activate the validator
AbstractTestClass.__dict__['luminance'].__set__(self, value)
self.val = value
tc = TestClass()
print(tc.luminance)
tc.luminance = 10
print(tc.luminance)
tc.luminance = 25
print(tc.luminance)
Which results in:
7
10
Traceback (most recent call last):
File "abstract.py", line 47, in <module>
tc.luminance = 25
File "abstract.py", line 40, in luminance
AbstractTestClass.__dict__['luminance'].__set__(self, value)
File "abstract.py", line 14, in check_accepts
raise inst.exception('value %s is not valid' % value)
Exception: value 25 is not valid
A few points to think about:
The ValidateProperty is much simpler because a property setter only takes two parameters: self and the new_value
When using a class for a decorator, and the decorator takes arguments, then you will need __init__ to save the parameters, and __call__ to actually deal with the defd function
Calling a base class property setter is ugly, but you could hide that in a helper function
you might want to use a custom metaclass to ensure the validation code is run (which would also avoid the ugly base-class property call)
I suggested a metaclass above to eliminate the need for a direct call to the base class's abstractproperty, and here is an example of such:
from abc import ABCMeta, abstractproperty
class AbstractTestClassMeta(ABCMeta):
def __new__(metacls, cls, bases, clsdict):
# create new class
new_cls = super().__new__(metacls, cls, bases, clsdict)
# collect all base class dictionaries
base_dicts = [b.__dict__ for b in bases]
if not base_dicts:
return new_cls
# iterate through clsdict looking for properties
for name, obj in clsdict.items():
if not isinstance(obj, (property)):
continue
prop_set = getattr(obj, 'fset')
# found one, now look in bases for validation code
validators = []
for d in base_dicts:
b_obj = d.get(name)
if (
b_obj is not None and
isinstance(b_obj.fset, ValidateProperty)
):
validators.append(b_obj.fset)
if validators:
def check_validators(self, new_val):
for func in validators:
func(new_val)
prop_set(self, new_val)
new_prop = obj.setter(check_validators)
setattr(new_cls, name, new_prop)
return new_cls
This subclasses ABCMeta, and has ABCMeta do all of its work first, then does some additional processing. Namely:
go through the created class and look for properties
check the base classes to see if they have a matching abstractproperty
check the abstractproperty's fset code to see if it is an instance of ValidateProperty
if so, save it in a list of validators
if the list of validators is not empty
make a wrapper that will call each validator before calling the actual property's fset code
replace the found property with a new one that uses the wrapper as the setter code
ValidateProperty is a little different as well:
class ValidateProperty:
def __init__(self, exception, arg_type):
# called on the #ValidateProperty(...) line
#
# save the exception to raise and the expected argument type
self.exception = exception
self.arg_type = arg_type
self.validator = None
def __call__(self, func_or_value):
# on the first call, func_or_value is the function to use
# as the validator
if self.validator is None:
self.validator = func_or_value
return self
# every subsequent call will be to do the validation
if (
not isinstance(func_or_value, self.arg_type) or
not self.validator(None, func_or_value)
):
raise self.exception(
'%r is either not a type of %r or is outside '
'argument range' %
(func_or_value, type(func_or_value))
)
The base AbstractTestClass now uses the new AbstractTestClassMeta, and has the validator code directly in the abstractproperty:
class AbstractTestClass(metaclass=AbstractTestClassMeta):
#abstractproperty
def luminance(self):
# abstract property
pass
#luminance.setter
#ValidateProperty(Exception, int)
def luminance(self, value):
# abstract property validator
return 0 <= value <= 15
The final class is the same:
class TestClass(AbstractTestClass):
# concrete class
val = 7
#property
def luminance(self):
# concrete property
return self.val
#luminance.setter
def luminance(self, value):
# concrete property setter
# call base class first to activate the validator
# AbstractTestClass.__dict__['luminance'].__set__(self, value)
self.val = value