diff --git a/.github/workflows/ot.yml b/.github/workflows/ot.yml index be22bf8..087887f 100644 --- a/.github/workflows/ot.yml +++ b/.github/workflows/ot.yml @@ -5,10 +5,10 @@ on: [push] jobs: test: - runs-on: "ubuntu-20.04" + runs-on: "ubuntu-24.04" strategy: matrix: - python-version: [3.6, 3.7, 3.8, 3.9] + python-version: [3.8, 3.9, '3.10', 3.11, 3.12] steps: - uses: actions/checkout@v3 @@ -21,6 +21,6 @@ jobs: python -m pip install --upgrade pip pip install -r test_requirements.txt pip install -r requirements.txt - - name: Test with nosetests + - name: Test with pytest run: | - nosetests -v tests/test_* + pytest -v tests/test_* diff --git a/.gitignore b/.gitignore index 9b30cb9..f14b9eb 100644 --- a/.gitignore +++ b/.gitignore @@ -32,7 +32,6 @@ pip-delete-this-directory.txt .tox/ .coverage .cache -nosetests.xml coverage.xml # Translations @@ -52,4 +51,7 @@ env/ .vscode #Pypi -.pypirc \ No newline at end of file +.pypirc + +# Pyenv +.python-version diff --git a/DEVELOPING.md b/DEVELOPING.md index e4bea5e..9142ef2 100644 --- a/DEVELOPING.md +++ b/DEVELOPING.md @@ -50,14 +50,14 @@ other script in your environment, and continue to update and you make changes. ### Testing -This project's tests are built using the `unittest` [`Nose'](https://nose.readthedocs.org) modules. +This project's tests are built using the `unittest` [Pytest](https://docs.pytest.org/en/stable/) modules. To run the unit tests, install the core as well as development dependencies inside your `virtualenv`: $ pip install -r requirements.txt -r test_requirements.txt You can manually run the test suite for your version of python with: - $ nosetests + $ pytest If you would like to run the test suite against a variety of Python versions, we recommend installing `act` and running out Github Action "test" workflow: diff --git a/Makefile b/Makefile index 9a7a335..01ecd3b 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ coverage: coverage html test: - nosetests -v + pytest -v dist: python setup.py sdist --formats gztar bdist_wheel @@ -26,4 +26,4 @@ requirements: .requirements.txt .requirements.txt: requirements.txt python -m pip install --upgrade pip setuptools python -m pip install -r requirements.txt - python -m pip freeze > .requirements.txt \ No newline at end of file + python -m pip freeze > .requirements.txt diff --git a/setup.py b/setup.py index 9c5e0e8..3b9c0d1 100644 --- a/setup.py +++ b/setup.py @@ -12,71 +12,58 @@ def find_version(*file_paths): # Open in Latin-1 so that we avoid encoding errors. # Use codecs.open for Python 2 compatibility - with codecs.open(os.path.join(here, *file_paths), 'r', 'latin1') as f: + with codecs.open(os.path.join(here, *file_paths), "r", "latin1") as f: version_file = f.read() # The version line must have the form # __version__ = 'ver' - version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", - version_file, re.M) + version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", version_file, re.M) if version_match: return version_match.group(1) raise RuntimeError("Unable to find version string.") + # Get the long description from the relevant file -with codecs.open('README.rst', encoding='utf-8') as f: +with codecs.open("README.rst", encoding="utf-8") as f: long_description = f.read() -install_requires = [ - 'requests', - 'six', - 'pytz', - 'python-jose', - 'rsa>=4.7' -] +install_requires = ["requests", "six", "pytz", "python-jose", "rsa>=4.7"] setup( - name = 'opentok', - version = find_version('opentok', 'version.py'), - description = 'OpenTok server-side SDK', - long_description_content_type='text/x-rst', - url='https://github.com/opentok/Opentok-Python-SDK/', + name="opentok", + version=find_version("opentok", "version.py"), + description="OpenTok server-side SDK", + long_description_content_type="text/x-rst", + url="https://github.com/opentok/Opentok-Python-SDK/", long_description=long_description, - - author='TokBox, Inc.', - author_email='support@tokbox.com', - license='LICENSE.txt', - - classifiers = [ - 'Development Status :: 5 - Production/Stable', - - 'Intended Audience :: Developers', - 'Intended Audience :: Telecommunications Industry', - - 'License :: OSI Approved :: MIT License', - - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3.9', - - 'Topic :: Communications', - 'Topic :: Communications :: Chat', - 'Topic :: Communications :: Conferencing', - 'Topic :: Multimedia :: Video :: Capture', - 'Topic :: Multimedia :: Video :: Display', - 'Topic :: Multimedia :: Sound/Audio :: Players', - 'Topic :: Multimedia :: Sound/Audio :: Capture/Recording', - 'Topic :: Software Development :: Libraries :: Python Modules' + author="TokBox, Inc.", + author_email="support@tokbox.com", + license="LICENSE.txt", + classifiers=[ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "Intended Audience :: Telecommunications Industry", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Topic :: Communications", + "Topic :: Communications :: Chat", + "Topic :: Communications :: Conferencing", + "Topic :: Multimedia :: Video :: Capture", + "Topic :: Multimedia :: Video :: Display", + "Topic :: Multimedia :: Sound/Audio :: Players", + "Topic :: Multimedia :: Sound/Audio :: Capture/Recording", + "Topic :: Software Development :: Libraries :: Python Modules", ], - - keywords = 'video chat tokbox tok opentok python media webrtc archiving realtime', - + keywords="video chat tokbox tok opentok python media webrtc archiving realtime", packages=find_packages(exclude=["contrib", "docs", "tests*"]), - install_requires=install_requires, - - include_package_data = True, + include_package_data=True, ) diff --git a/test_requirements.txt b/test_requirements.txt index 7e4e92a..93ad042 100644 --- a/test_requirements.txt +++ b/test_requirements.txt @@ -1,4 +1,4 @@ -nose +pytest httpretty expects wheel diff --git a/tests/test_archive_api.py b/tests/test_archive_api.py index 60dd7d7..00ffd82 100644 --- a/tests/test_archive_api.py +++ b/tests/test_archive_api.py @@ -1,6 +1,6 @@ +import pytest import unittest from six import text_type, u, b, PY2, PY3 -from nose.tools import raises from expects import * import httpretty from sure import expect @@ -294,21 +294,19 @@ def test_start_archive_with_1280x720_resolution(self): expect(archive).to(have_property(u("url"), equal(None))) def test_start_archive_individual_and_resolution_throws_error(self): - self.assertRaises( - OpenTokException, - self.opentok.start_archive, - session_id=self.session_id, - output_mode=OutputModes.individual, - resolution="640x480", - ) + with pytest.raises(OpenTokException): + self.opentok.start_archive( + session_id=self.session_id, + output_mode=OutputModes.individual, + resolution="640x480", + ) - self.assertRaises( - OpenTokException, - self.opentok.start_archive, - session_id=self.session_id, - output_mode=OutputModes.individual, - resolution="1280x720", - ) + with pytest.raises(OpenTokException): + self.opentok.start_archive( + session_id=self.session_id, + output_mode=OutputModes.individual, + resolution="1280x720", + ) @httpretty.activate def test_start_voice_archive(self): @@ -549,7 +547,9 @@ def test_start_archive_with_layout(self): content_type=u("application/json"), ) - archive = self.opentok.start_archive(self.session_id, layout={"type": "pip", "screenshareType": "horizontal"}) + archive = self.opentok.start_archive( + self.session_id, layout={"type": "pip", "screenshareType": "horizontal"} + ) validate_jwt_header(self, httpretty.last_request().headers[u("x-opentok-auth")]) expect(httpretty.last_request().headers[u("user-agent")]).to( @@ -565,7 +565,9 @@ def test_start_archive_with_layout(self): body = json.loads(httpretty.last_request().body.decode("utf-8")) expect(body).to(have_key(u("sessionId"), u("SESSIONID"))) expect(body).to(have_key(u("name"), None)) - expect(body).to(have_key(u("layout"), {"type": "pip", "screenshareType": "horizontal"})) + expect(body).to( + have_key(u("layout"), {"type": "pip", "screenshareType": "horizontal"}) + ) expect(archive).to(be_an(Archive)) expect(archive).to( have_property(u("id"), u("30b3ebf1-ba36-4f5b-8def-6f70d9986fe9")) @@ -1078,7 +1080,7 @@ def test_find_archives_with_offset_and_count(self): @httpretty.activate def test_find_archives_with_sessionid(self): - """ Test get_archives method using session_id parameter """ + """Test get_archives method using session_id parameter""" httpretty.register_uri( httpretty.GET, u("https://api.opentok.com/v2/project/{0}/archive").format(self.api_key), @@ -1166,7 +1168,7 @@ def test_find_archives_with_sessionid(self): @httpretty.activate def test_find_archives_with_offset_count_sessionId(self): - """ Test get_archives method using all parameters: offset, count and sessionId """ + """Test get_archives method using all parameters: offset, count and sessionId""" httpretty.register_uri( httpretty.GET, u("https://api.opentok.com/v2/project/{0}/archive").format(self.api_key), @@ -1237,7 +1239,7 @@ def test_find_archives_with_offset_count_sessionId(self): @httpretty.activate def test_find_archives_alternative_method(self): - """ Test list_archives method using all parameters: offset, count and sessionId """ + """Test list_archives method using all parameters: offset, count and sessionId""" httpretty.register_uri( httpretty.GET, u("https://api.opentok.com/v2/project/{0}/archive").format(self.api_key), @@ -1419,7 +1421,7 @@ def test_find_archive_with_unknown_properties(self): @httpretty.activate def test_set_archive_layout(self): - """ Test set archive layout functionality """ + """Test set archive layout functionality""" archive_id = u("f6e7ee58-d6cf-4a59-896b-6d56b158ec71") httpretty.register_uri( @@ -1443,7 +1445,7 @@ def test_set_archive_layout(self): @httpretty.activate def test_set_archive_screenshare_type(self): - """ Test set archive layout functionality """ + """Test set archive layout functionality""" archive_id = u("f6e7ee58-d6cf-4a59-896b-6d56b158ec71") httpretty.register_uri( @@ -1455,7 +1457,9 @@ def test_set_archive_screenshare_type(self): content_type=u("application/json"), ) - self.opentok.set_archive_layout(archive_id, "bestFit", screenshare_type="horizontalPresentation") + self.opentok.set_archive_layout( + archive_id, "bestFit", screenshare_type="horizontalPresentation" + ) validate_jwt_header(self, httpretty.last_request().headers[u("x-opentok-auth")]) expect(httpretty.last_request().headers[u("user-agent")]).to( @@ -1476,7 +1480,7 @@ def test_set_archive_screenshare_type(self): @httpretty.activate def test_set_custom_archive_layout(self): - """ Test set a custom archive layout specifying the 'stylesheet' parameter """ + """Test set a custom archive layout specifying the 'stylesheet' parameter""" archive_id = u("f6e7ee58-d6cf-4a59-896b-6d56b158ec71") httpretty.register_uri( @@ -1506,47 +1510,49 @@ def test_set_custom_archive_layout(self): def test_start_archive_with_streammode_auto(self): url = f"https://api.opentok.com/v2/project/{self.api_key}/archive" - httpretty.register_uri(httpretty.POST, - url, - responses=[ - httpretty.Response(body=json.dumps({"streamMode":"auto"}), - content_type="application/json", - status=200) - ]) + httpretty.register_uri( + httpretty.POST, + url, + responses=[ + httpretty.Response( + body=json.dumps({"streamMode": "auto"}), + content_type="application/json", + status=200, + ) + ], + ) - response = requests.post(url) response.status_code.should.equal(200) - response.json().should.equal({"streamMode":"auto"}) + response.json().should.equal({"streamMode": "auto"}) response.headers["Content-Type"].should.equal("application/json") - - @httpretty.activate def test_start_archive_with_streammode_manual(self): url = f"https://api.opentok.com/v2/project/{self.api_key}/archive" - httpretty.register_uri(httpretty.POST, - url, - responses=[ - httpretty.Response(body=json.dumps({"streamMode":"manual"}), - content_type="application/json", - status=200) - ]) + httpretty.register_uri( + httpretty.POST, + url, + responses=[ + httpretty.Response( + body=json.dumps({"streamMode": "manual"}), + content_type="application/json", + status=200, + ) + ], + ) - response = requests.post(url) response.status_code.should.equal(200) - response.json().should.equal({"streamMode":"manual"}) + response.json().should.equal({"streamMode": "manual"}) response.headers["Content-Type"].should.equal("application/json") - - @httpretty.activate def test_set_archive_layout_throws_exception(self): - """ Test invalid request in set archive layout """ + """Test invalid request in set archive layout""" archive_id = u("f6e7ee58-d6cf-4a59-896b-6d56b158ec71") httpretty.register_uri( @@ -1558,9 +1564,5 @@ def test_set_archive_layout_throws_exception(self): content_type=u("application/json"), ) - self.assertRaises( - ArchiveError, - self.opentok.set_archive_layout, - archive_id, - "horizontalPresentation", - ) + with pytest.raises(ArchiveError): + self.opentok.set_archive_layout(archive_id, "horizontalPresentation") diff --git a/tests/test_custom_jwt_claims.py b/tests/test_custom_jwt_claims.py index a210199..a311aa4 100644 --- a/tests/test_custom_jwt_claims.py +++ b/tests/test_custom_jwt_claims.py @@ -1,6 +1,5 @@ import unittest from six import text_type, u, b, PY2, PY3 -from nose.tools import raises from expects import * from opentok import Client, __version__ diff --git a/tests/test_http_options.py b/tests/test_http_options.py index 2b3d8d4..8b7b3d9 100644 --- a/tests/test_http_options.py +++ b/tests/test_http_options.py @@ -1,6 +1,6 @@ +import pytest import unittest from six import u -from nose.tools import raises import httpretty import requests @@ -27,7 +27,7 @@ def setUp(self): def tearDown(self): httpretty.disable() - @raises(OpenTokException) def test_timeout(self): - opentok = Client(self.api_key, self.api_secret, timeout=1) - opentok.create_session() + with pytest.raises(OpenTokException): + opentok = Client(self.api_key, self.api_secret, timeout=1) + opentok.create_session() diff --git a/tests/test_initialization.py b/tests/test_initialization.py index d3e6158..7a41892 100644 --- a/tests/test_initialization.py +++ b/tests/test_initialization.py @@ -1,5 +1,5 @@ +import pytest import unittest -from nose.tools import raises import platform from opentok import Client @@ -14,16 +14,16 @@ def setUp(self): def test_intialization(self): opentok = Client(self.api_key, self.api_secret) assert isinstance(opentok, Client) - self.assertEquals(opentok.proxies, None) + self.assertEqual(opentok.proxies, None) def test_set_proxies(self): opentok = Client(self.api_key, self.api_secret) opentok.proxies = {"https": "https://foo.bar"} - self.assertEquals(opentok.proxies, {"https": "https://foo.bar"}) + self.assertEqual(opentok.proxies, {"https": "https://foo.bar"}) - @raises(TypeError) def test_initialization_without_required_params(self): - opentok = Client() + with pytest.raises(TypeError): + opentok = Client() def test_initialization_with_api_url(self): opentok = Client(self.api_key, self.api_secret, self.api_url) @@ -39,13 +39,18 @@ def test_initialization_with_timeout(self): def test_user_agent(self): opentok = Client(self.api_key, self.api_secret, self.api_url) - assert opentok.user_agent == f"OpenTok-Python-SDK/{opentok.app_version} python/{platform.python_version()}" - + assert ( + opentok.user_agent + == f"OpenTok-Python-SDK/{opentok.app_version} python/{platform.python_version()}" + ) + def test_append_to_user_agent(self): opentok = Client(self.api_key, self.api_secret, self.api_url) - opentok.append_to_user_agent('/my_appended_user_agent_string') - assert opentok.user_agent == f"OpenTok-Python-SDK/{opentok.app_version} python/{platform.python_version()}/my_appended_user_agent_string" - + opentok.append_to_user_agent("/my_appended_user_agent_string") + assert ( + opentok.user_agent + == f"OpenTok-Python-SDK/{opentok.app_version} python/{platform.python_version()}/my_appended_user_agent_string" + ) if __name__ == "__main__": diff --git a/tests/test_session.py b/tests/test_session.py index 9e5c9ba..959fa40 100644 --- a/tests/test_session.py +++ b/tests/test_session.py @@ -1,6 +1,5 @@ import unittest from six import text_type, u, b, PY2, PY3 -from nose.tools import raises from opentok import Client, Session, Roles, MediaModes from .helpers import token_decoder, token_signature_validator diff --git a/tests/test_session_creation.py b/tests/test_session_creation.py index bc82d0b..dc65493 100644 --- a/tests/test_session_creation.py +++ b/tests/test_session_creation.py @@ -1,7 +1,7 @@ +import pytest import unittest from six import u, b from six.moves.urllib.parse import parse_qs -from nose.tools import raises from expects import * import httpretty from .validate_jwt import validate_jwt_header @@ -109,9 +109,8 @@ def test_failure_create_routed_session(self): content_type=u("text/xml"), ) - self.assertRaises( - OpenTokException, self.opentok.create_session, media_mode=MediaModes.routed - ) + with pytest.raises(OpenTokException): + self.opentok.create_session(media_mode=MediaModes.routed) @httpretty.activate def test_create_session_with_location_hint(self): @@ -263,42 +262,39 @@ def test_create_always_archive_mode_session(self): expect(session).to(have_property(u("e2ee"), False)) def test_complains_about_always_archive_mode_and_relayed_session(self): - self.assertRaises( - OpenTokException, - self.opentok.create_session, - media_mode=MediaModes.relayed, - archive_mode=ArchiveModes.always, - ) + with pytest.raises(OpenTokException): + self.opentok.create_session( + media_mode=MediaModes.relayed, archive_mode=ArchiveModes.always + ) def test_auto_archive_errors(self): - self.assertRaises( - OpenTokException, - self.opentok.create_session, - media_mode=MediaModes.routed, - archive_mode=ArchiveModes.manual, - archive_name="my_archive", - ) - self.assertRaises( - OpenTokException, - self.opentok.create_session, - media_mode=MediaModes.routed, - archive_mode=ArchiveModes.manual, - archive_resolution="640x480", - ) - self.assertRaises( - OpenTokException, - self.opentok.create_session, - media_mode=MediaModes.routed, - archive_mode=ArchiveModes.always, - archive_name="my_incredibly_long_name_that_is_definitely_going_to_be_over_the_80_character_limit_we_currently_impose", - ) - self.assertRaises( - OpenTokException, - self.opentok.create_session, - media_mode=MediaModes.routed, - archive_mode=ArchiveModes.always, - archive_resolution="10x10", - ) + with pytest.raises(OpenTokException): + self.opentok.create_session( + media_mode=MediaModes.routed, + archive_mode=ArchiveModes.manual, + archive_name="my_archive", + ) + + with pytest.raises(OpenTokException): + self.opentok.create_session( + media_mode=MediaModes.routed, + archive_mode=ArchiveModes.manual, + archive_resolution="640x480", + ) + + with pytest.raises(OpenTokException): + self.opentok.create_session( + media_mode=MediaModes.routed, + archive_mode=ArchiveModes.always, + archive_name="my_incredibly_long_name_that_is_definitely_going_to_be_over_the_80_character_limit_we_currently_impose", + ) + + with pytest.raises(OpenTokException): + self.opentok.create_session( + media_mode=MediaModes.routed, + archive_mode=ArchiveModes.always, + archive_resolution="10x10", + ) @httpretty.activate def test_create_session_with_e2ee(self): diff --git a/tests/test_token_generation.py b/tests/test_token_generation.py index 6434daf..28d68bf 100644 --- a/tests/test_token_generation.py +++ b/tests/test_token_generation.py @@ -1,6 +1,6 @@ +import pytest import unittest from six import text_type, u, PY2, PY3 -from nose.tools import raises import time import datetime import calendar @@ -94,22 +94,22 @@ def test_generate_no_data_token(self): assert u("connection_data") not in token_decoder(token) assert token_signature_validator(token, self.api_secret) - @raises(TypeError) def test_does_not_generate_token_without_params(self): - self.opentok.generate_token() + with pytest.raises(TypeError): + self.opentok.generate_token() - @raises(TypeError) def test_does_not_generate_token_without_session(self): - self.opentok.generate_token(role=Roles.subscriber) + with pytest.raises(TypeError): + self.opentok.generate_token(role=Roles.subscriber) - @raises(OpenTokException) def test_does_not_generate_token_invalid_session(self): - self.opentok.generate_token(u("NOT A REAL SESSIONID")) + with pytest.raises(OpenTokException): + self.opentok.generate_token(u("NOT A REAL SESSIONID")) - @raises(OpenTokException) def test_does_not_generate_token_without_api_key_match(self): - # this session_id has the wrong api_key - session_id = u( - "1_MX42NTQzMjF-flNhdCBNYXIgMTUgMTQ6NDI6MjMgUERUIDIwMTR-MC40OTAxMzAyNX4" - ) - self.opentok.generate_token(session_id) + with pytest.raises(OpenTokException): + # this session_id has the wrong api_key + session_id = u( + "1_MX42NTQzMjF-flNhdCBNYXIgMTUgMTQ6NDI6MjMgUERUIDIwMTR-MC40OTAxMzAyNX4" + ) + self.opentok.generate_token(session_id)