diff --git a/.github/workflows/ruff.yml b/.github/workflows/ruff.yml
new file mode 100644
index 00000000..47c12129
--- /dev/null
+++ b/.github/workflows/ruff.yml
@@ -0,0 +1,11 @@
+name: Ruff
+run-name: Ruff
+
+on: [ push, pull_request ]
+
+jobs:
+  ruff:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v4
+      - uses: chartboost/ruff-action@v1
diff --git a/m3u8/__init__.py b/m3u8/__init__.py
index aeb70294..5eae2376 100644
--- a/m3u8/__init__.py
+++ b/m3u8/__init__.py
@@ -3,7 +3,6 @@
 # license that can be found in the LICENSE file.
 
 import os
-import sys
 from urllib.parse import urljoin, urlsplit
 
 from m3u8.httpclient import DefaultHTTPClient
diff --git a/m3u8/model.py b/m3u8/model.py
index cd1f7397..152aa7f0 100644
--- a/m3u8/model.py
+++ b/m3u8/model.py
@@ -2,7 +2,6 @@
 # Use of this source code is governed by a MIT License
 # license that can be found in the LICENSE file.
 import decimal
-import errno
 import os
 
 from m3u8.mixins import BasePathMixin, GroupedBasePathMixin
@@ -1609,81 +1608,6 @@ def dumps(self):
     def __str__(self):
         return self.dumps()
 
-class ImagePlaylist(BasePathMixin):
-    '''
-    ImagePlaylist object representing a link to a
-    variant M3U8 image playlist with a specific bitrate.
-
-    Attributes:
-
-    `image_stream_info` is a named tuple containing the attributes:
-     `bandwidth`, `resolution` which is a tuple (w, h) of integers and `codecs`,
-
-    More info: https://github.com/image-media-playlist/spec/blob/master/image_media_playlist_v0_4.pdf
-    '''
-
-    def __init__(self, base_uri, uri, image_stream_info):
-        self.uri = uri
-        self.base_uri = base_uri
-
-        resolution = image_stream_info.get('resolution')
-        if resolution is not None:
-            values = resolution.split('x')
-            resolution_pair = (int(values[0]), int(values[1]))
-        else:
-            resolution_pair = None
-
-        self.image_stream_info = StreamInfo(
-            bandwidth=image_stream_info.get('bandwidth'),
-            average_bandwidth=image_stream_info.get('average_bandwidth'),
-            video=image_stream_info.get('video'),
-            # Audio, subtitles, closed captions, video range and hdcp level should not exist in
-            # EXT-X-IMAGE-STREAM-INF, so just hardcode them to None.
-            audio=None,
-            subtitles=None,
-            closed_captions=None,
-            program_id=image_stream_info.get('program_id'),
-            resolution=resolution_pair,
-            codecs=image_stream_info.get('codecs'),
-            video_range=None,
-            hdcp_level=None,
-            frame_rate=None,
-            pathway_id=image_stream_info.get('pathway_id'),
-            stable_variant_id=image_stream_info.get('stable_variant_id')
-        )
-
-    def __str__(self):
-        image_stream_inf = []
-        if self.image_stream_info.program_id:
-            image_stream_inf.append('PROGRAM-ID=%d' %
-                                     self.image_stream_info.program_id)
-        if self.image_stream_info.bandwidth:
-            image_stream_inf.append('BANDWIDTH=%d' %
-                                     self.image_stream_info.bandwidth)
-        if self.image_stream_info.average_bandwidth:
-            image_stream_inf.append('AVERAGE-BANDWIDTH=%d' %
-                                     self.image_stream_info.average_bandwidth)
-        if self.image_stream_info.resolution:
-            res = (str(self.image_stream_info.resolution[0]) + 'x' +
-                   str(self.image_stream_info.resolution[1]))
-            image_stream_inf.append('RESOLUTION=' + res)
-        if self.image_stream_info.codecs:
-            image_stream_inf.append('CODECS=' +
-                                     quoted(self.image_stream_info.codecs))
-        if self.uri:
-            image_stream_inf.append('URI=' + quoted(self.uri))
-        if self.image_stream_info.pathway_id:
-            image_stream_inf.append(
-                'PATHWAY-ID=' + quoted(self.image_stream_info.pathway_id)
-            )
-        if self.image_stream_info.stable_variant_id:
-            image_stream_inf.append(
-                'STABLE-VARIANT-ID=' + quoted(self.image_stream_info.stable_variant_id)
-            )
-
-        return '#EXT-X-IMAGE-STREAM-INF:' + ','.join(image_stream_inf)
-
-
 def find_key(keydata, keylist):
     if not keydata:
         return None
diff --git a/m3u8/parser.py b/m3u8/parser.py
index 9a2345db..47c10f36 100644
--- a/m3u8/parser.py
+++ b/m3u8/parser.py
@@ -5,7 +5,6 @@
 import itertools
 import re
 from datetime import datetime, timedelta
-from urllib.parse import urljoin as _urljoin
 
 try:
     from backports.datetime_fromisoformat import MonkeyPatch
diff --git a/tests/m3u8server.py b/tests/m3u8server.py
index 01fc234d..1d135e7f 100644
--- a/tests/m3u8server.py
+++ b/tests/m3u8server.py
@@ -14,7 +14,7 @@
 
 
 @route("/path/to/redirect_me")
-def simple():
+def redirect_route():
     redirect("/simple.m3u8")
 
 
@@ -25,14 +25,14 @@ def simple():
 
 
 @route("/timeout_simple.m3u8")
-def simple():
+def timeout_simple():
     time.sleep(5)
     response.set_header("Content-Type", "application/vnd.apple.mpegurl")
     return m3u8_file("simple-playlist.m3u8")
 
 
 @route("/path/to/relative-playlist.m3u8")
-def simple():
+def relative_playlist():
     response.set_header("Content-Type", "application/vnd.apple.mpegurl")
     return m3u8_file("relative-playlist.m3u8")
 
diff --git a/tests/test_loader.py b/tests/test_loader.py
index 862a86f9..509b7714 100644
--- a/tests/test_loader.py
+++ b/tests/test_loader.py
@@ -3,6 +3,7 @@
 # license that can be found in the LICENSE file.
 
 import os
+import socket
 import urllib.parse
 import m3u8
 import pytest
@@ -140,8 +141,8 @@ def test_presence_of_base_uri_if_provided_when_loading_from_string():
 
 def test_raise_timeout_exception_if_timeout_happens_when_loading_from_uri():
     try:
-        obj = m3u8.load(playlists.TIMEOUT_SIMPLE_PLAYLIST_URI, timeout=1)
-    except:
+        m3u8.load(playlists.TIMEOUT_SIMPLE_PLAYLIST_URI, timeout=1)
+    except socket.timeout:
         assert True
     else:
         assert False
diff --git a/tests/test_model.py b/tests/test_model.py
index 6edbb197..492f19c4 100755
--- a/tests/test_model.py
+++ b/tests/test_model.py
@@ -7,7 +7,6 @@
 
 import datetime
 import os
-import sys
 
 import playlists
 import pytest
@@ -135,30 +134,30 @@ def test_segment_discontinuity_attribute():
     obj = m3u8.M3U8(playlists.DISCONTINUITY_PLAYLIST_WITH_PROGRAM_DATE_TIME)
     segments = obj.segments
 
-    assert segments[0].discontinuity == False
-    assert segments[5].discontinuity == True
-    assert segments[6].discontinuity == False
+    assert segments[0].discontinuity is False
+    assert segments[5].discontinuity is True
+    assert segments[6].discontinuity is False
 
 
 def test_segment_cue_out_attribute():
     obj = m3u8.M3U8(playlists.CUE_OUT_PLAYLIST)
     segments = obj.segments
 
-    assert segments[1].cue_out == True
-    assert segments[2].cue_out == True
-    assert segments[3].cue_out == False
+    assert segments[1].cue_out is True
+    assert segments[2].cue_out is True
+    assert segments[3].cue_out is False
 
 
 def test_segment_cue_out_start_attribute():
     obj = m3u8.M3U8(playlists.CUE_OUT_WITH_DURATION_PLAYLIST)
 
-    assert obj.segments[0].cue_out_start == True
+    assert obj.segments[0].cue_out_start is True
 
 
 def test_segment_cue_in_attribute():
     obj = m3u8.M3U8(playlists.CUE_OUT_WITH_DURATION_PLAYLIST)
 
-    assert obj.segments[2].cue_in == True
+    assert obj.segments[2].cue_in is True
 
 
 def test_segment_cue_out_cont_dumps():
@@ -219,8 +218,8 @@ def test_segment_cue_out_in_dumps():
 def test_segment_elemental_scte35_attribute():
     obj = m3u8.M3U8(playlists.CUE_OUT_ELEMENTAL_PLAYLIST)
     segments = obj.segments
-    assert segments[4].cue_out == True
-    assert segments[9].cue_out == False
+    assert segments[4].cue_out is True
+    assert segments[9].cue_out is False
     assert (
         segments[4].scte35 == "/DAlAAAAAAAAAP/wFAUAAAABf+//wpiQkv4ARKogAAEBAQAAQ6sodg=="
     )
@@ -229,14 +228,14 @@ def test_segment_elemental_scte35_attribute():
 def test_segment_envivio_scte35_attribute():
     obj = m3u8.M3U8(playlists.CUE_OUT_ENVIVIO_PLAYLIST)
     segments = obj.segments
-    assert segments[3].cue_out == True
+    assert segments[3].cue_out is True
     assert (
         segments[4].scte35 == "/DAlAAAENOOQAP/wFAUBAABrf+//N25XDf4B9p/gAAEBAQAAxKni9A=="
     )
     assert (
         segments[5].scte35 == "/DAlAAAENOOQAP/wFAUBAABrf+//N25XDf4B9p/gAAEBAQAAxKni9A=="
     )
-    assert segments[7].cue_out == False
+    assert segments[7].cue_out is False
 
 
 def test_segment_unknown_scte35_attribute():
@@ -247,8 +246,8 @@ def test_segment_unknown_scte35_attribute():
 
 def test_segment_cue_out_no_duration():
     obj = m3u8.M3U8(playlists.CUE_OUT_NO_DURATION_PLAYLIST)
-    assert obj.segments[0].cue_out_start == True
-    assert obj.segments[2].cue_in == True
+    assert obj.segments[0].cue_out_start is True
+    assert obj.segments[2].cue_in is True
 
 
 def test_segment_asset_metadata_dumps():
@@ -301,7 +300,7 @@ def test_key_attribute_without_initialization_vector():
 
     assert "AES-128" == obj.keys[0].method
     assert "/key" == obj.keys[0].uri
-    assert None == obj.keys[0].iv
+    assert None is obj.keys[0].iv
 
 
 def test_session_keys_on_clear_playlist():
@@ -341,7 +340,7 @@ def test_session_key_attribute_without_initialization_vector():
 
     assert "AES-128" == obj.session_keys[0].method
     assert "/key" == obj.session_keys[0].uri
-    assert None == obj.session_keys[0].iv
+    assert None is obj.session_keys[0].iv
 
 
 def test_segments_attribute():
@@ -371,7 +370,7 @@ def test_segments_attribute_without_title():
 
     assert "/foo/bar-1.ts" == obj.segments[0].uri
     assert 1500 == obj.segments[0].duration
-    assert None == obj.segments[0].title
+    assert None is obj.segments[0].title
 
 
 def test_segments_attribute_without_duration():
@@ -384,7 +383,7 @@ def test_segments_attribute_without_duration():
 
     assert "/foo/bar-1.ts" == obj.segments[0].uri
     assert "Segment title" == obj.segments[0].title
-    assert None == obj.segments[0].duration
+    assert None is obj.segments[0].duration
 
 
 def test_segments_attribute_with_byterange():
@@ -502,34 +501,34 @@ def test_playlists_attribute():
     assert "/url/1.m3u8" == obj.playlists[0].uri
     assert 1 == obj.playlists[0].stream_info.program_id
     assert 320000 == obj.playlists[0].stream_info.bandwidth
-    assert None == obj.playlists[0].stream_info.closed_captions
-    assert None == obj.playlists[0].stream_info.codecs
+    assert None is obj.playlists[0].stream_info.closed_captions
+    assert None is obj.playlists[0].stream_info.codecs
 
-    assert None == obj.playlists[0].media[0].uri
+    assert None is obj.playlists[0].media[0].uri
     assert "high" == obj.playlists[0].media[0].group_id
     assert "VIDEO" == obj.playlists[0].media[0].type
-    assert None == obj.playlists[0].media[0].language
+    assert None is obj.playlists[0].media[0].language
     assert "High" == obj.playlists[0].media[0].name
-    assert None == obj.playlists[0].media[0].default
-    assert None == obj.playlists[0].media[0].autoselect
-    assert None == obj.playlists[0].media[0].forced
-    assert None == obj.playlists[0].media[0].characteristics
+    assert None is obj.playlists[0].media[0].default
+    assert None is obj.playlists[0].media[0].autoselect
+    assert None is obj.playlists[0].media[0].forced
+    assert None is obj.playlists[0].media[0].characteristics
 
     assert "/url/2.m3u8" == obj.playlists[1].uri
     assert 1 == obj.playlists[1].stream_info.program_id
     assert 120000 == obj.playlists[1].stream_info.bandwidth
-    assert None == obj.playlists[1].stream_info.closed_captions
+    assert None is obj.playlists[1].stream_info.closed_captions
     assert "mp4a.40.5" == obj.playlists[1].stream_info.codecs
 
-    assert None == obj.playlists[1].media[0].uri
+    assert None is obj.playlists[1].media[0].uri
     assert "low" == obj.playlists[1].media[0].group_id
     assert "VIDEO" == obj.playlists[1].media[0].type
-    assert None == obj.playlists[1].media[0].language
+    assert None is obj.playlists[1].media[0].language
     assert "Low" == obj.playlists[1].media[0].name
     assert "YES" == obj.playlists[1].media[0].default
     assert "YES" == obj.playlists[1].media[0].autoselect
-    assert None == obj.playlists[1].media[0].forced
-    assert None == obj.playlists[1].media[0].characteristics
+    assert None is obj.playlists[1].media[0].forced
+    assert None is obj.playlists[1].media[0].characteristics
 
     assert [] == obj.iframe_playlists
 
@@ -545,8 +544,8 @@ def test_playlists_attribute_without_program_id():
 
     assert "/url/1.m3u8" == obj.playlists[0].uri
     assert 320000 == obj.playlists[0].stream_info.bandwidth
-    assert None == obj.playlists[0].stream_info.codecs
-    assert None == obj.playlists[0].stream_info.program_id
+    assert None is obj.playlists[0].stream_info.codecs
+    assert None is obj.playlists[0].stream_info.program_id
 
 
 def test_playlists_attribute_with_resolution():
@@ -554,7 +553,7 @@ def test_playlists_attribute_with_resolution():
 
     assert 2 == len(obj.playlists)
     assert (512, 288) == obj.playlists[0].stream_info.resolution
-    assert None == obj.playlists[1].stream_info.resolution
+    assert None is obj.playlists[1].stream_info.resolution
 
 
 def test_iframe_playlists_attribute():
@@ -587,9 +586,9 @@ def test_iframe_playlists_attribute():
     assert "avc1.4d001f" == obj.iframe_playlists[0].iframe_stream_info.codecs
 
     assert "/url/2.m3u8" == obj.iframe_playlists[1].uri
-    assert None == obj.iframe_playlists[1].iframe_stream_info.program_id
+    assert None is obj.iframe_playlists[1].iframe_stream_info.program_id
     assert "120000" == obj.iframe_playlists[1].iframe_stream_info.bandwidth
-    assert None == obj.iframe_playlists[1].iframe_stream_info.resolution
+    assert None is obj.iframe_playlists[1].iframe_stream_info.resolution
     assert "avc1.4d400d" == obj.iframe_playlists[1].iframe_stream_info.codecs
 
 
@@ -599,7 +598,7 @@ def test_version_attribute():
     assert 2 == obj.version
 
     mock_parser_data(obj, {})
-    assert None == obj.version
+    assert None is obj.version
 
 
 def test_version_settable_as_int():
@@ -622,7 +621,7 @@ def test_allow_cache_attribute():
     assert "no" == obj.allow_cache
 
     mock_parser_data(obj, {})
-    assert None == obj.allow_cache
+    assert None is obj.allow_cache
 
 
 def test_files_attribute_should_list_all_files_including_segments_and_key():
@@ -1009,22 +1008,6 @@ def test_should_normalize_variant_streams_urls_if_base_path_passed_to_constructo
     assert obj.dumps().strip() == expected
 
 
-def test_should_normalize_segments_and_key_urls_if_base_path_attribute_updated():
-    base_path = "http://videoserver.com/hls/live"
-
-    obj = m3u8.M3U8(playlists.PLAYLIST_WITH_ENCRYPTED_SEGMENTS_AND_IV)
-    obj.base_path = base_path  # update later
-
-    expected = (
-        playlists.PLAYLIST_WITH_ENCRYPTED_SEGMENTS_AND_IV_SORTED.replace(", IV", ",IV")
-        .replace("../../../../hls", base_path)
-        .replace("/hls-key", base_path)
-        .strip()
-    )
-
-    assert obj.dumps() == expected
-
-
 def test_should_normalize_segments_and_key_urls_if_base_path_attribute_updated():
     base_path = "http://videoserver.com/hls/live"
 
@@ -1230,15 +1213,6 @@ def test_should_round_frame_rate():
     assert expected == obj.dumps().strip()
 
 
-@pytest.mark.skipif(sys.version_info >= (3,), reason="unicode not available in v3")
-def test_m3u8_unicode_method():
-    obj = m3u8.M3U8(playlists.SIMPLE_PLAYLIST)
-
-    result = unicode(obj).strip()
-    expected = playlists.SIMPLE_PLAYLIST.strip()
-    assert result == expected
-
-
 def test_add_segment_to_playlist():
     obj = m3u8.M3U8()
 
@@ -1270,7 +1244,7 @@ def test_find_key_throws_when_no_match():
                 # deliberately empty
             ],
         )
-    except KeyError as e:
+    except KeyError:
         threw = True
     finally:
         assert threw
@@ -1572,13 +1546,6 @@ def test_add_content_steering_base_uri_update():
     )
 
 
-def test_dump_should_work_for_variant_playlists_with_image_playlists():
-    obj = m3u8.M3U8(playlists.VARIANT_PLAYLIST_WITH_IMAGE_PLAYLISTS)
-
-    expected = playlists.VARIANT_PLAYLIST_WITH_IMAGE_PLAYLISTS.strip()
-
-    assert expected == obj.dumps().strip()
-
 def test_dump_should_work_for_variant_playlists_with_image_playlists():
     obj = m3u8.M3U8(playlists.VARIANT_PLAYLIST_WITH_IMAGE_PLAYLISTS)
 
diff --git a/tests/test_parser.py b/tests/test_parser.py
index 0e8878af..0a61077a 100644
--- a/tests/test_parser.py
+++ b/tests/test_parser.py
@@ -162,8 +162,8 @@ def test_should_parse_variant_playlist():
     data = m3u8.parse(playlists.VARIANT_PLAYLIST)
     playlists_list = list(data["playlists"])
 
-    assert True == data["is_variant"]
-    assert None == data["media_sequence"]
+    assert True is data["is_variant"]
+    assert None is data["media_sequence"]
     assert 4 == len(playlists_list)
 
     assert "http://example.com/low.m3u8" == playlists_list[0]["uri"]
@@ -180,8 +180,8 @@ def test_should_parse_variant_playlist_with_cc_subtitles_and_audio():
     data = m3u8.parse(playlists.VARIANT_PLAYLIST_WITH_CC_SUBS_AND_AUDIO)
     playlists_list = list(data["playlists"])
 
-    assert True == data["is_variant"]
-    assert None == data["media_sequence"]
+    assert True is data["is_variant"]
+    assert None is data["media_sequence"]
     assert 2 == len(playlists_list)
 
     assert "http://example.com/with-cc-hi.m3u8" == playlists_list[0]["uri"]
@@ -252,7 +252,7 @@ def test_should_parse_variant_playlist_with_iframe_playlists():
     data = m3u8.parse(playlists.VARIANT_PLAYLIST_WITH_IFRAME_PLAYLISTS)
     iframe_playlists = list(data["iframe_playlists"])
 
-    assert True == data["is_variant"]
+    assert True is data["is_variant"]
 
     assert 4 == len(iframe_playlists)
 
@@ -271,7 +271,7 @@ def test_should_parse_variant_playlist_with_alt_iframe_playlists_layout():
     data = m3u8.parse(playlists.VARIANT_PLAYLIST_WITH_ALT_IFRAME_PLAYLISTS_LAYOUT)
     iframe_playlists = list(data["iframe_playlists"])
 
-    assert True == data["is_variant"]
+    assert True is data["is_variant"]
 
     assert 4 == len(iframe_playlists)
 
@@ -289,7 +289,7 @@ def test_should_parse_variant_playlist_with_alt_iframe_playlists_layout():
 def test_should_parse_iframe_playlist():
     data = m3u8.parse(playlists.IFRAME_PLAYLIST)
 
-    assert True == data["is_i_frames_only"]
+    assert True is data["is_i_frames_only"]
     assert 4.12 == data["segments"][0]["duration"]
     assert "9400@376" == data["segments"][0]["byterange"]
     assert "segment1.ts" == data["segments"][0]["uri"]
@@ -299,7 +299,7 @@ def test_should_parse_variant_playlist_with_image_playlists():
     data = m3u8.parse(playlists.VARIANT_PLAYLIST_WITH_IMAGE_PLAYLISTS)
     image_playlists = list(data['image_playlists'])
 
-    assert True == data['is_variant']
+    assert True is data['is_variant']
     assert 2 == len(image_playlists)
     assert '320x180' == image_playlists[0]['image_stream_info']['resolution']
     assert 'jpeg' == image_playlists[0]['image_stream_info']['codecs']
@@ -311,7 +311,7 @@ def test_should_parse_variant_playlist_with_image_playlists():
 def test_should_parse_vod_image_playlist():
     data = m3u8.parse(playlists.VOD_IMAGE_PLAYLIST)
 
-    assert True == data['is_images_only']
+    assert True is data['is_images_only']
     assert 8 == len(data['tiles'])
     assert 'preroll-ad-1.jpg' == data['segments'][0]['uri']
     assert '640x360' == data['tiles'][0]['resolution']
@@ -322,7 +322,7 @@ def test_should_parse_vod_image_playlist():
 def test_should_parse_vod_image_playlist2():
     data = m3u8.parse(playlists.VOD_IMAGE_PLAYLIST2)
 
-    assert True == data['is_images_only']
+    assert True is data['is_images_only']
     assert '640x360' == data['tiles'][0]['resolution']
     assert '4x3' == data['tiles'][0]['layout']
     assert 2.002 == data['tiles'][0]['duration']
@@ -332,7 +332,7 @@ def test_should_parse_vod_image_playlist2():
 def test_should_parse_live_image_playlist():
     data = m3u8.parse(playlists.LIVE_IMAGE_PLAYLIST)
 
-    assert True == data['is_images_only']
+    assert True is data['is_images_only']
     assert 10 == len(data['segments'])
     assert 'content-123.jpg' == data['segments'][0]['uri']
     assert 'content-124.jpg' == data['segments'][1]['uri']
@@ -348,7 +348,7 @@ def test_should_parse_live_image_playlist():
 def test_should_parse_playlist_using_byteranges():
     data = m3u8.parse(playlists.PLAYLIST_USING_BYTERANGES)
 
-    assert False == data["is_i_frames_only"]
+    assert False is data["is_i_frames_only"]
     assert 10 == data["segments"][0]["duration"]
     assert "76242@0" == data["segments"][0]["byterange"]
     assert "segment.ts" == data["segments"][0]["uri"]
@@ -356,10 +356,10 @@ def test_should_parse_playlist_using_byteranges():
 
 def test_should_parse_endlist_playlist():
     data = m3u8.parse(playlists.SIMPLE_PLAYLIST)
-    assert True == data["is_endlist"]
+    assert True is data["is_endlist"]
 
     data = m3u8.parse(playlists.SLIDING_WINDOW_PLAYLIST)
-    assert False == data["is_endlist"]
+    assert False is data["is_endlist"]
 
 
 def test_should_parse_ALLOW_CACHE():
@@ -769,8 +769,8 @@ def test_gap():
     data = m3u8.parse(playlists.GAP_PLAYLIST)
 
     assert data["segments"][0]["gap_tag"] is None
-    assert data["segments"][1]["gap_tag"] == True
-    assert data["segments"][2]["gap_tag"] == True
+    assert data["segments"][1]["gap_tag"] is True
+    assert data["segments"][2]["gap_tag"] is True
     assert data["segments"][3]["gap_tag"] is None
 
 
@@ -781,7 +781,7 @@ def test_gap_in_parts():
     assert data["segments"][0]["parts"][0].get("gap", None) is None
     assert data["segments"][0]["parts"][1]["gap_tag"] is None
     assert data["segments"][0]["parts"][1]["gap"] == "YES"
-    assert data["segments"][0]["parts"][2]["gap_tag"] == True
+    assert data["segments"][0]["parts"][2]["gap_tag"] is True
     assert data["segments"][0]["parts"][2].get("gap", None) is None
 
 
@@ -789,7 +789,7 @@ def test_should_parse_variant_playlist_with_iframe_with_average_bandwidth():
     data = m3u8.parse(playlists.VARIANT_PLAYLIST_WITH_IFRAME_AVERAGE_BANDWIDTH)
     iframe_playlists = list(data["iframe_playlists"])
 
-    assert True == data["is_variant"]
+    assert True is data["is_variant"]
 
     assert 4 == len(iframe_playlists)
 
@@ -812,7 +812,7 @@ def test_should_parse_variant_playlist_with_iframe_with_video_range():
     data = m3u8.parse(playlists.VARIANT_PLAYLIST_WITH_IFRAME_VIDEO_RANGE)
     iframe_playlists = list(data["iframe_playlists"])
 
-    assert True == data["is_variant"]
+    assert True is data["is_variant"]
 
     assert 4 == len(iframe_playlists)
 
@@ -830,7 +830,7 @@ def test_should_parse_variant_playlist_with_iframe_with_hdcp_level():
     data = m3u8.parse(playlists.VARIANT_PLAYLIST_WITH_IFRAME_HDCP_LEVEL)
     iframe_playlists = list(data["iframe_playlists"])
 
-    assert True == data["is_variant"]
+    assert True is data["is_variant"]
 
     assert 4 == len(iframe_playlists)
 
@@ -868,13 +868,13 @@ def test_content_steering():
 
 def test_cue_in_pops_scte35_data_and_duration():
     data = m3u8.parse(playlists.CUE_OUT_ELEMENTAL_PLAYLIST)
-    assert data["segments"][9]["cue_in"] == True
+    assert data["segments"][9]["cue_in"] is True
     assert (
         data["segments"][9]["scte35"]
         == "/DAlAAAAAAAAAP/wFAUAAAABf+//wpiQkv4ARKogAAEBAQAAQ6sodg=="
     )
     assert data["segments"][9]["scte35_duration"] == "50"
-    assert data["segments"][10]["cue_in"] == False
+    assert data["segments"][10]["cue_in"] is False
     assert data["segments"][10]["scte35"] is None
     assert data["segments"][10]["scte35_duration"] is None