Skip to content

Commit

Permalink
SG-31340 Deprecation of Python 2 (#295)
Browse files Browse the repository at this point in the history
* remove references to py2 and skip tests

* small fix

* revert change

* revert change

* revert change

* revert change

* remove badge

* use assertRaisesRegex
  • Loading branch information
minna-feng authored Aug 17, 2023
1 parent b3ebbb5 commit b3f6c5a
Show file tree
Hide file tree
Showing 8 changed files with 11 additions and 119 deletions.
59 changes: 1 addition & 58 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[![VFX Platform](https://img.shields.io/badge/vfxplatform-2020-blue.svg)](http://www.vfxplatform.com/)
[![Python 2.7 3.7](https://img.shields.io/badge/python-2.7%20%7C%203.7-blue.svg)](https://www.python.org/)
[![Python 3.7](https://img.shields.io/badge/python-3.7-blue.svg)](https://www.python.org/)
[![Reference Documentation](http://img.shields.io/badge/doc-reference-blue.svg)](http://developer.shotgridsoftware.com/python-api)
[![Build Status](https://dev.azure.com/shotgun-ecosystem/Python%20API/_apis/build/status/shotgunsoftware.python-api?branchName=master)](https://dev.azure.com/shotgun-ecosystem/Python%20API/_build/latest?definitionId=108&branchName=master)
[![Coverage Status](https://coveralls.io/repos/github/shotgunsoftware/python-api/badge.svg?branch=master)](https://coveralls.io/github/shotgunsoftware/python-api?branch=master)
Expand Down Expand Up @@ -37,63 +37,6 @@ The API comes with a copy of the `httplib2` inside the `shotgun_api3/lib` folder

where `vX.Y.Z` is a release found on `httplib2`'s [release page](https://github.com/httplib2/httplib2/releases).

## Maintaining Python 2 and 3 compatibility

python-api should remain compatible with both Python 2, and 3. To make this easier, we use [six](https://six.readthedocs.io/). When adding code that works with types that have changed between Python 2 and 3, notably strings and files, it's advisable to use the `six` types for casting and comparisons. Be sure to follow Python 2 and 3 compatible conventions in code, especially when raising or capturing exceptions and printing. While we don't use `future`, [this page](https://python-future.org/compatible_idioms.html) contains a fairly comprehensive list of Python 2/3 compatibility sticking points to look out for.

Additionally, the [python-modernize](https://python-modernize.readthedocs.io/en/latest/) tool can be helpful when updating Python 2 code for Python 3 compatibility.

### Examples:

#### Comparisons against changed types:

Python 2:

```
if isinstance(my_variable, str):
```

Python 2/3:

```
if isinstance(my_variable, six.string_types):
```

#### Catching exceptions

Python 2:

```
except SomeExceptionType, e:
print "I like to swallow exceptions!"
```

Python 2/3:

```
from __future__ import print_function
except SomeExceptionType as e:
print("I like to swallow exceptions!")
```

#### Print statements

Python 2:

```
print "My spoon is too big!"
```

Python 2/3:

```
from __future__ import print_function
print("My spoon is too big!")
```


Additionally, when testing locally, tests should be run for both python 2 and python 3 to ensure changes won't break cross-compatibility.

## Tests

Integration and unit tests are provided.
Expand Down
2 changes: 0 additions & 2 deletions azure-pipelines-templates/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@ jobs:
strategy:
matrix:
# We support these two versions of Python.
Python27:
python.version: '2.7'
Python37:
python.version: '3.7'
Python39:
Expand Down
7 changes: 1 addition & 6 deletions tests/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,7 @@
from shotgun_api3.shotgun import ServerCapabilities
from shotgun_api3.lib import six
from shotgun_api3.lib.six.moves import urllib

if six.PY2:
from shotgun_api3.lib.six.moves.configparser import SafeConfigParser as ConfigParser
else:
from shotgun_api3.lib.six.moves.configparser import ConfigParser

from shotgun_api3.lib.six.moves.configparser import ConfigParser

try:
# Attempt to import skip from unittest. Since this was added in Python 2.7
Expand Down
6 changes: 0 additions & 6 deletions tests/mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,6 @@
# may not have inspect
inspect = None

try:
BaseException
except NameError:
# Python 2.4 compatibility
BaseException = Exception

try:
from functools import wraps
except ImportError:
Expand Down
6 changes: 1 addition & 5 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -1206,11 +1206,7 @@ def _id_in_result(self, entity_type, filters, expected_id):
for particular filters.
"""
results = self.sg.find(entity_type, filters)
# can't use 'any' in python 2.4
for result in results:
if result['id'] == expected_id:
return True
return False
return any(result['id'] == expected_id for result in results)

# TODO test all applicable data types for 'in'
# 'currency' => [BigDecimal, Float, NilClass],
Expand Down
1 change: 0 additions & 1 deletion tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -564,7 +564,6 @@ def test_parse_records(self):
system = platform.system().lower()
if system == 'darwin':
local_path_field = "local_path_mac"
# python 2.4 returns 'Microsoft'
elif system in ['windows', 'microsoft']:
local_path_field = "local_path_windows"
elif system == 'linux':
Expand Down
38 changes: 8 additions & 30 deletions tests/test_mockgun.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,28 +53,6 @@
)


# FIXME: This should probably be refactored into a base class for
# all test bases
class TestBaseWithExceptionTests(unittest.TestCase):
"""
Implements a Python 2.4 compatible assertRaisesRegexp like method. This
was introduced in Python 2.7.
"""
def assertRaisesRegexp(self, exception_type, re_msg, func):
try:
func()
except exception_type as exception:
matches = re.findall(re_msg, str(exception))
if not matches:
self.fail("Expected exception to match '%s', got '%s' instead." % (
re_msg, str(exception)
))
except Exception as ex:
self.fail("Expected exception of type %s, got %s" % (exception_type, type(ex)))
else:
self.fail("Expected %s was not raised." % exception_type)


class TestMockgunModuleInterface(unittest.TestCase):
"""
mockgun.py was turned into a module. Ensure we haven't broken the interface.
Expand All @@ -93,7 +71,7 @@ def test_interface_intact(self):
mockgun.Shotgun


class TestValidateFilterSyntax(TestBaseWithExceptionTests):
class TestValidateFilterSyntax(unittest.TestCase):
"""
Tests filter syntax support.
"""
Expand Down Expand Up @@ -127,7 +105,7 @@ def test_filter_array_or_dict(self):
)

# We can't have not dict/list values for filters however.
self.assertRaisesRegexp(
self.assertRaisesRegex(
ShotgunError,
"Filters can only be lists or dictionaries, not int.",
lambda: self._mockgun.find(
Expand All @@ -137,7 +115,7 @@ def test_filter_array_or_dict(self):
)


class TestEntityFieldComparison(TestBaseWithExceptionTests):
class TestEntityFieldComparison(unittest.TestCase):
"""
Checks if entity fields comparison work.
"""
Expand Down Expand Up @@ -191,7 +169,7 @@ def test_find_entity_with_none_link(self):
self.assertEqual(items[0]["id"], self._project_link["id"])


class TestTextFieldOperators(TestBaseWithExceptionTests):
class TestTextFieldOperators(unittest.TestCase):
"""
Checks if text field comparison work.
"""
Expand All @@ -210,7 +188,7 @@ def test_operator_contains(self):
self.assertTrue(item)


class TestMultiEntityFieldComparison(TestBaseWithExceptionTests):
class TestMultiEntityFieldComparison(unittest.TestCase):
"""
Ensures multi entity field comparison work.
"""
Expand Down Expand Up @@ -293,7 +271,7 @@ def test_find_with_none(self):
self.assertTrue(len(item["users"]) > 0)


class TestFilterOperator(TestBaseWithExceptionTests):
class TestFilterOperator(unittest.TestCase):
"""
Unit tests for the filter_operator filter syntax.
"""
Expand Down Expand Up @@ -408,7 +386,7 @@ def test_nested_filter_operators(self):

def test_invalid_operator(self):

self.assertRaisesRegexp(
self.assertRaisesRegex(
ShotgunError,
"Unknown filter_operator type: bad",
lambda: self._mockgun.find(
Expand All @@ -421,7 +399,7 @@ def test_invalid_operator(self):
])
)

self.assertRaisesRegexp(
self.assertRaisesRegex(
ShotgunError,
"Bad filter operator, requires keys 'filter_operator' and 'filters',",
lambda: self._mockgun.find(
Expand Down
11 changes: 0 additions & 11 deletions tests/test_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -506,16 +506,5 @@ def _test_mimetypes_import(self, platform, major, minor, patch_number, result, m
mock.platform = platform
self.assertEqual(_is_mimetypes_broken(), result)

def test_correct_mimetypes_imported(self):
"""
Makes sure fix is imported for only for Python 2.7.0 to 2.7.7 on win32
"""
self._test_mimetypes_import("win32", 2, 6, 9, False)
for patch_number in range(0, 10): # 0 to 9 inclusively
self._test_mimetypes_import("win32", 2, 7, patch_number, True)
self._test_mimetypes_import("win32", 2, 7, 10, False)
self._test_mimetypes_import("win32", 3, 0, 0, False)
self._test_mimetypes_import("darwin", 2, 7, 0, False)

if __name__ == '__main__':
unittest.main()

0 comments on commit b3f6c5a

Please sign in to comment.