Receiving True boolean value for Django unit tests instead of False - python

I'm doing some unit tests for my Django database and I keep getting a True value instead of the False I expected to get because that entry isn't in my database:
import requests
from django.test import TestCase
from convoapp.models import InputInfo
class InputInfoTestCase(TestCase):
def setUp(self):
#valid entry
InputInfo.objects.create(name="Skywalker", conversation_id='1', message_body='I am a Jedi, like my father before me')
#invalid entry - missing 'name' field
InputInfo.objects.create(conversation_id='4', message_body="No, I am your Father")
#invalid entry - integer entered instead of string
InputInfo.objects.create(name='Leia', conversation_id=3, message_body='You are a little short')
def test_for_valid_entries(self):
luke = InputInfo.objects.get(name='Skywalker')
self.assertTrue(bool(luke), True)
def test_for_invalid_entries(self):
vader = InputInfo.objects.get(conversation_id='4')
#invalid because of non-strong entry for conversation_id
#leia = InputInfo.objects.get(name='Leia')
self.assertFalse(bool(vader))
I get the error:
Traceback (most recent call last):
File "C:\Users\ELITEBOOK\documents\github\challenge\convoapp\tests.py", line 25, in test_for_invalid_entries
self.assertFalse(bool(vader))
AssertionError: True is not false
Why is vaderreturning True? I assume it's because of InputInfo.objects.create(conversation_id='4', message_body="No, I am your Father"), is it because the entry is temporarily created? Because after the test ends it's not in my database

the setUp functions is called before each test so yeah you have the vader entry in your db (because you request conversation_id=4 which exists since setUp was called before testing).
That said, casting to bool doesn't make a lot of sense, if your trying to see if you have the entry or not you should user :
self.assertIsNone(vader)
or
self.assertTrue(vader is None)
This way you know exactly what you are testing

you are creating an object with the id 4 thus its returning true, and as its test database thus you cannot find data after the test ends
rather if you think its mistaking
try the lower code and check
def test_for_invalid_entries(self):
vader = InputInfo.objects.get(conversation_id=5)
#invalid because of non-strong entry for conversation_id
#leia = InputInfo.objects.get(name='Leia')
self.assertFalse(bool(vader))

Related

Django database sqlite display of value of attribute

I'm on a project using django and I wrote my models.py
I have two classes
class Adresse(models.Model):
numV=models.IntegerField(blank=False,null=False)
complementdest=models.TextField(blank=False,null=False)
complementadr=models.TextField(blank=False,null=False)
commune=models.TextField(blank=False,null=False)
codeP=models.IntegerField(blank=False,null=False)
pays=models.TextField(blank=False,null=False)
def __str__(self):
return self.numV
return self.complementdest
return self.complementadr
return self.commune
return self.codeP
return self.pays
def __Adr__(self):
return self.adr1.all()
and
class CompteCandidat(myUser):
sexe = models.TextField(max_length=10)
datecr = models.DateTimeField(auto_now_add = True)
adresse=models.OneToOneField('Adresse',related_name='adr1',null=True, default=None)
def __str__(self):
return self.first_name
return self.last_name
return self.email
return self.sexe
def __Adr__(self):
return self.adresse.all()
I try to do some tests like this:
adresse=Adresse(numV='254',complementdest='xxxxx',complementadr='Eugene napoleon',commune='Paris',codeP='75012',pays='France')
c1=CompteCandidat(username='Luna',first_name='celia',last_name='durand',password='CCC',email='hello2#gmail.com',type='candidat',adresse=adresse)
adresse.save()
c1.save()
and when I try to see what I have in my Adresse or in my CompteCandidat by using this command it didn't work
>>> Adresse.__getattribute__(numV)
Traceback (most recent call last):
File "<input>", line 1, in <module>
NameError: name 'numV' is not defined
i want to know what i'm suppose to do to display what I have in Adresse and CompteCandidat in order to be sure that the add works
i know i Can do :
>>> adresse.numV
'254'
but it works only in the console there is an another way to consult all the database without using the name of the temporery variables ????
You can use
Adresse.objects.all()
to see all records or Adresse.object.filter(numV='254)
to see records satisfying this condition.
For full reference please check:
https://docs.djangoproject.com/ja/1.9/topics/db/queries/
At first in the console try this:
>>>A = {numV='254',complementdest='xxxxx',complementadr='Eugene napoleon',commune='Paris',codeP='75012',pays='France'}
>>> adresse = Adresse(**A)
>>> adresse.save()
At first you will face an error beacuse your numV is Integer but you are assigning an String to it, so should edit numV = '254' to numV = 254 at first line.
Then try above steps again and post that in which step face error.
Two things :
__str__ must only return a single string - as it stands your code tries to return multiple non string values.
the __getattribute__ method (and it's counterpart getattr) should be passed the name of the attribute i.e. a string. Also you shouldn't be trying to call __getattribute__ directly except in exceptional circumstances: ie. you have some form of circular access confilct - which you don't here.
There is no reason that adresse.numV shouldn't work directly in your code - that is the normal way to retrieve attributes from an instance. You should only use getattr if you have the attribute name in a string from elsewhere.
At the risk of sounding rude - if you are struggling to write code that correctly accesses attributes then maybe trying to write a Django App is a case of trying to run before you walk.

Generating instances of class in loop gives TypeError: 'list' object is not callable

I've looked through a lot of replies regarding this error, however none was helpfull for my special case and since I'm new to Python, I have difficulties applying the hints to my problem.
I have a class in a file Aheat.py that reads
class Aheat():
name = ""
time = 0
place = 0
def __init__(self,name,time,place):
self.name = name
self.time = time
self.place = place
And a file main.py where I want to read a html file, extract information, and create a list of objects of my class to work with them later on.
The (hopefully) essential part of my main.py reads
import urllib2
import re
from Aheat import Aheat
s = read something from url
ssplit = re.split('<p', s) # now every entry of ssplit contains an event
# and description and all the runners
HeatList = []
for part in ssplit:
newHeat = Aheat("foo",1,1) # of course this is just an example
HeatList.append(newHeat)
But this gives me the following error:
Traceback (most recent call last):
File "/home/username/Workspace/ECLIPSE/running/main.py", line 22, in <module>
newHeat = Aheat("foo",1,1)
TypeError: 'list' object is not callable
which is thrown when performing the second iteration.
If I take out the generation of the object of the loop, i.e.
newHeat = Aheat("foo",1,1)
for part in ssplit:
HeatList.append(newHeat)
My code executes without a problem, but this is not what I want. I'm also not sure, if I can initialize a specific number of instances a priori, since the number of objects is estimated in the loop.
I'm using Eclipse and Python 2.7.
regex is going to bite you.
<p == <pre> || <progress> || <param> || <p> || (any user created directives on a page.)
follow the links in your comments to read up on why we shouldn't parse html with regex.
Thanks, #MarkR ( btw, I was only supplementing your comment and I was agreeing with you )
Why not put the list in your class or better yet extend list functionality with your class.
class AHeat(list):
def append(self,name,time,place):
return super(AHeat,self).append([name,time,place])
# main
heatList= AHeat()
heatList.append("foo",1,2)
heatList.append("bar",3,4)
print(heatList[0])
print(heatList[1])
> ['foo', 1, 2]
> ['bar', 3, 4]
Also

how to check the username before registering?

please help to write the test.
views.py:
def ajax_username_check(request):
"""
ajax check username for registration form
return true - no matched
return false - matched
"""
result = True
if request.method == 'POST' and request.is_ajax():
username = request.POST.get('username', '')
try:
check_username_match = User.objects.get(username=username)
except:
pass
else:
result = False
data = {
'result': result,
}
return HttpResponse(json.dumps(data), content_type='application/json')
tests.py:
class TestAjaxCheckUsername(TestCase):
def setUp(self):
self.client = Client()
self.record = User.objects.create(
user_id=2,
username='qqqqqq',
password='pbkdf2_sha256$12000$Bm1GmmeGtnyU$v4E1UUcXWjk7pmQEkIWXvY2Hsw2ycG783R/bVpoVEWk=',
is_active=1,
is_staff=0,
is_superuser=0,
email='asasas#mail.ru'
)
def test_diary(self):
json_string = json.dumps({'username':'qqqqqq'})
self.response = self.client.post('/ajax_username_check/', json_string, "text/json", HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertContains(self.response, true)
error message:
ERROR: test_diary (app_accounts.tests.TestAjaxCheckUsername)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/kalinins/.virtualenvs/kinopom_project/kinopom/app_accounts/tests.py", line 17, in setUp
email='asasas#mail.ru'
File "/home/kalinins/.virtualenvs/kinopom_project/kinopom_env/local/lib/python2.7/site-packages/django/db/models/manager.py", line 157, in create
return self.get_queryset().create(**kwargs)
File "/home/kalinins/.virtualenvs/kinopom_project/kinopom_env/local/lib/python2.7/site-packages/django/db/models/query.py", line 320, in create
obj = self.model(**kwargs)
File "/home/kalinins/.virtualenvs/kinopom_project/kinopom_env/local/lib/python2.7/site-packages/django/db/models/base.py", line 417, in __init__
raise TypeError("'%s' is an invalid keyword argument for this function" % list(kwargs)[0])
TypeError: 'user_id' is an invalid keyword argument for this function
I am trying to verify the existence of a user named qqqqqq using Ajax-request. I need to check the return value for the function ajax_username_check()
I have read this post and tried to use it, but to no avail
User has no field user_id, it has a field id. However, I wouldn't set that either, as the ID may already exist and usually Django chooses the model ids. So I would just remove the user_id=2 line.
Two other comments: first, never use a bare except: like that, use except User.DoesNotExist: explicitly, otherwise you might accidentally catch who knows what exception.
Second, I wouldn't use get() here at all: what you're looking for is whether the User exists or not. So:
result = {'result': User.objects.filter(username=username).exists()}
should do.
You do not appear to have read the error message.
Firstly, this is not a problem with checking a user or with registering: the error message clearly comes from the setUp method of your test. The rest of the code is irrelevant.
Secondly, the message tells you exactly what is wrong: user_id is not a valid argument. That is because there is no such field "user_id". Maybe you mean id?

WTForms How to use a DecimalField which generates proper field errors on bad input

Have a look at this example
class MyForm(ForM):
...snip...
quantity = DecimalField(u'Quantity', [NumberRange(1, 8)])
...snip...
This works nicely if the user is co-operative and enters something that can be coerced to a numeric type. However, if the user enters, say: "asdf" into this field in the browser then DecimalField throws a Type Error when I try to render it in the browser.
Here's the relevant parts of the traceback:
Traceback (most recent call last):
File "/path/to/app/venv/local/lib/python2.7/site-packages/jinja2/environment.py", line 894, in render
return self.environment.handle_exception(exc_info, True)
File "/path/to/app/www/templates/submodule/user/submission.html", line 26, in block "submodule_content"
{{form.quantity}}
File "/path/to/app/venv/local/lib/python2.7/site-packages/wtforms/fields/core.py", line 139, in __call__
return self.widget(self, **kwargs)
File "/path/to/app/venv/local/lib/python2.7/site-packages/wtforms/widgets/core.py", line 123, in __call__
kwargs['value'] = field._value()
File "/path/to/app/venv/local/lib/python2.7/site-packages/wtforms/fields/core.py", line 542, in _value
return format % self.data
TypeError: a float is required
Instead of this behaviour, I'd like the field to have an error added to itself, so that I can still render t.
My current solution involves using a TextField instead of a DecimalField and providing an IsNumeric validator with a call method like:
def __call__(self, form, field):
if field.data:
try:
field.data = float(field.data)
except ValueError as e:
raise ValidationError(self.message)
This works nearly perfectly, and is my current solution, but surely there must be a wtforms-idiomatic way to do this.
I had to deal with similar problem. SelectMultipleField with coerce=text_type(which is a default kwarg) converts input data to str/unicode. That means it 'coerced' None (a value fed into my field when user didn't select anything) into "None" - which was huge pain to debug. your question clearly indicates that it was not only me who dove into wtforms internal validation process.
The correct solution I found is, you write a custom subclass of StringField(textfield) and override __call__, process_data, and process_formdata methods to suit your needs. __call__ is for rendering them into html(which should be done by another widget callable), process_data is usually for getting data from python objects(which means server-side), and process_formdata is like process_data except it deals with user-submitted forms. or, if you want DRY(don't repeat yourself), you can override __init__ and make your custom validator default.
edit:
The DecimalField's idiotic code is what causes TypeError. Take a look at its _value() method, which is used by DecimalField's rendering widget to get X for <input type="text" ... value=X>
def _value(self):
if self.raw_data:
return self.raw_data[0]
elif self.data is not None:
if self.places is not None: # <-- this line brings you the pain
if hasattr(self.data, 'quantize'):
exp = decimal.Decimal('.1') ** self.places
if self.rounding is None:
quantized = self.data.quantize(exp)
else:
quantized = self.data.quantize(exp, rounding=self.rounding)
return text_type(quantized)
else:
# If for some reason, data is a float or int, then format
# as we would for floats using string formatting.
format = '%%0.%df' % self.places
return format % self.data
else:
return text_type(self.data)
else:
return ''
it checks field.places before the type of field.data - field.places is declared upon field creation, and is merely saying that you want N digits of precision; it does not indicate that you have N digit of Decimal as your fields.data, but wtforms devs somehow decided that checking field.places is enough to assume the field contains corresponding floating point number. (the codes checks whether there is quantize attribute on field.data but that only works for decimals)
I think you have to write your own subclass of DecimalField. here's my attempt at writing a non-idiot version of DecimalField :
from wtforms.fields.core import DecimalField as _DecimalField
class DecimalField(_DecimalField):
def _value(self):
try:
float(self.data) #check whether you have a 'number'
return super(DeciamlField, self)._value()
except (TypeError, ValueError): #self.data is 'None', 'asdf' ...
return text_type(self.data) if self.data else ''

Django unit test client response has empty context

I have a unit test that's failing in an assertion that passes in another test in the same test case class.
Here's the passing test:
def test_home(self):
c = Client()
resp = c.get('/')
self.assertEqual(resp.status_code, 200)
self.assertTrue('a_formset' in resp.context)
Here's the failing test:
def test_number_initial_number_of_forms(self):
c = Client()
resp = c.get('/')
self.assertEqual(resp.context['a_formset'].total_form_count(), 1)
In the second test, I get the error TypeError: 'NoneType' object has no attribute '__getitem__'.
If I execute the second test as
def test_number_initial_number_of_forms(self):
c = Client()
resp = c.get('/')
self.assertTrue('a_formset' in resp.context)
self.assertEqual(resp.context['a_formset'].total_form_count(), 1)
I get the error TypeError: argument of type 'NoneType' is not iterable. I've confirmed via print statements in the second test that the response.content contains the page I expect to get, that the status code is correct, and that the template is correct. But the response's context is consistently None in the second test.
I'm running my Django unit tests through the standard "python manage.py test ..." interface, so I don't believe I'm running into the "context is empty from the shell" issue.
What's going on with this?
Edit:
If I add print type(resp.context['a_formset']) to each test, for the working test I get <class 'django.forms.formsets.AFormFormSet'>. For the non-working test, I get TypeError: 'NoneType' object has no attribute '__getitem__' again.
It's because you ran into some error, exited the shell and restarted it.
But you forgot to start environment...
from django.test.utils import setup_test_environment
>>> setup_test_environment()
That was my problem. Hope it works...
Today I run into the same issue. The second test gets same page has nothing in response.context
I made a research and found that
1) test client uses signals to populate context,
2) my view method is not called for the second test
I turned on a debugger and found that the guilty one is 'Cache middleware'. Knowing that I found this ticket and this SO question (the latter has a solution).
So, in short: the second request is served from cache, not from a view, thus a view is not executed and test-client doesn't get the signal and have no ability to populate context.
I can not disable cache middleware for my project, so I added next hack-lines into my settings:
if 'test' in sys.argv:
CACHE_MIDDLEWARE_SECONDS = 0
Hope this helps someone
You can also clear cache manually by calling cache.clear() inside a test method:
from django.core.cache import cache
import pytest
class TestPostView:
#pytest.mark.django_db(transaction=True)
def test_index_post(self, client, post):
cache.clear()
response = client.get('/')

Categories