Repository: numba/numba

Issue:
Numba reassigns sys.stdout
<!--

Thanks for opening an issue! To help the Numba team handle your information
efficiently, please first ensure that there is no other issue present that
already describes the issue you have
(search at https://github.com/numba/numba/issues?&q=is%3Aissue).

If there is no issue present please jump to a section below and delete the
irrelevant one depending on whether you are:

 * Making a feature request.
 * Reporting a bug.

For more general "how do I do X?" type questions, please speak to us in real
time on https://gitter.im/numba/numba or post to the Numba mailing list
https://groups.google.com/a/continuum.io/forum/#!forum/numba-users.

-->



## Reporting a bug

<!--

Before submitting a bug report please ensure that you can check off these boxes:

-->

- [*] I am using the latest released version of Numba (most recent is visible in
 the change log (https://github.com/numba/numba/blob/master/CHANGE_LOG).
- [*] I have included below a minimal working reproducer (if you are unsure how
 to write one see http://matthewrocklin.com/blog/work/2018/02/28/minimal-bug-reports).


```
import sys
import numba


@numba.njit
def f0(a,b):
  return a+b


@numba.njit
def f1(begin1, end1, begin2, end2):
  if begin1 > begin2: return f1(begin2, end2, begin1, end1)
  return end1 + 1 >= begin2

sys.api_version, sys.stdout = 12345, None


print>>sys.stderr, sys.api_version, sys.stdout  # 12345, None
f0(0,1)      # Does not reassign stdout
print>>sys.stderr, sys.api_version, sys.stdout  # 12345, None
f1(0,1,2,3)  # Reassigned stdout
print>>sys.stderr, sys.api_version, sys.stdout  # 12345, file object


assert sys.api_version == 12345  # Pass. From which we can infer reload was not called
assert sys.stdout is None  # Fail. sys.stdout was assigned and not reset.
```

I came across this because it breaks the IntelliJ unittest runner (which sets sys.stdout before numba), like so: https://youtrack.jetbrains.com/issue/PY-23940 , which causes and exception after running unit tests.

It would be more friendly if numba didn't poke at sys.

Seen in: numba==0.38.1


Discussion:
Thanks for the report. I've tried this on Python 3 and Python 2 and can't reproduce. Just doing `conda create -n foo_pyversion numba python=version`, then running the example. Which OS are you trying this on? Is there anything else you think that might be special about your set up that could be influencing such behaviours?

We try very hard not to have interesting installations.

```
Ubuntu 14.04
Python 2.7.6
numba==0.38.1
llvmlite==0.23.2
```

Full pip:
```
% pip freeze 
acme==0.17.0
apispec==0.35.0
appdirs==1.4.3
apt-xapian-index==0.45
argcomplete==0.8.4
awscli==1.10.45
backports-abc==0.5
backports.functools-lru-cache==1.5
backports.shutil-get-terminal-size==1.0.0
backports.ssl-match-hostname==3.5.0.1
beautifulsoup4==4.2.1
bencode==1.0
bleach==2.0.0
boto==2.0
boto3==1.4.7
botocore==1.7.35
certbot==0.17.0
certifi==2017.4.17
cffi==1.7.0
chardet==3.0.4
chromedriver-binary==2.36.0
click==6.7
colorama==0.2.5
command-not-found==0.3
ConfigArgParse==0.11.0
configobj==5.0.6
configparser==3.5.0
cryptography==1.7.2
csvdiff==0.3.3
cvxopt==1.1.4
cycler==0.10.0
Cython==0.27.3
cytoolz==0.8.2
tory=dataIngest
debtagshw==0.1
decorator==4.0.11
defer==1.0.6
dill==0.2.7.1
dirspec==13.10
dnspython==1.15.0
docutils==0.12
ecdsa==0.13
entrypoints==0.2.2
enum34==1.1.6
Flask==0.12.2
flask-apispec==0.6.0.post0
Flask-Compress==1.4.0
Flask-Cors==3.0.3
Flask-Script==2.0.6
flask-swagger-ui==3.6.0
Flask-Testing==0.7.1
funcsigs==1.0.2
functools32==3.2.3.post2
future==0.16.0
futures==3.0.5
fuzzywuzzy==0.14.0
gprof2dot==2016.10.13
gyp==0.1
html5lib==0.999999999
httplib2==0.8
hyperopt==0.0.2
idna==2.5
imbalanced-learn==0.1.8
imblearn==0.0
ipaddress==1.0.16
ipykernel==4.6.1
ipython==5.3.0
ipython-genutils==0.2.0
ipywidgets==6.0.0
itsdangerous==0.24
jedi==0.9.0
Jinja2==2.9.6
jmespath==0.9.0
joblib==0.11
jsonschema==2.6.0
jupyter==1.0.0
jupyter-client==5.0.1
jupyter-console==5.1.0
jupyter-core==4.3.0
jwt==0.5.2
Keras==2.0.3
language-tags==0.4.3
lifelines==0.9.4
llvmlite==0.23.2
lxml==3.3.3
Markdown==2.6.11
MarkupSafe==1.0
marshmallow==3.0.0b8
matplotlib==2.1.0
mistune==0.7.4
mock==2.0.0
multiprocess==0.70.4
MySQL-python==1.2.3
nbconvert==5.1.1
nbformat==4.3.0
ndg-httpsclient==0.4.2
networkx==1.11
nose==1.3.7
notebook==5.0.0
numba==0.38.1
numexpr==2.6.2
numpy==1.14.0
oauthlib==0.6.1
oneconf==0.3.7.14.4.1
openpyxl==1.7.0
packaging==16.8
PAM==0.4.2
pandas==0.22.0
pandocfilters==1.4.1
paramiko==1.15.1
parsedatetime==2.1
pathlib2==2.1.0
patsy==0.2.1
pbr==3.0.0
pexpect==4.2.1
pickleshare==0.7.4
pika==0.11.2
pika-pool==0.1.3
Pillow==2.3.0
piston-mini-client==0.7.5
progressbar2==3.34.3
prompt-toolkit==1.0.14
protobuf==3.2.0
psutil==5.3.1
psycopg2==2.7.3.2
psycopg2-binary==2.7.4
ptyprocess==0.5.1
py4j==0.10.4
pyasn1==0.1.9
pycparser==2.14
pycrypto==2.6.1
pycups==1.9.66
pycurl==7.19.3
pydot==1.2.3
pyfscache==0.9.12
pygam==0.3.0
Pygments==2.2.0
pygobject==3.12.0
pygraphviz==1.3.1
pyhocon==0.3.33
PyICU==1.5
PyJWT==1.5.3
pymongo==3.3.0
pyOpenSSL==17.0.0
pyorient==1.5.4
pyparsing==2.2.0
pyreadline==2.1
pyRFC3339==1.0
pyserial==2.6
pysmbc==1.0.14.1
pyspark==2.1.0+hadoop2.7
pysphere==0.1.7
python-apt===0.9.3.5ubuntu2
python-dateutil==2.6.0
python-debian===0.1.21-nmu2ubuntu2
python-utils==2.2.0
python2-pythondialog==3.3.0
pytz==2016.10
pyxdg==0.25
PyYAML==3.10
pyzmq==16.0.2
qtconsole==4.3.0
readline==6.2.4.1
redis==2.10.6
reportlab==3.0
requests==2.18.1
rsa==3.4.2
s3transfer==0.1.13
scandir==1.5
scikit-learn==0.19.1
scipy==1.0.0
selenium==3.11.0
sessioninstaller==0.0.0
simplegeneric==0.8.1
simplejson==3.13.2
singledispatch==3.4.0.3
six==1.11.0
snakeviz==0.4.1
software-center-aptd-plugins==0.0.0
SQLAlchemy==1.2.7
ssh-import-id==3.21
statsmodels==0.8.0
subprocess32==3.2.7
sympy==0.7.4.1
tables==3.1.1
tensorflow==1.1.0
terminado==0.6
testpath==0.3
Theano==0.9.0
toolz==0.8.2
tornado==4.5.1
traitlets==4.3.2
Twisted-Core==13.2.0
Twisted-Web==13.2.0
typing==3.5.3.0
urllib3==1.21.1
version==0.1.1
virtualenv==1.11.4
wcwidth==0.1.7
webargs==1.8.1
webencodings==0.5.1
Werkzeug==0.12.1
widgetsnbextension==2.0.0
xgboost==0.7.post3
xlrd==0.9.2
xlwt==0.7.5
zope.component==4.3.0
zope.event==4.0.1
zope.hookable==4.0.4
zope.interface==4.3.2
```
PS ... I haven't been able able to confirm that reload is the cause - I don't see how its possible know if reload was called (variables assigned to a module namespace survive the reload, except if they're reinitialized by the module itself):
```
import sys
sys.stdout = None
sys.zzz = 123
sys = reload(sys)
sys.stderr.write("sys.stdout = {}\n".format(sys.stdout)) # Reset to file object
sys.stderr.write("sys.zzz = {}\n".format(sys.zzz)) # Surprise success!
sys.stderr.flush()
```

It could be something's directly assigning to sys.stdout/err, or that reload(sys) is called.
OK -- I've updated the example in the original question and discovered:

 - sys.stdout is assigned to. reload(sys) is not called, otherwise it would have reset sys.api_version
 - the problem only happens for the recursive call

Weird.
Yeah, this is very weird.  We do some manipulation of sys.stdout in our unit testing code in order to capture printed output, but it isn't obvious to me where this happens in the Numba code itself.
I still cannot reproduce this.

Log from trying with an install from `Anaconda`:

<details>

```
$ cat issue3027.py 
import sys
import numba


@numba.njit
def f0(a,b):
  return a+b


@numba.njit
def f1(begin1, end1, begin2, end2):
  if begin1 > begin2: return f1(begin2, end2, begin1, end1)
  return end1 + 1 >= begin2

sys.api_version, sys.stdout = 12345, None


print>>sys.stderr, sys.api_version, sys.stdout  # 12345, None
f0(0,1)      # Does not reassign stdout
print>>sys.stderr, sys.api_version, sys.stdout  # 12345, None
f1(0,1,2,3)  # Reassigned stdout
print>>sys.stderr, sys.api_version, sys.stdout  # 12345, file object


assert sys.api_version == 12345  # Pass. From which we can infer reload was not called
assert sys.stdout is None  # Fail. sys.stdout was assigned and not reset.

$ conda create -n issue3027 python=2 numba -y -q
Solving environment: ...working... done

## Package Plan ##

  environment location: <path>/anaconda3/envs/issue3027

  added / updated specs: 
    - numba
    - python=2


The following packages will be downloaded:

    package                    |            build
    ---------------------------|-----------------
    numpy-1.14.5               |   py27hcd700cb_0          94 KB
    numpy-base-1.14.5          |   py27hdbf6ddf_0         4.1 MB
    ------------------------------------------------------------
                                           Total:         4.2 MB

The following NEW packages will be INSTALLED:

    blas:            1.0-mkl                
    ca-certificates: 2018.03.07-0           
    certifi:         2018.4.16-py27_0       
    enum34:          1.1.6-py27h99a27e9_1   
    funcsigs:        1.0.2-py27h83f16ab_0   
    intel-openmp:    2018.0.3-0             
    libedit:         3.1.20170329-h6b74fdf_2
    libffi:          3.2.1-hd88cf55_4       
    libgcc-ng:       7.2.0-hdf63c60_3       
    libgfortran-ng:  7.2.0-hdf63c60_3       
    libstdcxx-ng:    7.2.0-hdf63c60_3       
    llvmlite:        0.23.1-py27hdbcaa40_0  
    mkl:             2018.0.3-1             
    mkl_fft:         1.0.1-py27h3010b51_0   
    mkl_random:      1.0.1-py27h629b387_0   
    ncurses:         6.1-hf484d3e_0         
    numba:           0.38.0-py27h637b7d7_0  
    numpy:           1.14.5-py27hcd700cb_0  
    numpy-base:      1.14.5-py27hdbf6ddf_0  
    openssl:         1.0.2o-h20670df_0      
    pip:             10.0.1-py27_0          
    python:          2.7.15-h1571d57_0      
    readline:        7.0-ha6073c6_4         
    setuptools:      39.2.0-py27_0          
    singledispatch:  3.4.0.3-py27h9bcb476_0 
    six:             1.11.0-py27h5f960f1_1  
    sqlite:          3.23.1-he433501_0      
    tk:              8.6.7-hc745277_3       
    wheel:           0.31.1-py27_0          
    zlib:            1.2.11-ha838bed_2      

Preparing transaction: ...working... done
Verifying transaction: ...working... done
Executing transaction: ...working... done

$ source activate issue3027

(issue3027) 
$ python issue3027.py 
12345 None
12345 None
12345 None

```

</details>

And the same but installing from pip:

<details>

```
$ cat issue3027.py 
import sys
import numba


@numba.njit
def f0(a,b):
  return a+b


@numba.njit
def f1(begin1, end1, begin2, end2):
  if begin1 > begin2: return f1(begin2, end2, begin1, end1)
  return end1 + 1 >= begin2

sys.api_version, sys.stdout = 12345, None


print>>sys.stderr, sys.api_version, sys.stdout  # 12345, None
f0(0,1)      # Does not reassign stdout
print>>sys.stderr, sys.api_version, sys.stdout  # 12345, None
f1(0,1,2,3)  # Reassigned stdout
print>>sys.stderr, sys.api_version, sys.stdout  # 12345, file object


assert sys.api_version == 12345  # Pass. From which we can infer reload was not called
assert sys.stdout is None  # Fail. sys.stdout was assigned and not reset.

$ conda create -n issue3027_pip python=2 -y -q
Solving environment: ...working... done

## Package Plan ##

  environment location: <path>/anaconda3/envs/issue3027_pip

  added / updated specs: 
    - python=2


The following NEW packages will be INSTALLED:

    ca-certificates: 2018.03.07-0           
    certifi:         2018.4.16-py27_0       
    libedit:         3.1.20170329-h6b74fdf_2
    libffi:          3.2.1-hd88cf55_4       
    libgcc-ng:       7.2.0-hdf63c60_3       
    libstdcxx-ng:    7.2.0-hdf63c60_3       
    ncurses:         6.1-hf484d3e_0         
    openssl:         1.0.2o-h20670df_0      
    pip:             10.0.1-py27_0          
    python:          2.7.15-h1571d57_0      
    readline:        7.0-ha6073c6_4         
    setuptools:      39.2.0-py27_0          
    sqlite:          3.23.1-he433501_0      
    tk:              8.6.7-hc745277_3       
    wheel:           0.31.1-py27_0          
    zlib:            1.2.11-ha838bed_2      

Preparing transaction: ...working... done
Verifying transaction: ...working... done                                                                                       
Executing transaction: ...working... done                                                                                       
                                                                                                                                
$ source activate issue3027_pip                                                                                                 

(issue3027_pip)                                                                                                                 
$ pip install numba                                                                                                             
Collecting numba                                                                                                                
  Downloading https://files.pythonhosted.org/packages/4a/9c/6617f797227451a3878a357be6c338084232bf87d971c80bde45cb4952f9/numba-0.38.1-cp27-cp27mu-manylinux1_x86_64.whl (1.9MB)                                                                                 
    100% |████████████████████████████████| 1.9MB 1.7MB/s 
Collecting funcsigs (from numba)                                                                                                
  Downloading https://files.pythonhosted.org/packages/69/cb/f5be453359271714c01b9bd06126eaf2e368f1fddfff30818754b5ac2328/funcsigs-1.0.2-py2.py3-none-any.whl                                                                                                    
Collecting llvmlite>=0.23.0dev0 (from numba)                                                                                    
  Downloading https://files.pythonhosted.org/packages/61/53/64df44dd638d4424d83079365f94592dfacc83149ff2b386bc72f9fa84f1/llvmlite-0.23.2-cp27-cp27mu-manylinux1_x86_64.whl (15.8MB)                                                                             
    100% |████████████████████████████████| 15.8MB 824kB/s 
Collecting numpy (from numba)                                                                                                   
  Downloading https://files.pythonhosted.org/packages/6a/a9/c01a2d5f7b045f508c8cefef3b079fe8c413d05498ca0ae877cffa230564/numpy-1.14.5-cp27-cp27mu-manylinux1_x86_64.whl (12.1MB)                                                                                
    100% |████████████████████████████████| 12.1MB 1.0MB/s 
Collecting singledispatch (from numba)                                                                                          
  Downloading https://files.pythonhosted.org/packages/c5/10/369f50bcd4621b263927b0a1519987a04383d4a98fb10438042ad410cf88/singledispatch-3.4.0.3-py2.py3-none-any.whl                                                                                            
Collecting enum34 (from numba)                                                                                                  
  Downloading https://files.pythonhosted.org/packages/c5/db/e56e6b4bbac7c4a06de1c50de6fe1ef3810018ae11732a50f15f62c7d050/enum34-1.1.6-py2-none-any.whl                                                                                                          
Collecting six (from singledispatch->numba)                                                                                     
  Using cached https://files.pythonhosted.org/packages/67/4b/141a581104b1f6397bfa78ac9d43d8ad29a7ca43ea90a2d863fe3056e86a/six-1.11.0-py2.py3-none-any.whl                                                                                                       
Installing collected packages: funcsigs, enum34, llvmlite, numpy, six, singledispatch, numba                                    
Successfully installed enum34-1.1.6 funcsigs-1.0.2 llvmlite-0.23.2 numba-0.38.1 numpy-1.14.5 singledispatch-3.4.0.3 six-1.11.0  

(issue3027_pip)                                                                                                                 
$ python issue3027.py                                                                                                           
12345 None                                                                                                                      
12345 None                                                                                                                      
12345 None                                                                                                                      
```

</details>

@stuz5000 can you reproduce this using exactly what I've done or do you need that larger environment listed in https://github.com/numba/numba/issues/3027#issuecomment-396778163 ? Thanks.
Works fine in conda:
```
ubuntu@ip:$ curl -O https://repo.continuum.io/archive/Anaconda3-5.0.1-Linux-x86_64.sh
ubuntu@ip:$  bash Anaconda3-5.0.1-Linux-x86_64.sh
ubuntu@ip:$ source ~/.bashrc
ubuntu@ip:$ cat > issue3027.py 
import sys
import numba


@numba.njit
def f0(a,b):
  return a+b


@numba.njit
def f1(begin1, end1, begin2, end2):
  if begin1 > begin2: return f1(begin2, end2, begin1, end1)
  return end1 + 1 >= begin2

sys.api_version, sys.stdout = 12345, None


print>>sys.stderr, sys.api_version, sys.stdout  # 12345, None
f0(0,1)      # Does not reassign stdout
print>>sys.stderr, sys.api_version, sys.stdout  # 12345, None
f1(0,1,2,3)  # Reassigned stdout
print>>sys.stderr, sys.api_version, sys.stdout  # 12345, file object


assert sys.api_version == 12345  # Pass. From which we can infer reload was not called
assert sys.stdout is None  # Fail. sys.stdout was assigned and not reset.


ubuntu@ip:$  conda create -n issue3027 python=2 numba -y -q


Package plan for installation in environment /home/ubuntu/anaconda3/envs/issue3027:

The following NEW packages will be INSTALLED:

    blas:            1.0-mkl                
    ca-certificates: 2018.03.07-0           
    certifi:         2018.4.16-py27_0       
    enum34:          1.1.6-py27h99a27e9_1   
    funcsigs:        1.0.2-py27h83f16ab_0   
    intel-openmp:    2018.0.3-0             
    libedit:         3.1.20170329-h6b74fdf_2
    libffi:          3.2.1-hd88cf55_4       
    libgcc-ng:       7.2.0-hdf63c60_3       
    libgfortran-ng:  7.2.0-hdf63c60_3       
    libstdcxx-ng:    7.2.0-hdf63c60_3       
    llvmlite:        0.23.1-py27hdbcaa40_0  
    mkl:             2018.0.3-1             
    mkl_fft:         1.0.1-py27h3010b51_0   
    mkl_random:      1.0.1-py27h629b387_0   
    ncurses:         6.1-hf484d3e_0         
    numba:           0.38.0-py27h637b7d7_0  
    numpy:           1.14.5-py27hcd700cb_0  
    numpy-base:      1.14.5-py27hdbf6ddf_0  
    openssl:         1.0.2o-h20670df_0      
    pip:             10.0.1-py27_0          
    python:          2.7.15-h1571d57_0      
    readline:        7.0-ha6073c6_4         
    setuptools:      39.2.0-py27_0          
    singledispatch:  3.4.0.3-py27h9bcb476_0 
    six:             1.11.0-py27h5f960f1_1  
    sqlite:          3.23.1-he433501_0      
    tk:              8.6.7-hc745277_3       
    wheel:           0.31.1-py27_0          
    zlib:            1.2.11-ha838bed_2      



ubuntu@ip:$  source activate issue3027_pip 

CondaEnvironmentNotFoundError: Could not find environment: issue3027_pip .
You can list all discoverable environments with `conda info --envs`.


ubuntu@ip:$  conda info --envs
# conda environments:
#
issue3027                /home/ubuntu/anaconda3/envs/issue3027
root                  *  /home/ubuntu/anaconda3

ubuntu@ip:$  source activate /home/ubuntu/anaconda3/envs/issue3027 
(/home/ubuntu/anaconda3/envs/issue3027) ubuntu@ip:$   python2 issue3027.py
```


On the same host (outside of conda), and on another (on which only RabbitMQ was previously installed):

```
Welcome to Ubuntu 14.04.2 LTS (GNU/Linux 3.13.0-48-generic x86_64)

   sudo apt-get install python-pip python-dev
   sudo pip install pip==9.0.1
   sudo pip install numpy==1.14.0
   sudo pip install 'llvmlite==0.23.2'
   sudo pip install numba==0.38.1 
   python issue3027.py   # Fail
```

@stuartarchibald  -- I didn't see the second half of your conda instructions. Will try again.
Both the conda installs worked fine.
Updating the non-conda install to the same pip package versions as the conda install still fails.

```
   sudo apt-get install python-pip python-dev
   sudo pip install pip==9.0.1
   sudo pip install 'enum34==1.1.6' 'funcsigs==1.0.2' 'llvmlite==0.23.2' 'numba==0.38.1' 'numpy==1.14.5' 'singledispatch==3.4.0.3' 'six==1.11.0'
   python issue3027.py   # Fail
```

Thanks for the update @stuz5000. This narrows it down a bit? Anaconda Python is ok, but Ubuntu 14.04 stock Python 2.7 is not. I have to wonder if newer Ubuntu's suffer the same problem? I'll see if a Centos stock Python has this issue.
Doing the Centos equivalent of https://github.com/numba/numba/issues/3027#issuecomment-398194314, but with a `virtualenv`, on Centos 7, using stock Python 2.7, the problem is not present.
Hmmm -- tried the following on a set of AWS instances:

 * Ubuntu 18.04 LTS [PASS] (ami-e3293383)
 * Ubuntu 16.04 LTS [PASS] (ami-43243a23)
 * Ubuntu 14.04 LTS [FAIL]  (ami-e4293384)

```
   sudo apt-get update --yes
   sudo apt-get install  --yes python2.7 python-pip python-dev
   sudo pip install pip==9.0.1
   sudo pip install 'enum34==1.1.6' 'funcsigs==1.0.2' 'llvmlite==0.23.2' 'numba==0.38.1' 'numpy==1.14.5' 'singledispatch==3.4.0.3' 'six==1.11.0'
   python2.7 issue3027.py  # Pass/Fail?
```
... so it seems limited just to old versions of ubuntu. Which is odd. Why might the behavior of the same package differ between ubuntu versions? As I understand it, pip should install the same packages, right?

So, different base python installation? Different dependent C libraries? Non-deterministic behavior in numba (buffer overrun, etc...)?


Ok, thanks for trying that, seems like it's narrowed down a whole lot now. I believe pip should download the same packages, but probably worth checking it's doing so for completeness.

- It might be worth seeing what changed in the CPython 2.x series between Ubuntu 14.04 and 16.04?
- Perhaps try the oldest CPython 2.7 on 16.04 to narrow down the change, if that passes then you could just bisect the package releases between that and latest?
- Might also be worth trying to find a reproducer that doesn't use recursion?
- I had a quick skim of the CPython issue tracker and nothing jumped out, but that doesn't mean there isn't something in there!
With [some magic](https://stackoverflow.com/questions/50958222/possible-to-break-on-module-namespace-assignments/50958316?noredirect=1#50958316), its possible to trap assignments to sys

Whence:

numba/errors.py  calls colorama/initialise.py:init :
```
orig_stdout = sys.stdout
orig_stderr = sys.stderr

wrapped_stdout = sys.stdout
wrapped_stderr = sys.stderr

atexit_done = False


def reset_all():
    AnsiToWin32(orig_stdout).reset_all()


def init(autoreset=False, convert=None, strip=None, wrap=True):

    if not wrap and any([autoreset, convert, strip]):
        raise ValueError('wrap=False conflicts with any other arg=True')

    global wrapped_stdout, wrapped_stderr
    sys.stdout = wrapped_stdout = \
        wrap_stream(orig_stdout, convert, strip, autoreset, wrap)
    sys.stderr = wrapped_stderr = \
        wrap_stream(orig_stderr, convert, strip, autoreset, wrap)

    global atexit_done
    if not atexit_done:
        atexit.register(reset_all)
        atexit_done = True


def deinit():
    sys.stdout = orig_stdout
    sys.stderr = orig_stderr


def reinit():
    sys.stdout = wrapped_stdout
    sys.stderr = wrapped_stdout
```

`colorama>=0.3.9` resolves this issue.
I'll commit a PR
Well found :) So Numba is not at fault?

`colorama` is a relatively new optional dependency for Numba, everything works just fine without it, but if it is present it helps produce highlighted/coloured error messages. You can just switch it off by setting the env var `NUMBA_DISABLE_ERROR_MESSAGE_HIGHLIGHTING` to non-zero.

Resolving patch:
diff --git a/numba/errors.py b/numba/errors.py
--- a/numba/errors.py
+++ b/numba/errors.py
@@ -85,6 +85,17 @@ def highlight(self, msg):
 try:
     import colorama
 
+    # If the colorama version is < 0.3.9 it can break stdout/stderr in some
+    # situations, as a result if this condition is met colorama is disabled and
+    # the user is warned.
+    if tuple([int(x) for x in colorama.__version__.split('.')]) < (0, 3, 9):
+        msg = ("Insufficiently recent colorama version found. "
+               "Numba requires colorama >= 0.3.9")
+        # warn the user
+        warnings.warn(msg)
+        # trip the exception to disable color errors
+        raise ImportError
+
     # If Numba is running in testsuite mode then do not use error message
     # coloring so CI system output is consistently readable without having
     # to read between shell escape characters.


Test patch:
diff --git a/numba/tests/test_sys_stdin_assignment.py b/numba/tests/test_sys_stdin_assignment.py
new file mode 100644
--- /dev/null
+++ b/numba/tests/test_sys_stdin_assignment.py
@@ -0,0 +1,69 @@
+from __future__ import print_function, absolute_import, division
+
+import sys
+
+import unittest
+from numba import njit
+
+
+@njit
+def f0(a, b):
+    return a + b
+
+
+@njit
+def f1(begin1, end1, begin2, end2):
+    if begin1 > begin2: return f1(begin2, end2, begin1, end1)
+    return end1 + 1 >= begin2
+
+
+@njit
+def f0_2(a, b):
+    return a + b
+
+
+@njit
+def f1_2(begin1, end1, begin2, end2):
+    if begin1 > begin2: return f1_2(begin2, end2, begin1, end1)
+    return end1 + 1 >= begin2
+
+
+class TestSysStdinAssignment(unittest.TestCase):
+
+    def test_no_reassignment_of_stdout(self):
+        """
+        https://github.com/numba/numba/issues/3027
+        Older versions of colorama break stdout/err when recursive functions
+        are compiled.
+
+        This test should work irrespective of colorama version, or indeed its
+        presence. If the version is too low, it should be disabled and the test
+        should work anyway, if it is a sufficiently high version or it is not
+        present, it should work anyway.
+        """
+
+        originally = sys.stdout, sys.stderr
+
+        try:
+            sys.stdout = None
+            f0(0, 1)  # Not changed stdout?
+            self.assertEqual(sys.stdout, None)
+            f1(0, 1, 2, 3)  # Not changed stdout?
+            self.assertEqual(sys.stdout, None)
+
+            sys.stderr = None
+            f0_2(0, 1)  # Not changed stderr?
+            self.assertEqual(sys.stderr, None)
+            f1_2(0, 1, 2, 3)  # Not changed stderr?
+            self.assertEqual(sys.stderr, None)
+
+        finally:
+            sys.stdout, sys.stderr = originally
+
+        self.assertNotEqual(sys.stderr, None)
+        self.assertNotEqual(sys.stdout, None)
+
+
+if __name__ == '__main__':
+    unittest.main()
+