UnitTesting
UnitTesting copied to clipboard
SystemError: Parent module '' not loaded, cannot perform relative import
I had imported another test file, in one (main) test file like this:
from .text_extraction_unit_tests import PrefixStrippingViewUnitTests
wrap_plus_module = sys.modules["Wrap Plus.wrap_plus"]
def run_unit_tests(unit_tests_to_run=[]):
runner = unittest.TextTestRunner()
classes = \
[
PrefixStrippingViewUnitTests,
SemanticLineWrapUnitTests,
LineBalancingUnitTests,
]
if len( unit_tests_to_run ) < 1:
# Comment all the tests names on this list, to run all Unit Tests
unit_tests_to_run = \
[
# "test_semantic_line_wrap_line_starting_with_comment",
# "test_split_lines_with_trailing_new_line",
# "test_split_lines_without_trailing_new_line",
# "test_balance_characters_between_line_wraps_with_trailing_new_line",
# "test_balance_characters_between_line_wraps_without_trailing_new_line",
# "test_balance_characters_between_line_wraps_ending_with_long_word",
]
runner.run( suite( classes, unit_tests_to_run ) )
def suite(classes, unit_tests_to_run):
"""
Problem with sys.argv[1] when unittest module is in a script
https://stackoverflow.com/questions/2812218/problem-with-sys-argv1-when-unittest-module
Is there a way to loop through and execute all of the functions in a Python class?
https://stackoverflow.com/questions/2597827/is-there-a-way-to-loop-through-and-execute
looping over all member variables of a class in python
https://stackoverflow.com/questions/1398022/looping-over-all-member-variables-of-a-class
"""
suite = unittest.TestSuite()
unit_tests_to_run_count = len( unit_tests_to_run )
for _class in classes:
_object = _class()
for function_name in dir( _object ):
if function_name.lower().startswith( "test" ):
if unit_tests_to_run_count > 0 \
and function_name not in unit_tests_to_run:
continue
suite.addTest( _class( function_name ) )
return suite
Using this I can run the unit tests by my loader file inside the file Wrap Plus.wrap_plus
:
def run_tests():
"""
How do I unload (reload) a Python module?
https://stackoverflow.com/questions/437589/how-do-i-unload-reload-a-python-module
"""
print( "\n\n" )
sublime_plugin.reload_plugin( "Wrap Plus.tests.text_extraction_unit_tests" )
sublime_plugin.reload_plugin( "Wrap Plus.tests.semantic_linefeed_unit_tests" )
sublime_plugin.reload_plugin( "Wrap Plus.tests.semantic_linefeed_manual_tests" )
from .tests import semantic_linefeed_unit_tests
# Comment all the tests names on this list, to run all Unit Tests
unit_tests_to_run = \
[
# "test_semantic_line_wrap_ending_with_comma_list",
# "test_is_command_separated_list_5_items",
# "test_is_command_separated_list_4_items",
# "test_is_command_separated_list_3_items",
# "test_is_command_separated_list_2_items",
]
semantic_linefeed_unit_tests.run_unit_tests( unit_tests_to_run )
def plugin_loaded():
"""
Running single test from unittest.TestCase via command line
https://stackoverflow.com/questions/15971735/running-single-test-from-unittest-testcase
"""
run_tests()
And it successfully run I reload the Wrap Plus.wrap_plus
file:
reloading plugin Wrap Plus.tests.text_extraction_unit_tests
reloading plugin Wrap Plus.tests.semantic_linefeed_unit_tests
reloading plugin Wrap Plus.tests.semantic_linefeed_manual_tests
...................................................
----------------------------------------------------------------------
Ran 51 tests in 0.601s
OK
reloading plugin Wrap Plus.wrap_plus
But when I use the UnitTesting
command UnitTesting: Test Current Package
, I got this error:
semantic_linefeed_unit_tests (unittest.loader.ModuleImportFailure) ... ERROR
test_double_quotes_wrappting (text_extraction_unit_tests.PrefixStrippingViewUnitTests) ... ok
test_double_quotes_wrappting_without_leading_whitespace (text_extraction_unit_tests.PrefixStrippingViewUnitTests) ... ok
test_triple_quotes_comment (text_extraction_unit_tests.PrefixStrippingViewUnitTests) ... ok
test_triple_quotes_wrappting (text_extraction_unit_tests.PrefixStrippingViewUnitTests) ... ok
test_triple_quotes_wrappting_without_leading_whitespace (text_extraction_unit_tests.PrefixStrippingViewUnitTests) ... ok
======================================================================
ERROR: semantic_linefeed_unit_tests (unittest.loader.ModuleImportFailure)
----------------------------------------------------------------------
Traceback (most recent call last):
File "./python3.3/unittest/case.py", line 384, in _executeTestPart
File "./python3.3/unittest/loader.py", line 32, in testFailure
ImportError: Failed to import test module: semantic_linefeed_unit_tests
Traceback (most recent call last):
File "./python3.3/unittest/loader.py", line 261, in _find_tests
File "./python3.3/unittest/loader.py", line 239, in _get_module_from_name
File "D:\SublimeText\Data\Packages\Wrap Plus\tests\semantic_linefeed_unit_tests.py", line 11, in <module>
from .text_extraction_unit_tests import PrefixStrippingViewUnitTests
SystemError: Parent module '' not loaded, cannot perform relative import
----------------------------------------------------------------------
Ran 6 tests in 0.544s
FAILED (errors=1)
UnitTesting: Done.
Changing the initial import structure from:
from .text_extraction_unit_tests import PrefixStrippingViewUnitTests
wrap_plus_module = sys.modules["Wrap Plus.wrap_plus"]
def run_unit_tests(unit_tests_to_run=[]):
runner = unittest.TextTestRunner()
classes = \
[
PrefixStrippingViewUnitTests,
SemanticLineWrapUnitTests,
LineBalancingUnitTests,
]
...
to:
wrap_plus_module = sys.modules["Wrap Plus.wrap_plus"]
def run_unit_tests(unit_tests_to_run=[]):
runner = unittest.TextTestRunner()
classes = \
[
sys.modules["Wrap Plus.tests.text_extraction_unit_tests"].PrefixStrippingViewUnitTests,
SemanticLineWrapUnitTests,
LineBalancingUnitTests,
]
...
Seems to solved the problem. Now all the Unit Tests ran with success:
...
text_extraction_unit_tests.PrefixStrippingViewUnitTests) ... ok
----------------------------------------------------------------------
Ran 51 tests in 0.939s
OK
UnitTesting: Done.
I am not sure why, but I tried this fix on another package, and it did not worked. Then I searched and found this other solution by changing this:
class ClearCursorsCaretsLastSelectionUnitTests(sys.modules["ClearCursorsCarets.tests.utilities"].BasicSublimeTextViewTestCase):
To this:
import os
import sys
import importlib
CURRENT_DIRECTORY = os.path.dirname( os.path.dirname( os.path.realpath( __file__ ) ) )
CURRENT_PACKAGE_NAME = os.path.basename( CURRENT_DIRECTORY ).rsplit('.', 1)[0]
utilities = importlib.import_module( CURRENT_PACKAGE_NAME + ".tests.utilities" )
class ClearCursorsCaretsLastSelectionUnitTests(utilities.BasicSublimeTextViewTestCase):
def test_1_selections_at_first_word(self):
pass
I am not sure what you want to achieve. You need to make sure that the tests are organized such as they could be discovered by discover
.
They are being discovered, the error was the importing of helper functions/classes from helper files.
I had created an utilities.py
to put common functions/classes through all my tests files on my package, but when was calling the UnitTesting
package to run the tests, it could not import the functions from the utilities files. For example, given the following file structure:
$ tree
.
├── clear_cursors_carets.py
├── tests
│ ├── __init__.py
│ ├── clear_cursors_carets_first_selection_unit_tests.py
│ ├── clear_cursors_carets_last_selection_unit_tests.py
│ ├── unit_tests_runner.py
│ └── utilities.py
└── unittesting.json
On the file utitiles.py
, I had the following class BasicSublimeTextViewTestCase
extending unittest.TestCase
:
import unittest
import textwrap
import sublime
import sublime_plugin
def wrap_text(text):
return textwrap.dedent( text ).strip( " " ).strip( "\n" )
class BasicSublimeTextViewTestCase(unittest.TestCase):
@classmethod
def setUp(self):
self.maxDiff = None
# Create a new Sublime Text view to perform the Unit Tests
self.view = sublime.active_window().new_file()
self.view.set_syntax_file( "Packages/Text/Plain text.tmLanguage" )
# make sure we have a window to work with
settings = sublime.load_settings("Preferences.sublime-settings")
settings.set("close_windows_when_empty", False)
def tearDown(self):
if self.view:
self.view.set_scratch(True)
self.view.window().focus_view(self.view)
self.view.window().run_command("close_file")
def setText(self, string, start_point=0):
self.view.run_command("append", {"characters": wrap_text( string ) })
selections = self.view.sel()
selections.clear()
selections.add( sublime.Region( start_point, start_point ) )
def create_test_text(self, start_point):
"""
1. (0, 4),
2. (5, 9),
3. (10, 14),
4. (16, 20),
5. (21, 25),
6. (26, 30),
"""
self.setText( """\
word
word
word
word
word
word""", start_point )
Then on my test files clear_cursors_carets_last_selection_unit_tests.py
and clear_cursors_carets_first_selection_unit_tests.py
, I would import the utilities
module, so I can use it:
import sublime
import sublime_plugin
import os
import sys
import importlib
CURRENT_DIRECTORY = os.path.dirname( os.path.dirname( os.path.realpath( __file__ ) ) )
CURRENT_PACKAGE_NAME = os.path.basename( CURRENT_DIRECTORY ).rsplit('.', 1)[0]
utilities = importlib.import_module( CURRENT_PACKAGE_NAME + ".tests.utilities" )
class ClearCursorsCaretsFirstSelectionUnitTests(utilities.BasicSublimeTextViewTestCase):
def test_1_selections_at_first_word(self):
self.create_test_text(0)
self.view.window().run_command( "find_under_expand" )
self.view.window().run_command( "single_selection_first" )
region = self.view.sel()[0]
self.assertEqual( sublime.Region(0, 4), region )
def test_2_selections_at_first_word(self):
self.create_test_text(0)
self.view.window().run_command( "find_under_expand" )
self.view.window().run_command( "find_under_expand" )
self.view.window().run_command( "single_selection_first" )
region = self.view.sel()[0]
self.assertEqual( sublime.Region(0, 4), region )
def test_3_selections_at_first_word(self):
self.create_test_text(0)
self.view.window().run_command( "find_under_expand" )
self.view.window().run_command( "find_under_expand" )
self.view.window().run_command( "find_under_expand" )
self.view.window().run_command( "single_selection_first" )
region = self.view.sel()[0]
self.assertEqual( sublime.Region(0, 4), region )
This was how I made it work. On the my first attempt, I was just trying to import utilities.py
file on my test files clear_cursors_carets_first_selection_unit_tests.py
and clear_cursors_carets_last_selection_unit_tests.py
with:
from .utilities import BasicSublimeTextViewTestCase
But this was failing with:
SystemError: Parent module '' not loaded, cannot perform relative import
When I called the UnitTesting
command UnitTesting: Test Current Package
on a project file like clear_cursors_carets_last_selection_unit_tests.py
.
But it was not falling when I used my own runner I already have setup. In addition to the UnitTesting
package to run tests, I also had make my own runner on the file unit_tests_runner.py
, so I can run individual Unit Tests and to be independent of the UnitTesting
package to run tests.
import sys
import unittest
def run_unit_tests(unit_tests_to_run=[]):
runner = unittest.TextTestRunner()
classes = \
[
sys.modules["ClearCursorsCarets.tests.clear_cursors_carets_first_selection_unit_tests"].ClearCursorsCaretsFirstSelectionUnitTests,
sys.modules["ClearCursorsCarets.tests.clear_cursors_carets_last_selection_unit_tests"].ClearCursorsCaretsLastSelectionUnitTests,
]
if len( unit_tests_to_run ) < 1:
# Comment all the tests names on this list, to run all Unit Tests
unit_tests_to_run = \
[
# "test_semantic_line_wrap_line_starting_with_comment",
]
runner.run( suite( classes, unit_tests_to_run ) )
def suite(classes, unit_tests_to_run):
"""
Problem with sys.argv[1] when unittest module is in a script
https://stackoverflow.com/questions/2812218/problem-with-sys-argv1-when-unittest-module-is-in-a-script
Is there a way to loop through and execute all of the functions in a Python class?
https://stackoverflow.com/questions/2597827/is-there-a-way-to-loop-through-and-execute-all-of-the-functions
looping over all member variables of a class in python
https://stackoverflow.com/questions/1398022/looping-over-all-member-variables-of-a-class-in-python
"""
suite = unittest.TestSuite()
unit_tests_to_run_count = len( unit_tests_to_run )
for _class in classes:
_object = _class()
for function_name in dir( _object ):
if function_name.lower().startswith( "test" ):
if unit_tests_to_run_count > 0 \
and function_name not in unit_tests_to_run:
continue
suite.addTest( _class( function_name ) )
return suite
Then I can call this runner from my main application using this:
def run_tests():
"""
How do I unload (reload) a Python module?
https://stackoverflow.com/questions/437589/how-do-i-unload-reload-a-python-module
"""
print( "\n\n" )
sublime_plugin.reload_plugin( "ClearCursorsCarets.tests.unit_tests_runner" )
sublime_plugin.reload_plugin( "ClearCursorsCarets.tests.utilities" )
sublime_plugin.reload_plugin( "ClearCursorsCarets.tests.clear_cursors_carets_first_selection_unit_tests" )
sublime_plugin.reload_plugin( "ClearCursorsCarets.tests.clear_cursors_carets_last_selection_unit_tests" )
from .tests import unit_tests_runner
# Comment all the tests names on this list, to run all Unit Tests
unit_tests_to_run = \
[
# "test_2_selections_at_last_word",
# "test_last_selection_with_6_selections_plus_redundant_expand_at_last_word",
]
unit_tests_runner.run_unit_tests( unit_tests_to_run )
def plugin_loaded():
"""
Running single test from unittest.TestCase via command line
https://stackoverflow.com/questions/15971735/running-single-test-from-unittest-testcase-via-command-line
"""
pass
run_tests()
On the beginning I was only using my runner to run Unit Tests, but @ehuss asked to use the UnitTesting package to run the tests on a pull request to his repository, then since then I started adding it as compatible with the runners I was already using.
Are you sure that the test cases are discoverable? AKAIK, unittest discover only search files named as test*.py
.
EDIT: I saw that you have changed the pattern for discovery.
I checked out your master branch: https://github.com/evandrocoan/Sublime-Wrap-Plus/tree/master and UnitTesting was working properly.
test_balance_characters_between_line_wraps_commented_line (semantic_linefeed_unit_tests.LineBalancingUnitTests) ... ok
test_balance_characters_between_line_wraps_ending_with_long_word (semantic_linefeed_unit_tests.LineBalancingUnitTests) ... ok
test_balance_characters_between_line_wraps_starting_with_comment (semantic_linefeed_unit_tests.LineBalancingUnitTests) ... ok
test_balance_characters_between_line_wraps_with_big_multi_line_balancing (semantic_linefeed_unit_tests.LineBalancingUnitTests) ... ok
test_balance_characters_between_line_wraps_with_comment_indentation_balance (semantic_linefeed_unit_tests.LineBalancingUnitTests) ... ok
test_balance_characters_between_line_wraps_with_long_subsequent_indentation (semantic_linefeed_unit_tests.LineBalancingUnitTests) ... ok
test_balance_characters_between_line_wraps_with_trailing_new_line (semantic_linefeed_unit_tests.LineBalancingUnitTests) ... ok
test_balance_characters_between_line_wraps_without_trailing_new_line (semantic_linefeed_unit_tests.LineBalancingUnitTests) ... ok
test_calculate_lines_count_with_maximum_lines_indent (semantic_linefeed_unit_tests.LineBalancingUnitTests) ... ok
test_calculate_lines_count_with_minimum_lines_indent (semantic_linefeed_unit_tests.LineBalancingUnitTests) ... ok
test_calculate_lines_count_with_only_one_line (semantic_linefeed_unit_tests.LineBalancingUnitTests) ... ok
test_split_lines_with_long_subsequent_indentation (semantic_linefeed_unit_tests.LineBalancingUnitTests) ... ok
test_split_lines_with_trailing_new_line (semantic_linefeed_unit_tests.LineBalancingUnitTests) ... ok
test_split_lines_with_very_long_line_and_word (semantic_linefeed_unit_tests.LineBalancingUnitTests) ... ok
test_split_lines_without_trailing_new_line (semantic_linefeed_unit_tests.LineBalancingUnitTests) ... ok
test_is_command_separated_list_2_items (semantic_linefeed_unit_tests.SemanticLineWrapUnitTests) ... ok
test_is_command_separated_list_3_items (semantic_linefeed_unit_tests.SemanticLineWrapUnitTests) ... ok
test_is_command_separated_list_4_items (semantic_linefeed_unit_tests.SemanticLineWrapUnitTests) ... ok
test_is_command_separated_list_5_items (semantic_linefeed_unit_tests.SemanticLineWrapUnitTests) ... ok
test_is_command_separated_list_lowerbound_with_1_items (semantic_linefeed_unit_tests.SemanticLineWrapUnitTests) ... ok
test_is_command_separated_list_lowerbound_with_2_items (semantic_linefeed_unit_tests.SemanticLineWrapUnitTests) ... ok
test_is_command_separated_list_lowerbound_with_3_items (semantic_linefeed_unit_tests.SemanticLineWrapUnitTests) ... ok
test_is_command_separated_list_lowerbound_with_trailing_1_space (semantic_linefeed_unit_tests.SemanticLineWrapUnitTests) ... ok
test_is_command_separated_list_lowerbound_with_trailing_2_space (semantic_linefeed_unit_tests.SemanticLineWrapUnitTests) ... ok
test_is_command_separated_list_upperbound_2_by_4_trailing_items (semantic_linefeed_unit_tests.SemanticLineWrapUnitTests) ... ok
test_is_command_separated_list_upperbound_with_1_by_5_trailing_items (semantic_linefeed_unit_tests.SemanticLineWrapUnitTests) ... ok
test_is_command_separated_list_upperbound_with_2_by_5_trailing_items (semantic_linefeed_unit_tests.SemanticLineWrapUnitTests) ... ok
test_is_command_separated_list_upperbound_with_4_middle_items (semantic_linefeed_unit_tests.SemanticLineWrapUnitTests) ... ok
test_semantic_line_wrap_ending_with_comma_list (semantic_linefeed_unit_tests.SemanticLineWrapUnitTests) ... ok
test_semantic_line_wrap_ending_with_trailling_comma_on_list (semantic_linefeed_unit_tests.SemanticLineWrapUnitTests) ... ok
test_semantic_line_wrap_long_word (semantic_linefeed_unit_tests.SemanticLineWrapUnitTests) ... ok
test_semantic_line_wrap_simple_sentence (semantic_linefeed_unit_tests.SemanticLineWrapUnitTests) ... ok
test_semantic_line_wrap_simple_sentence_with_dual_comma (semantic_linefeed_unit_tests.SemanticLineWrapUnitTests) ... ok
test_semantic_line_wrap_simple_sentence_with_dual_comma_with_3_items_minimum (semantic_linefeed_unit_tests.SemanticLineWrapUnitTests) ... ok
test_semantic_line_wrap_simple_sentence_with_single_comma (semantic_linefeed_unit_tests.SemanticLineWrapUnitTests) ... ok
test_semantic_line_wrap_with_0_items_list (semantic_linefeed_unit_tests.SemanticLineWrapUnitTests) ... ok
test_semantic_line_wrap_with_3_items_list (semantic_linefeed_unit_tests.SemanticLineWrapUnitTests) ... ok
test_semantic_line_wrap_with_79_characters (semantic_linefeed_unit_tests.SemanticLineWrapUnitTests) ... ok
test_semantic_line_wrap_with_80_characters (semantic_linefeed_unit_tests.SemanticLineWrapUnitTests) ... ok
test_semantic_line_wrap_with_81_characters (semantic_linefeed_unit_tests.SemanticLineWrapUnitTests) ... ok
test_semantic_line_wrap_with_81_characters_on_list_flushing (semantic_linefeed_unit_tests.SemanticLineWrapUnitTests) ... ok
test_semantic_line_wrap_with_comma_list_on_the_end (semantic_linefeed_unit_tests.SemanticLineWrapUnitTests) ... ok
test_semantic_line_wrap_with_comma_list_on_the_middle (semantic_linefeed_unit_tests.SemanticLineWrapUnitTests) ... ok
test_semantic_line_wrap_with_initial_indentation (semantic_linefeed_unit_tests.SemanticLineWrapUnitTests) ... ok
test_semantic_line_wrap_with_long_word_at_comma_list_end (semantic_linefeed_unit_tests.SemanticLineWrapUnitTests) ... ok
test_semantic_line_wrap_with_numeric_comma_list_on_the_end (semantic_linefeed_unit_tests.SemanticLineWrapUnitTests) ... ok
test_double_quotes_wrappting (text_extraction_unit_tests.PrefixStrippingViewUnitTests) ... ok
test_double_quotes_wrappting_without_leading_whitespace (text_extraction_unit_tests.PrefixStrippingViewUnitTests) ... ok
test_triple_quotes_comment (text_extraction_unit_tests.PrefixStrippingViewUnitTests) ... ok
test_triple_quotes_wrappting (text_extraction_unit_tests.PrefixStrippingViewUnitTests) ... ok
test_triple_quotes_wrappting_without_leading_whitespace (text_extraction_unit_tests.PrefixStrippingViewUnitTests) ... ok
----------------------------------------------------------------------
Ran 51 tests in 0.169s
OK
UnitTesting: Done.
EDIT: I just realized that you were talking about a different package.
I checked out https://github.com/evandrocoan/ClearCursorsCarets and UnitTesting was also working.
................
----------------------------------------------------------------------
Ran 16 tests in 0.133s
OK
UnitTesting: Done.
I see what's going on now. You were trying to use relative import from .utilities import BasicSublimeTextViewTestCase
. However, the tests was not imported as module so relative import is not possible. (You gave too much information so I missed it).
You could move the files into a folder with __init__.py
. In this way, the tests will be imported as a module. Check https://github.com/divmain/GitSavvy/tree/master/tests/test_git as an example.
But I am doing this already have then in a folder with __init__.py
and if I use from . import utilities
I got this error:
However, If I do:
CURRENT_DIRECTORY = os.path.dirname( os.path.dirname( os.path.realpath( __file__ ) ) )
CURRENT_PACKAGE_NAME = os.path.basename( CURRENT_DIRECTORY ).rsplit('.', 1)[0]
utilities = importlib.import_module( CURRENT_PACKAGE_NAME + ".tests.utilities" )
It does work:
This is my unittesting.json
file:
{
"tests_dir" : "tests",
"pattern" : "*unit_tests.py",
"async": false,
"deferred": false,
"verbosity": 1,
"capture_console": true,
"output": null
}
The differences I see from that example is the unittesting.json
which is almost empty:
{
"deferred": true,
"capture_console": true
}
And that the tests which does relative import are inside a folder called tests_git
with a __init__.py
and everything starts with the name test_
. On my project I set the "pattern" : "*unit_tests.py",
so I expect the test files to end with unit_tests.py
.
Am I required to move everything to another folder inside the tests folder with a __init__.py
, then the relative import will start working? But I wonder why I need to create another folder inside the tests folder for the from . import BasicSublimeTextViewTestCase
to work.
Unittesting only imports directories under tests as modules, so you have to put it under /tests/testsomrthingelse/
. In fact, the top level __init__.py
is never used.
I may look into the possibility to import tests
as a module.
Edit: it seems that it requires quite some work based on the unittest
’s discover
function. I don’t expect to see it soon.
Hopefully this can be fixed as part of #155.
I am not sure how easy or how hard it would be done. It seems that unittest.discover
doesn't try to import the starting directory as a module.
Yeah, the default implementation of discover
is a bit screwy. It patches sys.path
and does other weird stuff. For UnitTesting, we can guarantee that tests will always be inside a package that is already loaded or loadable (with some caveats around dependencies). This should let us use a simpler approach that behaves more predictably.
If we specify start_dir = 'PATH TO PACKAGE'
rather than start_dir = 'PATH TO PACKAGE/tests'
, it should theoretically import tests
module as a package if a __init__.py
is found. But then it will run into a danger that for example a file testsomething.py
under PACKAGE/src/
may be wrongly classified as a test file.
Could we just pass start_dir='PATH TO PACKAGE/tests', top_level_dir='PATH TO PACKAGE'
? I haven't tried it out, and my understanding of the overcomplicated default loader logic is incomplete, but it seems like this may be what it's for.
It would work only if there is a __init__.py
under tests
so it will break a lot of current users of UnitTesting.
Hopefully the next update will handle it.