diff --git a/README.md b/README.md index c587cef4..916fb70d 100644 --- a/README.md +++ b/README.md @@ -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) @@ -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. diff --git a/azure-pipelines-templates/run-tests.yml b/azure-pipelines-templates/run-tests.yml index aa16bf7e..31782ef0 100644 --- a/azure-pipelines-templates/run-tests.yml +++ b/azure-pipelines-templates/run-tests.yml @@ -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: diff --git a/tests/base.py b/tests/base.py index c6a2d592..6793b1e4 100644 --- a/tests/base.py +++ b/tests/base.py @@ -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 diff --git a/tests/mock.py b/tests/mock.py index b07172a3..456c0259 100644 --- a/tests/mock.py +++ b/tests/mock.py @@ -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: diff --git a/tests/test_api.py b/tests/test_api.py index 0e341838..f4bb1eb2 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -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], diff --git a/tests/test_client.py b/tests/test_client.py index 540b7471..b1ccdbc3 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -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': diff --git a/tests/test_mockgun.py b/tests/test_mockgun.py index ce851135..08976d2a 100644 --- a/tests/test_mockgun.py +++ b/tests/test_mockgun.py @@ -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. @@ -93,7 +71,7 @@ def test_interface_intact(self): mockgun.Shotgun -class TestValidateFilterSyntax(TestBaseWithExceptionTests): +class TestValidateFilterSyntax(unittest.TestCase): """ Tests filter syntax support. """ @@ -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( @@ -137,7 +115,7 @@ def test_filter_array_or_dict(self): ) -class TestEntityFieldComparison(TestBaseWithExceptionTests): +class TestEntityFieldComparison(unittest.TestCase): """ Checks if entity fields comparison work. """ @@ -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. """ @@ -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. """ @@ -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. """ @@ -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( @@ -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( diff --git a/tests/test_unit.py b/tests/test_unit.py index 1755b51c..c8ce4fcc 100644 --- a/tests/test_unit.py +++ b/tests/test_unit.py @@ -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()