Repository: Pyomo/pyomo

Issue:
Pyomo 5.6 installation fails on Windows
Hi,

It appears Pyomo 5.6 installation fails on Windows (7, at least) as the installation requires Visual Studio C++, due to Cython code. If I hack setup.py setting using_cython=False, then installation is successful.

I believe assuming Cython will work "out of the box" on Windows is problematic. See
https://github.com/cython/cython/wiki/InstallingOnWindows

Can you please fix this?

Thanks.


Discussion:
Can you provide a little more context? What python interpreter are you using, and how are you installing Pyomo?  My understanding from looking at the `setup.py` is that installation should still proceed if either Cython is unavailable of a compilation step fails. 
Thanks for responding so quickly.

Anaconda Python 3.6.4. Installing Pyomo using pip 9.0.1. I think setup.py effectively checks if Cython is installed. This is not the problem as Cython is distributed with Anaconda and the cythonize function works fine. On Windows, you also need the correct C-compiler for Cython to work (as discussed in the above link). Here's the error:

"error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual C++ Build Tools": http://landinghub.visualstudio.com/visual-cpp-build-tools"

I haven't tried getting this version of Microsoft Visual C++.  

This issue does not occur on Linux and macOS.
I just checked: I already have Microsoft Visual C++ 14.
The install should still succeed, as the call to `cythonize` is within a try-except. Can you post the full error and stack trace?
I can't send you the full stack trace. A usual Python stack trace is not produced, and cythonize seems to work as usual. It's the C-compilation that's failing. Here's the full error:

Building wheels for collected packages: Pyomo
  Running setup.py bdist_wheel for Pyomo: started
  Running setup.py bdist_wheel for Pyomo: finished with status 'error'
  running build_ext
  building 'pyomo.core.expr.expr_pyomo5' extension
  error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual C++ Build Tools": http://landinghub.visualstudio.com/visual-cpp-build-tools
  
  ----------------------------------------
  Running setup.py clean for Pyomo
Failed to build Pyomo
    building 'pyomo.core.expr.expr_pyomo5' extension
    error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual C++ Build Tools": http://landinghub.visualstudio.com/visual-cpp-build-tools
    
    ----------------------------------------
  Rolling back uninstall of pyomo

Note that I already have Microsoft Visual C++ 14.

Resolving patch:
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -52,36 +52,57 @@ def read(*rnames):
 from setuptools import setup
 import sys
 
+CYTHON_REQUIRED = "required"
 if 'develop' in sys.argv:
     using_cython = False
 else:
-    using_cython = True
+    using_cython = "automatic"
 if '--with-cython' in sys.argv:
-    using_cython = True
+    using_cython = CYTHON_REQUIRED
     sys.argv.remove('--with-cython')
+if '--without-cython' in sys.argv:
+    using_cython = False
+    sys.argv.remove('--without-cython')
 
 ext_modules = []
 if using_cython:
     try:
         import platform
-        if not platform.python_implementation() == "CPython":
-            raise RuntimeError()
+        if platform.python_implementation() != "CPython":
+            # break out of this try-except (disable Cython)
+            raise RuntimeError("Cython is only supported under CPython")
         from Cython.Build import cythonize
         #
         # Note: The Cython developers recommend that you destribute C source
         # files to users.  But this is fine for evaluating the utility of Cython
         #
         import shutil
-        files = ["pyomo/core/expr/expr_pyomo5.pyx", "pyomo/core/expr/numvalue.pyx", "pyomo/core/util.pyx", "pyomo/repn/standard_repn.pyx", "pyomo/repn/plugins/cpxlp.pyx", "pyomo/repn/plugins/gams_writer.pyx", "pyomo/repn/plugins/baron_writer.pyx", "pyomo/repn/plugins/ampl/ampl_.pyx"]
+        files = [
+            "pyomo/core/expr/expr_pyomo5.pyx",
+            "pyomo/core/expr/numvalue.pyx",
+            "pyomo/core/util.pyx",
+            "pyomo/repn/standard_repn.pyx",
+            "pyomo/repn/plugins/cpxlp.pyx",
+            "pyomo/repn/plugins/gams_writer.pyx",
+            "pyomo/repn/plugins/baron_writer.pyx",
+            "pyomo/repn/plugins/ampl/ampl_.pyx",
+        ]
         for f in files:
             shutil.copyfile(f[:-1], f)
         ext_modules = cythonize(files)
     except:
+        if using_cython == CYTHON_REQUIRED:
+            print("""
+ERROR: Cython was explicitly requested with --with-cython, but cythonization
+       of core Pyomo modules failed.
+""")
+            raise
         using_cython = False
 
 packages = _find_packages('pyomo')
 
-setup(name='Pyomo',
+def run_setup():
+   setup(name='Pyomo',
       #
       # Note: trunk should have *next* major.minor
       #     VOTD and Final releases will have major.minor.revnum
@@ -115,6 +136,7 @@ def read(*rnames):
         'Programming Language :: Python :: 3.4',
         'Programming Language :: Python :: 3.5',
         'Programming Language :: Python :: 3.6',
+        'Programming Language :: Python :: 3.7',
         'Programming Language :: Python :: Implementation :: CPython',
         'Programming Language :: Python :: Implementation :: Jython',
         'Programming Language :: Python :: Implementation :: PyPy',
@@ -164,3 +186,34 @@ def read(*rnames):
         pyomo.results_schema=pyomo.scripting.commands
       """
       )
+
+try:
+    run_setup()
+except SystemExit as e_info:
+    # Cython can generate a SystemExit exception on Windows if the
+    # environment is missing / has an incorrect Microsoft compiler.
+    # Since Cython is not strictly required, we will disable Cython and
+    # try re-running setup(), but only for this very specific situation.
+    if 'Microsoft Visual C++' not in e_info.message:
+        raise
+    elif using_cython == CYTHON_REQUIRED:
+        print("""
+ERROR: Cython was explicitly requested with --with-cython, but cythonization
+       of core Pyomo modules failed.
+""")
+        raise
+    else:
+        print("""
+ERROR: setup() failed:
+    %s
+Re-running setup() without the Cython modules
+""" % (e_info.message,))
+        ext_modules = []
+        run_setup()
+        print("""
+WARNING: Installation completed successfully, but the attempt to cythonize
+         core Pyomo modules failed.  Cython provides performance
+         optimizations and is not required for any Pyomo functionality.
+         Cython returned the following error:
+   "%s"
+""" % (e_info.message,))


Test patch: