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

Port majority of pants/util #6073

Merged
merged 7 commits into from
Jul 9, 2018
Merged
Show file tree
Hide file tree
Changes from 3 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
42 changes: 31 additions & 11 deletions src/python/pants/util/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,22 @@ python_library(
)

python_library(
name = 'contextutil',
sources = ['contextutil.py'],
dependencies = [
'3rdparty/python:ansicolors',
'3rdparty/python:six',
':dirutil',
':tarutil',
],
name = 'contextutil',
sources = ['contextutil.py'],
dependencies = [
'3rdparty/python:ansicolors',
'3rdparty/python:future',
':dirutil',
':tarutil',
],
)

python_library(
name = 'collections',
sources = ['collections.py'],
dependencies = [
'3rdparty/python:future',
]
)

python_library(
Expand Down Expand Up @@ -48,7 +51,7 @@ python_library(
name = 'eval',
sources = ['eval.py'],
dependencies = [
'3rdparty/python:six',
'3rdparty/python:future',
]
)

Expand All @@ -63,6 +66,9 @@ python_library(
python_library(
name = 'filtering',
sources = ['filtering.py'],
dependencies = [
'3rdparty/python:future',
]
)

python_library(
Expand All @@ -78,6 +84,9 @@ python_library(
python_library(
name = 'netrc',
sources = ['netrc.py'],
dependencies = [
'3rdparty/python:future',
]
)

python_library(
Expand All @@ -92,6 +101,9 @@ python_library(
python_library(
name = 'osutil',
sources = ['osutil.py'],
dependencies = [
'3rdparty/python:future',
]
)

python_library(
Expand All @@ -107,12 +119,16 @@ python_library(
python_library(
name = 'retry',
sources = ['retry.py'],
dependencies = [
'3rdparty/python:future',
]
)

python_library(
name = 'rwbuf',
sources = ['rwbuf.py'],
dependencies = [
'3rdparty/python:future',
'3rdparty/python:six',
]
)
Expand All @@ -121,6 +137,7 @@ python_library(
name = 's3_log_aggregator',
sources = ['s3_log_aggregator.py'],
dependencies = [
'3rdparty/python:future',
'3rdparty/python:s3logparse'
]
)
Expand All @@ -135,14 +152,17 @@ python_binary(

python_library(
name = 'socket',
sources = ['socket.py']
sources = ['socket.py'],
dependencies = [
'3rdparty/python:future',
]
)

python_library(
name = 'strutil',
sources = ['strutil.py'],
dependencies = [
'3rdparty/python:six',
'3rdparty/python:future',
],
)

Expand Down
2 changes: 2 additions & 0 deletions src/python/pants/util/collections.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
from __future__ import (absolute_import, division, generators, nested_scopes, print_function,
unicode_literals, with_statement)

from builtins import next


def combined_dict(*dicts):
"""Combine one or more dicts into a new, unified dict (dicts to the right take precedence)."""
Expand Down
6 changes: 4 additions & 2 deletions src/python/pants/util/contextutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@
import time
import uuid
import zipfile
from builtins import object, str
from contextlib import closing, contextmanager

from colors import green
from six import string_types
from future.utils import string_types

from pants.util.dirutil import safe_delete
from pants.util.tarutil import TarFile
Expand Down Expand Up @@ -291,7 +292,8 @@ def open_tar(path_or_file, *args, **kwargs):
If path_or_file is a file, caller must close it separately.
"""
(path, fileobj) = ((path_or_file, None) if isinstance(path_or_file, string_types)
else (None, path_or_file))
else (None, path_or_file)) # TODO(python3port): stop using six.string_types
# This should only accept python3 `str`, not byte strings.
with closing(TarFile.open(path, *args, fileobj=fileobj, **kwargs)) as tar:
yield tar

Expand Down
7 changes: 4 additions & 3 deletions src/python/pants/util/eval.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
from __future__ import (absolute_import, division, generators, nested_scopes, print_function,
unicode_literals, with_statement)

from builtins import range, str
from textwrap import dedent

import six
import future


def parse_expression(val, acceptable_types, name=None, raise_type=ValueError):
Expand All @@ -26,7 +27,7 @@ def parse_expression(val, acceptable_types, name=None, raise_type=ValueError):
def format_type(typ):
return typ.__name__

if not isinstance(val, six.string_types):
if not isinstance(val, future.utils.string_types):
raise raise_type('The raw `val` is not a string. Given {} of type {}.'
.format(val, format_type(type(val))))

Expand All @@ -35,7 +36,7 @@ def get_name():

def format_raw_value():
lines = val.splitlines()
for line_number in six.moves.range(0, len(lines)):
for line_number in range(0, len(lines)):
lines[line_number] = "{line_number:{width}}: {line}".format(
line_number=line_number + 1,
line=lines[line_number],
Expand Down
4 changes: 2 additions & 2 deletions src/python/pants/util/filtering.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ def create_filter(predicate_param, predicate_factory):
# NOTE: Do not inline this into create_filters above. A separate function is necessary
# in order to capture the different closure on each invocation.
modifier, param = _extract_modifier(predicate_param)
predicates = map(predicate_factory, param.split(','))
predicates = [predicate_factory(p) for p in param.split(',')]
def filt(x):
return modifier(any(map(lambda pred: pred(x), predicates)))
return modifier(any(pred(x) for pred in predicates))
return filt


Expand Down
1 change: 1 addition & 0 deletions src/python/pants/util/netrc.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import collections
import os
from builtins import object
from netrc import netrc as NetrcDb
from netrc import NetrcParseError

Expand Down
3 changes: 2 additions & 1 deletion src/python/pants/util/osutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import os
from functools import reduce


logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -45,7 +46,7 @@ def get_normalized_os_name():


def all_normalized_os_names():
return OS_ALIASES.keys()
return list(OS_ALIASES.keys())


def known_os_names():
Expand Down
1 change: 1 addition & 0 deletions src/python/pants/util/retry.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import logging
import time
from builtins import range


logger = logging.getLogger(__name__)
Expand Down
1 change: 1 addition & 0 deletions src/python/pants/util/rwbuf.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
unicode_literals, with_statement)

import threading
from builtins import object, str
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@benjyw can you look over this file please?

This override means that in line 39, during call to _RWBuf.write(), it will call _RWBuf.do_write() with unicode, rather than bytes, which might be a problem. However, do_write() simply raises NotImplementedError, so I don't know if this actually matters?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand correctly, from builtins import str is a no-op in py3 but renames py2's unicode type to str in py2? I think this definitely will have consequences. A low-level IO method should always operate on raw bytes (str in py2, bytes in py3), never on encoded strings.

However this file only explicitly uses str in one line, and that's hacky:

self.do_write(str(s))

If s is already binary data, no problem, but if it's text, then in python2 that str(s) would attempt to encode it using the default encoding, which is not guaranteed to work.

So really write() should check if the argument is bytes, and throw an exception of not. That way we'll find out eagerly if any call sites do the wrong thing.

Does that make sense?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I imagine something like from builtins import bytes and then in write() check for isinstance(s, bytes).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, exactly. from builtins import str modifies Python2's str() function so that it gets a unicode, rather than bytes, representation.

Agreed with that change. I'll break it out into a separate PR since it's a substantial semantic change + we have no explicit tests for this file.

Copy link
Contributor

@benjyw benjyw Jul 9, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually what I'm proposing involves no semantic change. This commit, as stands, would be a major semantic change, as it would cast arbitrary bytes into text, which might explode. So you can't merge this as-is.


from six import StringIO

Expand Down
1 change: 1 addition & 0 deletions src/python/pants/util/s3_log_aggregator.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import os
import sys
from builtins import object
from collections import defaultdict

from s3logparse.s3logparse import parse_log_lines
Expand Down
1 change: 1 addition & 0 deletions src/python/pants/util/socket.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import io
import select
import socket
from builtins import object


def teardown_socket(s):
Expand Down
12 changes: 6 additions & 6 deletions src/python/pants/util/strutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,29 @@
import re
import shlex

import six
import future


def ensure_binary(text_or_binary):
if isinstance(text_or_binary, six.binary_type):
if isinstance(text_or_binary, future.utils.binary_type):
return text_or_binary
elif isinstance(text_or_binary, six.text_type):
elif isinstance(text_or_binary, future.utils.text_type):
return text_or_binary.encode('utf8')
else:
raise TypeError('Argument is neither text nor binary type.({})'.format(type(text_or_binary)))


def ensure_text(text_or_binary):
if isinstance(text_or_binary, six.binary_type):
if isinstance(text_or_binary, future.utils.binary_type):
return text_or_binary.decode('utf-8')
elif isinstance(text_or_binary, six.text_type):
elif isinstance(text_or_binary, future.utils.text_type):
return text_or_binary
else:
raise TypeError('Argument is neither text nor binary type ({})'.format(type(text_or_binary)))


def is_text_or_binary(obj):
return isinstance(obj, (six.text_type, six.binary_type))
return isinstance(obj, (future.utils.text_type, future.utils.binary_type))


def safe_shlex_split(text_or_binary):
Expand Down
1 change: 1 addition & 0 deletions src/python/pants/util/xml_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from __future__ import (absolute_import, division, generators, nested_scopes, print_function,
unicode_literals, with_statement)

from builtins import object
from xml.dom.minidom import parse


Expand Down
10 changes: 8 additions & 2 deletions tests/python/pants_test/util/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ python_tests(
sources = ['test_collections.py'],
coverage = ['pants.util.collections'],
dependencies = [
'3rdparty/python:future',
'src/python/pants/util:collections',
]
)
Expand All @@ -24,6 +25,7 @@ python_tests(
sources = ['test_contextutil.py'],
coverage = ['pants.util.contextutil'],
dependencies = [
'3rdparty/python:future',
'3rdparty/python:mock',
'src/python/pants/util:contextutil',
'src/python/pants/util:process_handler',
Expand All @@ -35,8 +37,8 @@ python_tests(
sources = ['test_dirutil.py'],
coverage = ['pants.util.dirutil'],
dependencies = [
'3rdparty/python:future',
'3rdparty/python:mock',
'3rdparty/python:six',
'src/python/pants/util:contextutil',
'src/python/pants/util:dirutil',
'src/python/pants/util:objects',
Expand All @@ -47,7 +49,7 @@ python_tests(
name = 'eval',
sources = ['test_eval.py'],
dependencies = [
'3rdparty/python:six',
'3rdparty/python:future',
'src/python/pants/util:eval',
]
)
Expand All @@ -73,6 +75,7 @@ python_tests(
name = 'memo',
sources = ['test_memo.py'],
dependencies = [
'3rdparty/python:future',
'src/python/pants/util:memo',
'src/python/pants/util:meta',
]
Expand All @@ -91,6 +94,7 @@ python_tests(
name = 'netrc',
sources = ['test_netrc.py'],
dependencies = [
'3rdparty/python:future',
'3rdparty/python:mock',
'src/python/pants/util:netrc',
]
Expand All @@ -110,6 +114,7 @@ python_tests(
name = 'osutil',
sources = ['test_osutil.py'],
dependencies = [
'3rdparty/python:future',
'src/python/pants/util:osutil',
'tests/python/pants_test:test_base',
]
Expand Down Expand Up @@ -146,6 +151,7 @@ python_tests(
name = 'strutil',
sources = ['test_strutil.py'],
dependencies = [
'3rdparty/python:future',
'src/python/pants/util:strutil',
]
)
Expand Down
1 change: 1 addition & 0 deletions tests/python/pants_test/util/test_collections.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
unicode_literals, with_statement)

import unittest
from builtins import str

from pants.util.collections import assert_single_element, combined_dict, recursively_update

Expand Down
1 change: 1 addition & 0 deletions tests/python/pants_test/util/test_contextutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import unittest
import uuid
import zipfile
from builtins import next, object, range, str
from contextlib import contextmanager

import mock
Expand Down
6 changes: 3 additions & 3 deletions tests/python/pants_test/util/test_dirutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
import unittest
from contextlib import contextmanager

import future
import mock
import six

from pants.util import dirutil
from pants.util.contextutil import pushd, temporary_dir
Expand Down Expand Up @@ -120,10 +120,10 @@ def test_safe_walk(self):
# unicode constructor.
with temporary_dir() as tmpdir:
safe_mkdir(os.path.join(tmpdir, '中文'))
if isinstance(tmpdir, six.text_type):
if isinstance(tmpdir, future.utils.text_type):
tmpdir = tmpdir.encode('utf-8')
for _, dirs, _ in dirutil.safe_walk(tmpdir):
self.assertTrue(all(isinstance(dirname, six.text_type) for dirname in dirs))
self.assertTrue(all(isinstance(dirname, future.utils.text_type) for dirname in dirs))

@contextmanager
def tree(self):
Expand Down
Loading