Skip to content

Commit b0a2469

Browse files
Eric-ArellanoStu Hood
authored and
Stu Hood
committed
Python 3 - fixes to get green contrib (pantsbuild#6340)
All contrib folders should now be green on Python 2 and Python 3, excluding `googlejavaformat` and `python`. This fixes multiple issues causing Py3 failures + adds Py3 to Travis.
1 parent 070a5c5 commit b0a2469

File tree

21 files changed

+102
-92
lines changed

21 files changed

+102
-92
lines changed

.travis.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -175,15 +175,15 @@ matrix:
175175

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

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

188188
- <<: *default_test_config
189189
env:

contrib/go/src/python/pants/contrib/go/tasks/go_task.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ def go_stdlib(self):
9393
:rtype: frozenset of string
9494
"""
9595
out = self._go_dist.create_go_cmd('list', args=['std']).check_output()
96-
return frozenset(out.strip().split())
96+
return frozenset(out.decode('utf-8').strip().split())
9797

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

159159
# XTestImports are for black box tests. These test files live inside the package dir but
160160
# declare a different package and thus can only access the public members of the package's

contrib/go/tests/python/pants_test/contrib/go/subsystems/test_go_distribution.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@
1717

1818
class GoDistributionTest(unittest.TestCase):
1919

20+
@staticmethod
21+
def _generate_go_command_regex(gopath, final_value):
22+
goroot_env = r'GOROOT=[^ ]+'
23+
gopath_env = r'GOPATH={}'.format(gopath)
24+
# order of env values varies by interpreter and platform
25+
env_values = r'({goroot_env} {gopath_env}|{gopath_env} {goroot_env})'.format(goroot_env=goroot_env, gopath_env=gopath_env)
26+
return r'^{env_values} .*/go env {final_value}$'.format(env_values=env_values, final_value=final_value)
27+
2028
def distribution(self):
2129
return global_subsystem_instance(GoDistribution)
2230

@@ -46,10 +54,11 @@ def assert_no_gopath(self):
4654
self.assertEqual(go_env, go_cmd.env)
4755
self.assertEqual('go', os.path.basename(go_cmd.cmdline[0]))
4856
self.assertEqual(['env', 'GOPATH'], go_cmd.cmdline[1:])
49-
self.assertRegexpMatches(str(go_cmd),
50-
r'^GOROOT=[^ ]+ GOPATH={} .*/go env GOPATH'.format(default_gopath))
5157
self.assertEqual(default_gopath, go_cmd.check_output().decode('utf-8').strip())
5258

59+
regex = GoDistributionTest._generate_go_command_regex(gopath=default_gopath, final_value='GOPATH')
60+
self.assertRegexpMatches(str(go_cmd), regex)
61+
5362
def test_go_command_no_gopath(self):
5463
self.assert_no_gopath()
5564

@@ -68,4 +77,6 @@ def test_go_command_gopath(self):
6877
'GOPATH': '/tmp/fred'}, go_cmd.env)
6978
self.assertEqual('go', os.path.basename(go_cmd.cmdline[0]))
7079
self.assertEqual(['env', 'GOROOT'], go_cmd.cmdline[1:])
71-
self.assertRegexpMatches(str(go_cmd), r'^GOROOT=[^ ]+ GOPATH=/tmp/fred .*/go env GOROOT$')
80+
81+
regex = GoDistributionTest._generate_go_command_regex(gopath='/tmp/fred', final_value='GOROOT')
82+
self.assertRegexpMatches(str(go_cmd), regex)

contrib/go/tests/python/pants_test/contrib/go/tasks/test_go_compile_integration.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ def test_go_compile_simple(self):
2222
pants_run = self.run_pants_with_workdir(args, workdir)
2323
self.assert_success(pants_run)
2424
go_dist = global_subsystem_instance(GoDistribution)
25-
goos = go_dist.create_go_cmd('env', args=['GOOS']).check_output().strip()
26-
goarch = go_dist.create_go_cmd('env', args=['GOARCH']).check_output().strip()
25+
goos = go_dist.create_go_cmd('env', args=['GOOS']).check_output().decode('utf-8').strip()
26+
goarch = go_dist.create_go_cmd('env', args=['GOARCH']).check_output().decode('utf-8').strip()
2727
expected_files = set('contrib.go.examples.src.go.{libname}.{libname}/'
2828
'pkg/{goos}_{goarch}/{libname}.a'
2929
.format(libname=libname, goos=goos, goarch=goarch)

contrib/go/tests/python/pants_test/contrib/go/tasks/test_go_fetch.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ def test_get_remote_import_paths(self):
4141
""")
4242
remote_import_ids = go_fetch._get_remote_import_paths('github.com/u/a',
4343
gopath=self.build_root)
44-
self.assertItemsEqual(remote_import_ids, ['bitbucket.org/u/b', 'github.com/u/c'])
44+
self.assertEqual(sorted(remote_import_ids), sorted(['bitbucket.org/u/b', 'github.com/u/c']))
4545

4646
def test_resolve_and_inject_explicit(self):
4747
r1 = self.make_target(spec='3rdparty/go/r1', target_type=GoRemoteLibrary)
@@ -219,4 +219,4 @@ def test_issues_2616(self):
219219
""")
220220
remote_import_ids = go_fetch._get_remote_import_paths('github.com/u/a',
221221
gopath=self.build_root)
222-
self.assertItemsEqual(remote_import_ids, ['bitbucket.org/u/b', 'github.com/u/c'])
222+
self.assertEqual(sorted(remote_import_ids), sorted(['bitbucket.org/u/b', 'github.com/u/c']))

contrib/googlejavaformat/tests/python/pants_test/contrib/googlejavaformat/test_googlejavaformat.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ def test_lint_badformat(self):
8686
with self.assertRaises(TaskError) as error:
8787
self.execute(context)
8888
self.assertEqual(
89-
error.exception.message,
89+
str(error.exception),
9090
'google-java-format failed with exit code 1; to fix run: `./pants fmt <targets>`'
9191
)
9292

contrib/node/src/python/pants/contrib/node/subsystems/command.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ def check_output(self, **kwargs):
6363
:raises: :class:`subprocess.CalledProcessError` if the command fails.
6464
"""
6565
env, kwargs = self._prepare_env(kwargs)
66-
return subprocess.check_output(self.cmd, env=env, **kwargs)
66+
return subprocess.check_output(self.cmd, env=env, **kwargs).decode('utf-8')
6767

6868
def __str__(self):
6969
return ' '.join(self.cmd)

contrib/node/tests/python/pants_test/contrib/node/subsystems/test_node_distribution.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def setUp(self):
2121

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

2727
def test_node(self):
@@ -42,7 +42,7 @@ def test_node(self):
4242
def test_npm(self):
4343
npm_version_flag = self.distribution.get_package_manager('npm').run_command(
4444
args=['--version'])
45-
raw_version = npm_version_flag.check_output().decode('utf-8').strip()
45+
raw_version = npm_version_flag.check_output().strip()
4646

4747
npm_version_cmd = self.distribution.get_package_manager('npm').run_command(
4848
args=['version', '--json'])
@@ -54,7 +54,7 @@ def test_npm(self):
5454
def test_yarnpkg(self):
5555
yarnpkg_version_command = self.distribution.get_package_manager('yarn').run_command(
5656
args=['--version'])
57-
yarnpkg_version = yarnpkg_version_command.check_output().decode('utf-8').strip()
57+
yarnpkg_version = yarnpkg_version_command.check_output().strip()
5858
yarnpkg_versions_command = self.distribution.get_package_manager('yarn').run_command(
5959
args=['versions', '--json'])
6060
yarnpkg_versions = json.loads(yarnpkg_versions_command.check_output())
@@ -67,7 +67,7 @@ def test_node_command_path_injection(self):
6767

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

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

@@ -86,5 +86,5 @@ def test_node_command_path_injection_with_empty_path(self):
8686
node_bin_path = self.distribution._install_node()
8787
injected_paths = node_path_cmd.check_output(
8888
env={'PATH': ''}
89-
).decode('utf-8').strip().split(os.pathsep)
89+
).strip().split(os.pathsep)
9090
self.assertListEqual([node_bin_path, ''], injected_paths)

contrib/python/src/python/pants/contrib/python/checks/tasks/python_eval.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ class Error(TaskError):
3434
"""A richer failure exception type useful for tests."""
3535

3636
def __init__(self, *args, **kwargs):
37-
compiled = kwargs.pop(b'compiled')
38-
failed = kwargs.pop(b'failed')
37+
compiled = kwargs.pop('compiled')
38+
failed = kwargs.pop('failed')
3939
super(PythonEval.Error, self).__init__(*args, **kwargs)
4040
self.compiled = compiled
4141
self.failed = failed
@@ -139,9 +139,9 @@ def _compile_target(self, vt):
139139
executable_file_content = self._get_executable_file_content(exec_pex_parent, modules)
140140

141141
hasher = hashlib.sha1()
142-
hasher.update(reqs_pex.path())
143-
hasher.update(srcs_pex.path())
144-
hasher.update(executable_file_content)
142+
hasher.update(reqs_pex.path().encode('utf-8'))
143+
hasher.update(srcs_pex.path().encode('utf-8'))
144+
hasher.update(executable_file_content.encode('utf-8'))
145145
exec_file_hash = hasher.hexdigest()
146146
exec_pex_path = os.path.realpath(os.path.join(exec_pex_parent, exec_file_hash))
147147
if not os.path.isdir(exec_pex_path):
@@ -215,7 +215,7 @@ def _resolve_requirements_for_versioned_target_closure(self, interpreter, vt):
215215
reqs_pex_path = os.path.realpath(os.path.join(self.workdir, str(interpreter.identity),
216216
vt.cache_key.hash))
217217
if not os.path.isdir(reqs_pex_path):
218-
req_libs = [t for t in vt.target.closure() if has_python_requirements(t)]
218+
req_libs = [t for t in vt.target.closure() if has_python_requirements(t)]
219219
with safe_concurrent_creation(reqs_pex_path) as safe_path:
220220
builder = PEXBuilder(safe_path, interpreter=interpreter, copy=True)
221221
dump_requirement_libs(builder, interpreter, req_libs, self.context.log)

contrib/python/tests/python/pants_test/contrib/python/checks/tasks/checkstyle/test_checker.py

Lines changed: 16 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
from pants_test.backend.python.tasks.python_task_test_base import PythonTaskTestBase
1313

1414
from pants.contrib.python.checks.tasks.checkstyle.checker import PythonCheckStyleTask
15-
from pants.contrib.python.checks.tasks.checkstyle.print_statements_subsystem import \
16-
PrintStatementsSubsystem
15+
from pants.contrib.python.checks.tasks.checkstyle.variable_names_subsystem import \
16+
VariableNamesSubsystem
1717

1818

1919
class PythonCheckStyleTaskTest(PythonTaskTestBase):
@@ -24,7 +24,7 @@ def task_type(cls):
2424
def setUp(self):
2525
super(PythonCheckStyleTaskTest, self).setUp()
2626
PythonCheckStyleTask.clear_plugins()
27-
PythonCheckStyleTask.register_plugin('print-statements', PrintStatementsSubsystem)
27+
PythonCheckStyleTask.register_plugin('variable-names', VariableNamesSubsystem)
2828

2929
def tearDown(self):
3030
super(PythonCheckStyleTaskTest, self).tearDown()
@@ -36,7 +36,8 @@ def test_no_sources(self):
3636

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

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

5759
def test_suppressed_file_passes(self):
5860
self.create_file('a/python/fail.py', contents=dedent("""
59-
print 'Print should not be used as a statement'
61+
class lower_case:
62+
pass
6063
"""))
6164
suppression_file = self.create_file('suppress.txt', contents=dedent("""
62-
a/python/fail\.py::print-statements"""))
65+
a/python/fail\.py::variable-names"""))
6366
target = self.make_target('a/python:fail', PythonLibrary, sources=['fail.py'])
6467
self.set_options(suppress=suppression_file)
6568
context = self.context(target_roots=[target], )
6669
task = self.create_task(context)
67-
6870
self.assertEqual(0, task.execute())
6971

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

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

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

107111
def test_syntax_error_nit(self):
@@ -121,21 +125,3 @@ def test_syntax_error_nit(self):
121125
""" |invalid python\n"""
122126
""" |""",
123127
str(nits[0]))
124-
125-
def test_multiline_nit_printed_only_once(self):
126-
self.create_file('a/python/fail.py', contents=dedent("""
127-
print ('Multi'
128-
'line') + 'expression'
129-
"""))
130-
target = self.make_target('a/python:fail', PythonLibrary, sources=['fail.py'])
131-
context = self.context(target_roots=[target])
132-
task = self.create_task(context)
133-
134-
nits = list(task.get_nits('a/python/fail.py'))
135-
136-
self.assertEqual(1, len(nits))
137-
self.assertEqual(
138-
"""T607:ERROR a/python/fail.py:002-003 Print used as a statement.\n"""
139-
""" |print ('Multi'\n"""
140-
""" | 'line') + 'expression'""",
141-
str(nits[0]))

contrib/python/tests/python/pants_test/contrib/python/checks/tasks/test_python_eval.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,17 @@
66

77
from textwrap import dedent
88

9+
import pytest
10+
from future.utils import PY3
911
from pants.backend.python.subsystems.python_repos import PythonRepos
1012
from pants.backend.python.subsystems.python_setup import PythonSetup
1113
from pants_test.backend.python.tasks.python_task_test_base import PythonTaskTestBase
1214

1315
from pants.contrib.python.checks.tasks.python_eval import PythonEval
1416

1517

18+
# TODO(python3port): https://github.com/pantsbuild/pants/issues/6354. Fix before switching fully to Py3.
19+
@pytest.mark.skipif(PY3, reason='PEX issue when using Python 3. https://github.com/pantsbuild/pants/issues/6354')
1620
class PythonEvalTest(PythonTaskTestBase):
1721

1822
@classmethod

contrib/scrooge/src/python/pants/contrib/scrooge/tasks/java_thrift_library_fingerprint_strategy.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ def compute_fingerprint(self, target):
2929
return fp
3030

3131
hasher = hashlib.sha1()
32-
hasher.update(fp)
33-
hasher.update(self._thrift_defaults.language(target))
32+
hasher.update(fp.encode('utf-8'))
33+
hasher.update(self._thrift_defaults.language(target).encode('utf-8'))
3434
hasher.update(str(self._thrift_defaults.compiler_args(target)).encode('utf-8'))
3535

3636
namespace_map = self._thrift_defaults.namespace_map(target)

contrib/scrooge/tests/python/pants_test/contrib/scrooge/tasks/test_thrift_linter.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,15 @@ def get_default_jvm_options():
4040
thrift_target = self.create_library('a', 'java_thrift_library', 'a', ['A.thrift'])
4141
task = self.create_task(self.context(target_roots=thrift_target))
4242
self._prepare_mocks(task)
43-
expected_include_paths = {'src/thrift/tweet', 'src/thrift/users'}
44-
expected_paths = {'src/thrift/tweet/a.thrift', 'src/thrift/tweet/b.thrift'}
43+
expected_include_paths = ['src/thrift/users', 'src/thrift/tweet']
44+
expected_paths = ['src/thrift/tweet/a.thrift', 'src/thrift/tweet/b.thrift']
4545
mock_calculate_compile_sources.return_value = (expected_include_paths, expected_paths)
4646
task._lint(thrift_target, task.tool_classpath('scrooge-linter'))
4747

4848
self._run_java_mock.assert_called_once_with(
4949
classpath='foo_classpath',
5050
main='com.twitter.scrooge.linter.Main',
5151
args=['--ignore-errors', '--include-path', 'src/thrift/users', '--include-path',
52-
'src/thrift/tweet', 'src/thrift/tweet/b.thrift', 'src/thrift/tweet/a.thrift'],
52+
'src/thrift/tweet', 'src/thrift/tweet/a.thrift', 'src/thrift/tweet/b.thrift'],
5353
jvm_options=get_default_jvm_options(),
5454
workunit_labels=[WorkUnitLabel.COMPILER, WorkUnitLabel.SUPPRESS_LABEL])

pants-plugins/tests/python/internal_backend_test/sitegen/test_sitegen.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,10 @@ class AllTheThingsTestCase(unittest.TestCase):
9595
def setUp(self):
9696
self.config = json.loads(CONFIG_JSON)
9797
self.soups = {
98-
'index': bs4.BeautifulSoup(INDEX_HTML),
99-
'subdir/page1': bs4.BeautifulSoup(P1_HTML),
100-
'subdir/page2': bs4.BeautifulSoup(P2_HTML),
101-
'subdir/page2_no_toc': bs4.BeautifulSoup(P2_HTML),
98+
'index': bs4.BeautifulSoup(INDEX_HTML, 'html.parser'),
99+
'subdir/page1': bs4.BeautifulSoup(P1_HTML, 'html.parser'),
100+
'subdir/page2': bs4.BeautifulSoup(P2_HTML, 'html.parser'),
101+
'subdir/page2_no_toc': bs4.BeautifulSoup(P2_HTML, 'html.parser'),
102102
}
103103
self.precomputed = sitegen.precompute(self.config, self.soups)
104104

src/python/pants/backend/jvm/ivy_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1017,7 +1017,7 @@ def generate_fetch_ivy(cls, jars, ivyxml, confs, resolve_hash_name):
10171017

10181018
@classmethod
10191019
def _write_ivy_xml_file(cls, ivyxml, template_data, template_relpath):
1020-
template_text = pkgutil.get_data(__name__, template_relpath)
1020+
template_text = pkgutil.get_data(__name__, template_relpath).decode('utf-8')
10211021
generator = Generator(template_text, lib=template_data)
10221022
with safe_open(ivyxml, 'w') as output:
10231023
generator.write(output)

0 commit comments

Comments
 (0)