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

Python 3 - fixes to get green contrib #6340

Merged
merged 21 commits into from
Aug 16, 2018
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
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
8 changes: 4 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -170,15 +170,15 @@ matrix:

- <<: *default_test_config
env:
- SHARD="Python contrib tests - shard 1"
- SHARD="Py2 - Python contrib tests"
script:
- ./build-support/bin/ci.sh -n -y 0/2 "${SHARD}"
- ./build-support/bin/ci.sh -n "${SHARD}"

- <<: *default_test_config
env:
- SHARD="Python contrib tests - shard 2"
- SHARD="Py3 - Python contrib tests"
script:
- ./build-support/bin/ci.sh -n -y 1/2 "${SHARD}"
- ./build-support/bin/ci.sh -3n "${SHARD}"

- <<: *default_test_config
env:
Expand Down
4 changes: 2 additions & 2 deletions contrib/go/src/python/pants/contrib/go/tasks/go_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ def go_stdlib(self):
:rtype: frozenset of string
"""
out = self._go_dist.create_go_cmd('list', args=['std']).check_output()
return frozenset(out.strip().split())
return frozenset(out.decode('utf-8').strip().split())

# This simple regex mirrors the behavior of the relevant go code in practice (see
# repoRootForImportDynamic and surrounding code in
Expand Down Expand Up @@ -154,7 +154,7 @@ def list_imports(self, pkg, gopath=None):
if returncode != 0:
raise self.ListDepsError('Problem listing imports for {}: {} failed with exit code {}'
.format(pkg, go_cmd, returncode))
data = json.loads(out)
data = json.loads(out.decode('utf-8'))

# XTestImports are for black box tests. These test files live inside the package dir but
# declare a different package and thus can only access the public members of the package's
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,15 @@ def assert_no_gopath(self):
self.assertEqual(go_env, go_cmd.env)
self.assertEqual('go', os.path.basename(go_cmd.cmdline[0]))
self.assertEqual(['env', 'GOPATH'], go_cmd.cmdline[1:])
self.assertRegexpMatches(str(go_cmd),
r'^GOROOT=[^ ]+ GOPATH={} .*/go env GOPATH'.format(default_gopath))
self.assertEqual(default_gopath, go_cmd.check_output().decode('utf-8').strip())

goroot_env = r'GOROOT=[^ ]+'
Copy link
Sponsor Member

Choose a reason for hiding this comment

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

Would be good to lift these into constants.

gopath_env = r'GOPATH={}'.format(default_gopath)
# order of env values varies by interpreter and platform
env_values = r'({goroot_env} {gopath_env}|{gopath_env} {goroot_env})'.format(goroot_env=goroot_env, gopath_env=gopath_env)
regex = r'^{env_values} .*/go env GOPATH$'.format(env_values=env_values)
self.assertRegexpMatches(str(go_cmd), regex)

def test_go_command_no_gopath(self):
self.assert_no_gopath()

Expand All @@ -68,4 +73,10 @@ def test_go_command_gopath(self):
'GOPATH': '/tmp/fred'}, go_cmd.env)
self.assertEqual('go', os.path.basename(go_cmd.cmdline[0]))
self.assertEqual(['env', 'GOROOT'], go_cmd.cmdline[1:])
self.assertRegexpMatches(str(go_cmd), r'^GOROOT=[^ ]+ GOPATH=/tmp/fred .*/go env GOROOT$')

goroot_env = r'GOROOT=[^ ]+'
gopath_env = r'GOPATH=/tmp/fred'
# order of env values varies by interpreter and platform
env_values = r'({goroot_env} {gopath_env}|{gopath_env} {goroot_env})'.format(goroot_env=goroot_env, gopath_env=gopath_env)
regex = r'^{env_values} .*/go env GOROOT$'.format(env_values=env_values)
self.assertRegexpMatches(str(go_cmd), regex)
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ def test_go_compile_simple(self):
pants_run = self.run_pants_with_workdir(args, workdir)
self.assert_success(pants_run)
go_dist = global_subsystem_instance(GoDistribution)
goos = go_dist.create_go_cmd('env', args=['GOOS']).check_output().strip()
goarch = go_dist.create_go_cmd('env', args=['GOARCH']).check_output().strip()
goos = go_dist.create_go_cmd('env', args=['GOOS']).check_output().decode('utf-8').strip()
goarch = go_dist.create_go_cmd('env', args=['GOARCH']).check_output().decode('utf-8').strip()
expected_files = set('contrib.go.examples.src.go.{libname}.{libname}/'
'pkg/{goos}_{goarch}/{libname}.a'
.format(libname=libname, goos=goos, goarch=goarch)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def test_get_remote_import_paths(self):
""")
remote_import_ids = go_fetch._get_remote_import_paths('github.com/u/a',
gopath=self.build_root)
self.assertItemsEqual(remote_import_ids, ['bitbucket.org/u/b', 'github.com/u/c'])
self.assertEqual(sorted(remote_import_ids), sorted(['bitbucket.org/u/b', 'github.com/u/c']))

def test_resolve_and_inject_explicit(self):
r1 = self.make_target(spec='3rdparty/go/r1', target_type=GoRemoteLibrary)
Expand Down Expand Up @@ -219,4 +219,4 @@ def test_issues_2616(self):
""")
remote_import_ids = go_fetch._get_remote_import_paths('github.com/u/a',
gopath=self.build_root)
self.assertItemsEqual(remote_import_ids, ['bitbucket.org/u/b', 'github.com/u/c'])
self.assertEqual(sorted(remote_import_ids), sorted(['bitbucket.org/u/b', 'github.com/u/c']))
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ def test_lint_badformat(self):
with self.assertRaises(TaskError) as error:
self.execute(context)
self.assertEqual(
error.exception.message,
str(error.exception),
'google-java-format failed with exit code 1; to fix run: `./pants fmt <targets>`'
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def check_output(self, **kwargs):
:raises: :class:`subprocess.CalledProcessError` if the command fails.
"""
env, kwargs = self._prepare_env(kwargs)
return subprocess.check_output(self.cmd, env=env, **kwargs)
return subprocess.check_output(self.cmd, env=env, **kwargs).decode('utf-8')

def __str__(self):
return ' '.join(self.cmd)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def setUp(self):

def test_bootstrap(self):
node_cmd = self.distribution.node_command(args=['--version'])
output = node_cmd.check_output().decode('utf-8').strip()
output = node_cmd.check_output().strip()
self.assertEqual(self.distribution.version(), output)

def test_node(self):
Expand All @@ -42,7 +42,7 @@ def test_node(self):
def test_npm(self):
npm_version_flag = self.distribution.get_package_manager('npm').run_command(
args=['--version'])
raw_version = npm_version_flag.check_output().decode('utf-8').strip()
raw_version = npm_version_flag.check_output().strip()

npm_version_cmd = self.distribution.get_package_manager('npm').run_command(
args=['version', '--json'])
Expand All @@ -54,7 +54,7 @@ def test_npm(self):
def test_yarnpkg(self):
yarnpkg_version_command = self.distribution.get_package_manager('yarn').run_command(
args=['--version'])
yarnpkg_version = yarnpkg_version_command.check_output().decode('utf-8').strip()
yarnpkg_version = yarnpkg_version_command.check_output().strip()
yarnpkg_versions_command = self.distribution.get_package_manager('yarn').run_command(
args=['versions', '--json'])
yarnpkg_versions = json.loads(yarnpkg_versions_command.check_output())
Expand All @@ -67,7 +67,7 @@ def test_node_command_path_injection(self):

# Test the case in which we do not pass in env,
# which should fall back to env=os.environ.copy()
injected_paths = node_path_cmd.check_output().decode('utf-8').strip().split(os.pathsep)
injected_paths = node_path_cmd.check_output().strip().split(os.pathsep)
self.assertEqual(node_bin_path, injected_paths[0])

def test_node_command_path_injection_with_overrided_path(self):
Expand All @@ -76,7 +76,7 @@ def test_node_command_path_injection_with_overrided_path(self):
node_bin_path = self.distribution._install_node()
injected_paths = node_path_cmd.check_output(
env={'PATH': '/test/path'}
).decode('utf-8').strip().split(os.pathsep)
).strip().split(os.pathsep)
self.assertEqual(node_bin_path, injected_paths[0])
self.assertListEqual([node_bin_path, '/test/path'], injected_paths)

Expand All @@ -86,5 +86,5 @@ def test_node_command_path_injection_with_empty_path(self):
node_bin_path = self.distribution._install_node()
injected_paths = node_path_cmd.check_output(
env={'PATH': ''}
).decode('utf-8').strip().split(os.pathsep)
).strip().split(os.pathsep)
self.assertListEqual([node_bin_path, ''], injected_paths)
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ class Error(TaskError):
"""A richer failure exception type useful for tests."""

def __init__(self, *args, **kwargs):
compiled = kwargs.pop(b'compiled')
failed = kwargs.pop(b'failed')
compiled = kwargs.pop('compiled')
failed = kwargs.pop('failed')
super(PythonEval.Error, self).__init__(*args, **kwargs)
self.compiled = compiled
self.failed = failed
Expand Down Expand Up @@ -139,9 +139,9 @@ def _compile_target(self, vt):
executable_file_content = self._get_executable_file_content(exec_pex_parent, modules)

hasher = hashlib.sha1()
hasher.update(reqs_pex.path())
hasher.update(srcs_pex.path())
hasher.update(executable_file_content)
hasher.update(reqs_pex.path().encode('utf-8'))
hasher.update(srcs_pex.path().encode('utf-8'))
hasher.update(executable_file_content.encode('utf-8'))
exec_file_hash = hasher.hexdigest()
exec_pex_path = os.path.realpath(os.path.join(exec_pex_parent, exec_file_hash))
if not os.path.isdir(exec_pex_path):
Expand Down Expand Up @@ -215,7 +215,7 @@ def _resolve_requirements_for_versioned_target_closure(self, interpreter, vt):
reqs_pex_path = os.path.realpath(os.path.join(self.workdir, str(interpreter.identity),
vt.cache_key.hash))
if not os.path.isdir(reqs_pex_path):
req_libs = [t for t in vt.target.closure() if has_python_requirements(t)]
req_libs = [t for t in vt.target.closure() if has_python_requirements(t)]
with safe_concurrent_creation(reqs_pex_path) as safe_path:
builder = PEXBuilder(safe_path, interpreter=interpreter, copy=True)
dump_requirement_libs(builder, interpreter, req_libs, self.context.log)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
from pants_test.backend.python.tasks.python_task_test_base import PythonTaskTestBase

from pants.contrib.python.checks.tasks.checkstyle.checker import PythonCheckStyleTask
from pants.contrib.python.checks.tasks.checkstyle.print_statements_subsystem import \
PrintStatementsSubsystem
from pants.contrib.python.checks.tasks.checkstyle.variable_names_subsystem import \
VariableNamesSubsystem
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The Print Statements tests don't work as expected on Py3. Because they raise a syntax error with Python 3, the tests weren't working as intended.

So, I changed to using Variable Names. The specific error doesn't matter much - this file tests the checker mechanics, and there are other files to check each specific subsystem.



class PythonCheckStyleTaskTest(PythonTaskTestBase):
Expand All @@ -24,7 +24,7 @@ def task_type(cls):
def setUp(self):
super(PythonCheckStyleTaskTest, self).setUp()
PythonCheckStyleTask.clear_plugins()
PythonCheckStyleTask.register_plugin('print-statements', PrintStatementsSubsystem)
PythonCheckStyleTask.register_plugin('variable-names', VariableNamesSubsystem)

def tearDown(self):
super(PythonCheckStyleTaskTest, self).tearDown()
Expand All @@ -36,7 +36,8 @@ def test_no_sources(self):

def test_pass(self):
self.create_file('a/python/pass.py', contents=dedent("""
print('Print is a function')
class UpperCase:
pass
"""))
target = self.make_target('a/python:pass', PythonLibrary, sources=['pass.py'])
context = self.context(target_roots=[target])
Expand All @@ -45,7 +46,8 @@ def test_pass(self):

def test_failure(self):
self.create_file('a/python/fail.py', contents=dedent("""
print 'Print should not be used as a statement'
class lower_case:
pass
"""))
target = self.make_target('a/python:fail', PythonLibrary, sources=['fail.py'])
context = self.context(target_roots=[target])
Expand All @@ -56,20 +58,21 @@ def test_failure(self):

def test_suppressed_file_passes(self):
self.create_file('a/python/fail.py', contents=dedent("""
print 'Print should not be used as a statement'
class lower_case:
pass
"""))
suppression_file = self.create_file('suppress.txt', contents=dedent("""
a/python/fail\.py::print-statements"""))
a/python/fail\.py::variable-names"""))
target = self.make_target('a/python:fail', PythonLibrary, sources=['fail.py'])
self.set_options(suppress=suppression_file)
context = self.context(target_roots=[target], )
task = self.create_task(context)

self.assertEqual(0, task.execute())

def test_failure_fail_false(self):
self.create_file('a/python/fail.py', contents=dedent("""
print 'Print should not be used as a statement'
class lower_case:
pass
"""))
target = self.make_target('a/python:fail', PythonLibrary, sources=['fail.py'])
self.set_options(fail=False)
Expand All @@ -90,7 +93,8 @@ def test_syntax_error(self):

def test_failure_print_nit(self):
self.create_file('a/python/fail.py', contents=dedent("""
print 'Print should not be used as a statement'
class lower_case:
pass
"""))
target = self.make_target('a/python:fail', PythonLibrary, sources=['fail.py'])
context = self.context(target_roots=[target])
Expand All @@ -100,8 +104,8 @@ def test_failure_print_nit(self):

self.assertEqual(1, len(nits))
self.assertEqual(
"""T607:ERROR a/python/fail.py:002 Print used as a statement.\n"""
""" |print 'Print should not be used as a statement'""",
"""T000:ERROR a/python/fail.py:002 Classes must be UpperCamelCased\n"""
""" |class lower_case:""",
str(nits[0]))

def test_syntax_error_nit(self):
Expand All @@ -121,21 +125,3 @@ def test_syntax_error_nit(self):
""" |invalid python\n"""
""" |""",
str(nits[0]))

def test_multiline_nit_printed_only_once(self):
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I couldn't think of an alternative test - it seems like the original was more related to print logic than checker logic?

Let me know if you have ideas.

self.create_file('a/python/fail.py', contents=dedent("""
print ('Multi'
'line') + 'expression'
"""))
target = self.make_target('a/python:fail', PythonLibrary, sources=['fail.py'])
context = self.context(target_roots=[target])
task = self.create_task(context)

nits = list(task.get_nits('a/python/fail.py'))

self.assertEqual(1, len(nits))
self.assertEqual(
"""T607:ERROR a/python/fail.py:002-003 Print used as a statement.\n"""
""" |print ('Multi'\n"""
""" | 'line') + 'expression'""",
str(nits[0]))
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ def compute_fingerprint(self, target):
return fp

hasher = hashlib.sha1()
hasher.update(fp)
hasher.update(self._thrift_defaults.language(target))
hasher.update(fp.encode('utf-8'))
hasher.update(self._thrift_defaults.language(target).encode('utf-8'))
hasher.update(str(self._thrift_defaults.compiler_args(target)).encode('utf-8'))

namespace_map = self._thrift_defaults.namespace_map(target)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,15 @@ def get_default_jvm_options():
thrift_target = self.create_library('a', 'java_thrift_library', 'a', ['A.thrift'])
task = self.create_task(self.context(target_roots=thrift_target))
self._prepare_mocks(task)
expected_include_paths = {'src/thrift/tweet', 'src/thrift/users'}
expected_paths = {'src/thrift/tweet/a.thrift', 'src/thrift/tweet/b.thrift'}
expected_include_paths = ['src/thrift/users', 'src/thrift/tweet']
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Set isn't deterministic between Py2 vs Py3, so have to use a list.

expected_paths = ['src/thrift/tweet/a.thrift', 'src/thrift/tweet/b.thrift']
mock_calculate_compile_sources.return_value = (expected_include_paths, expected_paths)
task._lint(thrift_target, task.tool_classpath('scrooge-linter'))

self._run_java_mock.assert_called_once_with(
classpath='foo_classpath',
main='com.twitter.scrooge.linter.Main',
args=['--ignore-errors', '--include-path', 'src/thrift/users', '--include-path',
'src/thrift/tweet', 'src/thrift/tweet/b.thrift', 'src/thrift/tweet/a.thrift'],
'src/thrift/tweet', 'src/thrift/tweet/a.thrift', 'src/thrift/tweet/b.thrift'],
jvm_options=get_default_jvm_options(),
workunit_labels=[WorkUnitLabel.COMPILER, WorkUnitLabel.SUPPRESS_LABEL])
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,10 @@ class AllTheThingsTestCase(unittest.TestCase):
def setUp(self):
self.config = json.loads(CONFIG_JSON)
self.soups = {
'index': bs4.BeautifulSoup(INDEX_HTML),
'subdir/page1': bs4.BeautifulSoup(P1_HTML),
'subdir/page2': bs4.BeautifulSoup(P2_HTML),
'subdir/page2_no_toc': bs4.BeautifulSoup(P2_HTML),
'index': bs4.BeautifulSoup(INDEX_HTML, 'html.parser'),
'subdir/page1': bs4.BeautifulSoup(P1_HTML, 'html.parser'),
'subdir/page2': bs4.BeautifulSoup(P2_HTML, 'html.parser'),
'subdir/page2_no_toc': bs4.BeautifulSoup(P2_HTML, 'html.parser'),
}
self.precomputed = sitegen.precompute(self.config, self.soups)

Expand Down
2 changes: 1 addition & 1 deletion src/python/pants/backend/jvm/ivy_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1017,7 +1017,7 @@ def generate_fetch_ivy(cls, jars, ivyxml, confs, resolve_hash_name):

@classmethod
def _write_ivy_xml_file(cls, ivyxml, template_data, template_relpath):
template_text = pkgutil.get_data(__name__, template_relpath)
template_text = pkgutil.get_data(__name__, template_relpath).decode('utf-8')
generator = Generator(template_text, lib=template_data)
with safe_open(ivyxml, 'w') as output:
generator.write(output)
Expand Down
7 changes: 4 additions & 3 deletions src/python/pants/backend/jvm/tasks/ivy_task_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,14 @@ def compute_fingerprint(self, target):
return None

hasher = hashlib.sha1()
hasher.update(target.payload.fingerprint().encode('utf-8'))
fingerprint = target.payload.fingerprint().encode('utf-8')
hasher.update(fingerprint)

for conf in self._confs:
hasher.update(conf)
hasher.update(conf.encode('utf-8'))

for element in hash_elements_for_target:
hasher.update(element)
hasher.update(element.encode('utf-8'))

return hasher.hexdigest() if PY3 else hasher.hexdigest().decode('utf-8')

Expand Down
Loading