Repository: cocotb/cocotb

Issue:
AttributeError: 'RegressionManager' object has no attribute 'TestFactory'
I have the following code:
```
#!/usr/bin/env python
import cocotb
import cocotb.regression
import cocotb.triggers


@cocotb.coroutine
def test_adder(dut, val_a, val_b):
    dut.a = val_a
    dut.b = val_b
    yield cocotb.triggers.Timer(10, 'ns')
    assert dut.z == val_a + val_b


test_factory = cocotb.regression.TestFactory(test_adder)
test_factory.add_option('val_a', range(16))
test_factory.add_option('val_b', range(16))
test_factory.generate_tests()
```
that fails with this error
```
$ COCOTB=$(cocotb-config --share) make
make results.xml
make[1]: Entering directory '/home/killruana/dev/cocostb_eval/adder'
PYTHONPATH=/home/killruana/dev/cocostb_eval/adder/build/libs/x86_64:/home/killruana/dev/cocostb_eval/adder:/home/killruana/dev/cocostb_eval/venv/lib/python3.7/site-packages: LD_LIBRARY_PATH=/home/killruana/dev/cocostb_eval/adder/build/libs/x86_64::/usr/lib:/usr/lib:/usr/lib:/usr/lib MODULE=test_adder   \
        TESTCASE= TOPLEVEL=Adder   TOPLEVEL_LANG= COCOTB_SIM=1 \
        /usr/bin/vvp -M /home/killruana/dev/cocostb_eval/adder/build/libs/x86_64 -m gpivpi sim_build/sim.vvp   
     -.--ns INFO     cocotb.gpi                                  gpi_embed.c:103  in embed_init_python               Using virtualenv at /home/killruana/dev/cocostb_eval/venv/bin/python.
     -.--ns INFO     cocotb.gpi                                GpiCommon.cpp:91   in gpi_print_registered_impl       VPI registered
    0.00ns INFO     cocotb.gpi                                  gpi_embed.c:278  in embed_sim_init                  Running on Icarus Verilog version 10.1 (stable)
    0.00ns INFO     cocotb.gpi                                  gpi_embed.c:279  in embed_sim_init                  Python interpreter initialised and cocotb loaded!
    0.00ns INFO     cocotb                                      __init__.py:131  in _initialise_testbench           Running tests with Cocotb v1.2.dev1 from /home/killruana/dev/cocostb_eval/venv/lib/python3.7/site-packages
    0.00ns INFO     cocotb                                      __init__.py:147  in _initialise_testbench           Seeding Python random module with 1552646051
    0.00ns CRITICAL cocotb.regression                         regression.py:135  in initialise                      Failed to import module test_adder: 'RegressionManager' object has no attribute 'TestFactory'
    0.00ns INFO     cocotb.regression                         regression.py:136  in initialise                      MODULE variable was "test_adder"
    0.00ns INFO     cocotb.regression                         regression.py:137  in initialise                      Traceback: 
    0.00ns INFO     cocotb.regression                         regression.py:138  in initialise                      Traceback (most recent call last):
                                                                                                                      File "/home/killruana/dev/cocostb_eval/venv/lib/python3.7/site-packages/cocotb/regression.py", line 133, in initialise
                                                                                                                        module = _my_import(module_name)
                                                                                                                      File "/home/killruana/dev/cocostb_eval/venv/lib/python3.7/site-packages/cocotb/regression.py", line 63, in _my_import
                                                                                                                        mod = __import__(name)
                                                                                                                      File "/home/killruana/dev/cocostb_eval/adder/test_adder.py", line 14, in <module>
                                                                                                                        test_factory = cocotb.regression.TestFactory(test_adder)
                                                                                                                    AttributeError: 'RegressionManager' object has no attribute 'TestFactory'
                                                                                                                    
Traceback (most recent call last):
  File "/home/killruana/dev/cocostb_eval/venv/lib/python3.7/site-packages/cocotb/__init__.py", line 167, in _initialise_testbench
    regression.initialise()
  File "/home/killruana/dev/cocostb_eval/venv/lib/python3.7/site-packages/cocotb/regression.py", line 133, in initialise
    module = _my_import(module_name)
  File "/home/killruana/dev/cocostb_eval/venv/lib/python3.7/site-packages/cocotb/regression.py", line 63, in _my_import
    mod = __import__(name)
  File "/home/killruana/dev/cocostb_eval/adder/test_adder.py", line 14, in <module>
    test_factory = cocotb.regression.TestFactory(test_adder)
AttributeError: 'RegressionManager' object has no attribute 'TestFactory'
Cocotb initialisation failed - exiting
    0.00ns ERROR    cocotb.scheduler                            __init__.py:190  in _sim_event                      Failing test at simulator request before test run completion: Simulator shutdown prematurely
    0.00ns ERROR    cocotb.gpi                                  gpi_embed.c:379  in embed_sim_event                 Passing event to upper layer failed
    0.00ns ERROR    cocotb.scheduler                            __init__.py:190  in _sim_event                      Failing test at simulator request before test run completion: Simulator shutdown prematurely
make[1]: Leaving directory '/home/killruana/dev/cocostb_eval/adder'
```


Discussion:

Resolving patch:
diff --git a/cocotb/__init__.py b/cocotb/__init__.py
--- a/cocotb/__init__.py
+++ b/cocotb/__init__.py
@@ -85,7 +85,7 @@
 
 
 scheduler = Scheduler()
-regression = None
+regression_manager = None
 
 plusargs = {}
 
@@ -161,11 +161,11 @@ def _initialise_testbench(root_name):
     modules = module_str.split(',')
     hooks = hooks_str.split(',') if hooks_str else []
 
-    global regression
+    global regression_manager
 
-    regression = RegressionManager(root_name, modules, tests=test_str, seed=seed, hooks=hooks)
-    regression.initialise()
-    regression.execute()
+    regression_manager = RegressionManager(root_name, modules, tests=test_str, seed=seed, hooks=hooks)
+    regression_manager.initialise()
+    regression_manager.execute()
 
     _rlock.release()
     return True
diff --git a/cocotb/regression.py b/cocotb/regression.py
--- a/cocotb/regression.py
+++ b/cocotb/regression.py
@@ -304,7 +304,7 @@ def _result_was():
         self.execute()
 
     def execute(self):
-        self._running_test = cocotb.regression.next_test()
+        self._running_test = cocotb.regression_manager.next_test()
         if self._running_test:
             start = ''
             end   = ''
diff --git a/cocotb/scheduler.py b/cocotb/scheduler.py
--- a/cocotb/scheduler.py
+++ b/cocotb/scheduler.py
@@ -309,7 +309,7 @@ def begin_test(self, trigger=None):
             if self._test_result is not None:
                 if _debug:
                     self.log.debug("Issue test result to regression object")
-                cocotb.regression.handle_result(self._test_result)
+                cocotb.regression_manager.handle_result(self._test_result)
                 self._test_result = None
             if self._entrypoint is not None:
                 test = self._entrypoint
@@ -732,7 +732,7 @@ def finish_scheduler(self, test_result):
            once we return the sim will close us so no cleanup is needed.
         """
         self.log.debug("Issue sim closedown result to regression object")
-        cocotb.regression.handle_result(test_result)
+        cocotb.regression_manager.handle_result(test_result)
 
     def cleanup(self):
         """Clear up all our state.


Test patch:
diff --git a/tests/test_cases/issue_857/Makefile b/tests/test_cases/issue_857/Makefile
new file mode 100644
--- /dev/null
+++ b/tests/test_cases/issue_857/Makefile
@@ -0,0 +1,31 @@
+###############################################################################
+# Copyright (c) 2015 Potential Ventures Ltd
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in the
+#       documentation and/or other materials provided with the distribution.
+#     * Neither the name of Potential Ventures Ltd,
+#       names of its contributors may be used to endorse or promote products
+#       derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL POTENTIAL VENTURES LTD BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+###############################################################################
+
+
+include ../../designs/sample_module/Makefile
+
+MODULE = issue_857
diff --git a/tests/test_cases/issue_857/issue_857.py b/tests/test_cases/issue_857/issue_857.py
new file mode 100644
--- /dev/null
+++ b/tests/test_cases/issue_857/issue_857.py
@@ -0,0 +1,29 @@
+import cocotb
+import cocotb.regression
+import cocotb.triggers
+
+
+@cocotb.coroutine
+def dummy_coroutine(dut):
+    yield cocotb.triggers.Timer(10, "ns")
+
+
+# Try to instantiate the TestFactory class using its full specifier name.
+#
+# In issue #857, a global variable named "regression" in the cocotb module hide
+# the module cocotb.regression, so the TestFactory class is not accessible with
+# an import like
+#
+# >>> import cocotb.regression
+# >>> factory = cocotb.regression.FactoryManager()
+#
+# The class is still accessible by an import like
+#
+# >>> from cocotb.regression import TestFactory
+# >>> factory = TestFactory()
+#
+# but the discoverer of the bug prefers the former approach.
+#
+# And in general, it's probably a good idea to not have name conflicts ;)
+test_factory = cocotb.regression.TestFactory(dummy_coroutine)
+test_factory.generate_tests()