Repository: adamchainz/django-mysql

Issue:
subprocess imports (PIPE, Popen, etc).
Summary: Subprocess imports throw an error on some architectures

Django Version: Django 1.11.1
Database and version used: CloudSQL MySQL 5.7
Version: Django-MySQL 2.1.0
Python version: 2.7 (GoogleAppEngine)

When deploying on certain cloud architectures (here Google App Engine), the valid way to use subprocess is to do a global import:

`import subprocess`

And then later utilize the imported namespace:

`subprocess.PIPE`

I am happy to send a patch if this is useful for you. For now I have modified my deployed code as a workaround. Thanks for creating a useful library!


Discussion:
Yes please make a PR :)

That's pretty evil of them to break the namespace like that. Have you got a docs link?
Ya, took a lot of head scratching to figure out. There is no documentation about it per se. Just a lot of StackOverflow questions like this one: https://stackoverflow.com/questions/40489794/importerror-cannot-import-name-popen-google-app-engine-deployment-error  :disappointed: 

I'll send a PR later today. Thanks again for a really neat library! :smile: 

Resolving patch:
diff --git a/django_mysql/models/query.py b/django_mysql/models/query.py
--- a/django_mysql/models/query.py
+++ b/django_mysql/models/query.py
@@ -4,11 +4,11 @@
 )
 
 import operator
+import subprocess
 import sys
 import time
 from copy import copy
 from functools import wraps
-from subprocess import PIPE, Popen
 
 import django
 from django.conf import settings
@@ -638,11 +638,11 @@ def pt_visual_explain(queryset, display=True):
         settings_to_cmd_args(connection.settings_dict) +
         ['-e', explain_query]
     )
-    mysql = Popen(mysql_command, stdout=PIPE)
-    visual_explain = Popen(
+    mysql = subprocess.Popen(mysql_command, stdout=subprocess.PIPE)
+    visual_explain = subprocess.Popen(
         ['pt-visual-explain', '-'],
         stdin=mysql.stdout,
-        stdout=PIPE
+        stdout=subprocess.PIPE
     )
     mysql.stdout.close()
     explanation = visual_explain.communicate()[0].decode(encoding="utf-8")
diff --git a/django_mysql/utils.py b/django_mysql/utils.py
--- a/django_mysql/utils.py
+++ b/django_mysql/utils.py
@@ -4,10 +4,10 @@
 )
 
 import os
+import subprocess
 import time
 from collections import defaultdict
 from contextlib import contextmanager
-from subprocess import PIPE, Popen, call
 from threading import Lock, Thread
 from weakref import WeakKeyDictionary
 
@@ -157,7 +157,8 @@ def settings_to_cmd_args(settings_dict):
 def have_program(program_name):
     global programs_memo
     if program_name not in programs_memo:
-        status = call(['which', program_name], stdout=PIPE)
+        status = subprocess.call(['which', program_name],
+                                 stdout=subprocess.PIPE)
         programs_memo[program_name] = (status == 0)
 
     return programs_memo[program_name]
@@ -223,9 +224,9 @@ def run(self):
 
         global fingerprint_thread
         master, slave = pty.openpty()
-        proc = Popen(
+        proc = subprocess.Popen(
             ['pt-fingerprint'],
-            stdin=PIPE,
+            stdin=subprocess.PIPE,
             stdout=slave,
             close_fds=True
         )


Test patch: