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

Make alt-src compatible with Python 3 #26

Merged
merged 2 commits into from
Apr 17, 2020
Merged

Conversation

querti
Copy link
Contributor

@querti querti commented Apr 15, 2020

More info in the commit message.

2to3 tool was used to automatically detect code lines which are
problematic for Python 3. They were fixed in a way that ensures
continued Python 2 compatibility. 'six' package was added as a
dependency as it is used in some fixes.
@querti
Copy link
Contributor Author

querti commented Apr 15, 2020

Two notes:

  1. python-six will have to be included in the dist-git specfile. I'm not exactly sure how this is done.
  2. Previously, six version was specified as >1.10. I had to remove this constraint because I believe that the highest version available on RHEL 6 is 1.9. I haven't figured out why the version was specified. @midnightercz do you remember why you specified it like this?

@querti querti marked this pull request as ready for review April 15, 2020 14:45
alt_src/alt_src.py Outdated Show resolved Hide resolved
tests/test_rpms.py Outdated Show resolved Hide resolved
@@ -658,6 +645,8 @@ def test_push_when_already_pushed(config_file, lookasidedir, default_config, cap
git_url = default_config['git_push_url'] % {'package':'rcm-repoquery'}
cmd = ['git', 'tag']
out = check_output(cmd, cwd=git_url)
if not isinstance(out, str) and isinstance(out, bytes):
Copy link
Member

Choose a reason for hiding this comment

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

Again it should be possible to instead add universal_newlines=True.

Copy link
Contributor Author

@querti querti Apr 16, 2020

Choose a reason for hiding this comment

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

Fixed. I want to point out though that check_output was added in Python 2.7 [1], so even though the project claims to be 2.6 compatible, the test suite is not. I hesitated to fix it because we don't know how many more things have to be fixed before the suite is 2.6 compatible (or 2.4 for that matter)

[1] https://docs.python.org/2/library/subprocess.html#subprocess.check_output

def test_get_state_with_error_other_than_enoent(tempdir):
options = MagicMock(koji=None, source=tempfile.mkstemp(dir=tempdir)[1])
processor = BaseProcessor(options)
processor.workdir = tempfile.mkstemp(dir=tempdir)[1]

# attempting to open state file raises generic IOError
with patch('__builtin__.open', autospec=True, side_effect=IOError):
with patch('six.moves.builtins.open', autospec=True, side_effect=IOError):
Copy link
Member

Choose a reason for hiding this comment

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

This doesn't make sense to me. My understanding of what happens when you do mock.patch('foo.bar.baz') is that, on foo.bar module, 'baz' will be pointed to a mock object for the duration of the context.

So, this mock would only be used if there was code of the form:

import six.moves.builtins

f = six.moves.builtins.open(...)

...and there isn't such code. I don't see any reason that a bare "open()" would be directed to the mock here.

I pulled this change locally, deleted the patch and it didn't change the outcome of the test at all, so this is consistent with this patch not doing anything useful.

Can you please investigate and remove or fix this if it is indeed useless?

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 have investigated the testcase and the reason why the patch is unnecessary is that an actual IOError (not a directory) is raised during the tested classes setup. This is because tempfile is specified as the workdir. So the test incidentally does what it's supposed to, even though it clearly wasn't the intended behaviour. I have fixed the setup and patched 'open' to raise a generic IOError, at least to prevent a user confusion about the intention of the testcase.

Also, it seems that patch doesn't work the way you expected because patching 'six.moves.builtins.open' raises a generic IOError on both Python 2 and 3. Removing the patch now causes it to raise no exceptions.

Copy link
Member

Choose a reason for hiding this comment

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

Thanks. I had a look into that to figure out where I went wrong and I figured out that mock.patch does work the way I expected, but my conclusion that it wouldn't affect a bare open() was wrong. I learned the reasons why that works:

  1. 'six.moves.builtins' is the same object as 'builtins', not a wrapper module as I'd thought it might be. So this patch on six.moves.builtins, in python3, is the same as patching on builtins.
>>> id(builtins)
140273681132816
>>> id(six.moves.builtins)
140273681132816
  1. builtins module is special, apparently anything set there can be looked up implicitly without having to be imported or having to use a qualified name.
>>> setattr(builtins, 'quux', lambda: 123)
>>> quux()
123

@@ -375,7 +381,7 @@ def check_package(self):
self.logger.debug("Got blacklist: %r", blacklist)
if blacklist and koji.util.multi_fnmatch(self.package, blacklist):
# raise FilterError, 'Blacklisted package: %s' % self.package
print 'Blacklisted package: %s, quitting' % self.package
print('Blacklisted package: %s, quitting' % self.package)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can I ask if there's a reason this is not a part of the log and simply a print statement?

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 have changed the prints to logger messages because there were only two of them. When this code was written, proper review processes were not yet properly implemented, so these kinds of things are quite common in our legacy codebase.

After the automatically detected problems were fixed, the following
issues had to be resolved to ensure that the whole test suite passes
in Python 3:

- in testcase 'test_get_state_with_error_other_than_enoent', '__builtin__'
  was changed to 'six.moves.builtins' because the built-in library
  was renamed in Python 3. Also, the testcase itself had been broken
  because it had raised an IOError due to an incorrect setup (file
  was assigned as a directory) and not because of the patched 'open'
  function. It was fixed despite incidentally fulfilling its desired
  function in order to prevent user confusion.

- In Python 3, output for invoked bash commands is a bytes type,
  which can cause many issues because the code expects to work with
  a string. Adding the 'universal_newlines' forces the output to be
  returned as a string.

Also, print statements were changed to logger messages.
@querti querti merged commit 90cdd4b into master Apr 17, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants