In Django shell:
from django.test import SimpleTestCase
c = SimpleTestCase()
haystack = '<html><b>contribution</b></html>'
c.assertInHTML('<b>contribution</b>', haystack)
c.assertInHTML('contribution', haystack)
I don't understand why the first assertion passes, but the second one doesn't:
AssertionError Traceback (most recent call last)
<ipython-input-15-20da22474686> in <module>()
5
6 c.assertInHTML('<b>contribution</b>', haystack)
----> 7 c.assertInHTML('contribution', haystack)
c:\...\lib\site-packages\django\test\testcases.py in assertInHTML(self, needle, haystack, count, msg_prefix)
680 else:
681 self.assertTrue(real_count != 0,
--> 682 msg_prefix + "Couldn't find '%s' in response" % needle)
683
684 def assertJSONEqual(self, raw, expected_data, msg=None):
C:\...\Programs\Python\Python35-32\lib\unittest\case.py in assertTrue(self, expr, msg)
675 if not expr:
676 msg = self._formatMessage(msg, "%s is not true" % safe_repr(expr))
--> 677 raise self.failureException(msg)
678
679 def _formatMessage(self, msg, standardMsg):
AssertionError: False is not true : Couldn't find 'contribution' in response
The Django docs just say "The passed-in arguments must be valid HTML." I don't think that is the problem, because the call to assert_and_parse_html on the first line doesn't raise:
def assertInHTML(self, needle, haystack, count=None, msg_prefix=''):
needle = assert_and_parse_html(self, needle, None,
'First argument is not valid HTML:')
haystack = assert_and_parse_html(self, haystack, None,
'Second argument is not valid HTML:')
real_count = haystack.count(needle)
if count is not None:
self.assertEqual(real_count, count,
msg_prefix + "Found %d instances of '%s' in response"
" (expected %d)" % (real_count, needle, count))
else:
self.assertTrue(real_count != 0,
msg_prefix + "Couldn't find '%s' in response" % needle)
I'm using Python 3.5.1 and Django 1.8.8.
This is a bug in Django:
assertInHTML(needle, haystack) has the following behaviour
assertInHTML('<p>a</p>', '<div><p>a</p><p>b</p></div>') passes: clearly correct
assertInHTML('<p>a</p><p>b</p>', '<p>a</p><p>b</p>') passes: possibly correct
assertInHTML('<p>a</p><p>b</p>', '<div><p>a</p><p>b</p></div>') fails with an assertion error.
The problem occurs when the needle does not have a unique root element that wraps everything else.
The proposed fix (which has been languishing for some time!) is to raise an exception if you try to do this - i.e., the needle must have a HTML tag that wraps everything inside it.
Related
EDIT. The issue was that everytime I would import the function, it would not changed with updates. For this I needed to do
import sys, importlib
importlib.reload(sys.modules['foo'])
from foo import bar
And it started working
I am trying to write a test using Pytest to detect a ValueError if a json file passed into a function is invalid. However, when I follow the example, the test doesn't detect that the ValueError was raised.
This is the function I want to test
import pytest
import json
def read_file(input_file):
try:
with open(input_file, "r", encoding='utf-8') as reader:
pre_input_data = json.load(reader)
except ValueError:
raise ValueError
And this is my test function
def test_read_file():
with pytest.raises(ValueError):
read_file("invalidJsonFile.json")
If I just run the original function, it raises the ValueError
read_file("invalidJsonFile.json")
Invalid json file: Expecting value: line 1 column 1 (char 0)
However, when I run the test, it says it did not get a ValueError
test_read_file()
Invalid json file: Expecting value: line 1 column 1 (char 0)
---------------------------------------------------------------------------
Failed Traceback (most recent call last)
<ipython-input-47-c42b81670a67> in <module>()
----> 1 test_read_file()
2 frames
<ipython-input-46-178e6c645f01> in test_read_file()
1 def test_read_file():
2 with pytest.raises(Exception):
----> 3 read_file("invalidJsonFile.json")
/usr/local/lib/python3.6/dist-packages/_pytest/python_api.py in __exit__(self, *tp)
727 __tracebackhide__ = True
728 if tp[0] is None:
--> 729 fail(self.message)
730 self.excinfo.__init__(tp)
731 suppress_exception = issubclass(self.excinfo.type, self.expected_exception)
/usr/local/lib/python3.6/dist-packages/_pytest/outcomes.py in fail(msg, pytrace)
115 """
116 __tracebackhide__ = True
--> 117 raise Failed(msg=msg, pytrace=pytrace)
118
119
Failed: DID NOT RAISE <class 'Exception'>
Are you sure you're running the same code you sent here? because in a stack trace it looks like you're reading a different file (which could be valid and then no exception will be raised, if it's empty for example).
----> 3 read_file("sampleData.csv")
Also, you do not need to except ValueError just to raise ValueError, when you use pytest.raises(ValueError): pytest will check if the exception is instanceof ValueError.
How to catch Sublime Text exceptions on their Python interpreter?
This was migrated to https://github.com/SublimeTextIssues/Core/issues/1359
I am trying to catch this exception:
try:
print( 'RUNNING' )
sublime.active_window().run_command( "side_bar_update_sync" )
isNotSyncedSideBarEnabled = False
print( 'RUNNING THIS' )
except BaseException:
isNotSyncedSideBarEnabled = True
print( 'RUNNING THIS ALSO' )
But when it is ran, it just does not catches it. Does not matter if I try it within TypeError, Exception or BaseException classes. This below is the full exception output.
reloading plugin SublimeDefaultSyntax.default_syntax
READ_PREF_ASYNC!!!!
updateIsSyncedSideBarEnabled!!!!
RUNNING
Traceback (most recent call last):
File "D:\User\Dropbox\Applications\SoftwareVersioning\SublimeText\sublime_plugin.py", line 538, in run_
return self.run()
TypeError: run() missing 1 required positional argument: 'enable'
RUNNING THIS
isNotSyncedSideBarEnabled: False
The problem is, the python cannot catch the exception throwed by run_command( "side_bar_update_sync" ). The exception catching for errors like trying to call self.view, when there is no self passed by, are working fine. This is the full code:
def plugin_loaded():
global isNotSyncedSideBarEnabled
packageControlSettings = sublime.load_settings('Package Control.sublime-settings')
userSettings = sublime.load_settings('Preferences.sublime-settings')
def updateIsSyncedSideBarEnabled():
global isNotSyncedSideBarEnabled
print(' updateIsSyncedSideBarEnabled!!!!')
sublime.active_window().run_command( "reveal_in_side_bar" )
try:
print( 'RUNNING' )
sublime.active_window().run_command( "side_bar_update_sync" )
isNotSyncedSideBarEnabled = False
print( 'RUNNING THIS' )
except BaseException:
isNotSyncedSideBarEnabled = True
print( 'RUNNING THIS ALSO' )
print( 'isNotSyncedSideBarEnabled: ' + str( isNotSyncedSideBarEnabled ) )
def read_pref_async():
print('READ_PREF_ASYNC!!!!')
updateIsSyncedSideBarEnabled()
def read_pref_package():
print('READ_PREF_PACKAGE!!!!')
updateIsSyncedSideBarEnabled()
def read_pref_preferences():
print('READ_PREF_PREFERENCES!!!!')
updateIsSyncedSideBarEnabled()
# read initial setting, after all packages being loaded
sublime.set_timeout_async( read_pref_async, 1000 )
# listen for changes
packageControlSettings.add_on_change( "Package Control", read_pref_package )
userSettings.add_on_change( "Preferences", read_pref_preferences )
#print( userSettings.get( "ignored_packages" ) )
#print( packageControlSettings.get( "installed_packages" ) )
This discussion may be followed by this Sublime Text Forum's thread: https://forum.sublimetext.com/t/how-to-add-remove-a-default-menu-entry-when-a-x-package-is-isnt-enabled-installed/22753?u=addons_zz
This are the lines from the file showed on the exception:
532 class ApplicationCommand(Command):
533 def run_(self, edit_token, args):
534 args = self.filter_args(args)
535 if args:
536 return self.run(**args)
537 else:
538 return self.run()
539
540 def run(self):
541 pass1
542
543 ... other classes
As stated on the question, it is indeed a bug on Sublime Text. Here's a smaller repro from the bug report:
import sublime_plugin
class TestCommandCommand(sublime_plugin.TextCommand):
def run(self, edit):
try:
ret = self.view.window().run_command("toggle_comment", {"comment": "no"})
except:
print("an exception")
else:
print(ret)
Console:
reloading plugin User.test
command: test_command
Traceback (most recent call last):
File "C:\Program Files\Sublime Text 3\sublime_plugin.py", line 792, in run_
return self.run(edit, **args)
TypeError: run() got an unexpected keyword argument 'comment'
None
Needless to say, this only happens for Python commands and not internal commands since those do not error at all. Also when do you try to run a command as sublime.active_window().run_command( "reveal_in_side_bar" ) and it does not exist, Sublime Text does not throw an exception. This is to allow plugins or menu entries do not throw errors when they are not available.
Let's say I have the following multi-line string:
cmd = """
a = 1 + 1
b = [
2 + 2,
4 + 4,
]
bork bork bork
"""
and I want to execute it in a particular scope:
scope = {}
exec( cmd, scope )
print scope[ 'b' ]
There's a SyntaxError at line 6 of the command, and I want to be able to report that to the user. How do I get the line number? I've tried this:
try:
exec( cmd, scope ) # <-- let's say this is on line 123 of the source file
except Exception, err:
a, b, c = sys.exc_info()
line_number = c.tb_lineno # <-- this gets me 123, not 6
print "%s at line %d (%s)" % ( a, line_number, b.message )
...but I get the line number of the exec statement, not the line number within the multi-line command.
Update: it turns out the handling of the type of exception that I arbitrarily chose for this example, the SyntaxError, is different from the handling of any other type. To clarify, I'm looking a solution that copes with any kind of exception.
For syntax errors, the source line number is available as the lineno flag on the exception object itself, in your case stored in err. This is specific to syntax errors where the line number is an integral part of the error:
>>> cmd = """
... 1 \ +
... 2 * "
... """
>>> try:
... exec cmd
... except SyntaxError as err:
... print err.lineno
...
2
If you want to also handle other errors, add a new except block except Exception, err, and use the traceback module to compute the line number for the runtime error.
import sys
import traceback
class InterpreterError(Exception): pass
def my_exec(cmd, globals=None, locals=None, description='source string'):
try:
exec(cmd, globals, locals)
except SyntaxError as err:
error_class = err.__class__.__name__
detail = err.args[0]
line_number = err.lineno
except Exception as err:
error_class = err.__class__.__name__
detail = err.args[0]
cl, exc, tb = sys.exc_info()
line_number = traceback.extract_tb(tb)[-1][1]
else:
return
raise InterpreterError("%s at line %d of %s: %s" % (error_class, line_number, description, detail))
Examples:
>>> my_exec("1+1") # no exception
>>>
>>> my_exec("1+1\nbork")
...
InterpreterError: NameError at line 2 of source string: name 'bork' is not defined
>>>
>>> my_exec("1+1\nbork bork bork")
...
InterpreterError: SyntaxError at line 2 of source string: invalid syntax
>>>
>>> my_exec("1+1\n'''")
...
InterpreterError: SyntaxError at line 2 of source string: EOF while scanning triple-quoted string
I downloaded the package http://nodebox.net/code/index.php/Linguistics#verb_conjugation
I'm getting an error even when I tried to get a tense of a verb .
import en
print en.is_verb('use')
#prints TRUE
print en.verb.tense('use')
KeyError Traceback (most recent call last)
/home/cse/version2_tense.py in <module>()
----> 1
2
3
4
5
/home/cse/en/__init__.pyc in tense(self, word)
124
125 def tense(self, word):
--> 126 return verb_lib.verb_tense(word)
127
128 def is_tense(self, word, tense, negated=False):
/home/cse/en/verb/__init__.pyc in verb_tense(v)
175
176 infinitive = verb_infinitive(v)
--> 177 a = verb_tenses[infinitive]
178 for tense in verb_tenses_keys:
179 if a[verb_tenses_keys[tense]] == v:
KeyError: ''
The reason you are getting this error is because there is a mistake in the ~/Library/Application Support/NodeBox/en/verb/verb.txt file they are using to create the dictionary.
use is the infinitive form, however, "used" is entered as the infinitive.
at line 5857:
used,,,uses,,using,,,,,used,used,,,,,,,,,,,,
should be:
use,,,uses,,using,,,,,used,used,,,,,,,,,,,,
after editing and saving the file:
import en
print en.is_verb("use")
print en.verb.infinitive('use')
print en.verb.tense('use')
gives:
True
use
infinitive
extra:
import en
print 'use %s' % en.verb.tense("use")
print 'uses %s' % en.verb.tense("uses")
print 'using %s' % en.verb.tense('using')
print 'used %s' % en.verb.tense('used')
use infinitive
uses 3rd singular present
using present participle
used past
I wanted to create an IDN-aware formencode validator to use in one of my projects. I used a portion of code from the Django project (http://code.djangoproject.com/svn/django/trunk/django/core/validators.py) to do that, but there must be a trivial error in my code I can't find :
class Email(formencode.validators.Email):
def _to_python(self, value, state):
try:
return super(Email, self)._to_python(value, state)
except formencode.Invalid as e:
# Trivial case failed. Try for possible IDN domain-part
print 'heywo !'
if value and u'#' in value:
parts = value.split(u'#')
try:
parts[-1] = parts[-1].encode('idna')
except UnicodeError:
raise e
try:
super(Email, self)._to_python(u'#'.join(parts), state)
except formencode.Invalid as ex:
raise ex
return value
else:
raise e
When I try to validate an email with an IDN domain (ex: test#wääl.de), the Invalid exception raised by the first call is thrown, and the portion of code after the first except is never executed ('heywo !' is never printed).
There is an example :
>>> from test.lib.validators import Email
>>> Email().to_python(u'test#zääz.de')
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/usr/local/lib/python2.6/dist-packages/FormEncode-1.2.3dev-py2.6.egg/formencode /api.py", line 416, in to_python
vp(value, state)
File "/usr/local/lib/python2.6/dist-packages/FormEncode-1.2.3dev-py2.6.egg/formencode /validators.py", line 1352, in validate_python
value, state)
Invalid: The domain portion of the email address is invalid (the portion after the #: z\xe4\xe4z.de)
What did I do wrong ?
Thanks.
Okay, found the answer. I was overloading _to_python instead of validate_python. The class now looks like :
class Email(formencode.validators.Email):
def validate_python(self, value, state):
try:
super(Email, self).validate_python(value, state)
except formencode.Invalid as e:
# Trivial case failed. Try for possible IDN domain-part
if value and u'#' in value:
parts = value.split(u'#')
try:
parts[-1] = parts[-1].encode('idna')
except UnicodeError:
raise e
try:
super(Email, self).validate_python(u'#'.join(parts), state)
except formencode.Invalid as ex:
raise ex
else:
raise e
It's working perfectly :)