Repository: pysmt/pysmt
Pull request #406 (2017-05-02 09:08:36)

Fixed cyclic import errors
This PR addresses issue #405 .

I created a test that invokes the python interpreter and checks that each pysmt module (except the testing ones and the solvers) can be imported as a standalone (i.e. without previously importing something else).

In order for this test to work I had to move some imports of the environment module inside some functions, but I think this trade-off is acceptable.


Patch:
diff --git a/pysmt/fnode.py b/pysmt/fnode.py
index 91430cf..d0a9c19 100644
--- a/pysmt/fnode.py
+++ b/pysmt/fnode.py
@@ -17,7 +17,7 @@
 #
 """FNode are the building blocks of formulae."""
 import collections
-import pysmt.environment
+import pysmt
 import pysmt.smtlib
 from pysmt.operators import (FORALL, EXISTS, AND, OR, NOT, IMPLIES, IFF,
                              SYMBOL, FUNCTION,
diff --git a/pysmt/oracles.py b/pysmt/oracles.py
index c5f6bfa..814f967 100644
--- a/pysmt/oracles.py
+++ b/pysmt/oracles.py
@@ -23,9 +23,9 @@ properties of formulae.
  * FreeVarsOracle says which variables are free in the formula
 """
 
+import pysmt
 import pysmt.walkers
 import pysmt.operators as op
-import pysmt.environment
 
 from pysmt import typing as types
 
diff --git a/pysmt/typing.py b/pysmt/typing.py
index 10c5447..3967c6d 100644
--- a/pysmt/typing.py
+++ b/pysmt/typing.py
@@ -31,6 +31,7 @@ on a factory service. Each BitVector width is represented by a
 different instance of BVType.
 
 """
+import pysmt
 from pysmt.exceptions import PysmtValueError
 
 
@@ -497,8 +498,6 @@ class TypeManager(object):
 
 # EOC TypeManager
 
-import pysmt.environment
-
 
 def BVType(width=32):
     """Returns the BV type for the given width."""


Test patch:
diff --git a/pysmt/test/test_imports.py b/pysmt/test/test_imports.py
new file mode 100644
index 0000000..0512ed3
--- /dev/null
+++ b/pysmt/test/test_imports.py
@@ -0,0 +1,45 @@
+#
+# This file is part of pySMT.
+#
+#   Copyright 2014 Andrea Micheli and Marco Gario
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+#
+
+import sys
+import subprocess
+import pkgutil
+import os.path
+
+from pysmt.test import TestCase, main
+import pysmt
+
+
+class TestImports(TestCase):
+
+    EXCLUSION_LIST = ["pysmt.test", "pysmt.solvers", "pysmt.cmd"]
+
+    def test_imports(self):
+        stack = [(pysmt.__name__, pysmt.__path__)]
+        while stack:
+            module_name, module_path = stack.pop()
+            for _, name, ispkg in pkgutil.iter_modules(module_path):
+                fullname = "%s.%s" % (module_name, name)
+                command = [sys.executable, '-c', 'import %s' % fullname]
+                returncode = subprocess.call(command)
+                self.assertEqual(returncode, 0, msg="Failed to import %s module" % fullname)
+                if ispkg and fullname not in TestImports.EXCLUSION_LIST:
+                    stack.append((fullname, [os.path.join(p, name) for p in module_path]))
+
+if __name__ == '__main__':
+    main()