Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

py3: remove csv_reader and makedirs from utils/compat.py #3030

Merged
merged 5 commits into from Jan 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dvc/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def getter(self):

return Remote(self.repo, name=remote)

getter.__name__ = str(name)
getter.__name__ = name
return cached_property(getter)


Expand Down
7 changes: 2 additions & 5 deletions dvc/daemon.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
from dvc.env import DVC_DAEMON
from dvc.utils import fix_env
from dvc.utils import is_binary
from dvc.utils.compat import cast_bytes_py2


logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -98,9 +97,7 @@ def daemon(args):

env = fix_env()
file_path = os.path.abspath(inspect.stack()[0][1])
env[cast_bytes_py2("PYTHONPATH")] = cast_bytes_py2(
os.path.dirname(os.path.dirname(file_path))
)
env[cast_bytes_py2(DVC_DAEMON)] = cast_bytes_py2("1")
env["PYTHONPATH"] = os.path.dirname(os.path.dirname(file_path))
env[DVC_DAEMON] = "1"

_spawn(cmd, env)
1 change: 0 additions & 1 deletion dvc/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import colorama

from dvc.progress import Tqdm
from dvc.utils.compat import RecursionError


FOOTER = (
Expand Down
2 changes: 1 addition & 1 deletion dvc/path_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def __str__(self):
return relpath(path)

def __repr__(self):
return str("{}: '{}'").format(type(self).__name__, self)
return "{}: '{}'".format(type(self).__name__, self)

# This permits passing it to file utils directly in Python 3.6+
# With Python 2.7, Python 3.5+ we are stuck with path_info.fspath for now
Expand Down
3 changes: 1 addition & 2 deletions dvc/repo/metrics/show.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
from dvc.exceptions import NoMetricsError
from dvc.exceptions import OutputNotFoundError
from dvc.repo import locked
from dvc.utils.compat import csv_reader
from dvc.utils.compat import open

NO_METRICS_FILE_AT_REFERENCE_WARNING = (
Expand Down Expand Up @@ -101,7 +100,7 @@ def _format_csv(content, delimiter):
"0.67528 0.289545 testing\n"
"0.671502 0.297848 validation\n"
"""
reader = csv_reader(io.StringIO(content), delimiter=delimiter)
reader = csv.reader(io.StringIO(content), delimiter=delimiter)
rows = [row for row in reader]
max_widths = [max(map(len, column)) for column in zip(*rows)]

Expand Down
9 changes: 2 additions & 7 deletions dvc/rwlock.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,7 @@

from .exceptions import DvcException
from .lock import LockError
from .utils.compat import (
convert_to_unicode,
FileNotFoundError,
JSONDecodeError,
str,
)
from .utils.compat import FileNotFoundError, JSONDecodeError, str
from .utils.fs import relpath

INFO_SCHEMA = {"pid": int, "cmd": str}
Expand Down Expand Up @@ -44,7 +39,7 @@ def _edit_rwlock(lock_dir):
try:
with open(path, "r") as fobj:
lock = json.load(fobj)
lock = SCHEMA(convert_to_unicode(lock))
lock = SCHEMA(lock)
except FileNotFoundError:
lock = SCHEMA({})
except JSONDecodeError as exc:
Expand Down
3 changes: 1 addition & 2 deletions dvc/scm/git/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
from dvc.utils import is_binary
from dvc.utils import relpath
from dvc.utils.fs import path_isin
from dvc.utils.compat import cast_bytes_py2
from dvc.utils.compat import open


Expand Down Expand Up @@ -76,7 +75,7 @@ def clone(url, to_path, rev=None):
# LD_LIBRARY_PATH that has been set by PyInstaller.
# See [1] for more info.
# [1] https://github.com/gitpython-developers/GitPython/issues/924
env[cast_bytes_py2(ld_key)] = ""
env[ld_key] = ""

try:
tmp_repo = git.Repo.clone_from(
Expand Down
4 changes: 1 addition & 3 deletions dvc/stage.py
Original file line number Diff line number Diff line change
Expand Up @@ -421,10 +421,8 @@ def update(self):

@staticmethod
def validate(d, fname=None):
from dvc.utils.compat import convert_to_unicode

try:
Stage.COMPILED_SCHEMA(convert_to_unicode(d))
Stage.COMPILED_SCHEMA(d)
except MultipleInvalid as exc:
raise StageFileFormatError(fname, exc)

Expand Down
9 changes: 3 additions & 6 deletions dvc/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,8 @@
from ruamel.yaml import YAML
from shortuuid import uuid

from dvc.utils.compat import cast_bytes_py2
from dvc.utils.compat import fspath
from dvc.utils.compat import fspath_py35
from dvc.utils.compat import makedirs as _makedirs
from dvc.utils.compat import open


Expand Down Expand Up @@ -143,15 +141,15 @@ def makedirs(path, exist_ok=False, mode=None):
path = fspath_py35(path)

if mode is None:
_makedirs(path, exist_ok=exist_ok)
os.makedirs(path, exist_ok=exist_ok)
return

# utilize umask to set proper permissions since Python 3.7 the `mode`
# `makedirs` argument no longer affects the file permission bits of
# newly-created intermediate-level directories.
umask = os.umask(0o777 - mode)
try:
_makedirs(path, exist_ok=exist_ok)
os.makedirs(path, exist_ok=exist_ok)
finally:
os.umask(umask)

Expand Down Expand Up @@ -205,8 +203,7 @@ def fix_env(env=None):
lp_key = "LD_LIBRARY_PATH"
lp_orig = env.get(lp_key + "_ORIG", None)
if lp_orig is not None:
# NOTE: py2 doesn't like unicode strings in environ
env[cast_bytes_py2(lp_key)] = cast_bytes_py2(lp_orig)
env[lp_key] = lp_orig
else:
env.pop(lp_key, None)

Expand Down
95 changes: 0 additions & 95 deletions dvc/utils/compat.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"""Handle import compatibility between Python 2 and Python 3"""

import errno
import os
import sys
from contextlib import contextmanager

Expand All @@ -14,84 +13,6 @@
#: Python 3.x?
is_py3 = _ver[0] == 3

# simplified version of ipython_genutils/encoding.py
DEFAULT_ENCODING = sys.getdefaultencoding()

if _ver[:2] < (3, 5):
RecursionError = RuntimeError
else:
RecursionError = RecursionError


def no_code(x, encoding=None):
return x


def encode(u, encoding=None):
encoding = encoding or DEFAULT_ENCODING
return u.encode(encoding, "replace")


def csv_reader(unicode_csv_data, dialect=None, **kwargs):
"""csv.reader doesn't support Unicode input, so need to use some tricks
to work around this.

Source: https://docs.python.org/2/library/csv.html#csv-examples
"""
import csv

dialect = dialect or csv.excel

if is_py3:
# Python3 supports encoding by default, so just return the object
for row in csv.reader(unicode_csv_data, dialect=dialect, **kwargs):
yield [cell for cell in row]

else:
# csv.py doesn't do Unicode; encode temporarily as UTF-8:
reader = csv.reader(
utf_8_encoder(unicode_csv_data), dialect=dialect, **kwargs
)
for row in reader:
# decode UTF-8 back to Unicode, cell by cell:
yield [unicode(cell, "utf-8") for cell in row] # noqa: F821


def utf_8_encoder(unicode_csv_data):
"""Source: https://docs.python.org/2/library/csv.html#csv-examples"""
for line in unicode_csv_data:
yield line.encode("utf-8")


def cast_bytes(s, encoding=None):
"""Source: https://github.com/ipython/ipython_genutils"""
if not isinstance(s, bytes):
return encode(s, encoding)
return s


def _makedirs(name, mode=0o777, exist_ok=False):
"""Source: https://github.com/python/cpython/blob/
3ce3dea60646d8a5a1c952469a2eb65f937875b3/Lib/os.py#L196-L226
"""
head, tail = os.path.split(name)
if not tail:
head, tail = os.path.split(head)
if head and tail and not os.path.exists(head):
try:
_makedirs(head, exist_ok=exist_ok)
except OSError as e:
if e.errno != errno.EEXIST:
raise
cdir = os.curdir
if tail == cdir:
return
try:
os.mkdir(name, mode)
except OSError:
if not exist_ok or not os.path.isdir(name):
raise


@contextmanager
def ignore_file_not_found():
Expand All @@ -118,8 +39,6 @@ def ignore_file_not_found():
numeric_types = (int, long, float) # noqa: F821
integer_types = (int, long) # noqa: F821
input = raw_input # noqa: F821
cast_bytes_py2 = cast_bytes
makedirs = _makedirs
range = xrange # noqa: F821
FileNotFoundError = IOError
JSONDecodeError = ValueError
Expand All @@ -141,19 +60,9 @@ def __enter__(self):
def __exit__(self, *args):
self.close()

def convert_to_unicode(data):
if isinstance(data, builtin_str):
return str(data)
if isinstance(data, dict):
return dict(map(convert_to_unicode, data.items()))
if isinstance(data, (list, tuple)):
return type(data)(map(convert_to_unicode, data))
return data


elif is_py3:
import pathlib # noqa: F401
from os import makedirs # noqa: F401
from urllib.parse import ( # noqa: F401
urlparse, # noqa: F401
urlunparse, # noqa: F401
Expand All @@ -174,13 +83,9 @@ def convert_to_unicode(data):
integer_types = (int,) # noqa: F821
input = input # noqa: F821
open = open # noqa: F821
cast_bytes_py2 = no_code
range = range # noqa: F821
FileNotFoundError = FileNotFoundError

def convert_to_unicode(data):
return data


# Backport os.fspath() from Python 3.6
try:
Expand Down
2 changes: 1 addition & 1 deletion dvc/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def _is_release(dir_path, base_version):
["git", "describe", "--tags", "--exact-match"],
cwd=dir_path,
stderr=subprocess.STDOUT,
).decode("utf-8")
)
tag = output.strip()
return tag == base_version
except subprocess.CalledProcessError:
Expand Down
5 changes: 2 additions & 3 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,14 @@

from dvc.remote.ssh.connection import SSHConnection
from dvc.repo import Repo as DvcRepo
from dvc.utils.compat import cast_bytes_py2
from .basic_env import TestDirFixture, TestDvcGitFixture, TestGitFixture
from .dir_helpers import * # noqa


# Prevent updater and analytics from running their processes
os.environ[cast_bytes_py2("DVC_TEST")] = cast_bytes_py2("true")
os.environ["DVC_TEST"] = "true"
# Ensure progress output even when not outputting to raw sys.stderr console
os.environ[cast_bytes_py2("DVC_IGNORE_ISATTY")] = cast_bytes_py2("true")
os.environ["DVC_IGNORE_ISATTY"] = "true"


@pytest.fixture(autouse=True)
Expand Down
5 changes: 2 additions & 3 deletions tests/unit/test_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import mock

import dvc.version
from dvc.utils.compat import cast_bytes


def test_is_release():
Expand All @@ -13,10 +12,10 @@ def test_is_release():
assert ret is False

m.side_effect = None
m.return_value = cast_bytes(dvc.version._BASE_VERSION)
m.return_value = dvc.version._BASE_VERSION
ret = dvc.version._is_release(None, dvc.version._BASE_VERSION)
assert ret

m.return_value = cast_bytes("630d1741c2d5dd89a3176bd15b63121b905d35c9")
m.return_value = "630d1741c2d5dd89a3176bd15b63121b905d35c9"
ret = dvc.version._is_release(None, dvc.version._BASE_VERSION)
assert ret is False