Skip to content
Commits on Source (7)
......@@ -13,12 +13,14 @@
# work in conjunction with the .mailmap file at the root of this repository.
3kwa | Eugene Van den Bulke <eugene.vandenbulke@gmail.com> | 2018-06-01
ab12gu | Abhay Gupta <ab18gu@gmail.com> | 2018-03-02
aburgm | Armin Burgmeier <aburgmeier@bloomberg.net> | 2018-07-24
alanhdu | Alan Du <alanhdu@gmail.com> | 2018-06-05
albertmichaelj | Michael Albert <albertmichaelj@gmail.com> | 2019-02-27
aldanor | Ivan Smirnov <i.s.smirnov@gmail.com> | 2018-07-24
alexbw | Alex Wiltschko <alex.bw@gmail.com> | 2018-05-23
almarklein | Almar Klein <almar.klein@gmail.com> | 2018-06-04
analog-cbarber | Christopher Barber <christopher.barber@analog.com> | 2019-03-22
arkottke | Albert Kottke <albert.kottke@gmail.com> | 2018-07-23
asmeurer | Aaron Meurer <aaron.meurer@continuum.io> | Anaconda, Inc.
aterrel | Andy R. Terrel <andy.terrel@gmail.com> | Anaconda, Inc.
......@@ -92,6 +94,7 @@ Juanlu001 | Juan Luis Cano Rodríguez <juanlu001@gmail.com> | 2018-06-01
jusjusjus | jusjusjus <jschwabedal@gmail.com> | 2018-06-04
jwkvam | Jacques Kvam <jwkvam@gmail.com> | 2018-06-04
kalefranz | Kale Franz <kfranz@continuum.io> | Anaconda, Inc.
katietz | Kai Tietz <ktietz@anaconda.com> | Anaconda, Inc.
kdeldycke | Kevin Deldycke <kevin@deldycke.com> | 2018-06-05
kurtwheeler | Kurt Wheeler <kurt.wheeler91@gmail.com> | 2018-07-30
lidavidm | David Li <li.davidm96@gmail.com> | Anaconda, Inc.
......@@ -123,6 +126,7 @@ murraryreadccdc | M.G. Read <read@ccdc.cam.ac.uk> | 2019-02-05
mutirri | irritum <kamil.kwiek@continuum.io> | Anaconda, Inc.
mwiebe | Mark Wiebe <mwiebe@continuum.io> | Anaconda, Inc.
nehaljwani | Nehal J Wani <nehaljw.kkd1@gmail.com> | 2018-06-01
nh3 | Ni Huang <ni.huang@sanger.ac.uk> | 2019-03-20
nickeubank | Nick Eubank <nickeubank@users.noreply.github.com> | 2018-06-04
nicoddemus | Bruno Oliveira <nicoddemus@gmail.com> | 2018-05-23
njalerikson | Odegard, Ken <ken.odegard@gmail.com> | 2018-06-01
......@@ -151,6 +155,7 @@ shadowwalkersb | shadow_walker <shadowwalkersb@gmail.com> | 2018-06-04
ShannonGreen | Shannon Green <sgreen@cochlear.com> | 2018-07-26
soapy1 | Sophia Castellarin <scastellarin@continuum.io> | Anaconda, Inc.
soxofaan | Stefaan Lippens <stefaan@netlog.com> | 2018-06-06
spamlrot-tic | Stephen Palmroth <spalmrot@tudor.com> | 2019-03-26
srossross | srossross <srossross@gmail.com> | Anaconda, Inc.
stefanseefeld | Stefan Seefeld <stefan@seefeld.name> | Anaconda, Inc.
stuarteberg | Stuart Berg <bergs@janelia.hhmi.org> | 2018-06-04
......@@ -170,6 +175,7 @@ vestuto | Jason Vestuto <jvestuto@continuum.io> | Anaconda, Inc.
wojdyr | Marcin Wojdyr <wojdyr@gmail.com> | 2018-06-01
wulmer | Wolfgang Ulmer <wolfgang.ulmer@de.bosch.com> | 2018-06-11
Zaharid | Zahari <zaharid@gmail.com> | 2018-07-24
zdog234 | Zane Dufour <zane.dufour@gmail.com | 2019-03-26
zzag | Vlad Zagorodniy <vladzzag@gmail.com> | 2018-07-24
......
*.sh text eol=lf
*.psm1 text eol=lf
dev/start text eol=lf
## 4.6.10 (2019-04-01)
### Bug fixes
* Fix python-3 only FileNotFoundError usage in initialize.py (#8470)
* Fix more JSON encode errors for the _Null data type (#8471)
* Fix non-posix-compliant == in conda.sh (#8475, #8476)
* improve detection of pip dependency in environment.yml files to avoid warning message (#8478)
* fix condabin\conda.bat use of dp0, making PATH additions incorrect (#8480)
* init_fish_user: don't assume config file exists (#8481)
* Fix for chcp output ending with . (#8484)
### Docs improvements
* Changelogs for 4.6.8, 4.6.9
### Contributors
* @duncanmmacleod
* @nehaljwani
* @ilango100
* @jjhelmus
* @mingwandroid
* @msarahan
* @rrigdon
## 4.6.9 (2019-03-29)
### Improvements
* Improve CI for docs commits (#8387, #8401, #8417)
* Implement `conda init --reverse` to undo rc file and registry changes (#8400)
* Improve handling of unicode systems (#8342, #8435)
* Force the "COMSPEC" environment variable to always point to cmd.exe on windows. This was an implicit assumption that was not always true. (#8457, #8461)
### Bug fixes
* Add central C:/ProgramData/conda as a search path on Windows (#8272)
* remove direct use of ruamel_yaml (prefer internal abstraction, yaml_load) (#8392)
* Fix/improve `conda init` support for fish shell (#8437)
* Improve solver behavior in the presence of inconsistent environments (such as pip as a conda dependency of python, but also installed via pip itself) (#8444)
* Handle read-only filesystems for environments.txt (#8451, #8453)
* Fix conda env commands involving pip-installed dependencies being installed into incorrect locations (#8435)
### Docs improvements
* updated cheatsheet (#8402)
* updated color theme (#8403)
### Contributors
* @blackgear
* @dhirschfeld
* @jakirkham
* @jjhelmus
* @katietz
* @mingwandroid
* @msarahan
* @nehaljwani
* @rrigdon
* @soapy1
* @spamlrot-tic
## 4.6.8 (2019-03-06)
### Bug fixes
......
......@@ -55,6 +55,21 @@ To set up an environment to start developing on conda code, we recommend the fol
py.test tests/test_create.py -k create_install_update_remove_smoketest
3.1 Test-suite issues
If you do not have git installed and your test does not install it then
queries to conda --version will except (yeah, this should get fixed). To
workaround:
git describe > conda/.version
.. Then make this file PEP440 compliant.
.. (initially an every time you commit).
The tests-suite is very sensitive to the initial environment. We have make
some effort to make the tests runnable in popular IDEs, and in PyCharm's
case, many tests can be run from a clean environment (variable-wise)
## Development Environment, Windows cmd.exe shell
......
......@@ -2,11 +2,13 @@ PYTEST_EXE ?= $(shell which py.test)
PYTHON_EXE ?= $(shell sed 's/^\#!//' $(PYTEST_EXE) | head -1 | sed "s|$HOME|~|")
PYTHON_MAJOR_VERSION := $(shell $(PYTHON_EXE) -c "import sys; print(sys.version_info[0])")
TEST_PLATFORM := $(shell $(PYTHON_EXE) -c "import sys; print('win' if sys.platform.startswith('win') else 'unix')")
SYS_PREFIX := $(shell $(PYTHON_EXE) -c "import sys; print(sys.prefix)")
PYTHONHASHSEED := $(shell python -c "import random as r; print(r.randint(0,4294967296))")
PYTEST_VARS := PYTHONHASHSEED=$(PYTHONHASHSEED) PYTHON_MAJOR_VERSION=$(PYTHON_MAJOR_VERSION) TEST_PLATFORM=$(TEST_PLATFORM)
PYTEST := $(PYTEST_VARS) $(PYTEST_EXE)
# --basetemp is so that our environments are created via hardlinks, the most common way.
PYTEST := $(PYTEST_VARS) $(PYTEST_EXE) --basetemp=$(SYS_PREFIX)/../conda.tmp
ADD_COV := --cov-report xml --cov-report term-missing --cov-append --cov conda
......
......@@ -10,10 +10,10 @@ environment:
secure: ZaE7K9EHorv40AjYhSuWtQeRAsMN1+QqPf7u8rOlvEY50kdaHj87Mh5GIDZgJBzj
matrix:
- PYTHON: "C:\\Python36_64"
PYTHON_VERSION: "3.6"
- PYTHON: "C:\\Python3_64"
PYTHON_VERSION: "3.7"
PYTHON_ARCH: "64"
PYTHON_ROOT: "C:\\Miniconda36-x64"
PYTHON_ROOT: "C:\\Miniconda3-x64"
CONDA_INSTRUMENTATION_ENABLED: "true"
- PYTHON: "C:\\Python27_32"
......@@ -30,7 +30,7 @@ init:
- ECHO %PYTHON% %PYTHON_VERSION% %PYTHON_ARCH% %HOME%
# - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
#on_finish:
on_finish:
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
install:
......
......@@ -15,18 +15,20 @@ main_test: &main_test
- run:
name: unit tests
command: |
if [[ $(git diff origin/master --name-only | wc -l) == $(git diff origin/master --name-only | grep docs | wc -l) ]]; then
if [[ $(git diff origin/master --name-only | wc -l) == $(git diff origin/master --name-only | grep docs | wc -l) && $(git diff origin/master --name-only | grep docs) ]]; then
echo "Only docs changed detected, skipping tests"
else
echo "local_repodata_ttl: 1800" >> ~/.condarc
eval "$(sudo /opt/conda/bin/python -m conda init --dev bash)"
conda info
# remove the pkg cache. We can't hardlink from here anyway. Having it around causes log problems.
sudo rm -rf /opt/conda/pkgs/*-*-*
py.test $ADD_COV -m "not integration and not installed"
fi
- run:
name: integration tests
command: |
if [[ $(git diff origin/master --name-only | wc -l) == $(git diff origin/master --name-only | grep docs | wc -l) ]]; then
if [[ $(git diff origin/master --name-only | wc -l) == $(git diff origin/master --name-only | grep docs | wc -l) && $(git diff origin/master --name-only | grep docs) ]]; then
echo "Only docs changed detected, skipping tests"
else
eval "$(sudo /opt/conda/bin/python -m conda init --dev bash)"
......@@ -35,7 +37,13 @@ main_test: &main_test
fi
- run:
name: upload codecov
command: /opt/conda/bin/codecov --env PYTHON_VERSION --flags integration --required
command: |
if [[ $(git diff origin/master --name-only | wc -l) == $(git diff origin/master --name-only | grep docs | wc -l) && $(git diff origin/master --name-only | grep docs) ]]; then
echo "No codecov report to upload"
else
/opt/conda/bin/codecov --env PYTHON_VERSION --flags integration --required
echo "No codecov report to upload"
fi
conda_build_test: &conda_build_test
......@@ -129,7 +137,7 @@ conda_build_test: &conda_build_test
# test_overlinking_detection package doesn't have configure
# test_python_line_up_with_compiled_lib because older CB honors run_exports.yaml and not run_exports.json
command: |
if [[ $(git diff origin/master --name-only | wc -l) == $(git diff origin/master --name-only | grep docs | wc -l) ]]; then
if [[ $(git diff origin/master --name-only | wc -l) == $(git diff origin/master --name-only | grep docs | wc -l) && $(git diff origin/master --name-only | grep docs) ]]; then
echo "Only docs changed detected, skipping tests"
else
eval "$(sudo /opt/conda/bin/python -m conda init --dev bash)"
......@@ -157,7 +165,7 @@ conda_build_test: &conda_build_test
# test_setuptools_test_requirements upstream changes that affect 'conda skeleton'
# rpm-libX11-devel returns 404 error
command: |
if [[ $(git diff origin/master --name-only | wc -l) == $(git diff origin/master --name-only | grep docs | wc -l) ]]; then
if [[ $(git diff origin/master --name-only | wc -l) == $(git diff origin/master --name-only | grep docs | wc -l) && $(git diff origin/master --name-only | grep docs) ]]; then
echo "Only docs changed detected, skipping tests"
else
eval "$(sudo /opt/conda/bin/python -m conda init --dev bash)"
......@@ -222,8 +230,8 @@ workflows:
version: 2
conda tests:
jobs:
# - py37 main tests
- py36 main tests
- py37 main tests
# - py36 main tests
- py27 main tests
# - 3.0 conda-build
- 3.10 conda-build
......
provider:
win: azure
echo %PKG_VERSION% > conda\.version
%PYTHON% setup.py install --single-version-externally-managed --record record.txt
if %errorlevel% neq 0 exit /b %errorlevel%
%PYTHON% -m conda init --install
if %errorlevel% neq 0 exit /b %errorlevel%
......@@ -5,11 +5,20 @@
from __future__ import absolute_import, division, print_function, unicode_literals
import os
from os.path import dirname
from os.path import abspath, dirname
import sys
# This hack is from http://kmike.ru/python-with-strings-attached/
# It is needed ro prevent str() conversion of %r. Against general
# advice, we return `unicode` from various things on Python 2,
# in particular the `__repr__` and `__str__` of our exceptions.
if sys.version_info[0] == 2:
# ignore flake8 on this because it finds this as an error on py3 even though it is guarded
reload(sys) # NOQA
sys.setdefaultencoding('utf-8')
from ._vendor.auxlib.packaging import get_version
from .common.compat import text_type
from .common.compat import text_type, iteritems
__all__ = (
"__name__", "__version__", "__author__", "__email__", "__license__", "__summary__", "__url__",
......@@ -29,8 +38,13 @@ __url__ = "https://github.com/conda/conda"
if os.getenv('CONDA_ROOT') is None:
os.environ[str('CONDA_ROOT')] = sys.prefix
CONDA_PACKAGE_ROOT = dirname(__file__)
CONDA_PACKAGE_ROOT = abspath(dirname(__file__))
def another_to_unicode(val):
# ignore flake8 on this because it finds this as an error on py3 even though it is guarded
if isinstance(val, basestring) and not isinstance(val, unicode): # NOQA
return unicode(val, encoding='utf-8') # NOQA
return val
class CondaError(Exception):
return_code = 1
......@@ -42,12 +56,32 @@ class CondaError(Exception):
self._caused_by = caused_by
super(CondaError, self).__init__(message)
# If we add __unicode__ to CondaError then we must also add it to all classes that
# inherit from it if they have their own __repr__ (and maybe __str__) function.
if sys.version_info[0] > 2:
def __repr__(self):
return '%s: %s' % (self.__class__.__name__, text_type(self))
else:
# We must return unicode here.
def __unicode__(self):
new_kwargs = dict()
for k, v in iteritems(self._kwargs):
new_kwargs[another_to_unicode(k)] = another_to_unicode(v)
new_message = another_to_unicode(self.message)
res = '%s' % (new_message % new_kwargs)
return res
def __repr__(self):
return '%s: %s' % (self.__class__.__name__, self.__unicode__())
def __str__(self):
try:
if sys.version_info[0] > 2:
return text_type(self.message % self._kwargs)
else:
return self.__unicode__().encode('utf-8')
except Exception:
debug_message = "\n".join((
"class: " + self.__class__.__name__,
......@@ -77,14 +111,39 @@ class CondaMultiError(CondaError):
self.errors = errors
super(CondaMultiError, self).__init__(None)
if sys.version_info[0] > 2:
def __repr__(self):
errs = []
for e in self.errors:
if isinstance(e, EnvironmentError) and not isinstance(e, CondaError):
errs.append(text_type(e))
else:
# We avoid Python casting this back to a str()
# by using e.__repr__() instead of repr(e)
# https://github.com/scrapy/cssselect/issues/34
errs.append(e.__repr__())
res = '\n'.join(errs)
return res
else:
# We must return unicode here.
def __unicode__(self):
errs = []
for e in self.errors:
if isinstance(e, EnvironmentError) and not isinstance(e, CondaError):
errs.append(text_type(e))
else:
# We avoid Python casting this back to a str()
# by using e.__repr__() instead of repr(e)
# https://github.com/scrapy/cssselect/issues/34
errs.append(e.__repr__())
res = '\n'.join(errs)
return res
def __repr__(self):
return '\n'.join(text_type(e)
if isinstance(e, EnvironmentError) and not isinstance(e, CondaError)
else repr(e)
for e in self.errors) + '\n'
return '%s: %s' % (self.__class__.__name__, self.__unicode__())
def __str__(self):
return '\n'.join(text_type(e) for e in self.errors) + '\n'
return str('\n').join(str(e) for e in self.errors) + str('\n')
def dump_map(self):
return dict(exception_type=text_type(type(self)),
......
......@@ -72,6 +72,11 @@ class _Null(object):
def __hash__(self):
return hash(_Null)
def __json__(self):
return 'null'
to_json = __json__
# Use this NULL object when needing to distinguish a value from None
# For example, when parsing json, you may need to determine if a json key was given and set
......
# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, print_function
import codecs
import collections
from itertools import chain
import os
import sys
from ._vendor.five import WhateverIO as StringIO, with_metaclass
from ._vendor.six import (PY2, PY3, integer_types, iteritems, iterkeys, itervalues, string_types,
......@@ -10,6 +13,9 @@ from ._vendor.six import (PY2, PY3, integer_types, iteritems, iterkeys, itervalu
StringIO, with_metaclass = StringIO, with_metaclass
PY2, PY3, integer_types, iteritems, iterkeys, itervalues, string_types = PY2, PY3, integer_types, iteritems, iterkeys, itervalues, string_types # NOQA
text_type, wraps = text_type, wraps
from shlex import split
from functools import partial
from tempfile import NamedTemporaryFile, template
try:
from collections import OrderedDict as odict # NOQA
......@@ -29,3 +35,122 @@ def isiterable(obj):
and type(obj) is not type)
else:
return not isinstance(obj, string_types) and isinstance(obj, collections.Iterable)
# shlex.split() is a poor function to use for anything general purpose (like calling subprocess).
# It does not handle Unicode at all on Python 2 and it mishandles it on Python 3, but all is not
# lost. We can escape it, then escape the escapes then call shlex.split() then un-escape that.
def shlex_split_unicode(to_split, posix=True):
# shlex.split does its own un-escaping that we must counter.
if sys.version_info.major == 2:
e_to_split = to_split.encode('unicode-escape').replace(b'\\', b'\\\\')
else:
e_to_split = to_split.replace('\\', '\\\\')
splits = split(e_to_split, posix=posix)
if sys.version_info.major == 2:
return [bytes(s).decode('unicode-escape') for s in splits]
else:
return splits
def utf8_writer(fp):
if sys.version_info[0] < 3:
return codecs.getwriter('utf-8')(fp)
else:
return fp
if sys.version_info[0] < 3:
def Utf8NamedTemporaryFile(mode='w+b', bufsize=-1, suffix="",
prefix=template, dir=None, delete=True):
if 'CONDA_TEST_SAVE_TEMPS' in os.environ:
delete = False
return codecs.getwriter('utf-8')(NamedTemporaryFile(mode=mode, bufsize=bufsize, suffix=suffix,
prefix=template, dir=None, delete=delete))
else:
def Utf8NamedTemporaryFile(mode='w+b', buffering=-1, newline=None,
suffix=None, prefix=None, dir=None, delete=True):
if 'CONDA_TEST_SAVE_TEMPS' in os.environ:
delete = False
encoding = None
if not 'b' in mode:
encoding = 'utf-8'
return NamedTemporaryFile(mode=mode, buffering=buffering, encoding=encoding,
newline=newline, suffix=suffix, prefix=prefix,
dir=dir, delete=delete)
'''
def shlex_split_unicode(to_split, posix=True):
if isinstance(to_split, string_types):
t=string_types[0]
elif isinstance(to_split, binary_type):
t=binary_type
to_split = ensure_text_type(to_split)
e_to_split = to_split.encode('ascii', 'backslashreplace').replace(b'\\', b'\\\\')
try:
e_to_split = str(e_to_split, 'ascii')
except:
pass
splits = split(e_to_split, posix=posix)
if t == binary_type:
res = [s.encode('unicode-escape') for s in splits]
else:
if sys.version_info[0] == 2:
res = [s.decode('unicode-escape') for s in splits]
else:
res = [bytes(s, 'ascii').decode('unicode-escape') for s in splits]
for r in res:
assert isinstance(r, t)
return res
from contextlib import contextmanager
import sys
#import shlex
#t = u'/var/folders/y1/ljv50nrs49gdqkrp01wy3_qm0000gn/T/190e_çñôáêß/bin/python3.5 -Wi -m compileall -q -l -i /var/folders/y1/ljv50nrs49gdqkrp01wy3_qm0000gn/T/tmp6tn_c5 ōγђ家固한áêñßôç'
#t2 = shlex.split(t)
class ImportBlocker(object):
def __init__(self, args):
self.module_names = [unicode(a) for a in args]
def find_module(self, fullname, path=None):
if unicode(fullname) in self.module_names:
return self
return None
def find_spec(self, fullname, path, target=None):
if fullname in self.module_names:
return self
return None
def load_module(self, name):
raise ImportError("%s is blocked and cannot be imported" % name)
@contextmanager
def blocked_imports(sys_module, *modules):
old_modules = dict({})
for m in modules:
if m in sys_module.modules:
old_modules[m] = sys_module.modules[m]
del sys_module.modules[m]
sys_meta_path = sys_module.meta_path[:]
sys_module.meta_path.insert(0, ImportBlocker(modules))
try:
yield True
finally:
for k, v in old_modules.items():
sys_module.modules[k] = v
sys_module.meta_path = sys_meta_path
with blocked_imports('cStringIO'):
if 'cStringIO' in sys.modules: print(sys.modules['cStringIO'])
import shlex
if 'cStringIO' in sys.modules: print(sys.modules['cStringIO'])
if 'cStringIO' in sys.modules: print(sys.modules['cStringIO'])
t = u'/var/folders/y1/ljv50nrs49gdqkrp01wy3_qm0000gn/T/190e_çñôáêß/bin/python3.5 -Wi -m compileall -q -l -i /var/folders/y1/ljv50nrs49gdqkrp01wy3_qm0000gn/T/tmp6tn_c5 ōγђ 家固한áêñßôç'
t2 = shlex.split(t)
'''
......@@ -75,7 +75,7 @@ from logging import getLogger
from os import getenv, listdir, remove
from os.path import abspath, dirname, expanduser, isdir, isfile, join
from re import compile
from shlex import split
from conda._vendor.auxlib.compat import shlex_split_unicode
from subprocess import CalledProcessError, PIPE, Popen
import sys
......@@ -89,7 +89,7 @@ GIT_DESCRIBE_REGEX = compile(r"(?:[_-a-zA-Z]*)"
def call(command, path=None, raise_on_error=True):
path = sys.prefix if path is None else abspath(path)
p = Popen(split(command), cwd=path, stdout=PIPE, stderr=PIPE)
p = Popen(shlex_split_unicode(command), cwd=path, stdout=PIPE, stderr=PIPE)
stdout, stderr = p.communicate()
rc = p.returncode
log.debug("{0} $ {1}\n"
......@@ -131,17 +131,22 @@ def _git_describe_tags(path):
raise CalledProcessError(response.rc, response.stderr)
def _get_version_from_git_tag(path):
def _get_version_from_git_tag(tag):
"""Return a PEP440-compliant version derived from the git status.
If that fails for any reason, return the changeset hash.
"""
m = GIT_DESCRIBE_REGEX.match(_git_describe_tags(path) or '')
m = GIT_DESCRIBE_REGEX.match(tag)
if m is None:
return None
version, post_commit, hash = m.groups()
return version if post_commit == '0' else "{0}.post{1}+{2}".format(version, post_commit, hash)
def _get_version_from_git_clone(path):
tag = _git_describe_tags(path) or ''
return _get_version_from_git_tag(tag)
def get_version(dunder_file):
"""Returns a version string for the current package, derived
either from git or from a .version file.
......@@ -157,7 +162,7 @@ def get_version(dunder_file):
"""
path = abspath(expanduser(dirname(dunder_file)))
try:
return _get_version_from_version_file(path) or _get_version_from_git_tag(path)
return _get_version_from_version_file(path) or _get_version_from_git_clone(path)
except CalledProcessError as e:
log.warn(repr(e))
return None
......
......@@ -182,9 +182,9 @@ def _environ_cols_windows(fp): # pragma: no cover
def _environ_cols_tput(*_): # pragma: no cover
"""cygwin xterm (windows)"""
try:
import shlex
cols = int(subprocess.check_call(shlex.split('tput cols')))
# rows = int(subprocess.check_call(shlex.split('tput lines')))
from conda._vendor.auxlib.compat import shlex_split_unicode
cols = int(subprocess.check_call(shlex_split_unicode('tput cols')))
# rows = int(subprocess.check_call(shlex_split_unicode('tput lines')))
return cols
except:
pass
......
This diff is collapsed.
......@@ -24,6 +24,13 @@ machine_bits = 8 * tuple.__itemsize__
APP_NAME = 'conda'
if on_win:
SEARCH_PATH = (
'C:/ProgramData/conda/.condarc',
'C:/ProgramData/conda/condarc',
'C:/ProgramData/conda/condarc.d',
)
else:
SEARCH_PATH = (
'/etc/conda/.condarc',
'/etc/conda/condarc',
......@@ -31,6 +38,9 @@ SEARCH_PATH = (
'/var/lib/conda/.condarc',
'/var/lib/conda/condarc',
'/var/lib/conda/condarc.d/',
)
SEARCH_PATH += (
'$CONDA_ROOT/.condarc',
'$CONDA_ROOT/condarc',
'$CONDA_ROOT/condarc.d/',
......
......@@ -3,6 +3,8 @@
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import absolute_import, division, print_function, unicode_literals
from collections import OrderedDict
from errno import ENOENT
from logging import getLogger
import os
......@@ -29,6 +31,8 @@ from ..common.os.linux import linux_get_libc_version
from ..common.path import expand, paths_equal
from ..common.url import has_scheme, path_to_url, split_scheme_auth_token
from .. import CONDA_PACKAGE_ROOT
try:
os.getcwd()
except (IOError, OSError) as e:
......@@ -63,6 +67,22 @@ user_rc_path = abspath(expanduser('~/.condarc'))
sys_rc_path = join(sys.prefix, '.condarc')
def mockable_context_envs_dirs(root_writable, root_prefix, _envs_dirs):
if root_writable:
fixed_dirs = (
join(root_prefix, 'envs'),
join('~', '.conda', 'envs'),
)
else:
fixed_dirs = (
join('~', '.conda', 'envs'),
join(root_prefix, 'envs'),
)
if on_win:
fixed_dirs += join(user_data_dir(APP_NAME, APP_NAME), 'envs'),
return tuple(IndexedSet(expand(p) for p in concatv(_envs_dirs, fixed_dirs)))
def channel_alias_validation(value):
if value and not has_scheme(value):
return "channel_alias value '%s' must have scheme/protocol." % value
......@@ -201,6 +221,7 @@ class Context(Configuration):
always_copy = PrimitiveParameter(False, aliases=('copy',))
always_yes = PrimitiveParameter(None, aliases=('yes',), element_type=(bool, NoneType))
debug = PrimitiveParameter(False)
dev = PrimitiveParameter(False)
dry_run = PrimitiveParameter(False)
error_upload_url = PrimitiveParameter(ERROR_UPLOAD_URL)
force = PrimitiveParameter(False)
......@@ -388,19 +409,7 @@ class Context(Configuration):
@property
def envs_dirs(self):
if self.root_writable:
fixed_dirs = (
join(self.root_prefix, 'envs'),
join('~', '.conda', 'envs'),
)
else:
fixed_dirs = (
join('~', '.conda', 'envs'),
join(self.root_prefix, 'envs'),
)
if on_win:
fixed_dirs += join(user_data_dir(APP_NAME, APP_NAME), 'envs'),
return tuple(IndexedSet(expand(p) for p in concatv(self._envs_dirs, fixed_dirs)))
return mockable_context_envs_dirs(self.root_writable, self.root_prefix, self._envs_dirs)
@property
def pkgs_dirs(self):
......@@ -475,11 +484,34 @@ class Context(Configuration):
return abspath(sys.prefix)
@property
# This is deprecated, please use conda_exe_vars_dict instead.
def conda_exe(self):
bin_dir = 'Scripts' if on_win else 'bin'
exe = 'conda.exe' if on_win else 'conda'
return join(self.conda_prefix, bin_dir, exe)
@property
def conda_exe_vars_dict(self):
'''
An OrderedDict so the vars can refer to each other if necessary.
None means unset it.
'''
if context.dev:
return OrderedDict([('CONDA_EXE', sys.executable),
('PYTHONPATH', os.path.dirname(CONDA_PACKAGE_ROOT) + '{}{}'.format(
os.pathsep, os.environ.get('PYTHONPATH', ''))),
('_CE_M', '-m'),
('_CE_CONDA', 'conda')])
else:
bin_dir = 'Scripts' if on_win else 'bin'
exe = 'conda.exe' if on_win else 'conda'
# I was going to use None to indicate a variable to unset, but that gets tricky with
# error-on-undefined.
return OrderedDict([('CONDA_EXE', os.path.join(sys.prefix, bin_dir, exe)),
('_CE_M', ''),
('_CE_CONDA', '')])
@memoizedproperty
def channel_alias(self):
from ..models.channel import Channel
......@@ -748,6 +780,7 @@ class Context(Configuration):
'allow_conda_downgrades',
'add_pip_as_python_dependency',
'debug',
'dev',
'default_python',
'enable_private_envs',
'error_upload_url', # should remain undocumented
......@@ -1082,6 +1115,86 @@ def reset_context(search_path=SEARCH_PATH, argparse_args=None):
return context
class ContextStackObject(object):
def __init__(self, search_path=SEARCH_PATH, argparse_args=None):
self.set_value(search_path, argparse_args)
def set_value(self, search_path=SEARCH_PATH, argparse_args=None):
self.search_path = search_path
self.argparse_args = argparse_args
def apply(self):
reset_context(self.search_path, self.argparse_args)
class ContextStack(object):
def __init__(self):
self._stack = [ContextStackObject() for _ in range(3)]
self._stack_idx = 0
self._last_search_path = None
self._last_argparse_args = None
def push(self, search_path, argparse_args):
self._stack_idx += 1
old_len = len(self._stack)
if self._stack_idx >= old_len:
self._stack.extend([ContextStackObject() for _ in range(old_len)])
self._stack[self._stack_idx].set_value(search_path, argparse_args)
self.apply()
def apply(self):
if self._last_search_path != self._stack[self._stack_idx].search_path or \
self._last_argparse_args != self._stack[self._stack_idx].argparse_args:
# Expensive:
self._stack[self._stack_idx].apply()
self._last_search_path = self._stack[self._stack_idx].search_path
self._last_argparse_args = self._stack[self._stack_idx].argparse_args
def pop(self):
self._stack_idx -= 1
self._stack[self._stack_idx].apply()
def replace(self, search_path, argparse_args):
self._stack[self._stack_idx].set_value(search_path, argparse_args)
self._stack[self._stack_idx].apply()
context_stack = ContextStack()
def stack_context(pushing, search_path=SEARCH_PATH, argparse_args=None):
if pushing:
# Fast
context_stack.push(search_path, argparse_args)
else:
# Slow
context_stack.pop()
# Default means "The configuration when there are no condarc files present". It is
# all the settings and defaults that are built in to the code and *not* the default
# value of search_path=SEARCH_PATH. It means search_path=().
def stack_context_default(pushing, argparse_args=None):
return stack_context(pushing, search_path=(), argparse_args=argparse_args)
def replace_context(pushing, search_path=SEARCH_PATH, argparse_args=None):
return context_stack.replace(search_path, argparse_args)
def replace_context_default(pushing, argparse_args=None):
return context_stack.replace(search_path=(), argparse_args=argparse_args)
# Tests that want to only declare 'I support the project-wide default for how to
# manage stacking of contexts'. Tests that are known to be careful with context
# can use `replace_context_with_default` which might be faster, though it should
# be a stated goal to set conda_tests_ctxt_mgmt_def_pol to replace_context_default
# and not to stack_context_default.
conda_tests_ctxt_mgmt_def_pol = replace_context_default
@memoize
def _get_cpu_info():
# DANGER: This is rather slow
......@@ -1176,6 +1289,10 @@ def _first_writable_envs_dir():
# Calling this function will *create* an envs directory if one does not already
# exist. Any caller should intend to *use* that directory for *writing*, not just reading.
for envs_dir in context.envs_dirs:
if envs_dir == os.devnull:
continue
# The magic file being used here could change in the future. Don't write programs
# outside this code base that rely on the presence of this file.
# This value is duplicated in conda.gateways.disk.create.create_envs_directory().
......
......@@ -200,7 +200,7 @@ def print_envs_list(known_conda_prefixes, output=True):
disp_env(prefix)
if output:
print()
print('')
def check_non_admin():
......
......@@ -551,6 +551,15 @@ def configure_parser_create(sub_parsers):
action="store_true",
help=SUPPRESS,
)
p.add_argument(
"--dev",
action=NullCountAction,
help="Use `sys.executable -m conda` in wrapper scripts instead of CONDA_EXE "
"This is mainly for use during tests where we test new conda source "
"against old Python versions.",
dest="dev",
default=NULL,
)
p.set_defaults(func='.main_create.execute')
......@@ -645,6 +654,12 @@ def configure_parser_init(sub_parsers):
help=SUPPRESS,
default=NULL,
)
setup_type_group.add_argument(
"--reverse",
action="store_true",
help="Undo past effects of conda init.",
default=NULL,
)
p.add_argument(
'shells',
......@@ -757,6 +772,15 @@ def configure_parser_install(sub_parsers):
help="Allow clobbering of overlapping file paths within packages, "
"and suppress related warnings.",
)
p.add_argument(
"--dev",
action=NullCountAction,
help="Use `sys.executable -m conda` in wrapper scripts instead of CONDA_EXE "
"This is mainly for use during tests where we test new conda source "
"against old Python versions.",
dest="dev",
default=NULL,
)
p.set_defaults(func='.main_install.execute')
......@@ -969,6 +993,15 @@ def configure_parser_remove(sub_parsers, name='remove'):
nargs='*',
help="Package names to %s from the environment." % name,
)
p.add_argument(
"--dev",
action=NullCountAction,
help="Use `sys.executable -m conda` in wrapper scripts instead of CONDA_EXE "
"This is mainly for use during tests where we test new conda source "
"against old Python versions.",
dest="dev",
default=NULL,
)
p.set_defaults(func='.main_remove.execute')
......@@ -1005,6 +1038,31 @@ def configure_parser_run(sub_parsers):
default=NULL,
)
p.add_argument(
"--dev",
action=NullCountAction,
help="Sets `CONDA_EXE` to `python -m conda`, assuming the CWD contains"
"the root of conda development sources. This is mainly for use"
"during tests where we test new conda source against old Python"
"versions.",
dest="dev",
default=NULL,
)
p.add_argument(
"--debug-wrapper-scripts",
action=NullCountAction,
help="When this is set, where implemented, the shell wrapper scripts"
"will echo to stderr a lot of debugging information.",
dest="debug_wrapper_scripts",
default=NULL,
)
p.add_argument(
"--cwd",
help="Current working directory for command to run in. Defaults to cwd",
default=os.getcwd()
)
p.add_argument(
'executable_call',
nargs=REMAINDER,
......
......@@ -30,7 +30,7 @@ def find_executable(executable, include_others=True):
else:
dir_paths = []
dir_paths.extend(os.environ[str('PATH')].split(os.pathsep))
dir_paths.extend(os.environ.get('PATH', '').split(os.pathsep))
for dir_path in dir_paths:
if on_win:
......