Repository: WebexCommunity/WebexPythonSDK (language: python)

Issue:
PEP8 requirement
There are a lot of files and lines that do not adhere to PEP8 as required based on the documentation. When testing, most tests fail because of this. 
Cards - Choices
Good evening,

Can you please provide an example of how to use the Choices input for adaptive cards?  I am receiving the following error when I try to pass a list.

item.to_dict() for item in property_value
AttributeError: 'str' object has no attribute 'to_dict'

Thanks,
Ken


Discussion / hints:
Yeah, it looks like the recent additions were not properly formatted or checked against `flake8`. To help resolve these errors and get the tests working again, I am going to use [black](https://black.readthedocs.io/en/stable/) and [ruff](https://docs.astral.sh/ruff/) to help with the formatting and get the `flake8` linting working again.

In v2, we'll re-tool to use `black` or `ruff` for formatting and linting.
Modified the inputs.py with the following and it worked:

super().__init__(
            **serializable_properties=[]**,
            simple_properties=[
                'id', 'type', 'isMultiSelect', 'style', 'value', 'height',
                'separator', 'spacing',**'choices'**
            ],
        )

example list to pass it 

choice_list = [{'title':'customer1', 'value':'customer1'},{'title':'customer2', 'value':'customer2'}]

mychoice = Choices(choice_list, id='customer')
This is still an issue, and I don't like to have to modify a 3rd party library unless necessary, this method works without the need to modify the WebexPythonSDK. This will modify the attributes of your instance rather than the library. Keep in mind that if you upgrade the library, your modifications may be overwritten. However, this is a quick fix until the issue is resolved and.

```python
choices = [{"title":  "foo", "value": "1"}, {"title": "bar", "value": "2"},]
report.serializable_properties = []
report.simple_properties.append("choices")
```

Fix patch:
diff --git a/.flake8 b/.flake8
index cd5f612..af6b616 100644
--- a/.flake8
+++ b/.flake8
@@ -11,13 +11,14 @@ ignore =
     # W503 line break before binary operator
     W503,
 exclude =
+    __pycache__,
     .git/,
     .idea/,
     .venv/,
     .vscode/,
-    __pycache__,
     dist/,
     docs/conf.py,
+    generator/templates/,
     venv/,
     versioneer.py,
     webexteamssdk/_version.py,
diff --git a/.ruff.toml b/.ruff.toml
new file mode 100644
index 0000000..9a6714f
--- /dev/null
+++ b/.ruff.toml
@@ -0,0 +1,25 @@
+line-length = 79
+
+
+extend-exclude = [
+    "versioneer.py",
+    "webexteamssdk/_version.py",
+    "generator/**",
+]
+
+[lint]
+# B: flake8-bugbear
+# Q: flake8-quotes
+extend-select = [ "B", "Q", "W" ]
+
+ignore-init-module-imports = true
+ignore = [
+    # E402 module level import not at top of file
+    "E402",
+    # F401 'builtins.*' imported but unused
+    "F401",
+    # F403 'from builtins import *' used; unable to detect undefined names
+    "F403",
+    # F405 'unicode' may be undefined, or defined from star imports: builtins
+    "F405",
+]
diff --git a/LICENSE b/LICENSE
index ce0147c..10e1d02 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
 The MIT License (MIT)
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
diff --git a/Pipfile b/Pipfile
index 889eb37..ec39e52 100644
--- a/Pipfile
+++ b/Pipfile
@@ -14,3 +14,4 @@ pytest = "*"
 flake8 = "*"
 twine = "*"
 ipython = "*"
+pyyaml = "*"
diff --git a/Pipfile.lock b/Pipfile.lock
index d944c03..7fdbaf7 100644
--- a/Pipfile.lock
+++ b/Pipfile.lock
@@ -1,7 +1,7 @@
 {
     "_meta": {
         "hash": {
-            "sha256": "f501f12c797edb3647818ad301bf55c8b4a9a9830017be53554259e9f459e97c"
+            "sha256": "1ea57274034c50d8f1cc643603390a0d48c15f3fe45cdd5eb1c60403c4a3b40b"
         },
         "pipfile-spec": 6,
         "requires": {},
@@ -14,9 +14,156 @@
         ]
     },
     "default": {
-        "sanitized-package": {
-            "editable": true,
-            "path": "."
+        "certifi": {
+            "hashes": [
+                "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f",
+                "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"
+            ],
+            "markers": "python_version >= '3.6'",
+            "version": "==2024.2.2"
+        },
+        "charset-normalizer": {
+            "hashes": [
+                "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027",
+                "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087",
+                "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786",
+                "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8",
+                "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09",
+                "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185",
+                "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574",
+                "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e",
+                "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519",
+                "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898",
+                "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269",
+                "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3",
+                "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f",
+                "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6",
+                "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8",
+                "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a",
+                "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73",
+                "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc",
+                "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714",
+                "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2",
+                "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc",
+                "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce",
+                "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d",
+                "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e",
+                "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6",
+                "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269",
+                "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96",
+                "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d",
+                "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a",
+                "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4",
+                "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77",
+                "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d",
+                "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0",
+                "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed",
+                "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068",
+                "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac",
+                "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25",
+                "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8",
+                "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab",
+                "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26",
+                "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2",
+                "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db",
+                "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f",
+                "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5",
+                "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99",
+                "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c",
+                "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d",
+                "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811",
+                "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa",
+                "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a",
+                "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03",
+                "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b",
+                "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04",
+                "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c",
+                "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001",
+                "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458",
+                "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389",
+                "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99",
+                "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985",
+                "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537",
+                "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238",
+                "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f",
+                "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d",
+                "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796",
+                "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a",
+                "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143",
+                "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8",
+                "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c",
+                "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5",
+                "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5",
+                "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711",
+                "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4",
+                "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6",
+                "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c",
+                "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7",
+                "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4",
+                "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b",
+                "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae",
+                "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12",
+                "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c",
+                "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae",
+                "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8",
+                "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887",
+                "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b",
+                "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4",
+                "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f",
+                "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5",
+                "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33",
+                "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519",
+                "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"
+            ],
+            "markers": "python_full_version >= '3.7.0'",
+            "version": "==3.3.2"
+        },
+        "future": {
+            "hashes": [
+                "sha256:929292d34f5872e70396626ef385ec22355a1fae8ad29e1a734c3e43f9fbc216",
+                "sha256:bd2968309307861edae1458a4f8a4f3598c03be43b97521076aebf5d94c07b05"
+            ],
+            "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
+            "version": "==1.0.0"
+        },
+        "idna": {
+            "hashes": [
+                "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc",
+                "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"
+            ],
+            "markers": "python_version >= '3.5'",
+            "version": "==3.7"
+        },
+        "pyjwt": {
+            "hashes": [
+                "sha256:5c6eca3c2940464d106b99ba83b00c6add741c9becaec087fb7ccdefea71350e",
+                "sha256:8d59a976fb773f3e6a39c85636357c4f0e242707394cadadd9814f5cbaa20e96"
+            ],
+            "version": "==1.7.1"
+        },
+        "requests": {
+            "hashes": [
+                "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f",
+                "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"
+            ],
+            "markers": "python_version >= '3.7'",
+            "version": "==2.31.0"
+        },
+        "requests-toolbelt": {
+            "hashes": [
+                "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6",
+                "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06"
+            ],
+            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
+            "version": "==1.0.0"
+        },
+        "urllib3": {
+            "hashes": [
+                "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d",
+                "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19"
+            ],
+            "markers": "python_version >= '3.8'",
+            "version": "==2.2.1"
         },
         "webexteamssdk": {
             "editable": true,
@@ -26,49 +173,34 @@
     "develop": {
         "alabaster": {
             "hashes": [
-                "sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3",
-                "sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2"
+                "sha256:75a8b99c28a5dad50dd7f8ccdd447a121ddb3892da9e53d1ca5cca3106d58d65",
+                "sha256:b46733c07dce03ae4e150330b975c75737fa60f0a7c591b6c8bf4928a28e2c92"
             ],
-            "markers": "python_version >= '3.6'",
-            "version": "==0.7.13"
+            "markers": "python_version >= '3.9'",
+            "version": "==0.7.16"
         },
         "asttokens": {
             "hashes": [
-                "sha256:4622110b2a6f30b77e1473affaa97e711bc2f07d3f10848420ff1898edbe94f3",
-                "sha256:6b0ac9e93fb0335014d382b8fa9b3afa7df546984258005da0b9e7095b3deb1c"
-            ],
-            "version": "==2.2.1"
-        },
-        "attrs": {
-            "hashes": [
-                "sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836",
-                "sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99"
+                "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24",
+                "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0"
             ],
-            "markers": "python_version >= '3.6'",
-            "version": "==22.2.0"
+            "version": "==2.4.1"
         },
         "babel": {
             "hashes": [
-                "sha256:1ad3eca1c885218f6dce2ab67291178944f810a10a9b5f3cb8382a5a232b64fe",
-                "sha256:5ef4b3226b0180dedded4229651c8b0e1a3a6a2837d45a073272f313e4cf97f6"
-            ],
-            "markers": "python_version >= '3.6'",
-            "version": "==2.11.0"
-        },
-        "backcall": {
-            "hashes": [
-                "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e",
-                "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"
+                "sha256:6919867db036398ba21eb5c7a0f6b28ab8cbc3ae7a73a44ebe34ae74a4e7d363",
+                "sha256:efb1a25b7118e67ce3a259bed20545c29cb68be8ad2c784c83689981b7a57287"
             ],
-            "version": "==0.2.0"
+            "markers": "python_version >= '3.7'",
+            "version": "==2.14.0"
         },
-        "bleach": {
+        "backports.tarfile": {
             "hashes": [
-                "sha256:1a1a85c1595e07d8db14c5f09f09e6433502c51c595970edc090551f0db99414",
-                "sha256:33c16e3353dbd13028ab4799a0f89a83f113405c766e9c122df8a06f5b85b3f4"
+                "sha256:91d59138ea401ee2a95e8b839c1e2f51f3e9ca76bdba8b6a29f8d773564686a8",
+                "sha256:b2f4df351db942d094db94588bbf2c6938697a5f190f44c934acc697da56008b"
             ],
-            "markers": "python_version >= '3.7'",
-            "version": "==6.0.0"
+            "markers": "python_version < '3.12'",
+            "version": "==1.1.0"
         },
         "certifi": {
             "hashes": [
@@ -78,64 +210,6 @@
             "markers": "python_version >= '3.6'",
             "version": "==2024.2.2"
         },
-        "cffi": {
-            "hashes": [
-                "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc",
-                "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a",
-                "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417",
-                "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab",
-                "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520",
-                "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36",
-                "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743",
-                "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8",
-                "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed",
-                "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684",
-                "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56",
-                "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324",
-                "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d",
-                "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235",
-                "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e",
-                "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088",
-                "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000",
-                "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7",
-                "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e",
-                "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673",
-                "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c",
-                "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe",
-                "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2",
-                "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098",
-                "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8",
-                "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a",
-                "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0",
-                "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b",
-                "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896",
-                "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e",
-                "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9",
-                "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2",
-                "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b",
-                "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6",
-                "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404",
-                "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f",
-                "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0",
-                "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4",
-                "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc",
-                "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936",
-                "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba",
-                "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872",
-                "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb",
-                "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614",
-                "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1",
-                "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d",
-                "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969",
-                "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b",
-                "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4",
-                "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627",
-                "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956",
-                "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"
-            ],
-            "markers": "platform_python_implementation != 'PyPy'",
-            "version": "==1.16.0"
-        },
         "charset-normalizer": {
             "hashes": [
                 "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027",
@@ -232,53 +306,6 @@
             "markers": "python_full_version >= '3.7.0'",
             "version": "==3.3.2"
         },
-        "colorama": {
-            "hashes": [
-                "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44",
-                "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"
-            ],
-            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6'",
-            "version": "==0.4.6"
-        },
-        "cryptography": {
-            "hashes": [
-                "sha256:01911714117642a3f1792c7f376db572aadadbafcd8d75bb527166009c9f1d1b",
-                "sha256:0e89f7b84f421c56e7ff69f11c441ebda73b8a8e6488d322ef71746224c20fce",
-                "sha256:12d341bd42cdb7d4937b0cabbdf2a94f949413ac4504904d0cdbdce4a22cbf88",
-                "sha256:15a1fb843c48b4a604663fa30af60818cd28f895572386e5f9b8a665874c26e7",
-                "sha256:1cdcdbd117681c88d717437ada72bdd5be9de117f96e3f4d50dab3f59fd9ab20",
-                "sha256:1df6fcbf60560d2113b5ed90f072dc0b108d64750d4cbd46a21ec882c7aefce9",
-                "sha256:3c6048f217533d89f2f8f4f0fe3044bf0b2090453b7b73d0b77db47b80af8dff",
-                "sha256:3e970a2119507d0b104f0a8e281521ad28fc26f2820687b3436b8c9a5fcf20d1",
-                "sha256:44a64043f743485925d3bcac548d05df0f9bb445c5fcca6681889c7c3ab12764",
-                "sha256:4e36685cb634af55e0677d435d425043967ac2f3790ec652b2b88ad03b85c27b",
-                "sha256:5f8907fcf57392cd917892ae83708761c6ff3c37a8e835d7246ff0ad251d9298",
-                "sha256:69b22ab6506a3fe483d67d1ed878e1602bdd5912a134e6202c1ec672233241c1",
-                "sha256:6bfadd884e7280df24d26f2186e4e07556a05d37393b0f220a840b083dc6a824",
-                "sha256:6d0fbe73728c44ca3a241eff9aefe6496ab2656d6e7a4ea2459865f2e8613257",
-                "sha256:6ffb03d419edcab93b4b19c22ee80c007fb2d708429cecebf1dd3258956a563a",
-                "sha256:810bcf151caefc03e51a3d61e53335cd5c7316c0a105cc695f0959f2c638b129",
-                "sha256:831a4b37accef30cccd34fcb916a5d7b5be3cbbe27268a02832c3e450aea39cb",
-                "sha256:887623fe0d70f48ab3f5e4dbf234986b1329a64c066d719432d0698522749929",
-                "sha256:a0298bdc6e98ca21382afe914c642620370ce0470a01e1bef6dd9b5354c36854",
-                "sha256:a1327f280c824ff7885bdeef8578f74690e9079267c1c8bd7dc5cc5aa065ae52",
-                "sha256:c1f25b252d2c87088abc8bbc4f1ecbf7c919e05508a7e8628e6875c40bc70923",
-                "sha256:c3a5cbc620e1e17009f30dd34cb0d85c987afd21c41a74352d1719be33380885",
-                "sha256:ce8613beaffc7c14f091497346ef117c1798c202b01153a8cc7b8e2ebaaf41c0",
-                "sha256:d2a27aca5597c8a71abbe10209184e1a8e91c1fd470b5070a2ea60cafec35bcd",
-                "sha256:dad9c385ba8ee025bb0d856714f71d7840020fe176ae0229de618f14dae7a6e2",
-                "sha256:db4b65b02f59035037fde0998974d84244a64c3265bdef32a827ab9b63d61b18",
-                "sha256:e09469a2cec88fb7b078e16d4adec594414397e8879a4341c6ace96013463d5b",
-                "sha256:e53dc41cda40b248ebc40b83b31516487f7db95ab8ceac1f042626bc43a2f992",
-                "sha256:f1e85a178384bf19e36779d91ff35c7617c885da487d689b05c1366f9933ad74",
-                "sha256:f47be41843200f7faec0683ad751e5ef11b9a56a220d57f300376cd8aba81660",
-                "sha256:fb0cef872d8193e487fc6bdb08559c3aa41b659a7d9be48b2e10747f47863925",
-                "sha256:ffc73996c4fca3d2b6c1c8c12bfd3ad00def8621da24f547626bf06441400449"
-            ],
-            "index": "pypi",
-            "markers": "python_version >= '3.7'",
-            "version": "==42.0.4"
-        },
         "decorator": {
             "hashes": [
                 "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330",
@@ -289,34 +316,44 @@
         },
         "docutils": {
             "hashes": [
-                "sha256:33995a6753c30b7f577febfc2c50411fec6aac7f7ffeb7c4cfe5991072dcf9e6",
-                "sha256:5e1de4d849fee02c63b040a4a3fd567f4ab104defd8a5511fbbc24a8a017efbc"
+                "sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6",
+                "sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b"
             ],
             "markers": "python_version >= '3.7'",
-            "version": "==0.19"
+            "version": "==0.20.1"
         },
-        "executing": {
+        "exceptiongroup": {
             "hashes": [
-                "sha256:0314a69e37426e3608aada02473b4161d4caf5a4b244d1d0c48072b8fee7bacc",
-                "sha256:19da64c18d2d851112f09c287f8d3dbbdf725ab0e569077efb6cdcbd3497c107"
+                "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14",
+                "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"
             ],
+            "markers": "python_version < '3.11'",
             "version": "==1.2.0"
         },
+        "executing": {
+            "hashes": [
+                "sha256:35afe2ce3affba8ee97f2d69927fa823b08b472b7b994e36a52a964b93d16147",
+                "sha256:eac49ca94516ccc753f9fb5ce82603156e590b27525a8bc32cce8ae302eb61bc"
+            ],
+            "markers": "python_version >= '3.5'",
+            "version": "==2.0.1"
+        },
         "flake8": {
             "hashes": [
-                "sha256:15e351d19611c887e482fb960eae4d44845013cc142d42896e9862f775d8cf5c",
-                "sha256:f04b9fcbac03b0a3e58c0ab3a0ecc462e023a9faf046d57794184028123aa208"
+                "sha256:33f96621059e65eec474169085dc92bf26e7b2d47366b70be2f67ab80dc25132",
+                "sha256:a6dfbb75e03252917f2473ea9653f7cd799c3064e54d4c8140044c5c065f53c3"
             ],
             "index": "pypi",
-            "version": "==3.8.3"
+            "markers": "python_full_version >= '3.8.1'",
+            "version": "==7.0.0"
         },
         "idna": {
             "hashes": [
-                "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca",
-                "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"
+                "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc",
+                "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"
             ],
             "markers": "python_version >= '3.5'",
-            "version": "==3.6"
+            "version": "==3.7"
         },
         "imagesize": {
             "hashes": [
@@ -328,60 +365,84 @@
         },
         "importlib-metadata": {
             "hashes": [
-                "sha256:7efb448ec9a5e313a57655d35aa54cd3e01b7e1fbcf72dce1bf06119420f5bad",
-                "sha256:e354bedeb60efa6affdcc8ae121b73544a7aa74156d047311948f6d711cd378d"
+                "sha256:30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570",
+                "sha256:b78938b926ee8d5f020fc4772d487045805a55ddbad2ecf21c6d60938dc7fcd2"
             ],
-            "markers": "python_version < '3.12'",
-            "version": "==6.0.0"
+            "markers": "python_version >= '3.8'",
+            "version": "==7.1.0"
+        },
+        "iniconfig": {
+            "hashes": [
+                "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3",
+                "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"
+            ],
+            "markers": "python_version >= '3.7'",
+            "version": "==2.0.0"
         },
         "ipython": {
             "hashes": [
-                "sha256:b13a1d6c1f5818bd388db53b7107d17454129a70de2b87481d555daede5eb49e",
-                "sha256:b38c31e8fc7eff642fc7c597061fff462537cf2314e3225a19c906b7b0d8a345"
+                "sha256:07232af52a5ba146dc3372c7bf52a0f890a23edf38d77caef8d53f9cdc2584c1",
+                "sha256:7468edaf4f6de3e1b912e57f66c241e6fd3c7099f2ec2136e239e142e800274d"
             ],
             "index": "pypi",
-            "version": "==8.10.0"
+            "markers": "python_version >= '3.10'",
+            "version": "==8.23.0"
         },
         "jaraco.classes": {
             "hashes": [
-                "sha256:2353de3288bc6b82120752201c6b1c1a14b058267fa424ed5ce5984e3b922158",
-                "sha256:89559fa5c1d3c34eff6f631ad80bb21f378dbcbb35dd161fd2c6b93f5be2f98a"
+                "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd",
+                "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790"
             ],
-            "markers": "python_version >= '3.7'",
-            "version": "==3.2.3"
+            "markers": "python_version >= '3.8'",
+            "version": "==3.4.0"
         },
-        "jedi": {
+        "jaraco.context": {
             "hashes": [
-                "sha256:203c1fd9d969ab8f2119ec0a3342e0b49910045abe6af0a3ae83a5764d54639e",
-                "sha256:bae794c30d07f6d910d32a7048af09b5a39ed740918da923c6b780790ebac612"
+                "sha256:3e16388f7da43d384a1a7cd3452e72e14732ac9fe459678773a3608a812bf266",
+                "sha256:c2f67165ce1f9be20f32f650f25d8edfc1646a8aeee48ae06fb35f90763576d2"
             ],
-            "markers": "python_version >= '3.6'",
-            "version": "==0.18.2"
+            "markers": "python_version >= '3.8'",
+            "version": "==5.3.0"
+        },
+        "jaraco.functools": {
+            "hashes": [
+                "sha256:c279cb24c93d694ef7270f970d499cab4d3813f4e08273f95398651a634f0925",
+                "sha256:daf276ddf234bea897ef14f43c4e1bf9eefeac7b7a82a4dd69228ac20acff68d"
+            ],
+            "markers": "python_version >= '3.8'",
+            "version": "==4.0.0"
         },
-        "jeepney": {
+        "jedi": {
             "hashes": [
-                "sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806",
-                "sha256:c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755"
+                "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd",
+                "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0"
             ],
-            "markers": "sys_platform == 'linux'",
-            "version": "==0.8.0"
+            "markers": "python_version >= '3.6'",
+            "version": "==0.19.1"
         },
         "jinja2": {
             "hashes": [
                 "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa",
                 "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90"
             ],
-            "index": "pypi",
             "markers": "python_version >= '3.7'",
             "version": "==3.1.3"
         },
         "keyring": {
             "hashes": [
-                "sha256:771ed2a91909389ed6148631de678f82ddc73737d85a927f382a8a1b157898cd",
-                "sha256:ba2e15a9b35e21908d0aaf4e0a47acc52d6ae33444df0da2b49d41a46ef6d678"
+                "sha256:26fc12e6a329d61d24aa47b22a7c5c3f35753df7d8f2860973cf94f4e1fb3427",
+                "sha256:7230ea690525133f6ad536a9b5def74a4bd52642abe594761028fc044d7c7893"
             ],
-            "markers": "python_version >= '3.7'",
-            "version": "==23.13.1"
+            "markers": "python_version >= '3.8'",
+            "version": "==25.1.0"
+        },
+        "markdown-it-py": {
+            "hashes": [
+                "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1",
+                "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"
+            ],
+            "markers": "python_version >= '3.8'",
+            "version": "==3.0.0"
         },
         "markupsafe": {
             "hashes": [
@@ -451,81 +512,104 @@
         },
         "matplotlib-inline": {
             "hashes": [
-                "sha256:f1f41aab5328aa5aaea9b16d083b128102f8712542f819fe7e6a420ff581b311",
-                "sha256:f887e5f10ba98e8d2b150ddcf4702c1e5f8b3a20005eb0f74bfdbd360ee6f304"
+                "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90",
+                "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca"
             ],
-            "markers": "python_version >= '3.5'",
-            "version": "==0.1.6"
+            "markers": "python_version >= '3.8'",
+            "version": "==0.1.7"
         },
         "mccabe": {
             "hashes": [
-                "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42",
-                "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"
+                "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325",
+                "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"
             ],
-            "version": "==0.6.1"
+            "markers": "python_version >= '3.6'",
+            "version": "==0.7.0"
         },
-        "more-itertools": {
+        "mdurl": {
             "hashes": [
-                "sha256:250e83d7e81d0c87ca6bd942e6aeab8cc9daa6096d12c5308f3f92fa5e5c1f41",
-                "sha256:5a6257e40878ef0520b1803990e3e22303a41b5714006c32a3fd8304b26ea1ab"
+                "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8",
+                "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"
             ],
             "markers": "python_version >= '3.7'",
-            "version": "==9.0.0"
+            "version": "==0.1.2"
+        },
+        "more-itertools": {
+            "hashes": [
+                "sha256:686b06abe565edfab151cb8fd385a05651e1fdf8f0a14191e4439283421f8684",
+                "sha256:8fccb480c43d3e99a00087634c06dd02b0d50fbf088b380de5a41a015ec239e1"
+            ],
+            "markers": "python_version >= '3.8'",
+            "version": "==10.2.0"
+        },
+        "nh3": {
+            "hashes": [
+                "sha256:0316c25b76289cf23be6b66c77d3608a4fdf537b35426280032f432f14291b9a",
+                "sha256:1a814dd7bba1cb0aba5bcb9bebcc88fd801b63e21e2450ae6c52d3b3336bc911",
+                "sha256:1aa52a7def528297f256de0844e8dd680ee279e79583c76d6fa73a978186ddfb",
+                "sha256:22c26e20acbb253a5bdd33d432a326d18508a910e4dcf9a3316179860d53345a",
+                "sha256:40015514022af31975c0b3bca4014634fa13cb5dc4dbcbc00570acc781316dcc",
+                "sha256:40d0741a19c3d645e54efba71cb0d8c475b59135c1e3c580f879ad5514cbf028",
+                "sha256:551672fd71d06cd828e282abdb810d1be24e1abb7ae2543a8fa36a71c1006fe9",
+                "sha256:66f17d78826096291bd264f260213d2b3905e3c7fae6dfc5337d49429f1dc9f3",
+                "sha256:85cdbcca8ef10733bd31f931956f7fbb85145a4d11ab9e6742bbf44d88b7e351",
+                "sha256:a3f55fabe29164ba6026b5ad5c3151c314d136fd67415a17660b4aaddacf1b10",
+                "sha256:b4427ef0d2dfdec10b641ed0bdaf17957eb625b2ec0ea9329b3d28806c153d71",
+                "sha256:ba73a2f8d3a1b966e9cdba7b211779ad8a2561d2dba9674b8a19ed817923f65f",
+                "sha256:c21bac1a7245cbd88c0b0e4a420221b7bfa838a2814ee5bb924e9c2f10a1120b",
+                "sha256:c551eb2a3876e8ff2ac63dff1585236ed5dfec5ffd82216a7a174f7c5082a78a",
+                "sha256:c790769152308421283679a142dbdb3d1c46c79c823008ecea8e8141db1a2062",
+                "sha256:d7a25fd8c86657f5d9d576268e3b3767c5cd4f42867c9383618be8517f0f022a"
+            ],
+            "version": "==0.2.17"
         },
         "packaging": {
             "hashes": [
-                "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2",
-                "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"
+                "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5",
+                "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"
             ],
             "markers": "python_version >= '3.7'",
-            "version": "==23.0"
+            "version": "==24.0"
         },
         "parso": {
             "hashes": [
-                "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0",
-                "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"
+                "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18",
+                "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d"
             ],
             "markers": "python_version >= '3.6'",
-            "version": "==0.8.3"
+            "version": "==0.8.4"
         },
         "pexpect": {
             "hashes": [
-                "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937",
-                "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"
-            ],
-            "markers": "sys_platform != 'win32'",
-            "version": "==4.8.0"
-        },
-        "pickleshare": {
-            "hashes": [
-                "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca",
-                "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"
+                "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523",
+                "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"
             ],
-            "version": "==0.7.5"
+            "markers": "sys_platform != 'win32' and sys_platform != 'emscripten'",
+            "version": "==4.9.0"
         },
         "pkginfo": {
             "hashes": [
-                "sha256:4b7a555a6d5a22169fcc9cf7bfd78d296b0361adad412a346c1226849af5e546",
-                "sha256:8fd5896e8718a4372f0ea9cc9d96f6417c9b986e23a4d116dda26b62cc29d046"
+                "sha256:5df73835398d10db79f8eecd5cd86b1f6d29317589ea70796994d49399af6297",
+                "sha256:889a6da2ed7ffc58ab5b900d888ddce90bce912f2d2de1dc1c26f4cb9fe65097"
             ],
             "markers": "python_version >= '3.6'",
-            "version": "==1.9.6"
+            "version": "==1.10.0"
         },
         "pluggy": {
             "hashes": [
-                "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0",
-                "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"
+                "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981",
+                "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be"
             ],
-            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
-            "version": "==0.13.1"
+            "markers": "python_version >= '3.8'",
+            "version": "==1.4.0"
         },
         "prompt-toolkit": {
             "hashes": [
-                "sha256:3e163f254bef5a03b146397d7c1963bd3e2812f0964bb9a24e6ec761fd28db63",
-                "sha256:aa64ad242a462c5ff0363a7b9cfe696c20d55d9fc60c11fd8e632d064804d305"
+                "sha256:3527b7af26106cbc65a040bcc84839a3566ec1b051bb0bfe953631e704b0ff7d",
+                "sha256:a11a29cb3bf0a28a387fe5122cdb649816a957cd9261dcedf8c9f1fef33eacf6"
             ],
-            "markers": "python_full_version >= '3.6.2'",
-            "version": "==3.0.36"
+            "markers": "python_full_version >= '3.7.0'",
+            "version": "==3.0.43"
         },
         "ptyprocess": {
             "hashes": [
@@ -541,85 +625,120 @@
             ],
             "version": "==0.2.2"
         },
-        "py": {
-            "hashes": [
-                "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719",
-                "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"
-            ],
-            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
-            "version": "==1.11.0"
-        },
         "pycodestyle": {
             "hashes": [
-                "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367",
-                "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e"
-            ],
-            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
-            "version": "==2.6.0"
-        },
-        "pycparser": {
-            "hashes": [
-                "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9",
-                "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"
+                "sha256:41ba0e7afc9752dfb53ced5489e89f8186be00e599e712660695b7a75ff2663f",
+                "sha256:44fe31000b2d866f2e41841b18528a505fbd7fef9017b04eff4e2648a0fadc67"
             ],
-            "version": "==2.21"
+            "markers": "python_version >= '3.8'",
+            "version": "==2.11.1"
         },
         "pyflakes": {
             "hashes": [
-                "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92",
-                "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"
+                "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f",
+                "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a"
             ],
-            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
-            "version": "==2.2.0"
+            "markers": "python_version >= '3.8'",
+            "version": "==3.2.0"
         },
         "pygments": {
             "hashes": [
-                "sha256:77a3299119af881904cd5ecd1ac6a66214b6e9bed1f2db16993b54adede64094",
-                "sha256:f7e36cffc4c517fbc252861b9a6e4644ca0e5abadf9a113c72d1358ad09b9500"
+                "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c",
+                "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"
             ],
-            "index": "pypi",
             "markers": "python_version >= '3.7'",
-            "version": "==2.15.0"
+            "version": "==2.17.2"
         },
         "pytest": {
             "hashes": [
-                "sha256:5c0db86b698e8f170ba4582a492248919255fcd4c79b1ee64ace34301fb589a1",
-                "sha256:7979331bfcba207414f5e1263b5a0f8f521d0f457318836a7355531ed1a4c7d8"
+                "sha256:2a8386cfc11fa9d2c50ee7b2a57e7d898ef90470a7a34c4b949ff59662bb78b7",
+                "sha256:ac978141a75948948817d360297b7aae0fcb9d6ff6bc9ec6d514b85d5a65c044"
             ],
             "index": "pypi",
-            "version": "==5.4.3"
-        },
-        "pytz": {
-            "hashes": [
-                "sha256:01a0681c4b9684a28304615eba55d1ab31ae00bf68ec157ec3708a8182dbbcd0",
-                "sha256:78f4f37d8198e0627c5f1143240bb0206b8691d8d7ac6d78fee88b78733f8c4a"
+            "markers": "python_version >= '3.8'",
+            "version": "==8.1.1"
+        },
+        "pyyaml": {
+            "hashes": [
+                "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5",
+                "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc",
+                "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df",
+                "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741",
+                "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206",
+                "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27",
+                "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595",
+                "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62",
+                "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98",
+                "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696",
+                "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290",
+                "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9",
+                "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d",
+                "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6",
+                "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867",
+                "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47",
+                "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486",
+                "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6",
+                "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3",
+                "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007",
+                "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938",
+                "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0",
+                "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c",
+                "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735",
+                "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d",
+                "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28",
+                "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4",
+                "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba",
+                "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8",
+                "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef",
+                "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5",
+                "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd",
+                "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3",
+                "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0",
+                "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515",
+                "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c",
+                "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c",
+                "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924",
+                "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34",
+                "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43",
+                "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859",
+                "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673",
+                "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54",
+                "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a",
+                "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b",
+                "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab",
+                "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa",
+                "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c",
+                "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585",
+                "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d",
+                "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"
             ],
-            "version": "==2022.7.1"
+            "index": "pypi",
+            "markers": "python_version >= '3.6'",
+            "version": "==6.0.1"
         },
         "readme-renderer": {
             "hashes": [
-                "sha256:cd653186dfc73055656f090f227f5cb22a046d7f71a841dfa305f55c9a513273",
-                "sha256:f67a16caedfa71eef48a31b39708637a6f4664c4394801a7b0d6432d13907343"
+                "sha256:1818dd28140813509eeed8d62687f7cd4f7bad90d4db586001c5dc09d4fde311",
+                "sha256:19db308d86ecd60e5affa3b2a98f017af384678c63c88e5d4556a380e674f3f9"
             ],
-            "markers": "python_version >= '3.7'",
-            "version": "==37.3"
+            "markers": "python_version >= '3.8'",
+            "version": "==43.0"
         },
         "requests": {
             "hashes": [
                 "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f",
                 "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"
             ],
-            "index": "pypi",
             "markers": "python_version >= '3.7'",
             "version": "==2.31.0"
         },
         "requests-toolbelt": {
             "hashes": [
-                "sha256:18565aa58116d9951ac39baa288d3adb5b3ff975c4f25eee78555d89e8f247f7",
-                "sha256:62e09f7ff5ccbda92772a29f394a49c3ad6cb181d568b1337626b2abb628a63d"
+                "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6",
+                "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06"
             ],
             "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
-            "version": "==0.10.1"
+            "version": "==1.0.0"
         },
         "rfc3986": {
             "hashes": [
@@ -629,21 +748,13 @@
             "markers": "python_version >= '3.7'",
             "version": "==2.0.0"
         },
-        "secretstorage": {
-            "hashes": [
-                "sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77",
-                "sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99"
-            ],
-            "markers": "sys_platform == 'linux'",
-            "version": "==3.3.3"
-        },
-        "setuptools": {
+        "rich": {
             "hashes": [
-                "sha256:16ccf598aab3b506593c17378473978908a2734d7336755a8769b480906bec1c",
-                "sha256:b440ee5f7e607bb8c9de15259dba2583dd41a38879a7abc1d43a71c59524da48"
+                "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222",
+                "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432"
             ],
-            "markers": "python_version >= '3.7'",
-            "version": "==67.2.0"
+            "markers": "python_full_version >= '3.7.0'",
+            "version": "==13.7.1"
         },
         "six": {
             "hashes": [
@@ -662,43 +773,53 @@
         },
         "sphinx": {
             "hashes": [
-                "sha256:97dbf2e31fc5684bb805104b8ad34434ed70e6c588f6896991b2fdfd2bef8c00",
-                "sha256:b9daeb9b39aa1ffefc2809b43604109825300300b987a24f45976c001ba1a8fd"
+                "sha256:30d03bbaa53b77d38863fd6b95cc4edb4a84a1512787b3b0c12fb3b4fb25d9e9",
+                "sha256:e6a8f418321429669ef9c1e20c1f294b3fe1f248206b46044c86e1545480687f"
             ],
             "index": "pypi",
-            "version": "==3.1.2"
+            "markers": "python_version >= '3.9'",
+            "version": "==7.3.5"
         },
         "sphinx-rtd-theme": {
             "hashes": [
-                "sha256:22c795ba2832a169ca301cd0a083f7a434e09c538c70beb42782c073651b707d",
-                "sha256:373413d0f82425aaa28fb288009bf0d0964711d347763af2f1b65cafcb028c82"
+                "sha256:bd5d7b80622406762073a04ef8fadc5f9151261563d47027de09910ce03afe6b",
+                "sha256:ec93d0856dc280cf3aee9a4c9807c60e027c7f7b461b77aeffed682e68f0e586"
             ],
             "index": "pypi",
-            "version": "==0.5.0"
+            "markers": "python_version >= '3.6'",
+            "version": "==2.0.0"
         },
         "sphinxcontrib-applehelp": {
             "hashes": [
-                "sha256:29d341f67fb0f6f586b23ad80e072c8e6ad0b48417db2bde114a4c9746feb228",
-                "sha256:828f867945bbe39817c210a1abfd1bc4895c8b73fcaade56d45357a348a07d7e"
+                "sha256:c40a4f96f3776c4393d933412053962fac2b84f4c99a7982ba42e09576a70619",
+                "sha256:cb61eb0ec1b61f349e5cc36b2028e9e7ca765be05e49641c97241274753067b4"
             ],
-            "markers": "python_version >= '3.8'",
-            "version": "==1.0.4"
+            "markers": "python_version >= '3.9'",
+            "version": "==1.0.8"
         },
         "sphinxcontrib-devhelp": {
             "hashes": [
-                "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e",
-                "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4"
+                "sha256:6485d09629944511c893fa11355bda18b742b83a2b181f9a009f7e500595c90f",
+                "sha256:9893fd3f90506bc4b97bdb977ceb8fbd823989f4316b28c3841ec128544372d3"
             ],
-            "markers": "python_version >= '3.5'",
-            "version": "==1.0.2"
+            "markers": "python_version >= '3.9'",
+            "version": "==1.0.6"
         },
         "sphinxcontrib-htmlhelp": {
             "hashes": [
-                "sha256:0cbdd302815330058422b98a113195c9249825d681e18f11e8b1f78a2f11efff",
-                "sha256:c38cb46dccf316c79de6e5515e1770414b797162b23cd3d06e67020e1d2a6903"
+                "sha256:0dc87637d5de53dd5eec3a6a01753b1ccf99494bd756aafecd74b4fa9e729015",
+                "sha256:393f04f112b4d2f53d93448d4bce35842f62b307ccdc549ec1585e950bc35e04"
             ],
-            "markers": "python_version >= '3.8'",
-            "version": "==2.0.1"
+            "markers": "python_version >= '3.9'",
+            "version": "==2.0.5"
+        },
+        "sphinxcontrib-jquery": {
+            "hashes": [
+                "sha256:1620739f04e36a2c779f1a131a2dfd49b2fd07351bf1968ced074365933abc7a",
+                "sha256:f936030d7d0147dd026a4f2b5a57343d233f1fc7b363f68b3d4f1cb0993878ae"
+            ],
+            "markers": "python_version >= '2.7'",
+            "version": "==4.1"
         },
         "sphinxcontrib-jsmath": {
             "hashes": [
@@ -710,88 +831,91 @@
         },
         "sphinxcontrib-qthelp": {
             "hashes": [
-                "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72",
-                "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6"
+                "sha256:053dedc38823a80a7209a80860b16b722e9e0209e32fea98c90e4e6624588ed6",
+                "sha256:e2ae3b5c492d58fcbd73281fbd27e34b8393ec34a073c792642cd8e529288182"
             ],
-            "markers": "python_version >= '3.5'",
-            "version": "==1.0.3"
+            "markers": "python_version >= '3.9'",
+            "version": "==1.0.7"
         },
         "sphinxcontrib-serializinghtml": {
             "hashes": [
-                "sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd",
-                "sha256:aa5f6de5dfdf809ef505c4895e51ef5c9eac17d0f287933eb49ec495280b6952"
+                "sha256:326369b8df80a7d2d8d7f99aa5ac577f51ea51556ed974e7716cfd4fca3f6cb7",
+                "sha256:93f3f5dc458b91b192fe10c397e324f262cf163d79f3282c158e8436a2c4511f"
             ],
-            "markers": "python_version >= '3.5'",
-            "version": "==1.1.5"
+            "markers": "python_version >= '3.9'",
+            "version": "==1.1.10"
         },
         "stack-data": {
             "hashes": [
-                "sha256:32d2dd0376772d01b6cb9fc996f3c8b57a357089dec328ed4b6553d037eaf815",
-                "sha256:cbb2a53eb64e5785878201a97ed7c7b94883f48b87bfb0bbe8b623c74679e4a8"
+                "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9",
+                "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"
             ],
-            "version": "==0.6.2"
+            "version": "==0.6.3"
         },
-        "tqdm": {
+        "tomli": {
             "hashes": [
-                "sha256:5f4f682a004951c1b450bc753c710e9280c5746ce6ffedee253ddbcbf54cf1e4",
-                "sha256:6fee160d6ffcd1b1c68c65f14c829c22832bc401726335ce92c52d395944a6a1"
+                "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc",
+                "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"
             ],
-            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
-            "version": "==4.64.1"
+            "markers": "python_version < '3.11'",
+            "version": "==2.0.1"
         },
         "traitlets": {
             "hashes": [
-                "sha256:9e6ec080259b9a5940c797d58b613b5e31441c2257b87c2e795c5228ae80d2d8",
-                "sha256:f6cde21a9c68cf756af02035f72d5a723bf607e862e7be33ece505abf4a3bad9"
+                "sha256:8cdd83c040dab7d1dee822678e5f5d100b514f7b72b01615b26fc5718916fdf9",
+                "sha256:fcdf85684a772ddeba87db2f398ce00b40ff550d1528c03c14dbf6a02003cd80"
             ],
-            "markers": "python_version >= '3.7'",
-            "version": "==5.9.0"
+            "markers": "python_version >= '3.8'",
+            "version": "==5.14.2"
         },
         "twine": {
             "hashes": [
-                "sha256:34352fd52ec3b9d29837e6072d5a2a7c6fe4290e97bba46bb8d478b5c598f7ab",
-                "sha256:ba9ff477b8d6de0c89dd450e70b2185da190514e91c42cc62f96850025c10472"
+                "sha256:89b0cc7d370a4b66421cc6102f269aa910fe0f1861c124f573cf2ddedbc10cf4",
+                "sha256:a262933de0b484c53408f9edae2e7821c1c45a3314ff2df9bdd343aa7ab8edc0"
             ],
             "index": "pypi",
-            "version": "==3.2.0"
+            "markers": "python_version >= '3.8'",
+            "version": "==5.0.0"
+        },
+        "typing-extensions": {
+            "hashes": [
+                "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0",
+                "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a"
+            ],
+            "markers": "python_version < '3.12'",
+            "version": "==4.11.0"
         },
         "urllib3": {
             "hashes": [
-                "sha256:051d961ad0c62a94e50ecf1af379c3aba230c66c710493493560c0c223c49f20",
-                "sha256:ce3711610ddce217e6d113a2732fafad960a03fd0318c91faa79481e35c11224"
+                "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d",
+                "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19"
             ],
             "markers": "python_version >= '3.8'",
-            "version": "==2.2.0"
+            "version": "==2.2.1"
         },
         "versioneer": {
             "hashes": [
-                "sha256:08e395c0acc544f78645b9c0ebfccaf47950ae61e0c85bd1aaea98ff59609aeb",
-                "sha256:ead1f78168150011189521b479d3a0dd2f55c94f5b07747b484fd693c3fbf335"
+                "sha256:0f1a137bb5d6811e96a79bb0486798aeae9b9c6efc24b389659cebb0ee396cb9",
+                "sha256:5ab283b9857211d61b53318b7c792cf68e798e765ee17c27ade9f6c924235731"
             ],
             "index": "pypi",
-            "version": "==0.18"
+            "markers": "python_version >= '3.7'",
+            "version": "==0.29"
         },
         "wcwidth": {
             "hashes": [
-                "sha256:795b138f6875577cd91bba52baf9e445cd5118fd32723b460e30a0af30ea230e",
-                "sha256:a5220780a404dbe3353789870978e472cfe477761f06ee55077256e509b156d0"
-            ],
-            "version": "==0.2.6"
-        },
-        "webencodings": {
-            "hashes": [
-                "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78",
-                "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"
+                "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859",
+                "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"
             ],
-            "version": "==0.5.1"
+            "version": "==0.2.13"
         },
         "zipp": {
             "hashes": [
-                "sha256:23f70e964bc11a34cef175bc90ba2914e1e4545ea1e3e2f67c079671883f9cb6",
-                "sha256:e8b2a36ea17df80ffe9e2c4fda3f693c3dad6df1697d3cd3af232db680950b0b"
+                "sha256:206f5a15f2af3dbaee80769fb7dc6f249695e940acca08dfb2a4769fe61e538b",
+                "sha256:2884ed22e7d8961de1c9a05142eb69a247f120291bc0206a00a7642f09b5b715"
             ],
-            "markers": "python_version >= '3.7'",
-            "version": "==3.13.0"
+            "markers": "python_version >= '3.8'",
+            "version": "==3.18.1"
         }
     }
 }
diff --git a/README.rst b/README.rst
index 30420c7..5448341 100644
--- a/README.rst
+++ b/README.rst
@@ -1,33 +1,31 @@
 =============
-WebexPythonSDK
+webexteamssdk
 =============
 
 *Work with the Webex APIs in native Python!*
 
 .. image:: https://img.shields.io/badge/license-MIT-blue.svg
-    :target: https://github.com/CiscoDevNet/webexteamssdk/blob/master/LICENSE
+    :target: https://github.com/WebexCommunity/WebexPythonSDK/blob/master/LICENSE
 .. image:: https://img.shields.io/pypi/v/webexteamssdk.svg
     :target: https://pypi.org/project/webexteamssdk/
 .. image:: https://img.shields.io/pypi/dw/webexteamssdk.svg
     :target: https://pypi.org/project/webexteamssdk/
-.. image:: https://travis-ci.org/CiscoDevNet/webexteamssdk.svg?branch=master
-    :target: https://travis-ci.org/CiscoDevNet/webexteamssdk
 .. image:: https://readthedocs.org/projects/webexteamssdk/badge/?version=latest
     :target: http://webexteamssdk.readthedocs.io/en/latest/?badge=latest
 
 ------------------------------------------------------------------------------------------------------------------------
 
 
-With release v1.6 we are wrapping up active development on the v1.x release and shifting our focus to the next major
-release v2!  Please see the work-in-progress `Release Plan`_ and contribute your ideas for v2.x enhancements by either
-opening enhancement issues_ or by joining our
-`webexteamssdk - Webex Teams SDK - Python Community Contributors <https://eurl.io/#BJ0A8gfOQ>`_ space and posting your
-ideas there.
+**webexteamssdk** v1.7 will be the last 🤞 release of the `webexteamssdk` package. This will be the last release
+supporting Python v2 and v3 compatibility; it is compatible Python v3 releases *up to Python v3.10*.
+
+Going forward, the `webexteamssdk` package will be replaced by the `WebexPythonSDK` package, which will support Python
+v3.10+.
 
 ------------------------------------------------------------------------------------------------------------------------
 
 
-**WebexPythonSDK** is a *community developed* Python library for working with the Webex APIs.  Our goal is to make
+**webexteamssdk** is a *community developed* Python library for working with the Webex APIs.  Our goal is to make
 working with Webex in Python a *native* and *natural* experience!
 
 .. code-block:: Python
@@ -58,9 +56,9 @@ working with Webex in Python a *native* and *natural* experience!
 
 
 That's more than 6 Webex API calls in less than 23 lines of code (with comments and whitespace), and likely more
-than that, since WebexPythonSDK handles pagination_ for you automatically!
+than that, since webexteamssdk handles pagination_ for you automatically!
 
-WebexPythonSDK makes your life better...  `Learn how!`__
+webexteamssdk makes your life better...  `Learn how!`__
 
 __ Introduction_
 
@@ -68,7 +66,7 @@ __ Introduction_
 Features
 --------
 
-WebexPythonSDK does all of this for you:
+webexteamssdk does all of this for you:
 
 * Transparently sources your Webex access token from your local environment
 
@@ -139,7 +137,7 @@ published releases.
 Questions, Support & Discussion
 -------------------------------
 
-WebexPythonSDK is a *community developed* and *community-supported* project.  If you experience any issues using this
+webexteamssdk is a *community developed* and *community-supported* project.  If you experience any issues using this
 package, please report them using the issues_ page.
 
 Please join the `Python Webex Teams Devs`__ Webex space to ask questions, join the discussion, and share your
@@ -151,7 +149,7 @@ __ Community_
 Contribution
 ------------
 
-WebexPythonSDK is a community development project.  Feedback, thoughts, ideas, and code contributions are welcome!
+webexteamssdk is a community development project.  Feedback, thoughts, ideas, and code contributions are welcome!
 Please see the `Contributing`_ guide for more information.
 
 
@@ -167,7 +165,7 @@ The development team may make additional name changes as the library evolves wit
 developer.webex.com.
 
 
-*Copyright (c) 2016-2020 Cisco and/or its affiliates.*
+*Copyright (c) 2016-2024 Cisco and/or its affiliates.*
 
 
 .. _Release Plan: https://github.com/CiscoDevNet/webexteamssdk/wiki/Release-Plans
diff --git a/docs/conf.py b/docs/conf.py
index 8bba024..cecf1c2 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -4,71 +4,69 @@
 import sys
 
 
-sys.path.insert(0, os.path.abspath('..'))
+sys.path.insert(0, os.path.abspath(".."))
 
 
 from webexteamssdk._version import get_versions
 
 
-project = u'webexteamssdk'
-copyright = u'Copyright (c) 2016-2020 Cisco and/or its affiliates.'
-author = u'Chris Lunsford'
-version = get_versions()['version']
-release = get_versions()['version']
+project = "webexteamssdk"
+copyright = "Copyright (c) 2016-2024 Cisco and/or its affiliates."
+author = "Chris Lunsford"
+version = get_versions()["version"]
+release = get_versions()["version"]
 language = None
 
 
 extensions = [
-    'sphinx.ext.autodoc',
-    'sphinx.ext.doctest',
-    'sphinx.ext.intersphinx',
-    'sphinx.ext.todo',
-    'sphinx.ext.coverage',
-    'sphinx.ext.viewcode',
-    'sphinx.ext.napoleon',
+    "sphinx.ext.autodoc",
+    "sphinx.ext.doctest",
+    "sphinx.ext.intersphinx",
+    "sphinx.ext.todo",
+    "sphinx.ext.coverage",
+    "sphinx.ext.viewcode",
+    "sphinx.ext.napoleon",
 ]
 
 
-master_doc = 'index'
-source_suffix = '.rst'
-exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
-templates_path = ['_templates']
-pygments_style = 'sphinx'
+master_doc = "index"
+source_suffix = ".rst"
+exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
+templates_path = ["_templates"]
+pygments_style = "sphinx"
 
 
 add_module_names = False
-autodoc_member_order = 'bysource'
+autodoc_member_order = "bysource"
 # autodoc_default_flags = ['members', 'undoc-members']
 autodoc_default_options = {
-    'members': None,
-    'undoc-members': None,
+    "members": None,
+    "undoc-members": None,
 }
 
 
 todo_include_todos = True
 
 
-
 # -- Options for HTML output ----------------------------------------------
 
 # The theme to use for HTML and HTML Help pages.  See the documentation for
 # a list of builtin themes.
 #
-#html_theme = 'alabaster'
-on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
+# html_theme = 'alabaster'
+on_rtd = os.environ.get("READTHEDOCS", None) == "True"
 
 if not on_rtd:
     import sphinx_rtd_theme
-    html_theme = 'sphinx_rtd_theme'
+
+    html_theme = "sphinx_rtd_theme"
     html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
 
 # Theme options are theme-specific and customize the look and feel of a theme
 # further.  For a list of options available for each theme, see the
 # documentation.
 #
-html_theme_options = {
-    'collapse_navigation': False
-}
+html_theme_options = {"collapse_navigation": False}
 
 # Add any paths that contain custom themes here, relative to this directory.
 # html_theme_path = []
@@ -176,36 +174,37 @@
 # html_search_scorer = 'scorer.js'
 
 # Output file base name for HTML help builder.
-htmlhelp_basename = 'webexteamssdkdoc'
-
+htmlhelp_basename = "webexteamssdkdoc"
 
 
 # -- Options for LaTeX output ---------------------------------------------
 
 latex_elements = {
-     # The paper size ('letterpaper' or 'a4paper').
-     #
-     # 'papersize': 'letterpaper',
-
-     # The font size ('10pt', '11pt' or '12pt').
-     #
-     # 'pointsize': '10pt',
-
-     # Additional stuff for the LaTeX preamble.
-     #
-     # 'preamble': '',
-
-     # Latex figure (float) alignment
-     #
-     # 'figure_align': 'htbp',
+    # The paper size ('letterpaper' or 'a4paper').
+    #
+    # 'papersize': 'letterpaper',
+    # The font size ('10pt', '11pt' or '12pt').
+    #
+    # 'pointsize': '10pt',
+    # Additional stuff for the LaTeX preamble.
+    #
+    # 'preamble': '',
+    # Latex figure (float) alignment
+    #
+    # 'figure_align': 'htbp',
 }
 
 # Grouping the document tree into LaTeX files. List of tuples
 # (source start file, target name, title,
 #  author, documentclass [howto, manual, or own class]).
 latex_documents = [
-    (master_doc, 'webexteamssdk.tex', u'webexteamssdk Documentation',
-     u'Chris Lunsford', 'manual'),
+    (
+        master_doc,
+        "webexteamssdk.tex",
+        "webexteamssdk Documentation",
+        "Chris Lunsford",
+        "manual",
+    ),
 ]
 
 # The name of an image file (relative to this directory) to place at the top of
@@ -241,14 +240,12 @@
 # latex_domain_indices = True
 
 
-
 # -- Options for manual page output ---------------------------------------
 
 # One entry per manual page. List of tuples
 # (source start file, name, description, authors, manual section).
 man_pages = [
-    (master_doc, 'webexteamssdk', u'webexteamssdk Documentation',
-     [author], 1)
+    (master_doc, "webexteamssdk", "webexteamssdk Documentation", [author], 1)
 ]
 
 # If true, show URL addresses after external links.
@@ -256,16 +253,21 @@
 # man_show_urls = False
 
 
-
 # -- Options for Texinfo output -------------------------------------------
 
 # Grouping the document tree into Texinfo files. List of tuples
 # (source start file, target name, title, author,
 #  dir menu entry, description, category)
 texinfo_documents = [
-    (master_doc, 'webexteamssdk', u'webexteamssdk Documentation',
-     author, 'webexteamssdk', 'One line description of project.',
-     'Miscellaneous'),
+    (
+        master_doc,
+        "webexteamssdk",
+        "webexteamssdk Documentation",
+        author,
+        "webexteamssdk",
+        "One line description of project.",
+        "Miscellaneous",
+    ),
 ]
 
 # Documents to append as an appendix to all manuals.
@@ -286,4 +288,4 @@
 
 
 # Example configuration for intersphinx: refer to the Python standard library.
-intersphinx_mapping = {'https://docs.python.org/': None}
+intersphinx_mapping = {"https://docs.python.org/": None}
diff --git a/docs/index.rst b/docs/index.rst
index 1e8f638..a1def8e 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -66,7 +66,7 @@ Webex Teams for Developers
 Leveraging the Webex Teams APIs and developing on top of the Webex Teams cloud is easy.  Signup for a `free account`_ and then head over to the `Webex Teams for Developers`_ website to learn more.
 
 
-*Copyright (c) 2016-2020 Cisco and/or its affiliates.*
+*Copyright (c) 2016-2024 Cisco and/or its affiliates.*
 
 
 .. _free account: `Webex Teams`
diff --git a/docs/installation.rst b/docs/installation.rst
index 5376248..658b34e 100644
--- a/docs/installation.rst
+++ b/docs/installation.rst
@@ -58,7 +58,7 @@ command:
     $ python setup.py install
 
 
-*Copyright (c) 2016-2020 Cisco and/or its affiliates.*
+*Copyright (c) 2016-2024 Cisco and/or its affiliates.*
 
 
 .. _Python Package Index (PyPI): https://pypi.python.org/pypi/webexteamssdk
diff --git a/docs/user/api.rst b/docs/user/api.rst
index 4d0b4bc..c9aad08 100644
--- a/docs/user/api.rst
+++ b/docs/user/api.rst
@@ -434,4 +434,4 @@ Actions
 
 .. autoclass:: webexteamssdk.cards.actions.ShowCard
 
-*Copyright (c) 2016-2020 Cisco and/or its affiliates.*
+*Copyright (c) 2016-2024 Cisco and/or its affiliates.*
diff --git a/docs/user/intro.rst b/docs/user/intro.rst
index 5014c45..8a6ecdc 100644
--- a/docs/user/intro.rst
+++ b/docs/user/intro.rst
@@ -151,7 +151,7 @@ webexteamssdk License
 .. include:: ../../LICENSE
 
 
-*Copyright (c) 2016-2020 Cisco and/or its affiliates.*
+*Copyright (c) 2016-2024 Cisco and/or its affiliates.*
 
 
 .. _MIT Open Source License: https://opensource.org/licenses/MIT
diff --git a/docs/user/quickstart.rst b/docs/user/quickstart.rst
index ca80e87..d6012b3 100644
--- a/docs/user/quickstart.rst
+++ b/docs/user/quickstart.rst
@@ -487,7 +487,7 @@ extend functionality and leverage all of the objects and quality of life feature
     >>> output = WebexTeamsAPI.new_method(param)
 
 
-*Copyright (c) 2016-2020 Cisco and/or its affiliates.*
+*Copyright (c) 2016-2024 Cisco and/or its affiliates.*
 
 
 .. _Webex Teams: https://www.webex.com/products/teams/index.html
diff --git a/examples/bot-example-flask.py b/examples/bot-example-flask.py
index 8c058de..aa35fc7 100755
--- a/examples/bot-example-flask.py
+++ b/examples/bot-example-flask.py
@@ -22,7 +22,7 @@
 
 This script supports Python versions 2 and 3.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -43,7 +43,6 @@
 SOFTWARE.
 """
 
-
 # Use future for Python v2 and v3 compatibility
 from __future__ import (
     absolute_import,
@@ -57,7 +56,7 @@
 __author__ = "Chris Lunsford"
 __author_email__ = "chrlunsf@cisco.com"
 __contributors__ = ["Brad Bester <brbester@cisco.com>"]
-__copyright__ = "Copyright (c) 2016-2020 Cisco and/or its affiliates."
+__copyright__ = "Copyright (c) 2016-2024 Cisco and/or its affiliates."
 __license__ = "MIT"
 
 
@@ -68,7 +67,7 @@
 
 
 # Module constants
-CAT_FACTS_URL = 'https://catfact.ninja/fact'
+CAT_FACTS_URL = "https://catfact.ninja/fact"
 
 
 # Initialize the environment
@@ -89,16 +88,16 @@ def get_catfact():
     response = requests.get(CAT_FACTS_URL, verify=False)
     response.raise_for_status()
     json_data = response.json()
-    return json_data['fact']
+    return json_data["fact"]
 
 
 # Core bot functionality
 # Your Webex Teams webhook should point to http://<serverip>:5000/events
-@flask_app.route('/events', methods=['GET', 'POST'])
+@flask_app.route("/events", methods=["GET", "POST"])
 def webex_teams_webhook_events():
     """Processes incoming requests to the '/events' URI."""
-    if request.method == 'GET':
-        return ("""<!DOCTYPE html>
+    if request.method == "GET":
+        return """<!DOCTYPE html>
                    <html lang="en">
                        <head>
                            <meta charset="UTF-8">
@@ -114,8 +113,8 @@ def webex_teams_webhook_events():
                    <blockquote>{}</blockquote>
                    </body>
                    </html>
-                """.format(get_catfact()))
-    elif request.method == 'POST':
+                """.format(get_catfact())
+    elif request.method == "POST":
         """Respond to inbound webhook JSON HTTP POST from Webex Teams."""
 
         # Get the POST data sent from Webex Teams
@@ -144,7 +143,7 @@ def webex_teams_webhook_events():
         me = api.people.me()
         if message.personId == me.id:
             # Message was sent by me (bot); do not respond.
-            return 'OK'
+            return "OK"
 
         else:
             # Message was sent by someone else; parse message and respond.
@@ -155,9 +154,9 @@ def webex_teams_webhook_events():
                 print("SENDING CAT FACT '{}'".format(cat_fact))
                 # Post the fact to the room where the request was received
                 api.messages.create(room.id, text=cat_fact)
-            return 'OK'
+            return "OK"
 
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     # Start the Flask web server
-    flask_app.run(host='0.0.0.0', port=5000)
+    flask_app.run(host="0.0.0.0", port=5000)
diff --git a/examples/bot-example-webpy.py b/examples/bot-example-webpy.py
index 259fbfe..550a481 100755
--- a/examples/bot-example-webpy.py
+++ b/examples/bot-example-webpy.py
@@ -22,7 +22,7 @@
 the time of this writing web.py (v0.38) only supports Python 2.
 Therefore this script only supports Python 2.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -43,7 +43,6 @@
 SOFTWARE.
 """
 
-
 # Use future for Python v2 and v3 compatibility
 from __future__ import (
     absolute_import,
@@ -57,7 +56,7 @@
 __author__ = "Brad Bester"
 __author_email__ = "brbester@cisco.com"
 __contributors__ = ["Chris Lunsford <chrlunsf@cisco.com>"]
-__copyright__ = "Copyright (c) 2016-2020 Cisco and/or its affiliates."
+__copyright__ = "Copyright (c) 2016-2024 Cisco and/or its affiliates."
 __license__ = "MIT"
 
 
@@ -68,12 +67,12 @@
 
 
 # Module constants
-CAT_FACTS_URL = 'https://catfact.ninja/fact'
+CAT_FACTS_URL = "https://catfact.ninja/fact"
 
 
 # Global variables
 # Your Webex Teams webhook should point to http://<serverip>:8080/events
-urls = ('/events', 'webhook')
+urls = ("/events", "webhook")
 # Create the web application instance
 app = web.application(urls, globals())
 # Create the Webex Teams API connection object
@@ -90,7 +89,7 @@ def get_catfact():
     response = requests.get(CAT_FACTS_URL, verify=False)
     response.raise_for_status()
     json_data = response.json()
-    return json_data['fact']
+    return json_data["fact"]
 
 
 class webhook(object):
@@ -120,7 +119,7 @@ def POST(self):
         me = api.people.me()
         if message.personId == me.id:
             # Message was sent by me (bot); do not respond.
-            return 'OK'
+            return "OK"
         else:
             # Message was sent by someone else; parse message and respond.
             if "/CAT" in message.text:
@@ -130,9 +129,9 @@ def POST(self):
                 print("SENDING CAT FACT '{}'".format(cat_fact))
                 # Post the fact to the room where the request was received
                 api.messages.create(room.id, text=cat_fact)
-        return 'OK'
+        return "OK"
 
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     # Start the web.py web server
     app.run()
diff --git a/examples/bot-with-card-example-flask.py b/examples/bot-with-card-example-flask.py
index f25e13e..f8149b5 100755
--- a/examples/bot-with-card-example-flask.py
+++ b/examples/bot-with-card-example-flask.py
@@ -31,7 +31,7 @@
 
 This script should support Python versions 3.6+ only.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -52,7 +52,6 @@
 SOFTWARE.
 """
 
-
 import os
 import sys
 from urllib.parse import urljoin
@@ -66,7 +65,7 @@
 __author__ = "JP Shipherd"
 __author_email__ = "jshipher@cisco.com"
 __contributors__ = ["Chris Lunsford <chrlunsf@cisco.com>"]
-__copyright__ = "Copyright (c) 2016-2020 Cisco and/or its affiliates."
+__copyright__ = "Copyright (c) 2016-2024 Cisco and/or its affiliates."
 __license__ = "MIT"
 
 
@@ -90,83 +89,72 @@
             "type": "TextBlock",
             "text": "Some ways to collect user input",
             "size": "medium",
-            "weight": "bolder"
+            "weight": "bolder",
         },
         {
             "type": "TextBlock",
             "text": "This **Input.Text** element collects some free from "
-                    "text. Designers can use attributes like `isMutiline`, "
-                    "`maxLength` and `placeholder to shape the way that users "
-                    "enter text in a form.",
-            "wrap": True
+            "text. Designers can use attributes like `isMutiline`, "
+            "`maxLength` and `placeholder to shape the way that users "
+            "enter text in a form.",
+            "wrap": True,
         },
         {
             "type": "Input.Text",
             "placeholder": "Text Field",
             "style": "text",
             "maxLength": 0,
-            "id": "TextFieldVal"
+            "id": "TextFieldVal",
         },
         {
             "type": "TextBlock",
             "text": "This **Input.Number** element collects a number. "
-                    "Designers can use the `max`, `min` and `placeholder` "
-                    "attributes to control the input options.",
-            "wrap": True
+            "Designers can use the `max`, `min` and `placeholder` "
+            "attributes to control the input options.",
+            "wrap": True,
         },
         {
             "type": "Input.Number",
             "placeholder": "Number",
             "min": -5,
             "max": 5,
-            "id": "NumberVal"
+            "id": "NumberVal",
         },
         {
             "type": "TextBlock",
             "text": "The **Input.ChoiceSet** element provides a variety of "
-                    "ways that users can choose from a set of options. This "
-                    "is the default view, but designers can use the `style` "
-                    "and `isMutiSelect` attributes to change the way it "
-                    "works. The choices are defined in an array attribute "
-                    "called `choices`.",
-            "wrap": True
+            "ways that users can choose from a set of options. This "
+            "is the default view, but designers can use the `style` "
+            "and `isMutiSelect` attributes to change the way it "
+            "works. The choices are defined in an array attribute "
+            "called `choices`.",
+            "wrap": True,
         },
         {
             "type": "Input.ChoiceSet",
             "id": "ColorChoiceVal",
             "value": "Red",
             "choices": [
-                {
-                    "title": "Red",
-                    "value": "Red"
-                },
-                {
-                    "title": "Blue",
-                    "value": "Blue"
-                },
-                {
-                    "title": "Green",
-                    "value": "Green"
-                }
-            ]
+                {"title": "Red", "value": "Red"},
+                {"title": "Blue", "value": "Blue"},
+                {"title": "Green", "value": "Green"},
+            ],
         },
         {
             "type": "Input.Toggle",
             "title": "This Input.Toggle element gets a true/false input.",
             "id": "Toggle",
             "wrap": True,
-            "value": "false"
-        }
+            "value": "false",
+        },
     ],
     "actions": [
         {
             "type": "Action.Submit",
             "title": "Submit",
-            "data": {
-                "formDemoAction": "Submit"
-            }
+            "data": {"formDemoAction": "Submit"},
         }
-    ]
+    ],
 }
 
 
@@ -209,7 +197,7 @@ def create_webhooks(webhook_url):
         resource=MESSAGE_WEBHOOK_RESOURCE,
         event=MESSAGE_WEBHOOK_EVENT,
         name=WEBHOOK_NAME,
-        targetUrl=urljoin(webhook_url, WEBHOOK_URL_SUFFIX)
+        targetUrl=urljoin(webhook_url, WEBHOOK_URL_SUFFIX),
     )
     print(webhook)
     print("Webhook successfully created.")
@@ -219,7 +207,7 @@ def create_webhooks(webhook_url):
         resource=CARDS_WEBHOOK_RESOURCE,
         event=CARDS_WEBHOOK_EVENT,
         name=WEBHOOK_NAME,
-        targetUrl=urljoin(webhook_url, WEBHOOK_URL_SUFFIX)
+        targetUrl=urljoin(webhook_url, WEBHOOK_URL_SUFFIX),
     )
     print(webhook)
     print("Webhook successfully created.")
@@ -244,8 +232,8 @@ def respond_to_button_press(webhook):
         room.id,
         parentId=message_id,
         markdown=f"This is the data sent from the button press.  A more "
-                 f"robust app would do something cool with this:\n"
-                 f"```\n{attachment_action.to_json(indent=2)}\n```"
+        f"robust app would do something cool with this:\n"
+        f"```\n{attachment_action.to_json(indent=2)}\n```",
     )
 
 
@@ -280,10 +268,12 @@ def respond_to_message(webhook):
         api.messages.create(
             room.id,
             text="If you see this your client cannot render cards",
-            attachments=[{
-                "contentType": "application/vnd.microsoft.card.adaptive",
-                "content": CARD_CONTENT
-            }],
+            attachments=[
+                {
+                    "contentType": "application/vnd.microsoft.card.adaptive",
+                    "content": CARD_CONTENT,
+                }
+            ],
         )
         return "OK"
 
@@ -299,13 +289,17 @@ def webex_teams_webhook_events():
     webhook_obj = Webhook(request.json)
 
     # Handle a new message event
-    if (webhook_obj.resource == MESSAGE_WEBHOOK_RESOURCE
-            and webhook_obj.event == MESSAGE_WEBHOOK_EVENT):
+    if (
+        webhook_obj.resource == MESSAGE_WEBHOOK_RESOURCE
+        and webhook_obj.event == MESSAGE_WEBHOOK_EVENT
+    ):
         respond_to_message(webhook_obj)
 
     # Handle an Action.Submit button press event
-    elif (webhook_obj.resource == CARDS_WEBHOOK_RESOURCE
-          and webhook_obj.event == CARDS_WEBHOOK_EVENT):
+    elif (
+        webhook_obj.resource == CARDS_WEBHOOK_RESOURCE
+        and webhook_obj.event == CARDS_WEBHOOK_EVENT
+    ):
         respond_to_button_press(webhook_obj)
 
     # Ignore anything else (which should never happen
diff --git a/examples/local_file_upload.py b/examples/local_file_upload.py
index 5228fed..bdf3441 100755
--- a/examples/local_file_upload.py
+++ b/examples/local_file_upload.py
@@ -17,7 +17,7 @@
 variable set to run this script.
 
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -38,7 +38,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import print_function
 
 import os
@@ -49,7 +48,7 @@
 __author__ = "Jeff Levensailor"
 __author_email__ = "jeff@levensailor.com"
 __contributors__ = ["Chris Lunsford <chrlunsf@cisco.com>"]
-__copyright__ = "Copyright (c) 2016-2020 Cisco and/or its affiliates."
+__copyright__ = "Copyright (c) 2016-2024 Cisco and/or its affiliates."
 __license__ = "MIT"
 
 
diff --git a/examples/ngrokwebhook.py b/examples/ngrokwebhook.py
index 0396958..71a4277 100755
--- a/examples/ngrokwebhook.py
+++ b/examples/ngrokwebhook.py
@@ -13,7 +13,7 @@
 To use script simply launch ngrok, and then launch this script.  After ngrok is
 killed, run this script a second time to remove webhook from Webex Teams.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -34,7 +34,6 @@
 SOFTWARE.
 """
 
-
 # Use future for Python v2 and v3 compatibility
 from __future__ import (
     absolute_import,
@@ -48,7 +47,7 @@
 __author__ = "Brad Bester"
 __author_email__ = "brbester@cisco.com"
 __contributors__ = ["Chris Lunsford <chrlunsf@cisco.com>"]
-__copyright__ = "Copyright (c) 2016-2020 Cisco and/or its affiliates."
+__copyright__ = "Copyright (c) 2016-2024 Cisco and/or its affiliates."
 __license__ = "MIT"
 
 
@@ -76,13 +75,17 @@
 def get_ngrok_public_url():
     """Get the ngrok public HTTP URL from the local client API."""
     try:
-        response = requests.get(url=NGROK_CLIENT_API_BASE_URL + "/tunnels",
-                                headers={'content-type': 'application/json'})
+        response = requests.get(
+            url=NGROK_CLIENT_API_BASE_URL + "/tunnels",
+            headers={"content-type": "application/json"},
+        )
         response.raise_for_status()
 
     except requests.exceptions.RequestException:
-        print("Could not connect to the ngrok client API; "
-              "assuming not running.")
+        print(
+            "Could not connect to the ngrok client API; "
+            "assuming not running."
+        )
         return None
 
     else:
@@ -123,5 +126,5 @@ def main():
         create_ngrok_webhook(api, public_url)
 
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     main()
diff --git a/examples/oauth-flask-ngrok.py b/examples/oauth-flask-ngrok.py
index ec71c88..903d7de 100644
--- a/examples/oauth-flask-ngrok.py
+++ b/examples/oauth-flask-ngrok.py
@@ -11,28 +11,29 @@
 
 You must create a Webex Integration in the My Webex Apps section of
 https://developer.webex.com. For details, see
-https://developer.webex.com/docs/integrations . Copy your integration Client ID,
-Client Secret, scopes and set Redirect URI as "http://localhost:5000/callback"
-or the public ngrok URI + "/callback".
+https://developer.webex.com/docs/integrations .
+Copy your integration Client ID, Client Secret, scopes and set Redirect URI as
+"http://localhost:5000/callback" or the public ngrok URI + "/callback".
 
 Copyright (c) 2022 Cisco and/or its affiliates.
 
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
-the Software, and to permit persons to whom the Software is furnished to do so,
-subject to the following conditions:
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
 
 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.
 
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
-FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
 """
 
 
@@ -77,10 +78,10 @@
 @app.route("/")
 def root():
     print("/ requested")
-    return ("""
+    return """
             <p>Hey, this is Flask!</p>
             <p>Click <a href="{}">here</a> to authorize Webex Integration.</p>
-            """.format(url_for("auth")))
+            """.format(url_for("auth"))
 
 
 # OAuth Step 1 - Build authorization URL and redirect user.
@@ -93,17 +94,19 @@ def auth():
     # State is used to prevent CSRF, generate random and save in session.
     # Not mandatory but improves security.
     oauth_state = str(uuid4())
-    session['oauth_state'] = oauth_state
+    session["oauth_state"] = oauth_state
 
     # All parameters we need to pass to authorization service
     oauth_params = {
-        'response_type': "code",
-        'client_id': OAUTH_CLIENT_ID,
-        'redirect_uri': OAUTH_CALLBACK_URI,
-        'scope': OAUTH_SCOPE,
-        'state': oauth_state
+        "response_type": "code",
+        "client_id": OAUTH_CLIENT_ID,
+        "redirect_uri": OAUTH_CALLBACK_URI,
+        "scope": OAUTH_SCOPE,
+        "state": oauth_state,
     }
-    authorizationUri = oauth_authorizationUri + urllib.parse.urlencode(oauth_params)
+    authorizationUri = oauth_authorizationUri + urllib.parse.urlencode(
+        oauth_params
+    )
 
     return redirect(authorizationUri)
 
@@ -121,22 +124,24 @@ def auth():
 def callback():
     print("OAuth callback received")
 
-    oauth_error = request.args.get("error_description", '')
+    oauth_error = request.args.get("error_description", "")
     if oauth_error:
         return "OAuth error: " + oauth_error
 
     oauth_code = request.args.get("code")
     if not oauth_code:
-        return "OAuth error: Authorization provider did not return authorization code."
+        return (
+            "OAuth error: Authorization provider did not return authorization "
+            "code."
+        )
 
     # check state to prevent CSRF
-    oauth_state = request.args.get('state', '')
+    oauth_state = request.args.get("state", "")
     if not oauth_state:
         return "OAuth error: Authorization provider did not return state."
-    if oauth_state != session['oauth_state']:
+    if oauth_state != session["oauth_state"]:
         return "OAuth error: State does not match."
 
-
     # There are three options how the OAuth authorization code can be used
 
     # 1.
@@ -148,17 +153,17 @@ def callback():
         client_id=OAUTH_CLIENT_ID,
         client_secret=OAUTH_CLIENT_SECRET,
         oauth_code=oauth_code,
-        redirect_uri=OAUTH_CALLBACK_URI
+        redirect_uri=OAUTH_CALLBACK_URI,
     )
     print(api.people.me())
     return "Welcome, {}!".format(api.people.me().displayName)
 
-
     # 2.
-    # The API connection object can be initialized with any string. Then use the
-    # access_tokens endpoint to obtain access and refresh tokens. The access
-    # token is valid for 14 days. The refresh token may be saved somewhere and
-    # later used to refresh the access token with access_tokens.refresh()
+    # The API connection object can be initialized with any string. Then use
+    # the access_tokens endpoint to obtain access and refresh tokens. The
+    # access token is valid for 14 days. The refresh token may be saved
+    # somewhere and later used to refresh the access token with
+    # access_tokens.refresh()
     # api = WebexTeamsAPI("any string")
     # access_tokens = api.access_tokens.get(
     #     client_id=OAUTH_CLIENT_ID,
@@ -173,11 +178,10 @@ def callback():
     # print(api.people.me())
     # return "Welcome, {}!".format(api.people.me().displayName)
 
-
     # 3.
     # Alternatively, can use requests to exchange authorization code to access
-    # token without using the Webex SDK. Useful if your authorization process is
-    # separate from the token usage. Save tokens somewhere for later use.
+    # token without using the Webex SDK. Useful if your authorization process
+    # is separate from the token usage. Save tokens somewhere for later use.
     # oauth_data = {
     #     'grant_type': "authorization_code",
     #     'redirect_uri': OAUTH_CALLBACK_URI,
@@ -187,7 +191,10 @@ def callback():
     # }
     # resp = requests.post(oauth_tokenUri, data=oauth_data)
     # if not resp.ok:
-    #     return "OAuth error: Authorization provider returned:<br>{}".format(resp.json()['error_description'])
+    #     return (
+    #         "OAuth error: Authorization provider returned:<br>{}"
+    #         "".format(resp.json()['error_description'])
+    #     )
     # else:
     #     oauth_tokens = resp.json()
     #     access_token = oauth_tokens["access_token"]
diff --git a/examples/people.py b/examples/people.py
index a140736..6abb0b0 100755
--- a/examples/people.py
+++ b/examples/people.py
@@ -1,12 +1,12 @@
 #!/usr/bin/env python
 #  -*- coding: utf-8 -*-
-""" Script to demonstrate the use of webexteamssdk for the people API
+"""Script to demonstrate the use of webexteamssdk for the people API
 
 The package natively retrieves your Webex Teams access token from the
 WEBEX_TEAMS_ACCESS_TOKEN environment variable.  You must have this environment
 variable set to run this script.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -27,7 +27,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
@@ -40,7 +39,7 @@
 __author__ = "Jose Bogarín Solano"
 __author_email__ = "jose@bogarin.co.cr"
 __contributors__ = ["Chris Lunsford <chrlunsf@cisco.com>"]
-__copyright__ = "Copyright (c) 2016-2020 Cisco and/or its affiliates."
+__copyright__ = "Copyright (c) 2016-2024 Cisco and/or its affiliates."
 __license__ = "MIT"
 
 from webexteamssdk import WebexTeamsAPI
diff --git a/examples/pyramidWebexTeamsBot/pyramidWebexTeamsBot/__init__.py b/examples/pyramidWebexTeamsBot/pyramidWebexTeamsBot/__init__.py
index 053488e..cc0557f 100755
--- a/examples/pyramidWebexTeamsBot/pyramidWebexTeamsBot/__init__.py
+++ b/examples/pyramidWebexTeamsBot/pyramidWebexTeamsBot/__init__.py
@@ -1,7 +1,7 @@
 #  -*- coding: utf-8 -*-
 """Main entry point.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,11 +22,10 @@
 SOFTWARE.
 """
 
-
 __author__ = "Jose Bogarín Solano"
 __author_email__ = "jose@bogarin.co.cr"
 __contributors__ = ["Chris Lunsford <chrlunsf@cisco.com>"]
-__copyright__ = "Copyright (c) 2016-2020 Cisco and/or its affiliates."
+__copyright__ = "Copyright (c) 2016-2024 Cisco and/or its affiliates."
 __license__ = "MIT"
 
 
diff --git a/examples/pyramidWebexTeamsBot/pyramidWebexTeamsBot/views.py b/examples/pyramidWebexTeamsBot/pyramidWebexTeamsBot/views.py
index 7632e65..8069b3d 100755
--- a/examples/pyramidWebexTeamsBot/pyramidWebexTeamsBot/views.py
+++ b/examples/pyramidWebexTeamsBot/pyramidWebexTeamsBot/views.py
@@ -22,7 +22,7 @@
 
 This script supports Python versions 2 and 3.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -43,7 +43,6 @@
 SOFTWARE.
 """
 
-
 # Use future for Python v2 and v3 compatibility
 from __future__ import (
     absolute_import,
@@ -60,7 +59,7 @@
     "Brad Bester <brbester@cisco.com>",
     "Chris Lunsford <chrlunsf@cisco.com>",
 ]
-__copyright__ = "Copyright (c) 2016-2020 Cisco and/or its affiliates."
+__copyright__ = "Copyright (c) 2016-2024 Cisco and/or its affiliates."
 __license__ = "MIT"
 
 
@@ -71,11 +70,12 @@
 
 
 import logging
+
 log = logging.getLogger(__name__)
 
 
 # Module constants
-CAT_FACTS_URL = 'https://catfact.ninja/fact'
+CAT_FACTS_URL = "https://catfact.ninja/fact"
 
 
 # Initialize the environment
@@ -94,12 +94,12 @@ def get_catfact():
     response = requests.get(CAT_FACTS_URL, verify=False)
     response.raise_for_status()
     json_data = response.json()
-    return json_data['fact']
+    return json_data["fact"]
 
 
 events_service = Service(
-    name='events',
-    path='/events',
+    name="events",
+    path="/events",
     description="Webex Teams Webhook",
 )
 
@@ -144,7 +144,7 @@ def post_events_service(request):
     me = api.people.me()
     if message.personId == me.id:
         # Message was sent by me (bot); do not respond.
-        return {'Message': 'OK'}
+        return {"Message": "OK"}
 
     else:
         # Message was sent by someone else; parse message and respond.
@@ -157,4 +157,4 @@ def post_events_service(request):
 
             # Post the fact to the room where the request was received
             api.messages.create(room.id, text=catfact)
-        return {'Message': 'OK'}
+        return {"Message": "OK"}
diff --git a/examples/pyramidWebexTeamsBot/setup.py b/examples/pyramidWebexTeamsBot/setup.py
index d14644f..97b92a4 100755
--- a/examples/pyramidWebexTeamsBot/setup.py
+++ b/examples/pyramidWebexTeamsBot/setup.py
@@ -1,7 +1,7 @@
 #  -*- coding: utf-8 -*-
 """A simple bot script, built on Pyramid using Cornice.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -25,7 +25,7 @@
 __author__ = "Jose Bogarín Solano"
 __author_email__ = "jose@bogarin.co.cr"
 __contributors__ = ["Chris Lunsford <chrlunsf@cisco.com>"]
-__copyright__ = "Copyright (c) 2016-2020 Cisco and/or its affiliates."
+__copyright__ = "Copyright (c) 2016-2024 Cisco and/or its affiliates."
 __license__ = "MIT"
 
 
@@ -34,20 +34,20 @@
 
 
 here = os.path.abspath(os.path.dirname(__file__))
-with open(os.path.join(here, 'README.rst')) as f:
+with open(os.path.join(here, "README.rst")) as f:
     README = f.read()
 
 
 setup(
-    name='pyramidWebexTeamsBot',
+    name="pyramidWebexTeamsBot",
     version=0.1,
-    description='Pyramid Webex Teams Bot application',
+    description="Pyramid Webex Teams Bot application",
     long_description=README,
     classifiers=[
         "Programming Language :: Python",
         "Framework :: Pylons",
         "Topic :: Internet :: WWW/HTTP",
-        "Topic :: Internet :: WWW/HTTP :: WSGI :: Application"
+        "Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
     ],
     keywords="web services",
     author=__author__,
@@ -55,13 +55,9 @@
     packages=find_packages(),
     include_package_data=True,
     zip_safe=False,
-    install_requires=[
-        'cornice',
-        'waitress',
-        'webexteamssdk'
-    ],
+    install_requires=["cornice", "waitress", "webexteamssdk"],
     entry_points="""[paste.app_factory]
                     main=pyramidWebexTeamsBot:main
                     """,
-    paster_plugins=['pyramid']
+    paster_plugins=["pyramid"],
 )
diff --git a/examples/simple.py b/examples/simple.py
index 9bb02e8..c27e6c1 100755
--- a/examples/simple.py
+++ b/examples/simple.py
@@ -11,7 +11,7 @@
 variable set to run this script.
 
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -32,16 +32,16 @@
 SOFTWARE.
 """
 
-
 from __future__ import print_function
 from webexteamssdk import WebexTeamsAPI
 
 
 DEMO_ROOM_NAME = "webexteamssdk Demo Room"
 DEMO_PEOPLE = ["test01@cmlccie.com", "test02@cmlccie.com"]
-DEMO_MESSAGE = u"Webex Teams rocks!  \ud83d\ude0e"
-DEMO_FILE_URL = \
+DEMO_MESSAGE = "Webex Teams rocks!  \ud83d\ude0e"
+DEMO_FILE_URL = (
     "https://www.webex.com/content/dam/wbx/us/images/dg-integ/teams_icon.png"
+)
 
 
 # Create a WebexTeamsAPI connection object; uses your WEBEX_TEAMS_ACCESS_TOKEN
@@ -58,8 +58,11 @@
 # Build a list of rooms with the name DEMO_ROOM_NAME
 existing_demo_rooms = [room for room in rooms if room.title == DEMO_ROOM_NAME]
 if existing_demo_rooms:
-    print("Found {} existing room(s); deleting them."
-          "".format(len(existing_demo_rooms)))
+    print(
+        "Found {} existing room(s); deleting them." "".format(
+            len(existing_demo_rooms)
+        )
+    )
     for room in existing_demo_rooms:
         # Delete the room
         api.rooms.delete(room.id)
diff --git a/generator/exceptions.py b/generator/exceptions.py
index 3587d67..b3b5566 100644
--- a/generator/exceptions.py
+++ b/generator/exceptions.py
@@ -1,8 +1,10 @@
 class ActionNotFoundError(Exception):
     pass
 
+
 class PropertyNotFoundError(Exception):
     pass
 
+
 class MissingKeyError(Exception):
-    pass
\ No newline at end of file
+    pass
diff --git a/generator/generate.py b/generator/generate.py
index 13d10a7..3c0da23 100644
--- a/generator/generate.py
+++ b/generator/generate.py
@@ -1,4 +1,3 @@
-import sys
 import os
 import yaml
 import argparse
@@ -8,14 +7,16 @@
 from utils import get_additional_parameters
 from exceptions import MissingKeyError
 
-def render_prop_mixin(env: Environment,
-                      name: str,
-                      properties: list,
-                      base_name: str,
-                      template_name: str="mixins.py",
-                      path_prefix: str="../webexteamssdk/models/mixins/"
-                     ) -> str:
-    """ Renders a simple property mixin for the SDK based on the 
+
+def render_prop_mixin(
+    env: Environment,
+    name: str,
+    properties: list,
+    base_name: str,
+    template_name: str = "mixins.py",
+    path_prefix: str = "../webexteamssdk/models/mixins/",
+) -> str:
+    """Renders a simple property mixin for the SDK based on the
         information provided in the descriptor file.
 
     Args:
@@ -25,14 +26,14 @@ def render_prop_mixin(env: Environment,
             name as {name}SimplePropertyMixin.
         properties(list): List of property extracted from the list.properties
             key in the descriptor file.
-        base_name(str): Base name of the descriptor file. Used to generate 
+        base_name(str): Base name of the descriptor file. Used to generate
             the filenames.
         template_name(str): Name of the template to use. Default: mixins.py
-        path_prefix(str): Path to the mixins folder.    
+        path_prefix(str): Path to the mixins folder.
             Default: ../webexteamssdk/models/mixins/
 
     Returns:
-        str: Path to the generated 
+        str: Path to the generated
     """
 
     # Render template based on loaded properties
@@ -43,70 +44,81 @@ def render_prop_mixin(env: Environment,
 
     with open(target_path, "w") as fh:
         fh.writelines(out)
-    
+
     return target_path
 
-def render_api_class(env: Environment,
-                     descr: dict,
-                     base_name: str,
-                     template_name: str = "api.py",
-                     path_prefix: str = "../webexteamssdk/api/"
-                    ) -> str:
-    """ Renders an API class based on the properties described in 
+
+def render_api_class(
+    env: Environment,
+    descr: dict,
+    base_name: str,
+    template_name: str = "api.py",
+    path_prefix: str = "../webexteamssdk/api/",
+) -> str:
+    """Renders an API class based on the properties described in
         the descr file.
 
     Args:
         env(Environment): The jinja environment to render under. Defines
             the templates that will be used.
-        descr(dict): Descriptor parsed from the yaml file defining the 
+        descr(dict): Descriptor parsed from the yaml file defining the
             properties of the endpoint and target api model.
-        base_name(str): Base name of the descriptor file. Used to generate 
+        base_name(str): Base name of the descriptor file. Used to generate
             the filenames.
         template_name(str): Name of the template to use. Default: api.py
         path_prefix(str): Path to the target api folder that the output will
             we placed in. Default: ../webexteamssdk/api/
-    
+
     Returns:
         str: The path to the generated api class
     """
-    create_parameters = get_additional_parameters(descr, 'create')
-    update_parameters = get_additional_parameters(descr, 'update')
+    create_parameters = get_additional_parameters(descr, "create")
+    update_parameters = get_additional_parameters(descr, "update")
 
     additional_code = descr.get("additional_code", None)
 
     # Render template
     tpl = env.get_template(template_name)
-    out = tpl.render(name=descr['name'],
-                    endpoint=descr['endpoint'],
-                    object_type=descr['object_type'],
-                    url_parameters=descr['url_parameters'],
-                    query_parameters=descr['query_parameters'],
-                    create_parameters=create_parameters,
-                    update_parameters=update_parameters,
-                    methods=descr['methods'],
-                    additional_code=additional_code),
+    out = tpl.render(
+        name=descr['name'],
+        endpoint=descr['endpoint'],
+        object_type=descr['object_type'],
+        url_parameters=descr['url_parameters'],
+        query_parameters=descr['query_parameters'],
+        create_parameters=create_parameters,
+        update_parameters=update_parameters,
+        methods=descr['methods'],
+        additional_code=additional_code,
+    )
 
     target_path = os.path.join(path_prefix, f"{base_name}.py")
 
     with open(target_path, "w") as fh:
         fh.writelines(out)
-    
+
     return target_path
 
+
 def main():
     # Setup arg parser
-    parser = argparse.ArgumentParser(description='Generate new endpoints for the SDK')
-    parser.add_argument('-d',
-                        '--descriptor',
-                        help="Path to the descriptor .yaml file",
-                        type=str,
-                        required=True)
-    parser.add_argument('-t',
-                        '--template_dir',
-                        help="Path to the templates directory",
-                        type=str,
-                        default="templates",
-                        required=False) 
+    parser = argparse.ArgumentParser(
+        description="Generate new endpoints for the SDK"
+    )
+    parser.add_argument(
+        "-d",
+        "--descriptor",
+        help="Path to the descriptor .yaml file",
+        type=str,
+        required=True,
+    )
+    parser.add_argument(
+        "-t",
+        "--template_dir",
+        help="Path to the templates directory",
+        type=str,
+        default="templates",
+        required=False,
+    )
     args = parser.parse_args()
 
     # Setup jinja environment and load information from description file
@@ -116,19 +128,19 @@ def main():
     base_name = os.path.splitext(os.path.basename(descr_file))[0]
 
     descr = yaml.safe_load(open(descr_file))
-    
+
     # Check that all required keys are present
     required_keys = [
-        'name',
-        'list.properties',
-        'endpoint',
-        'object_type',
-        'query_parameters',
-        'methods'
+        "name",
+        "list.properties",
+        "endpoint",
+        "object_type",
+        "query_parameters",
+        "methods",
     ]
 
     for key in required_keys:
-        # Check all keys - subkeys (i.e. d['list']['properties'] 
+        # Check all keys - subkeys (i.e. d['list']['properties']
         # can be passed in dot notation, so list.properties)
         keys = key.split(".")
 
@@ -138,40 +150,22 @@ def main():
                 raise MissingKeyError(f"Missing required key '{key}'")
             else:
                 d = d.get(sub_key)
-    
+
     # Add empty url_parameters key if there are no URL parameters defined
     if 'url_parameters' not in descr.keys():
         descr['url_parameters'] = []
 
-    mixin_path = render_prop_mixin(env=env, 
-                                   name=descr['name'],
-                                   properties=descr['list']['properties'],
-                                   base_name=base_name
-                                  )
+    mixin_path = render_prop_mixin(
+        env=env,
+        name=descr["name"],
+        properties=descr["list"]["properties"],
+        base_name=base_name,
+    )
     print(f"Rendered mixin for {descr['name']} to {mixin_path}")
 
-    api_path = render_api_class(env=env,
-                                descr=descr,
-                                base_name=base_name)
+    api_path = render_api_class(env=env, descr=descr, base_name=base_name)
     print(f"Rendered api class for {descr['name']} to {api_path}")
 
 
 if __name__ == "__main__":
     main()
-# print("Manually add: ")
-# print("In webexteamssdk/models/immutable.py")
-# print(f"from .mixins.{ base_name } import { descr['name'] }BasicPropertiesMixin")
-
-# cls_model_def = f"""
-# class { descr['name'] }(ImmutableData, { descr['name'] }BasicPropertiesMixin):
-#     \"\"\"Webex { descr['name'] } data model\"\"\"
-# """
-# print(cls_model_def)
-
-# print(f"{descr['object_type']}={ descr['name'] }")
-
-# print()
-# print()
-# print("In webexteamssdk/api/__init__.py")
-# print(f"from {base_name} import {descr['name']}API")
-# print(f"self.{descr['object_type']}s = {descr['name']}(self._session, object_factory)")
\ No newline at end of file
diff --git a/generator/models/meetings.yaml b/generator/models/meetings.yaml
index 2b60fa5..fe0197d 100644
--- a/generator/models/meetings.yaml
+++ b/generator/models/meetings.yaml
@@ -56,7 +56,7 @@ query_parameters:
   - name: hostEmail
     description: Email address for the meeting host (Needs admin-level scope).
     optional: True
-    type: basestring 
+    type: basestring
   - name: siteUrl
     description: URL of the webex site.
     optional: True
@@ -222,7 +222,7 @@ list:
       description: Whether or not meeting is recorded automatically.
       type: bool
     - name: allowAnyUserToBeCoHost
-      description: Allow any attendee with host account on site to become co host
+      description: Allow any attendee with host account on site to become cohost
       type: bool
     - name: enabledJoinBeforeHost
       description: Allow attendees to join before the host.
@@ -267,7 +267,7 @@ list:
       description: Number of minutes for the meeting to be automatically locked.
       type: int
     - name: allowFirstUserToBeCoHost
-      description: Allow the first joiner with host account on the meeting site to be co host.
+      description: Allow the first joiner with host account on the meeting site to be cohost.
       type: bool
     - name: allowAuthenticatedDevices
       description: Whether or not to allow authenticated video devices in the meeting's organization to start or join the meeting
@@ -286,4 +286,4 @@ list:
       type: list
     - name: simultaneousInterpretation
       description: Simultaneous interpretation information for the meeting.
-      type: dict
\ No newline at end of file
+      type: dict
diff --git a/generator/templates/api.py b/generator/templates/api.py
index fa41fce..55dd27b 100644
--- a/generator/templates/api.py
+++ b/generator/templates/api.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex {{ name }}s API wrapper.
 
-Copyright (c) 2016-2022 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -42,14 +42,14 @@
 )
 
 
-API_ENDPOINT = '{{ endpoint }}'
-OBJECT_TYPE = '{{ object_type }}'
+API_ENDPOINT = "{{ endpoint }}"
+OBJECT_TYPE = "{{ object_type }}"
 
 
 class {{ name }}sAPI(object):
-    """Webex {{ name }}s API.
+    """Webex {{ name }}s API.
 
-    Wraps the Webex {{ name }}s API and exposes the API as native Python
+    Wraps the Webex {{ name }}s API and exposes the API as native Python
     methods that return native Python objects.
 
     """
@@ -67,7 +67,7 @@ def __init__(self, session, object_factory):
         """
         check_type(session, RestSession)
 
-        super({{name }}sAPI, self).__init__()
+        super({{ name }}sAPI, self).__init__()
 
         self._session = session
         self._object_factory = object_factory
@@ -82,7 +82,7 @@ def list(self, {% for up in url_parameters -%}
             headers={},
              **request_parameters):
 
-        """List {{ object_type }}s.
+        """List {{ object_type }}s.
 
         Use query parameters to filter the response.
 
@@ -98,10 +98,10 @@ def list(self, {% for up in url_parameters -%}
 
         Args:
             {% for up in url_parameters -%}
-            {{ up['name'] }} ({{ up['type']}}): {{ up['description']}}
+            {{ up['name'] }} ({{ up['type']}}): {{ up['description']}}
             {% endfor -%}
             {% for qp in query_parameters -%}
-            {{ qp['name'] }} ({{ qp['type']}}): {{ qp['description']}}
+            {{ qp['name'] }} ({{ qp['type']}}): {{ qp['description']}}
             {% endfor -%}
             headers(dict): Additional headers to be passed.
             **request_parameters: Additional request parameters (provides
@@ -109,7 +109,7 @@ def list(self, {% for up in url_parameters -%}
 
         Returns:
             GeneratorContainer: A GeneratorContainer which, when iterated,
-            yields the {{ object_type }}s returned by the Webex query.
+            yields the {{ object_type }}s returned by the Webex query.
 
         Raises:
             TypeError: If the parameter types are incorrect.
@@ -117,22 +117,22 @@ def list(self, {% for up in url_parameters -%}
 
         """
         {% for up in url_parameters -%}
-        check_type({{ up['name'] }}, {{ up['type'] }})
+        check_type({{ up['name'] }}, {{ up['type'] }})
         {% endfor -%}
         {% for qp in query_parameters -%}
-        check_type({{ qp['name'] }}, {{ qp['type'] }}{% if qp['optional'] %}, optional=True{% endif %})
+        check_type({{ qp['name'] }}, {{ qp['type'] }}{% if qp['optional'] %}, optional=True{% endif %})
         {% endfor %}
 
         params = dict_from_items_with_values(
             request_parameters,
-            {% for qp in query_parameters -%} 
-            {{ qp['name'] }}={{ qp['name'] }},
+            {% for qp in query_parameters -%}
+            {{ qp['name'] }}={{ qp['name'] }},
             {% endfor %}
         )
         {% for qp in query_parameters -%}
         {% if qp['requestName'] %}
         if {{ qp['name'] }}:
-            params['{{qp['requestName']}}'] = params.pop("{{ qp['name'] }}")
+            params['{{qp['requestName']}}'] = params.pop("{{ qp['name'] }}")
         {% endif %}
         {%- endfor %}
         {%- if url_parameters %}
@@ -166,23 +166,23 @@ def create(self, {% for up in url_parameters -%}
                      {% endfor -%}
                      {% for cp in create_parameters -%}
                       {{ cp['name'] }}{% if cp['optional'] %}=None{% endif %},
-                     {% endfor -%} 
-    
+                     {% endfor -%}
+
                     **request_parameters):
-        """Create a {{ object_type }}.
+        """Create a {{ object_type }}.
 
         Args:
             {% for up in url_parameters -%}
-            {{ up['name'] }} ({{ up['type']}}): {{ up['description']}}
+            {{ up['name'] }} ({{ up['type']}}): {{ up['description']}}
             {% endfor -%}
             {% for cp in create_parameters -%}
-            {{ cp['name'] }} ({{ cp['type']}}): {{ cp['description']}}
+            {{ cp['name'] }} ({{ cp['type'] }}): {{ cp['description'] }}
             {% endfor -%}
             **request_parameters: Additional request parameters (provides
                 support for parameters that may be added in the future).
 
         Returns:
-            {{ name }}: A {{ name }} object with the details of the created
+            {{ name }}: A {{ name }} object with the details of the created
             {{ object_type }}.
 
         Raises:
@@ -191,22 +191,22 @@ def create(self, {% for up in url_parameters -%}
 
         """
         {% for up in url_parameters -%}
-        check_type({{ up['name'] }}, {{ up['type'] }})
+        check_type({{ up['name'] }}, {{ up['type'] }})
         {% endfor -%}
         {% for cp in create_parameters -%}
-        check_type({{ cp['name'] }}, {{ cp['type'] }}{% if cp['optional'] %}, optional=True{% endif %})
+        check_type({{ cp['name'] }}, {{ cp['type'] }}{% if cp['optional'] %}, optional=True{% endif %})
         {% endfor %}
         post_data = dict_from_items_with_values(
             request_parameters,
-            {% for cp in create_parameters -%} 
-            {{ cp['name'] }}={{ cp['name'] }},
+            {% for cp in create_parameters -%}
+            {{ cp['name'] }}={{ cp['name'] }},
             {% endfor %}
         )
 
         {% for cp in create_parameters -%}
         {% if cp['requestName'] %}
         if {{ cp['name'] }}:
-            post_data['{{cp['requestName']}}'] = post_data.pop("{{ cp['name'] }}")
+            post_data['{{cp['requestName']}}'] = post_data.pop("{{ cp['name'] }}")
         {% endif %}
         {%- endfor %}
         {%- if url_parameters %}
@@ -228,32 +228,24 @@ def create(self, {% for up in url_parameters -%}
 
     {% if "get" in methods %}
     def get(self, {% for up in url_parameters %}{{up['name']}}, {% endfor %}{{ object_type }}Id):
-        """Get details for a {{ object_type }}, by ID.
+        """Get details for a {{ object_type }}, by ID.
 
         Args:
             {% for up in url_parameters -%}
-            {{up['name']}} ({{ up['type']}}): {{ up['description']}}
+            {{up['name']}} ({{ up['type']}}): {{ up['description']}}
             {% endfor -%}
-            {{ object_type }}Id(basestring): The {{ object_type }} ID.
+            {{ object_type }}Id(basestring): The {{ object_type }} ID.
 
         Returns:
-            {{ name }}: A {{ name }} object with the details of the requested
-            {{ object_type }}.
+            {{ name }}: A {{ name }} object with the details of the requested
+            {{ object_type }}.
 
         Raises:
             TypeError: If the parameter types are incorrect.
             ApiError: If the Webex Teams cloud returns an error.
 
         """
-        {% for up in url_parameters -%}
-        check_type({{ up['name'] }}, {{ up['type'] }})
-        {% endfor -%}
-        check_type({{ object_type }}Id, basestring)
-        {%- if url_parameters %}
-            {%- set ups = [] -%}
-            {% for up in url_parameters|map(attribute='name') -%}
-            {% set ups = ups.append( up+"="+up ) %}
-            {%- endfor %}
+        check_type({{ object_type }}Id, basestring)
 
         # Add URL parameters to the API endpoint
         request_url = API_ENDPOINT.format({{ ups|join(", ") }})
@@ -261,7 +253,7 @@ def get(self, {% for up in url_parameters %}{{up['name']}}, {% endfor %}{{ objec
         request_url = API_ENDPOINT
         {% endif %}
         # API request
-        json_data = self._session.get(request_url + '/' + {{ object_type }}Id)
+        json_data = self._session.get(request_url + '/' + {{ object_type }}Id)
 
         # Return a membership object created from the response JSON data
         return self._object_factory(OBJECT_TYPE, json_data)
@@ -273,7 +265,7 @@ def delete(self, {% for up in url_parameters %}{{up['name']}}, {% endfor %}{{ ob
 
         Args:
             {% for up in url_parameters -%}
-            {{up['name']}} ({{ up['type']}}): {{ up['description']}}
+            {{up['name']}} ({{ up['type']}}): {{ up['description']}}
             {% endfor -%}
             {{ object_type }}Id(basestring): The {{ object_type }} ID.
 
@@ -283,7 +275,7 @@ def delete(self, {% for up in url_parameters %}{{up['name']}}, {% endfor %}{{ ob
 
         """
         {% for up in url_parameters -%}
-        check_type({{ up['name'] }}, {{ up['type'] }})
+        check_type({{ up['name'] }}, {{ up['type'] }})
         {% endfor -%}
         check_type({{ object_type }}Id, basestring)
         {%- if url_parameters %}
@@ -302,51 +294,48 @@ def delete(self, {% for up in url_parameters %}{{up['name']}}, {% endfor %}{{ ob
     {% endif %}
 
     {% if "update" in methods %}
-    def update(self, {% for up in url_parameters %}{{up['name']}}, {% endfor %}{{ object_type }}Id,
+    def update(self, {{ object_type }}Id,
                      {% for up in update_parameters -%}
                      {{ up['name'] }}{% if up['optional'] %}=None{% endif %},
-                     {% endfor -%} 
-    
+                     {% endfor -%}
+
                      **request_parameters):
-        """Update properties for a {{ object_type }}, by ID.
+        """Update properties for a {{ object_type }}, by ID.
 
         Args:
             {% for up in url_parameters -%}
-            {{up['name']}} ({{ up['type']}}): {{ up['description']}}
+            {{up['name']}} ({{ up['type']}}): {{ up['description']}}
             {% endfor -%}
-            {{ object_type }}Id(basestring): The {{ object_type }} ID.
+            {{ object_type }}Id(basestring): The {{ object_type }} ID.
             {% for up in update_parameters -%}
-            {{ up['name'] }} ({{ up['type']}}): {{ up['description']}}
-            {% endfor -%} 
+            {{ up['name'] }} ({{ up['type']}}): {{ up['description']}}
+            {% endfor -%}
             **request_parameters: Additional request parameters (provides
                 support for parameters that may be added in the future).
 
         Returns:
-            {{ name }}: A {{ name }} object with the updated Webex
-            {{ object_type }} details.
+            {{ name }}: A {{ name }} object with the updated Webex
+            {{ object_type }} details.
 
         Raises:
             TypeError: If the parameter types are incorrect.
             ApiError: If the Webex cloud returns an error.
 
         """
-        check_type({{ object_type }}Id, basestring)
-        {% for up in url_parameters -%}
-        check_type({{ up['name'] }}, {{ up['type'] }})
-        {% endfor -%}
+        check_type({{ object_type }}Id, basestring)
         {% for up in update_parameters -%}
-        check_type({{ up['name'] }}, {{ up['type'] }}{% if up['optional'] %}, optional=True{% endif %})
+        check_type({{ up['name'] }}, {{ up['type'] }}{% if up['optional'] %}, optional=True{% endif %})
         {% endfor %}
         put_data = dict_from_items_with_values(
             request_parameters,
-            {% for up in update_parameters -%} 
-            {{ up['name'] }}={{ up['name'] }},
+            {% for up in update_parameters -%}
+            {{ up['name'] }}={{ up['name'] }},
             {% endfor %}
         )
         {% for up in update_parameters -%}
         {% if up['requestName'] %}
         if {{ up['name'] }}:
-            put_data['{{up['requestName']}}'] = put_data.pop("{{ up['name'] }}")
+            put_data['{{up['requestName']}}'] = put_data.pop("{{ up['name'] }}")
         {% endif %}
         {%- endfor %}
         {%- if url_parameters %}
@@ -360,12 +349,12 @@ def update(self, {% for up in url_parameters %}{{up['name']}}, {% endfor %}{{ o
         request_url = API_ENDPOINT
         {% endif %}
         # API request
-        json_data = self._session.put(request_url + '/' + {{ object_type }}Id,
+        json_data = self._session.put(request_url + '/' + {{ object_type }}Id,
                                       json=put_data)
 
         # Return a membership object created from the response JSON data
         return self._object_factory(OBJECT_TYPE, json_data)
     {% endif %}
     {% if additional_code %}
-    {{ additional_code }}
-    {% endif %}
\ No newline at end of file
+    {{ additional_code }}
+    {% endif %}
diff --git a/generator/templates/mixins.py b/generator/templates/mixins.py
index dbbf660..54d9bf9 100644
--- a/generator/templates/mixins.py
+++ b/generator/templates/mixins.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex {{ name }}s data model.
 
-Copyright (c) 2016-2022 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
diff --git a/generator/utils.py b/generator/utils.py
index b40d610..88d3ee6 100644
--- a/generator/utils.py
+++ b/generator/utils.py
@@ -1,42 +1,49 @@
 from typing import Union
-from exceptions import ActionNotFoundError
+from exceptions import ActionNotFoundError, PropertyNotFoundError
 
-def create_property_struct_from_entry(prop: Union[str, dict],
-                                      prop_mapping: dict,
-                                      is_optional: bool=False) -> dict:
+
+def create_property_struct_from_entry(
+    prop: Union[str, dict], prop_mapping: dict, is_optional: bool = False
+) -> dict:
     if isinstance(prop, str):
         if prop not in prop_mapping.keys():
-            raise PropertyNotFoundError(f"Simple property {prop} is not part of the objects properties. Add it or specify it as a dict.")
-        
+            raise PropertyNotFoundError(
+                f"Simple property {prop} is not part of the objects "
+                f"properties. Add it or specify it as a dict."
+            )
+
         tmp = prop_mapping.get(prop).copy()
-        tmp['optional'] = is_optional
+        tmp["optional"] = is_optional
 
         return tmp
     elif isinstance(prop, dict):
         # ToDo: Add check that all required properties are present
         tmp = prop.copy()
-        tmp['optional'] = is_optional
+        tmp["optional"] = is_optional
 
         return tmp
-    
+
+
 def get_additional_parameters(descr: dict, action_key: str):
     # Create property mapping of parameters included in the list
     prop_mapping = {}
-    for prop in descr['list']['properties']:
-        prop_mapping[prop['name']] = prop
+    for prop in descr["list"]["properties"]:
+        prop_mapping[prop["name"]] = prop
 
     # Find all additional parameters that are not included in prop mapping
     if action_key not in descr.keys():
-        raise ActionNotFoundError(f"'{action_key}' is missing from your description file")
+        raise ActionNotFoundError(
+            f"'{action_key}' is missing from your description file"
+        )
 
-    addt_parameters = []    
+    addt_parameters = []
 
-    for p in descr.get(action_key).get('required', []):
+    for p in descr.get(action_key).get("required", []):
         addt_param = create_property_struct_from_entry(p, prop_mapping, False)
         addt_parameters.append(addt_param)
 
-    for p in descr.get(action_key).get('optional', []):
+    for p in descr.get(action_key).get("optional", []):
         addt_param = create_property_struct_from_entry(p, prop_mapping, True)
-        addt_parameters.append(addt_param)    
-    
-    return addt_parameters
\ No newline at end of file
+        addt_parameters.append(addt_param)
+
+    return addt_parameters
diff --git a/requirements.lock b/requirements.lock
index 7a12acd..fe71e67 100644
--- a/requirements.lock
+++ b/requirements.lock
@@ -1,63 +1,70 @@
-alabaster==0.7.12
-appnope==0.1.0
-attrs==19.3.0
-Babel==2.8.0
-backcall==0.2.0
-bleach==3.1.5
-certifi==2020.6.20
-chardet==3.0.4
-colorama==0.4.3
-decorator==4.4.2
-docutils==0.16
-flake8==3.8.3
-future==0.18.2
-idna==2.10
-imagesize==1.2.0
-importlib-metadata==1.7.0
-ipython==7.16.1
-ipython-genutils==0.2.0
-jedi==0.17.1
-Jinja2==2.11.2
-keyring==21.2.1
-MarkupSafe==1.1.1
-mccabe==0.6.1
-more-itertools==8.4.0
-packaging==20.4
-parso==0.7.0
-pexpect==4.8.0
-pickleshare==0.7.5
-pkginfo==1.5.0.1
-pluggy==0.13.1
-prompt-toolkit==3.0.5
-ptyprocess==0.6.0
-py==1.9.0
-pycodestyle==2.6.0
-pyflakes==2.2.0
-Pygments==2.6.1
+alabaster==0.7.16
+asttokens==2.4.1
+Babel==2.14.0
+backports.tarfile==1.1.0
+certifi==2024.2.2
+charset-normalizer==3.3.2
+decorator==5.1.1
+docutils==0.20.1
+exceptiongroup==1.2.0
+executing==2.0.1
+flake8==7.0.0
+future==1.0.0
+idna==3.7
+imagesize==1.4.1
+importlib_metadata==7.1.0
+iniconfig==2.0.0
+ipython==8.23.0
+jaraco.classes==3.4.0
+jaraco.context==5.3.0
+jaraco.functools==4.0.0
+jedi==0.19.1
+Jinja2==3.1.3
+keyring==25.1.0
+markdown-it-py==3.0.0
+MarkupSafe==2.1.5
+matplotlib-inline==0.1.7
+mccabe==0.7.0
+mdurl==0.1.2
+more-itertools==10.2.0
+nh3==0.2.17
+packaging==24.0
+parso==0.8.4
+pexpect==4.9.0
+pkginfo==1.10.0
+pluggy==1.4.0
+prompt-toolkit==3.0.43
+ptyprocess==0.7.0
+pure-eval==0.2.2
+pycodestyle==2.11.1
+pyflakes==3.2.0
+Pygments==2.17.2
 PyJWT==1.7.1
-pyparsing==2.4.7
-pytest==5.4.3
-pytz==2020.1
-readme-renderer==26.0
-requests==2.24.0
-requests-toolbelt==0.9.1
-rfc3986==1.4.0
-six==1.15.0
-snowballstemmer==2.0.0
-Sphinx==3.1.2
-sphinx-rtd-theme==0.5.0
-sphinxcontrib-applehelp==1.0.2
-sphinxcontrib-devhelp==1.0.2
-sphinxcontrib-htmlhelp==1.0.3
+pytest==8.1.1
+PyYAML==6.0.1
+readme_renderer==43.0
+requests==2.31.0
+requests-toolbelt==1.0.0
+rfc3986==2.0.0
+rich==13.7.1
+six==1.16.0
+snowballstemmer==2.2.0
+Sphinx==7.3.5
+sphinx-rtd-theme==2.0.0
+sphinxcontrib-applehelp==1.0.8
+sphinxcontrib-devhelp==1.0.6
+sphinxcontrib-htmlhelp==2.0.5
+sphinxcontrib-jquery==4.1
 sphinxcontrib-jsmath==1.0.1
-sphinxcontrib-qthelp==1.0.3
-sphinxcontrib-serializinghtml==1.1.4
-tqdm==4.47.0
-traitlets==4.3.3
-twine==3.2.0
-urllib3==1.25.9
-versioneer==0.18
-wcwidth==0.2.5
-webencodings==0.5.1
--e git+https://github.com/CiscoDevNet/webexteamssdk.git@b63a6dba6741e2aabd98a244415a0a574493f88e#egg=webexteamssdk
-zipp==3.1.0
+sphinxcontrib-qthelp==1.0.7
+sphinxcontrib-serializinghtml==1.1.10
+stack-data==0.6.3
+tomli==2.0.1
+traitlets==5.14.2
+twine==5.0.0
+typing_extensions==4.11.0
+urllib3==2.2.1
+versioneer==0.29
+wcwidth==0.2.13
+-e git+https://github.com/CiscoDevNet/webexteamssdk.git@f7d0e1338a3e765721e1d1e66cca87c7d4527ca3#egg=webexteamssdk
+zipp==3.18.1
diff --git a/script/build b/script/build
index 6948ef5..215b89d 100755
--- a/script/build
+++ b/script/build
@@ -1,7 +1,7 @@
 #!/usr/bin/env bash
 # Build the project's product(s).
 #
-# Copyright (c) 2016-2020 Cisco and/or its affiliates.
+# Copyright (c) 2016-2024 Cisco and/or its affiliates.
 # License: MIT
 
 
diff --git a/script/ci b/script/ci
index d54e27d..f3f1366 100755
--- a/script/ci
+++ b/script/ci
@@ -1,7 +1,7 @@
 #!/usr/bin/env bash
 # Run the project's test suite.
 #
-# Copyright (c) 2016-2020 Cisco and/or its affiliates.
+# Copyright (c) 2016-2024 Cisco and/or its affiliates.
 # License: MIT
 
 
diff --git a/script/clean b/script/clean
index 0e8a4f4..523c0f5 100755
--- a/script/clean
+++ b/script/clean
@@ -1,7 +1,7 @@
 #!/usr/bin/env bash
 # Clean the project directory.
 #
-# Copyright (c) 2016-2020 Cisco and/or its affiliates.
+# Copyright (c) 2016-2024 Cisco and/or its affiliates.
 # License: MIT
 
 
diff --git a/script/console b/script/console
index de884d7..6679b30 100755
--- a/script/console
+++ b/script/console
@@ -1,7 +1,7 @@
 #!/usr/bin/env bash
 # Open the project's console.
 #
-# Copyright (c) 2016-2020 Cisco and/or its affiliates.
+# Copyright (c) 2016-2024 Cisco and/or its affiliates.
 # License: MIT
 
 
diff --git a/script/installdeps b/script/installdeps
index 56ded63..968d077 100755
--- a/script/installdeps
+++ b/script/installdeps
@@ -1,7 +1,7 @@
 #!/usr/bin/env bash
 # Install all the development dependencies for this project.
 #
-# Copyright (c) 2016-2020 Cisco and/or its affiliates.
+# Copyright (c) 2016-2024 Cisco and/or its affiliates.
 # License: MIT
 
 
diff --git a/script/ipython_console.py b/script/ipython_console.py
index 32a277e..ac1ea8c 100755
--- a/script/ipython_console.py
+++ b/script/ipython_console.py
@@ -4,7 +4,6 @@
 Used to interactively work with the main package contents in IPython.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
@@ -16,7 +15,7 @@
 
 import webexteamssdk
 
-__copyright__ = "Copyright (c) 2016-2020 Cisco and/or its affiliates."
+__copyright__ = "Copyright (c) 2016-2024 Cisco and/or its affiliates."
 __license__ = "MIT"
 
 
diff --git a/script/setup b/script/setup
index 2a2556c..37b4a95 100755
--- a/script/setup
+++ b/script/setup
@@ -1,7 +1,7 @@
 #!/usr/bin/env bash
 # Setup or reset the project to its initial state.
 #
-# Copyright (c) 2016-2020 Cisco and/or its affiliates.
+# Copyright (c) 2016-2024 Cisco and/or its affiliates.
 # License: MIT
 
 
diff --git a/script/update b/script/update
index 40f08cc..2c69c53 100755
--- a/script/update
+++ b/script/update
@@ -1,7 +1,7 @@
 #!/usr/bin/env bash
 # Update the project's dependencies.
 #
-# Copyright (c) 2016-2020 Cisco and/or its affiliates.
+# Copyright (c) 2016-2024 Cisco and/or its affiliates.
 # License: MIT
 
 
diff --git a/setup.py b/setup.py
index b001503..babd589 100644
--- a/setup.py
+++ b/setup.py
@@ -1,7 +1,6 @@
 # -*- coding: utf-8 -*-
 """webexteamssdk setup module."""
 
-
 import os
 from codecs import open
 
@@ -10,47 +9,48 @@
 import versioneer
 
 
-__copyright__ = "Copyright (c) 2016-2020 Cisco and/or its affiliates."
+__copyright__ = "Copyright (c) 2016-2024 Cisco and/or its affiliates."
 __license__ = "MIT"
 
 
-PACKAGE_NAME = 'webexteamssdk'
+PACKAGE_NAME = "webexteamssdk"
 
 PACKAGE_KEYWORDS = [
-    'cisco',
-    'webex',
-    'teams',
-    'spark',
-    'python',
-    'api',
-    'sdk',
-    'enterprise',
-    'messaging',
+    "cisco",
+    "webex",
+    "teams",
+    "spark",
+    "python",
+    "api",
+    "sdk",
+    "enterprise",
+    "messaging",
 ]
 
 PACKAGE_CLASSIFIERS = [
-    'Development Status :: 5 - Production/Stable',
-    'Intended Audience :: Developers',
-    'Intended Audience :: System Administrators',
-    'Intended Audience :: Telecommunications Industry',
-    'Intended Audience :: Education',
-    'Natural Language :: English',
-    'License :: OSI Approved :: MIT License',
-    'Programming Language :: Python :: 2',
-    'Programming Language :: Python :: 2.7',
-    'Programming Language :: Python :: 3',
-    'Programming Language :: Python :: 3.5',
-    'Programming Language :: Python :: 3.6',
-    'Programming Language :: Python :: 3.7',
-    'Topic :: Communications',
-    'Topic :: Communications :: Chat'
+    "Development Status :: 5 - Production/Stable",
+    "Intended Audience :: Developers",
+    "Intended Audience :: System Administrators",
+    "Intended Audience :: Telecommunications Industry",
+    "Intended Audience :: Education",
+    "Natural Language :: English",
+    "License :: OSI Approved :: MIT License",
+    "Programming Language :: Python :: 2",
+    "Programming Language :: Python :: 2.7",
+    "Programming Language :: Python :: 3",
+    "Programming Language :: Python :: 3.10",
+    "Topic :: Communications",
+    "Topic :: Communications :: Chat",
 ]
 
+# TODO: Review the the dependencies when releasing WebexPythonSDK v2
+# PyJWT should be updated to ^2.8.0. Keeping it at 1.7.1 to maintain python v2
+# compatibility for now.
 INSTALLATION_REQUIREMENTS = [
-    'future',
-    'requests>=2.4.2',
-    'requests-toolbelt',
-    'PyJWT'
+    "future",
+    "requests>=2.4.2",
+    "requests-toolbelt",
+    "PyJWT==1.7.1",
 ]
 
 
@@ -59,37 +59,28 @@
 
 # Get package metadata
 metadata = {}
-with open(os.path.join(project_root, PACKAGE_NAME, '_metadata.py')) as f:
+with open(os.path.join(project_root, PACKAGE_NAME, "_metadata.py")) as f:
     exec(f.read(), metadata)
 
 
 # Get the long description from the project's README.rst file
-with open(os.path.join(project_root, 'README.rst'), encoding='utf-8') as f:
+with open(os.path.join(project_root, "README.rst"), encoding="utf-8") as f:
     long_description = f.read()
 
 
 setup(
     name=PACKAGE_NAME,
-
     version=versioneer.get_version(),
     cmdclass=versioneer.get_cmdclass(),
-
-    description=metadata['__description__'],
+    description=metadata["__description__"],
     long_description=long_description,
-
-    url=metadata['__url__'],
-    download_url=metadata['__download_url__'],
-
-    author=metadata['__author__'],
-    author_email=metadata['__author_email__'],
-
-    license=metadata['__license__'] + '; ' + metadata['__copyright__'],
-
+    url=metadata["__url__"],
+    download_url=metadata["__download_url__"],
+    author=metadata["__author__"],
+    author_email=metadata["__author_email__"],
+    license=metadata["__license__"] + "; " + metadata["__copyright__"],
     classifiers=PACKAGE_CLASSIFIERS,
-
     keywords=" ".join(PACKAGE_KEYWORDS),
-
-    packages=find_packages(include=[PACKAGE_NAME, PACKAGE_NAME + '.*']),
-
+    packages=find_packages(include=[PACKAGE_NAME, PACKAGE_NAME + ".*"]),
     install_requires=INSTALLATION_REQUIREMENTS,
 )
diff --git a/versioneer.py b/versioneer.py
index 3aa5da3..5edd4e4 100644
--- a/versioneer.py
+++ b/versioneer.py
@@ -1,4 +1,3 @@
-
 # Version: 0.18
 
 """The Versioneer - like a rocketeer, but for versions.
@@ -277,6 +276,7 @@
 """
 
 from __future__ import print_function
+
 try:
     import configparser
 except ImportError:
@@ -308,11 +308,13 @@ def get_root():
         setup_py = os.path.join(root, "setup.py")
         versioneer_py = os.path.join(root, "versioneer.py")
     if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)):
-        err = ("Versioneer was unable to run the project root directory. "
-               "Versioneer requires setup.py to be executed from "
-               "its immediate directory (like 'python setup.py COMMAND'), "
-               "or in a way that lets it use sys.argv[0] to find the root "
-               "(like 'python path/to/setup.py COMMAND').")
+        err = (
+            "Versioneer was unable to run the project root directory. "
+            "Versioneer requires setup.py to be executed from "
+            "its immediate directory (like 'python setup.py COMMAND'), "
+            "or in a way that lets it use sys.argv[0] to find the root "
+            "(like 'python path/to/setup.py COMMAND')."
+        )
         raise VersioneerBadRootError(err)
     try:
         # Certain runtime workflows (setup.py install/develop in a setuptools
@@ -325,8 +327,10 @@ def get_root():
         me_dir = os.path.normcase(os.path.splitext(me)[0])
         vsr_dir = os.path.normcase(os.path.splitext(versioneer_py)[0])
         if me_dir != vsr_dir:
-            print("Warning: build in %s is using versioneer.py from %s"
-                  % (os.path.dirname(me), versioneer_py))
+            print(
+                "Warning: build in %s is using versioneer.py from %s"
+                % (os.path.dirname(me), versioneer_py)
+            )
     except NameError:
         pass
     return root
@@ -348,6 +352,7 @@ def get(parser, name):
         if parser.has_option("versioneer", name):
             return parser.get("versioneer", name)
         return None
+
     cfg = VersioneerConfig()
     cfg.VCS = VCS
     cfg.style = get(parser, "style") or ""
@@ -372,17 +377,20 @@ class NotThisMethod(Exception):
 
 def register_vcs_handler(vcs, method):  # decorator
     """Decorator to mark a method as the handler for a particular VCS."""
+
     def decorate(f):
         """Store f in HANDLERS[vcs][method]."""
         if vcs not in HANDLERS:
             HANDLERS[vcs] = {}
         HANDLERS[vcs][method] = f
         return f
+
     return decorate
 
 
-def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False,
-                env=None):
+def run_command(
+    commands, args, cwd=None, verbose=False, hide_stderr=False, env=None
+):
     """Call the given command(s)."""
     assert isinstance(commands, list)
     p = None
@@ -390,10 +398,13 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False,
         try:
             dispcmd = str([c] + args)
             # remember shell=False, so use git.cmd on windows, not just git
-            p = subprocess.Popen([c] + args, cwd=cwd, env=env,
-                                 stdout=subprocess.PIPE,
-                                 stderr=(subprocess.PIPE if hide_stderr
-                                         else None))
+            p = subprocess.Popen(
+                [c] + args,
+                cwd=cwd,
+                env=env,
+                stdout=subprocess.PIPE,
+                stderr=(subprocess.PIPE if hide_stderr else None),
+            )
             break
         except EnvironmentError:
             e = sys.exc_info()[1]
@@ -418,7 +429,9 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False,
     return stdout, p.returncode
 
 
-LONG_VERSION_PY['git'] = '''
+LONG_VERSION_PY[
+    "git"
+] = '''
 # This file helps to compute a version number in source trees obtained from
 # git-archive tarball (such as those provided by githubs download-from-tag
 # feature). Distribution tarballs (built by setup.py sdist) and build
@@ -993,7 +1006,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose):
     # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of
     # just "foo-1.0". If we see a "tag: " prefix, prefer those.
     TAG = "tag: "
-    tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)])
+    tags = set([r[len(TAG) :] for r in refs if r.startswith(TAG)])
     if not tags:
         # Either we're using git < 1.8.3, or there really are no tags. We use
         # a heuristic: assume all version tags have a digit. The old git %d
@@ -1002,7 +1015,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose):
         # between branches and tags. By ignoring refnames without digits, we
         # filter out many common branch names like "release" and
         # "stabilization", as well as "HEAD" and "master".
-        tags = set([r for r in refs if re.search(r'\d', r)])
+        tags = set([r for r in refs if re.search(r"\d", r)])
         if verbose:
             print("discarding '%s', no digits" % ",".join(refs - tags))
     if verbose:
@@ -1010,19 +1023,26 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose):
     for ref in sorted(tags):
         # sorting will prefer e.g. "2.0" over "2.0rc1"
         if ref.startswith(tag_prefix):
-            r = ref[len(tag_prefix):]
+            r = ref[len(tag_prefix) :]
             if verbose:
                 print("picking %s" % r)
-            return {"version": r,
-                    "full-revisionid": keywords["full"].strip(),
-                    "dirty": False, "error": None,
-                    "date": date}
+            return {
+                "version": r,
+                "full-revisionid": keywords["full"].strip(),
+                "dirty": False,
+                "error": None,
+                "date": date,
+            }
     # no suitable tags, so version is "0+unknown", but full hex is still there
     if verbose:
         print("no suitable tags, using unknown + full revision id")
-    return {"version": "0+unknown",
-            "full-revisionid": keywords["full"].strip(),
-            "dirty": False, "error": "no suitable tags", "date": None}
+    return {
+        "version": "0+unknown",
+        "full-revisionid": keywords["full"].strip(),
+        "dirty": False,
+        "error": "no suitable tags",
+        "date": None,
+    }
 
 
 @register_vcs_handler("git", "pieces_from_vcs")
@@ -1037,8 +1057,9 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command):
     if sys.platform == "win32":
         GITS = ["git.cmd", "git.exe"]
 
-    out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root,
-                          hide_stderr=True)
+    out, rc = run_command(
+        GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=True
+    )
     if rc != 0:
         if verbose:
             print("Directory %s not under git control" % root)
@@ -1046,10 +1067,19 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command):
 
     # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty]
     # if there isn't one, this yields HEX[-dirty] (no NUM)
-    describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty",
-                                          "--always", "--long",
-                                          "--match", "%s*" % tag_prefix],
-                                   cwd=root)
+    describe_out, rc = run_command(
+        GITS,
+        [
+            "describe",
+            "--tags",
+            "--dirty",
+            "--always",
+            "--long",
+            "--match",
+            "%s*" % tag_prefix,
+        ],
+        cwd=root,
+    )
     # --long was added in git-1.5.5
     if describe_out is None:
         raise NotThisMethod("'git describe' failed")
@@ -1072,17 +1102,18 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command):
     dirty = git_describe.endswith("-dirty")
     pieces["dirty"] = dirty
     if dirty:
-        git_describe = git_describe[:git_describe.rindex("-dirty")]
+        git_describe = git_describe[: git_describe.rindex("-dirty")]
 
     # now we have TAG-NUM-gHEX or HEX
 
     if "-" in git_describe:
         # TAG-NUM-gHEX
-        mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe)
+        mo = re.search(r"^(.+)-(\d+)-g([0-9a-f]+)$", git_describe)
         if not mo:
             # unparseable. Maybe git-describe is misbehaving?
-            pieces["error"] = ("unable to parse git-describe output: '%s'"
-                               % describe_out)
+            pieces["error"] = (
+                "unable to parse git-describe output: '%s'" % describe_out
+            )
             return pieces
 
         # tag
@@ -1091,10 +1122,12 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command):
             if verbose:
                 fmt = "tag '%s' doesn't start with prefix '%s'"
                 print(fmt % (full_tag, tag_prefix))
-            pieces["error"] = ("tag '%s' doesn't start with prefix '%s'"
-                               % (full_tag, tag_prefix))
+            pieces["error"] = "tag '%s' doesn't start with prefix '%s'" % (
+                full_tag,
+                tag_prefix,
+            )
             return pieces
-        pieces["closest-tag"] = full_tag[len(tag_prefix):]
+        pieces["closest-tag"] = full_tag[len(tag_prefix) :]
 
         # distance: number of commits since tag
         pieces["distance"] = int(mo.group(2))
@@ -1105,13 +1138,15 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command):
     else:
         # HEX: no tags
         pieces["closest-tag"] = None
-        count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"],
-                                    cwd=root)
+        count_out, rc = run_command(
+            GITS, ["rev-list", "HEAD", "--count"], cwd=root
+        )
         pieces["distance"] = int(count_out)  # total number of commits
 
     # commit date: see ISO-8601 comment in git_versions_from_keywords()
-    date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"],
-                       cwd=root)[0].strip()
+    date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root)[
+        0
+    ].strip()
     pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1)
 
     return pieces
@@ -1167,16 +1202,22 @@ def versions_from_parentdir(parentdir_prefix, root, verbose):
     for i in range(3):
         dirname = os.path.basename(root)
         if dirname.startswith(parentdir_prefix):
-            return {"version": dirname[len(parentdir_prefix):],
-                    "full-revisionid": None,
-                    "dirty": False, "error": None, "date": None}
+            return {
+                "version": dirname[len(parentdir_prefix) :],
+                "full-revisionid": None,
+                "dirty": False,
+                "error": None,
+                "date": None,
+            }
         else:
             rootdirs.append(root)
             root = os.path.dirname(root)  # up a level
 
     if verbose:
-        print("Tried directories %s but none started with prefix %s" %
-              (str(rootdirs), parentdir_prefix))
+        print(
+            "Tried directories %s but none started with prefix %s"
+            % (str(rootdirs), parentdir_prefix)
+        )
     raise NotThisMethod("rootdir doesn't start with parentdir_prefix")
 
 
@@ -1205,11 +1246,17 @@ def versions_from_file(filename):
             contents = f.read()
     except EnvironmentError:
         raise NotThisMethod("unable to read _version.py")
-    mo = re.search(r"version_json = '''\n(.*)'''  # END VERSION_JSON",
-                   contents, re.M | re.S)
+    mo = re.search(
+        r"version_json = '''\n(.*)'''  # END VERSION_JSON",
+        contents,
+        re.M | re.S,
+    )
     if not mo:
-        mo = re.search(r"version_json = '''\r\n(.*)'''  # END VERSION_JSON",
-                       contents, re.M | re.S)
+        mo = re.search(
+            r"version_json = '''\r\n(.*)'''  # END VERSION_JSON",
+            contents,
+            re.M | re.S,
+        )
     if not mo:
         raise NotThisMethod("no version_json in _version.py")
     return json.loads(mo.group(1))
@@ -1218,8 +1265,9 @@ def versions_from_file(filename):
 def write_to_version_file(filename, versions):
     """Write the given version number to the given _version.py file."""
     os.unlink(filename)
-    contents = json.dumps(versions, sort_keys=True,
-                          indent=1, separators=(",", ": "))
+    contents = json.dumps(
+        versions, sort_keys=True, indent=1, separators=(",", ": ")
+    )
     with open(filename, "w") as f:
         f.write(SHORT_VERSION_PY % contents)
 
@@ -1251,8 +1299,7 @@ def render_pep440(pieces):
                 rendered += ".dirty"
     else:
         # exception #1
-        rendered = "0+untagged.%d.g%s" % (pieces["distance"],
-                                          pieces["short"])
+        rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"])
         if pieces["dirty"]:
             rendered += ".dirty"
     return rendered
@@ -1366,11 +1413,13 @@ def render_git_describe_long(pieces):
 def render(pieces, style):
     """Render the given version pieces into the requested style."""
     if pieces["error"]:
-        return {"version": "unknown",
-                "full-revisionid": pieces.get("long"),
-                "dirty": None,
-                "error": pieces["error"],
-                "date": None}
+        return {
+            "version": "unknown",
+            "full-revisionid": pieces.get("long"),
+            "dirty": None,
+            "error": pieces["error"],
+            "date": None,
+        }
 
     if not style or style == "default":
         style = "pep440"  # the default
@@ -1390,9 +1439,13 @@ def render(pieces, style):
     else:
         raise ValueError("unknown style '%s'" % style)
 
-    return {"version": rendered, "full-revisionid": pieces["long"],
-            "dirty": pieces["dirty"], "error": None,
-            "date": pieces.get("date")}
+    return {
+        "version": rendered,
+        "full-revisionid": pieces["long"],
+        "dirty": pieces["dirty"],
+        "error": None,
+        "date": pieces.get("date"),
+    }
 
 
 class VersioneerBadRootError(Exception):
@@ -1415,8 +1468,9 @@ def get_versions(verbose=False):
     handlers = HANDLERS.get(cfg.VCS)
     assert handlers, "unrecognized VCS '%s'" % cfg.VCS
     verbose = verbose or cfg.verbose
-    assert cfg.versionfile_source is not None, \
-        "please set versioneer.versionfile_source"
+    assert (
+        cfg.versionfile_source is not None
+    ), "please set versioneer.versionfile_source"
     assert cfg.tag_prefix is not None, "please set versioneer.tag_prefix"
 
     versionfile_abs = os.path.join(root, cfg.versionfile_source)
@@ -1470,9 +1524,13 @@ def get_versions(verbose=False):
     if verbose:
         print("unable to compute version")
 
-    return {"version": "0+unknown", "full-revisionid": None,
-            "dirty": None, "error": "unable to compute version",
-            "date": None}
+    return {
+        "version": "0+unknown",
+        "full-revisionid": None,
+        "dirty": None,
+        "error": "unable to compute version",
+        "date": None,
+    }
 
 
 def get_version():
@@ -1521,6 +1579,7 @@ def run(self):
             print(" date: %s" % vers.get("date"))
             if vers["error"]:
                 print(" error: %s" % vers["error"])
+
     cmds["version"] = cmd_version
 
     # we override "build_py" in both distutils and setuptools
@@ -1553,14 +1612,17 @@ def run(self):
             # now locate _version.py in the new build/ directory and replace
             # it with an updated value
             if cfg.versionfile_build:
-                target_versionfile = os.path.join(self.build_lib,
-                                                  cfg.versionfile_build)
+                target_versionfile = os.path.join(
+                    self.build_lib, cfg.versionfile_build
+                )
                 print("UPDATING %s" % target_versionfile)
                 write_to_version_file(target_versionfile, versions)
+
     cmds["build_py"] = cmd_build_py
 
     if "cx_Freeze" in sys.modules:  # cx_freeze enabled?
         from cx_Freeze.dist import build_exe as _build_exe
+
         # nczeczulin reports that py2exe won't like the pep440-style string
         # as FILEVERSION, but it can be used for PRODUCTVERSION, e.g.
         # setup(console=[{
@@ -1581,17 +1643,21 @@ def run(self):
                 os.unlink(target_versionfile)
                 with open(cfg.versionfile_source, "w") as f:
                     LONG = LONG_VERSION_PY[cfg.VCS]
-                    f.write(LONG %
-                            {"DOLLAR": "$",
-                             "STYLE": cfg.style,
-                             "TAG_PREFIX": cfg.tag_prefix,
-                             "PARENTDIR_PREFIX": cfg.parentdir_prefix,
-                             "VERSIONFILE_SOURCE": cfg.versionfile_source,
-                             })
+                    f.write(
+                        LONG
+                        % {
+                            "DOLLAR": "$",
+                            "STYLE": cfg.style,
+                            "TAG_PREFIX": cfg.tag_prefix,
+                            "PARENTDIR_PREFIX": cfg.parentdir_prefix,
+                            "VERSIONFILE_SOURCE": cfg.versionfile_source,
+                        }
+                    )
+
         cmds["build_exe"] = cmd_build_exe
         del cmds["build_py"]
 
-    if 'py2exe' in sys.modules:  # py2exe enabled?
+    if "py2exe" in sys.modules:  # py2exe enabled?
         try:
             from py2exe.distutils_buildexe import py2exe as _py2exe  # py3
         except ImportError:
@@ -1610,13 +1676,17 @@ def run(self):
                 os.unlink(target_versionfile)
                 with open(cfg.versionfile_source, "w") as f:
                     LONG = LONG_VERSION_PY[cfg.VCS]
-                    f.write(LONG %
-                            {"DOLLAR": "$",
-                             "STYLE": cfg.style,
-                             "TAG_PREFIX": cfg.tag_prefix,
-                             "PARENTDIR_PREFIX": cfg.parentdir_prefix,
-                             "VERSIONFILE_SOURCE": cfg.versionfile_source,
-                             })
+                    f.write(
+                        LONG
+                        % {
+                            "DOLLAR": "$",
+                            "STYLE": cfg.style,
+                            "TAG_PREFIX": cfg.tag_prefix,
+                            "PARENTDIR_PREFIX": cfg.parentdir_prefix,
+                            "VERSIONFILE_SOURCE": cfg.versionfile_source,
+                        }
+                    )
+
         cmds["py2exe"] = cmd_py2exe
 
     # we override different "sdist" commands for both environments
@@ -1643,8 +1713,10 @@ def make_release_tree(self, base_dir, files):
             # updated value
             target_versionfile = os.path.join(base_dir, cfg.versionfile_source)
             print("UPDATING %s" % target_versionfile)
-            write_to_version_file(target_versionfile,
-                                  self._versioneer_generated_versions)
+            write_to_version_file(
+                target_versionfile, self._versioneer_generated_versions
+            )
+
     cmds["sdist"] = cmd_sdist
 
     return cmds
@@ -1699,11 +1771,15 @@ def do_setup():
     root = get_root()
     try:
         cfg = get_config_from_root(root)
-    except (EnvironmentError, configparser.NoSectionError,
-            configparser.NoOptionError) as e:
+    except (
+        EnvironmentError,
+        configparser.NoSectionError,
+        configparser.NoOptionError,
+    ) as e:
         if isinstance(e, (EnvironmentError, configparser.NoSectionError)):
-            print("Adding sample versioneer config to setup.cfg",
-                  file=sys.stderr)
+            print(
+                "Adding sample versioneer config to setup.cfg", file=sys.stderr
+            )
             with open(os.path.join(root, "setup.cfg"), "a") as f:
                 f.write(SAMPLE_CONFIG)
         print(CONFIG_ERROR, file=sys.stderr)
@@ -1712,15 +1788,18 @@ def do_setup():
     print(" creating %s" % cfg.versionfile_source)
     with open(cfg.versionfile_source, "w") as f:
         LONG = LONG_VERSION_PY[cfg.VCS]
-        f.write(LONG % {"DOLLAR": "$",
-                        "STYLE": cfg.style,
-                        "TAG_PREFIX": cfg.tag_prefix,
-                        "PARENTDIR_PREFIX": cfg.parentdir_prefix,
-                        "VERSIONFILE_SOURCE": cfg.versionfile_source,
-                        })
-
-    ipy = os.path.join(os.path.dirname(cfg.versionfile_source),
-                       "__init__.py")
+        f.write(
+            LONG
+            % {
+                "DOLLAR": "$",
+                "STYLE": cfg.style,
+                "TAG_PREFIX": cfg.tag_prefix,
+                "PARENTDIR_PREFIX": cfg.parentdir_prefix,
+                "VERSIONFILE_SOURCE": cfg.versionfile_source,
+            }
+        )
+
+    ipy = os.path.join(os.path.dirname(cfg.versionfile_source), "__init__.py")
     if os.path.exists(ipy):
         try:
             with open(ipy, "r") as f:
@@ -1762,8 +1841,10 @@ def do_setup():
     else:
         print(" 'versioneer.py' already in MANIFEST.in")
     if cfg.versionfile_source not in simple_includes:
-        print(" appending versionfile_source ('%s') to MANIFEST.in" %
-              cfg.versionfile_source)
+        print(
+            " appending versionfile_source ('%s') to MANIFEST.in"
+            % cfg.versionfile_source
+        )
         with open(manifest_in, "a") as f:
             f.write("include %s\n" % cfg.versionfile_source)
     else:
diff --git a/webexteamssdk/__init__.py b/webexteamssdk/__init__.py
index 45c18ea..3806fa0 100644
--- a/webexteamssdk/__init__.py
+++ b/webexteamssdk/__init__.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Community-developed Python SDK for the Webex Teams APIs.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
@@ -34,20 +33,53 @@
 
 import webexteamssdk.models.cards as cards
 from ._metadata import (
-    __author__, __author_email__, __copyright__, __description__,
-    __download_url__, __license__, __title__, __url__, __version__,
+    __author__,
+    __author_email__,
+    __copyright__,
+    __description__,
+    __download_url__,
+    __license__,
+    __title__,
+    __url__,
+    __version__,
 )
 from .api import WebexTeamsAPI
 from .exceptions import (
-    AccessTokenError, ApiError, ApiWarning, MalformedResponse, RateLimitError,
-    RateLimitWarning, webexteamssdkException, webexteamssdkWarning,
+    AccessTokenError,
+    ApiError,
+    ApiWarning,
+    MalformedResponse,
+    RateLimitError,
+    RateLimitWarning,
+    webexteamssdkException,
+    webexteamssdkWarning,
 )
 from .models.dictionary import dict_data_factory
 from .models.immutable import (
-    AccessToken, AdminAuditEvent, AttachmentAction, Event, GuestIssuerToken,
-    immutable_data_factory, License, Membership, Message, Organization, Person,
-    Role, Room, RoomMeetingInfo, Team, TeamMembership, Webhook, WebhookEvent,
-    Recording
+    AccessToken,
+    AdminAuditEvent,
+    AttachmentAction,
+    Event,
+    GuestIssuerToken,
+    immutable_data_factory,
+    License,
+    Meeting,
+    MeetingInvitee,
+    MeetingRegistrant,
+    MeetingTemplate,
+    Membership,
+    Message,
+    Organization,
+    Person,
+    Recording,
+    Role,
+    Room,
+    RoomMeetingInfo,
+    RoomTab,
+    Team,
+    TeamMembership,
+    Webhook,
+    WebhookEvent,
 )
 from .models.simple import simple_data_factory, SimpleDataModel
 from .utils import WebexTeamsDateTime
diff --git a/webexteamssdk/_metadata.py b/webexteamssdk/_metadata.py
index e5ecd88..f4ce515 100644
--- a/webexteamssdk/_metadata.py
+++ b/webexteamssdk/_metadata.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Package metadata.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,13 +22,13 @@
 SOFTWARE.
 """
 
-__title__ = 'webexteamssdk'
-__description__ = 'Community-developed Python SDK for the Webex Teams APIs'
-__url__ = 'https://github.com/CiscoDevNet/webexteamssdk'
-__download_url__ = 'https://pypi.python.org/pypi/webexteamssdk'
-__author__ = 'Chris Lunsford'
-__author_email__ = 'chrlunsf@cisco.com'
-__copyright__ = "Copyright (c) 2016-2020 Cisco and/or its affiliates."
+__title__ = "webexteamssdk"
+__description__ = "Community-developed Python SDK for the Webex Teams APIs"
+__url__ = "https://github.com/CiscoDevNet/webexteamssdk"
+__download_url__ = "https://pypi.python.org/pypi/webexteamssdk"
+__author__ = "Chris Lunsford"
+__author_email__ = "chrlunsf@cisco.com"
+__copyright__ = "Copyright (c) 2016-2024 Cisco and/or its affiliates."
 __license__ = "MIT"
 
 
@@ -36,5 +36,6 @@
 # imported.
 if __name__ == "webexteamssdk._metadata":
     from ._version import get_versions
-    __version__ = get_versions()['version']
+
+    __version__ = get_versions()["version"]
     del get_versions
diff --git a/webexteamssdk/_version.py b/webexteamssdk/_version.py
index 4bb8350..e4a338f 100644
--- a/webexteamssdk/_version.py
+++ b/webexteamssdk/_version.py
@@ -1,4 +1,3 @@
-
 # This file helps to compute a version number in source trees obtained from
 # git-archive tarball (such as those provided by githubs download-from-tag
 # feature). Distribution tarballs (built by setup.py sdist) and build
@@ -58,17 +57,20 @@ class NotThisMethod(Exception):
 
 def register_vcs_handler(vcs, method):  # decorator
     """Decorator to mark a method as the handler for a particular VCS."""
+
     def decorate(f):
         """Store f in HANDLERS[vcs][method]."""
         if vcs not in HANDLERS:
             HANDLERS[vcs] = {}
         HANDLERS[vcs][method] = f
         return f
+
     return decorate
 
 
-def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False,
-                env=None):
+def run_command(
+    commands, args, cwd=None, verbose=False, hide_stderr=False, env=None
+):
     """Call the given command(s)."""
     assert isinstance(commands, list)
     p = None
@@ -76,10 +78,13 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False,
         try:
             dispcmd = str([c] + args)
             # remember shell=False, so use git.cmd on windows, not just git
-            p = subprocess.Popen([c] + args, cwd=cwd, env=env,
-                                 stdout=subprocess.PIPE,
-                                 stderr=(subprocess.PIPE if hide_stderr
-                                         else None))
+            p = subprocess.Popen(
+                [c] + args,
+                cwd=cwd,
+                env=env,
+                stdout=subprocess.PIPE,
+                stderr=(subprocess.PIPE if hide_stderr else None),
+            )
             break
         except EnvironmentError:
             e = sys.exc_info()[1]
@@ -116,16 +121,22 @@ def versions_from_parentdir(parentdir_prefix, root, verbose):
     for i in range(3):
         dirname = os.path.basename(root)
         if dirname.startswith(parentdir_prefix):
-            return {"version": dirname[len(parentdir_prefix):],
-                    "full-revisionid": None,
-                    "dirty": False, "error": None, "date": None}
+            return {
+                "version": dirname[len(parentdir_prefix) :],
+                "full-revisionid": None,
+                "dirty": False,
+                "error": None,
+                "date": None,
+            }
         else:
             rootdirs.append(root)
             root = os.path.dirname(root)  # up a level
 
     if verbose:
-        print("Tried directories %s but none started with prefix %s" %
-              (str(rootdirs), parentdir_prefix))
+        print(
+            "Tried directories %s but none started with prefix %s"
+            % (str(rootdirs), parentdir_prefix)
+        )
     raise NotThisMethod("rootdir doesn't start with parentdir_prefix")
 
 
@@ -181,7 +192,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose):
     # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of
     # just "foo-1.0". If we see a "tag: " prefix, prefer those.
     TAG = "tag: "
-    tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)])
+    tags = set([r[len(TAG) :] for r in refs if r.startswith(TAG)])
     if not tags:
         # Either we're using git < 1.8.3, or there really are no tags. We use
         # a heuristic: assume all version tags have a digit. The old git %d
@@ -190,7 +201,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose):
         # between branches and tags. By ignoring refnames without digits, we
         # filter out many common branch names like "release" and
         # "stabilization", as well as "HEAD" and "master".
-        tags = set([r for r in refs if re.search(r'\d', r)])
+        tags = set([r for r in refs if re.search(r"\d", r)])
         if verbose:
             print("discarding '%s', no digits" % ",".join(refs - tags))
     if verbose:
@@ -198,19 +209,26 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose):
     for ref in sorted(tags):
         # sorting will prefer e.g. "2.0" over "2.0rc1"
         if ref.startswith(tag_prefix):
-            r = ref[len(tag_prefix):]
+            r = ref[len(tag_prefix) :]
             if verbose:
                 print("picking %s" % r)
-            return {"version": r,
-                    "full-revisionid": keywords["full"].strip(),
-                    "dirty": False, "error": None,
-                    "date": date}
+            return {
+                "version": r,
+                "full-revisionid": keywords["full"].strip(),
+                "dirty": False,
+                "error": None,
+                "date": date,
+            }
     # no suitable tags, so version is "0+unknown", but full hex is still there
     if verbose:
         print("no suitable tags, using unknown + full revision id")
-    return {"version": "0+unknown",
-            "full-revisionid": keywords["full"].strip(),
-            "dirty": False, "error": "no suitable tags", "date": None}
+    return {
+        "version": "0+unknown",
+        "full-revisionid": keywords["full"].strip(),
+        "dirty": False,
+        "error": "no suitable tags",
+        "date": None,
+    }
 
 
 @register_vcs_handler("git", "pieces_from_vcs")
@@ -225,8 +243,9 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command):
     if sys.platform == "win32":
         GITS = ["git.cmd", "git.exe"]
 
-    out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root,
-                          hide_stderr=True)
+    out, rc = run_command(
+        GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=True
+    )
     if rc != 0:
         if verbose:
             print("Directory %s not under git control" % root)
@@ -234,10 +253,19 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command):
 
     # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty]
     # if there isn't one, this yields HEX[-dirty] (no NUM)
-    describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty",
-                                          "--always", "--long",
-                                          "--match", "%s*" % tag_prefix],
-                                   cwd=root)
+    describe_out, rc = run_command(
+        GITS,
+        [
+            "describe",
+            "--tags",
+            "--dirty",
+            "--always",
+            "--long",
+            "--match",
+            "%s*" % tag_prefix,
+        ],
+        cwd=root,
+    )
     # --long was added in git-1.5.5
     if describe_out is None:
         raise NotThisMethod("'git describe' failed")
@@ -260,17 +288,18 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command):
     dirty = git_describe.endswith("-dirty")
     pieces["dirty"] = dirty
     if dirty:
-        git_describe = git_describe[:git_describe.rindex("-dirty")]
+        git_describe = git_describe[: git_describe.rindex("-dirty")]
 
     # now we have TAG-NUM-gHEX or HEX
 
     if "-" in git_describe:
         # TAG-NUM-gHEX
-        mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe)
+        mo = re.search(r"^(.+)-(\d+)-g([0-9a-f]+)$", git_describe)
         if not mo:
             # unparseable. Maybe git-describe is misbehaving?
-            pieces["error"] = ("unable to parse git-describe output: '%s'"
-                               % describe_out)
+            pieces["error"] = (
+                "unable to parse git-describe output: '%s'" % describe_out
+            )
             return pieces
 
         # tag
@@ -279,10 +308,12 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command):
             if verbose:
                 fmt = "tag '%s' doesn't start with prefix '%s'"
                 print(fmt % (full_tag, tag_prefix))
-            pieces["error"] = ("tag '%s' doesn't start with prefix '%s'"
-                               % (full_tag, tag_prefix))
+            pieces["error"] = "tag '%s' doesn't start with prefix '%s'" % (
+                full_tag,
+                tag_prefix,
+            )
             return pieces
-        pieces["closest-tag"] = full_tag[len(tag_prefix):]
+        pieces["closest-tag"] = full_tag[len(tag_prefix) :]
 
         # distance: number of commits since tag
         pieces["distance"] = int(mo.group(2))
@@ -293,13 +324,15 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command):
     else:
         # HEX: no tags
         pieces["closest-tag"] = None
-        count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"],
-                                    cwd=root)
+        count_out, rc = run_command(
+            GITS, ["rev-list", "HEAD", "--count"], cwd=root
+        )
         pieces["distance"] = int(count_out)  # total number of commits
 
     # commit date: see ISO-8601 comment in git_versions_from_keywords()
-    date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"],
-                       cwd=root)[0].strip()
+    date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root)[
+        0
+    ].strip()
     pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1)
 
     return pieces
@@ -330,8 +363,7 @@ def render_pep440(pieces):
                 rendered += ".dirty"
     else:
         # exception #1
-        rendered = "0+untagged.%d.g%s" % (pieces["distance"],
-                                          pieces["short"])
+        rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"])
         if pieces["dirty"]:
             rendered += ".dirty"
     return rendered
@@ -445,11 +477,13 @@ def render_git_describe_long(pieces):
 def render(pieces, style):
     """Render the given version pieces into the requested style."""
     if pieces["error"]:
-        return {"version": "unknown",
-                "full-revisionid": pieces.get("long"),
-                "dirty": None,
-                "error": pieces["error"],
-                "date": None}
+        return {
+            "version": "unknown",
+            "full-revisionid": pieces.get("long"),
+            "dirty": None,
+            "error": pieces["error"],
+            "date": None,
+        }
 
     if not style or style == "default":
         style = "pep440"  # the default
@@ -469,9 +503,13 @@ def render(pieces, style):
     else:
         raise ValueError("unknown style '%s'" % style)
 
-    return {"version": rendered, "full-revisionid": pieces["long"],
-            "dirty": pieces["dirty"], "error": None,
-            "date": pieces.get("date")}
+    return {
+        "version": rendered,
+        "full-revisionid": pieces["long"],
+        "dirty": pieces["dirty"],
+        "error": None,
+        "date": pieces.get("date"),
+    }
 
 
 def get_versions():
@@ -485,8 +523,9 @@ def get_versions():
     verbose = cfg.verbose
 
     try:
-        return git_versions_from_keywords(get_keywords(), cfg.tag_prefix,
-                                          verbose)
+        return git_versions_from_keywords(
+            get_keywords(), cfg.tag_prefix, verbose
+        )
     except NotThisMethod:
         pass
 
@@ -495,13 +534,16 @@ def get_versions():
         # versionfile_source is the relative path from the top of the source
         # tree (where the .git directory might live) to this file. Invert
         # this to find the root from __file__.
-        for i in cfg.versionfile_source.split('/'):
+        for i in cfg.versionfile_source.split("/"):
             root = os.path.dirname(root)
     except NameError:
-        return {"version": "0+unknown", "full-revisionid": None,
-                "dirty": None,
-                "error": "unable to find root of source tree",
-                "date": None}
+        return {
+            "version": "0+unknown",
+            "full-revisionid": None,
+            "dirty": None,
+            "error": "unable to find root of source tree",
+            "date": None,
+        }
 
     try:
         pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose)
@@ -515,6 +557,10 @@ def get_versions():
     except NotThisMethod:
         pass
 
-    return {"version": "0+unknown", "full-revisionid": None,
-            "dirty": None,
-            "error": "unable to compute version", "date": None}
+    return {
+        "version": "0+unknown",
+        "full-revisionid": None,
+        "dirty": None,
+        "error": "unable to compute version",
+        "date": None,
+    }
diff --git a/webexteamssdk/api/__init__.py b/webexteamssdk/api/__init__.py
index 35d9fde..a64e386 100644
--- a/webexteamssdk/api/__init__.py
+++ b/webexteamssdk/api/__init__.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams API wrappers.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -25,7 +25,8 @@
 from past.types import basestring
 
 from webexteamssdk.config import (
-    DEFAULT_BASE_URL, DEFAULT_SINGLE_REQUEST_TIMEOUT,
+    DEFAULT_BASE_URL,
+    DEFAULT_SINGLE_REQUEST_TIMEOUT,
     DEFAULT_WAIT_ON_RATE_LIMIT,
 )
 from webexteamssdk.environment import WEBEX_TEAMS_ACCESS_TOKEN
@@ -69,18 +70,22 @@ class WebexTeamsAPI(object):
     them in a simple hierarchical structure.
     """
 
-    def __init__(self, access_token=None, base_url=DEFAULT_BASE_URL,
-                 single_request_timeout=DEFAULT_SINGLE_REQUEST_TIMEOUT,
-                 wait_on_rate_limit=DEFAULT_WAIT_ON_RATE_LIMIT,
-                 object_factory=immutable_data_factory,
-                 client_id=None,
-                 client_secret=None,
-                 oauth_code=None,
-                 redirect_uri=None,
-                 proxies=None,
-                 be_geo_id=None,
-                 caller=None,
-                 disable_ssl_verify=False):
+    def __init__(
+        self,
+        access_token=None,
+        base_url=DEFAULT_BASE_URL,
+        single_request_timeout=DEFAULT_SINGLE_REQUEST_TIMEOUT,
+        wait_on_rate_limit=DEFAULT_WAIT_ON_RATE_LIMIT,
+        object_factory=immutable_data_factory,
+        client_id=None,
+        client_secret=None,
+        oauth_code=None,
+        redirect_uri=None,
+        proxies=None,
+        be_geo_id=None,
+        caller=None,
+        disable_ssl_verify=False,
+    ):
         """Create a new WebexTeamsAPI object.
 
         An access token must be used when interacting with the Webex Teams API.
@@ -160,7 +165,8 @@ def __init__(self, access_token=None, base_url=DEFAULT_BASE_URL,
 
         # Init AccessTokensAPI wrapper early to use for oauth requests
         self.access_tokens = AccessTokensAPI(
-            base_url, object_factory,
+            base_url,
+            object_factory,
             single_request_timeout=single_request_timeout,
         )
 
@@ -171,12 +177,12 @@ def __init__(self, access_token=None, base_url=DEFAULT_BASE_URL,
                 client_id=client_id,
                 client_secret=client_secret,
                 code=oauth_code,
-                redirect_uri=redirect_uri
+                redirect_uri=redirect_uri,
             ).access_token
 
         # Set optional API metrics tracking variables from env vars if there
-        be_geo_id = be_geo_id or os.environ.get('BE_GEO_ID')
-        caller = caller or os.environ.get('WEBEX_PYTHON_SDK_CALLER')
+        be_geo_id = be_geo_id or os.environ.get("BE_GEO_ID")
+        caller = caller or os.environ.get("WEBEX_PYTHON_SDK_CALLER")
 
         # If an access token hasn't been provided as a parameter, environment
         # variable, or obtained via an OAuth exchange raise an error.
@@ -199,15 +205,17 @@ def __init__(self, access_token=None, base_url=DEFAULT_BASE_URL,
             proxies=proxies,
             be_geo_id=be_geo_id,
             caller=caller,
-            disable_ssl_verify=disable_ssl_verify
+            disable_ssl_verify=disable_ssl_verify,
         )
 
         # API wrappers
         self.admin_audit_events = AdminAuditEventsAPI(
-            self._session, object_factory,
+            self._session,
+            object_factory,
         )
         self.attachment_actions = AttachmentActionsAPI(
-            self._session, object_factory,
+            self._session,
+            object_factory,
         )
         self.events = EventsAPI(self._session, object_factory)
         self.guest_issuer = GuestIssuerAPI(self._session, object_factory)
@@ -221,14 +229,22 @@ def __init__(self, access_token=None, base_url=DEFAULT_BASE_URL,
         self.room_tabs = RoomTabsAPI(self._session, object_factory)
         self.teams = TeamsAPI(self._session, object_factory)
         self.team_memberships = TeamMembershipsAPI(
-            self._session, object_factory,
+            self._session,
+            object_factory,
         )
         self.webhooks = WebhooksAPI(self._session, object_factory)
         self.recordings = RecordingsAPI(self._session, object_factory)
         self.meetings = MeetingsAPI(self._session, object_factory)
-        self.meeting_templates = MeetingTemplatesAPI(self._session, object_factory)
-        self.meeting_invitees = MeetingInviteesAPI(self._session, object_factory)
-        self.meeting_registrants = MeetingRegistrantsAPI(self._session, object_factory)
+        self.meeting_templates = MeetingTemplatesAPI(
+            self._session, object_factory
+        )
+        self.meeting_invitees = MeetingInviteesAPI(
+            self._session, object_factory
+        )
+        self.meeting_registrants = MeetingRegistrantsAPI(
+            self._session, object_factory
+        )
+
     @property
     def access_token(self):
         """The access token used for API calls to the Webex Teams service."""
@@ -281,8 +297,9 @@ def from_oauth_code(cls, client_id, client_secret, code, redirect_uri):
             TypeError: If the parameter types are incorrect.
             ApiError: If the Webex Teams cloud returns an error.
         """
-        token_obj = cls.access_tokens.get(client_id, client_secret, code,
-                                          redirect_uri)
+        token_obj = cls.access_tokens.get(
+            client_id, client_secret, code, redirect_uri
+        )
 
         return cls(access_token=token_obj.access_token)
 
@@ -308,6 +325,7 @@ def from_oauth_refresh(cls, client_id, client_secret, refresh_token):
             TypeError: If the parameter types are incorrect.
             ApiError: If the Webex Teams cloud returns an error.
         """
-        token_obj = cls.access_tokens.refresh(client_id, client_secret,
-                                              refresh_token)
+        token_obj = cls.access_tokens.refresh(
+            client_id, client_secret, refresh_token
+        )
         return cls(access_token=token_obj.access_token)
diff --git a/webexteamssdk/api/access_tokens.py b/webexteamssdk/api/access_tokens.py
index aade7b5..8354c74 100644
--- a/webexteamssdk/api/access_tokens.py
+++ b/webexteamssdk/api/access_tokens.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Access-Tokens API wrapper.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
@@ -31,6 +30,7 @@
 )
 
 from future import standard_library
+
 standard_library.install_aliases()
 
 from builtins import *
@@ -49,8 +49,8 @@
 )
 
 
-API_ENDPOINT = 'access_token'
-OBJECT_TYPE = 'access_token'
+API_ENDPOINT = "access_token"
+OBJECT_TYPE = "access_token"
 
 
 class AccessTokensAPI(object):
@@ -133,9 +133,10 @@ def get(self, client_id, client_secret, code, redirect_uri):
         )
 
         # API request
-        response = requests.post(self._endpoint_url, data=post_data,
-                                 **self._request_kwargs)
-        check_response_code(response, EXPECTED_RESPONSE_CODE['POST'])
+        response = requests.post(
+            self._endpoint_url, data=post_data, **self._request_kwargs
+        )
+        check_response_code(response, EXPECTED_RESPONSE_CODE["POST"])
         json_data = extract_and_parse_json(response)
 
         # Return a access_token object created from the response JSON data
@@ -172,9 +173,10 @@ def refresh(self, client_id, client_secret, refresh_token):
         )
 
         # API request
-        response = requests.post(self._endpoint_url, data=post_data,
-                                 **self._request_kwargs)
-        check_response_code(response, EXPECTED_RESPONSE_CODE['POST'])
+        response = requests.post(
+            self._endpoint_url, data=post_data, **self._request_kwargs
+        )
+        check_response_code(response, EXPECTED_RESPONSE_CODE["POST"])
         json_data = extract_and_parse_json(response)
 
         # Return a AccessToken object created from the response JSON data
diff --git a/webexteamssdk/api/admin_audit_events.py b/webexteamssdk/api/admin_audit_events.py
index 6f4154c..2d0be55 100644
--- a/webexteamssdk/api/admin_audit_events.py
+++ b/webexteamssdk/api/admin_audit_events.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Admin Audit Events API wrapper.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
@@ -39,8 +38,8 @@
 from webexteamssdk.utils import check_type, dict_from_items_with_values
 
 
-API_ENDPOINT = 'adminAudit/events'
-OBJECT_TYPE = 'admin_audit_event'
+API_ENDPOINT = "adminAudit/events"
+OBJECT_TYPE = "admin_audit_event"
 
 
 class AdminAuditEventsAPI(object):
@@ -70,8 +69,16 @@ def __init__(self, session, object_factory):
         self._object_factory = object_factory
 
     @generator_container
-    def list(self, orgId, _from, to, actorId=None, max=100, offset=0,
-             **request_parameters):
+    def list(
+        self,
+        orgId,
+        _from,
+        to,
+        actorId=None,
+        max=100,
+        offset=0,
+        **request_parameters,
+    ):
         """List Organizations.
 
         This method supports Webex Teams's implementation of RFC5988 Web
diff --git a/webexteamssdk/api/attachment_actions.py b/webexteamssdk/api/attachment_actions.py
index 157b7c0..d844847 100644
--- a/webexteamssdk/api/attachment_actions.py
+++ b/webexteamssdk/api/attachment_actions.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Attachment Actions API wrapper.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
@@ -39,8 +38,8 @@
 from ..utils import check_type, dict_from_items_with_values
 
 
-API_ENDPOINT = 'attachment/actions'
-OBJECT_TYPE = 'attachment_action'
+API_ENDPOINT = "attachment/actions"
+OBJECT_TYPE = "attachment_action"
 
 
 class AttachmentActionsAPI(object):
@@ -95,10 +94,7 @@ def create(self, type, messageId, inputs, **request_parameters):
         check_type(inputs, dict)
 
         post_data = dict_from_items_with_values(
-            request_parameters,
-            type=type,
-            messageId=messageId,
-            inputs=inputs
+            request_parameters, type=type, messageId=messageId, inputs=inputs
         )
 
         json_data = self._session.post(API_ENDPOINT, json=post_data)
@@ -124,7 +120,7 @@ def get(self, id):
         check_type(id, basestring)
 
         # API request
-        json_data = self._session.get(API_ENDPOINT + '/' + id)
+        json_data = self._session.get(API_ENDPOINT + "/" + id)
 
         # Return a message object created from the response JSON data
         return self._object_factory(OBJECT_TYPE, json_data)
diff --git a/webexteamssdk/api/events.py b/webexteamssdk/api/events.py
index 51d3dae..1d46ab0 100644
--- a/webexteamssdk/api/events.py
+++ b/webexteamssdk/api/events.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Events API wrapper.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
@@ -42,8 +41,8 @@
 )
 
 
-API_ENDPOINT = 'events'
-OBJECT_TYPE = 'event'
+API_ENDPOINT = "events"
+OBJECT_TYPE = "event"
 
 
 class EventsAPI(object):
@@ -73,8 +72,16 @@ def __init__(self, session, object_factory):
         self._object_factory = object_factory
 
     @generator_container
-    def list(self, resource=None, type=None, actorId=None, _from=None, to=None,
-             max=None, **request_parameters):
+    def list(
+        self,
+        resource=None,
+        type=None,
+        actorId=None,
+        _from=None,
+        to=None,
+        max=None,
+        **request_parameters,
+    ):
         """List events.
 
         List events in your organization. Several query parameters are
@@ -162,7 +169,7 @@ def get(self, eventId):
         check_type(eventId, basestring)
 
         # API request
-        json_data = self._session.get(API_ENDPOINT + '/' + eventId)
+        json_data = self._session.get(API_ENDPOINT + "/" + eventId)
 
         # Return a room object created from the response JSON data
         return self._object_factory(OBJECT_TYPE, json_data)
diff --git a/webexteamssdk/api/guest_issuer.py b/webexteamssdk/api/guest_issuer.py
index db2afde..4d484f3 100644
--- a/webexteamssdk/api/guest_issuer.py
+++ b/webexteamssdk/api/guest_issuer.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Guest Issuer API wrapper.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -38,7 +38,7 @@
 from ..utils import (
     check_type,
     dict_from_items_with_values,
-    check_response_code
+    check_response_code,
 )
 from ..response_codes import EXPECTED_RESPONSE_CODE
 
@@ -110,23 +110,18 @@ def create(self, sub, name, iss, exp, secret):
         check_type(exp, basestring)
         check_type(secret, basestring)
 
-        payload = {
-            "sub": sub,
-            "name": name,
-            "iss": iss,
-            "exp": exp
-        }
+        payload = {"sub": sub, "name": name, "iss": iss, "exp": exp}
 
         key = base64.b64decode(secret)
         jwt_token = jwt.encode(payload, key, algorithm="HS256")
 
-        headers = {
-            "Authorization": "Bearer " + jwt_token.decode("utf-8")
-        }
+        # TODO: Remove `.decode("utf-8")` when Python 2 is no longer supported
+        # v1.7.1 is the last release of PyJWT that supports Python 2, and it
+        # returns a byte string for the JWT token.
+        headers = {"Authorization": "Bearer " + jwt_token.decode("utf-8")}
 
         json_data = self._session.post(
-            API_ENDPOINT + "/" + "login",
-            headers=headers
+            API_ENDPOINT + "/" + "login", headers=headers
         )
 
         return self._object_factory(OBJECT_TYPE, json_data)
diff --git a/webexteamssdk/api/licenses.py b/webexteamssdk/api/licenses.py
index 49a51e3..0ac92ed 100644
--- a/webexteamssdk/api/licenses.py
+++ b/webexteamssdk/api/licenses.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Licenses API wrapper.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
@@ -42,8 +41,8 @@
 )
 
 
-API_ENDPOINT = 'licenses'
-OBJECT_TYPE = 'license'
+API_ENDPOINT = "licenses"
+OBJECT_TYPE = "license"
 
 
 class LicensesAPI(object):
@@ -125,7 +124,7 @@ def get(self, licenseId):
         check_type(licenseId, basestring)
 
         # API request
-        json_data = self._session.get(API_ENDPOINT + '/' + licenseId)
+        json_data = self._session.get(API_ENDPOINT + "/" + licenseId)
 
         # Return a license object created from the returned JSON object
         return self._object_factory(OBJECT_TYPE, json_data)
diff --git a/webexteamssdk/api/meeting_invitees.py b/webexteamssdk/api/meeting_invitees.py
index 4dcfc9e..85a2543 100644
--- a/webexteamssdk/api/meeting_invitees.py
+++ b/webexteamssdk/api/meeting_invitees.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex MeetingInvitees API wrapper.
 
-Copyright (c) 2016-2022 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
@@ -42,8 +41,8 @@
 )
 
 
-API_ENDPOINT = 'meetingInvitees'
-OBJECT_TYPE = 'meetingInvitee'
+API_ENDPOINT = "meetingInvitees"
+OBJECT_TYPE = "meetingInvitee"
 
 
 class MeetingInviteesAPI(object):
@@ -71,15 +70,17 @@ def __init__(self, session, object_factory):
 
         self._session = session
         self._object_factory = object_factory
-    
-    @generator_container
-    def list(self, meetingId,
-                   max=None,
-                   hostEmail=None,
-                   panelist=None,
-                   headers={},
-             **request_parameters):
 
+    @generator_container
+    def list(
+        self,
+        meetingId,
+        max=None,
+        hostEmail=None,
+        panelist=None,
+        headers=None,
+        **request_parameters,
+    ):
         """List meetingInvitees.
 
         Use query parameters to filter the response.
@@ -95,10 +96,13 @@ def list(self, meetingId,
         container.
 
         Args:
-            meetingId (basestring): Unique id of the meeting for which invitees are requested.
-            max (int): Limit the number of meeting invitees
-            hostEmail (basestring): Email address for the meeting host (requires admin scope)
-            panelist (bool): Filter invitees or attendees based on their panelist status
+            meetingId (basestring): Unique id of the meeting for which invitees
+                are requested.
+            max (int): Limit the number of meeting invitees.
+            hostEmail (basestring): Email address for the meeting host
+                (requires admin scope).
+            panelist (bool): Filter invitees or attendees based on their
+                panelist status.
             headers(dict): Additional headers to be passed.
             **request_parameters: Additional request parameters (provides
                 support for parameters that may be added in the future).
@@ -116,7 +120,9 @@ def list(self, meetingId,
         check_type(max, int, optional=True)
         check_type(hostEmail, basestring, optional=True)
         check_type(panelist, bool, optional=True)
-        
+        check_type(headers, dict, optional=True)
+
+        headers = headers or {}
 
         params = dict_from_items_with_values(
             request_parameters,
@@ -124,9 +130,8 @@ def list(self, meetingId,
             max=max,
             hostEmail=hostEmail,
             panelist=panelist,
-            
         )
-        
+
         # API request - get items
 
         # Update headers
@@ -135,38 +140,43 @@ def list(self, meetingId,
         items = self._session.get_items(API_ENDPOINT, params=params)
 
         # Remove headers
-        for k, v in headers.items():
+        for k in headers.keys():
             del self._session.headers[k]
 
         # Yield membership objects created from the returned items JSON objects
         for item in items:
             yield self._object_factory(OBJECT_TYPE, item)
-    
-    
-    def create(self, meetingId,
-                     email,
-                     displayName=None,
-                     coHost=None,
-                     hostEmail=None,
-                     sendEmail=None,
-                     panelist=None,
-                     **request_parameters):
+
+    def create(
+        self,
+        meetingId,
+        email,
+        displayName=None,
+        coHost=None,
+        hostEmail=None,
+        sendEmail=None,
+        panelist=None,
+        **request_parameters,
+    ):
         """Create a meetingInvitee.
 
         Args:
-            meetingId (basestring): Unique id for the meeting that the invitee is part of
-            email (basestring): Email address for the meeting invitee
-            displayName (basestring): Display name of the meeting invitee
-            coHost (bool): CoHost status of the invitee
-            hostEmail (basestring): Email address for the meeting host (requires admin scope)
-            sendEmail (bool): If true, send an e-mail to the invitee
-            panelist (bool): Flag to indicate if the invitee is panelist or not
+            meetingId (basestring): Unique id for the meeting that the invitee
+                is part of.
+            email (basestring): Email address for the meeting invitee.
+            displayName (basestring): Display name of the meeting invitee.
+            coHost (bool): CoHost status of the invitee.
+            hostEmail (basestring): Email address for the meeting host
+                (requires admin scope).
+            sendEmail (bool): If true, send an e-mail to the invitee.
+            panelist (bool): Flag to indicate if the invitee is panelist or
+                not.
             **request_parameters: Additional request parameters (provides
                 support for parameters that may be added in the future).
 
         Returns:
-            MeetingInvitee: A MeetingInvitee object with the details of the created
-            meetingInvitee.
+            MeetingInvitee: A MeetingInvitee object with the details of the
+            created meetingInvitee.
 
         Raises:
             TypeError: If the parameter types are incorrect.
@@ -180,7 +190,7 @@ def create(self, meetingId,
         check_type(hostEmail, basestring, optional=True)
         check_type(sendEmail, bool, optional=True)
         check_type(panelist, bool, optional=True)
-        
+
         post_data = dict_from_items_with_values(
             request_parameters,
             meetingId=meetingId,
@@ -190,18 +200,14 @@ def create(self, meetingId,
             hostEmail=hostEmail,
             sendEmail=sendEmail,
             panelist=panelist,
-            
         )
 
-        
         # API request
         json_data = self._session.post(API_ENDPOINT, json=post_data)
 
         # Return a membership object created from the response JSON data
         return self._object_factory(OBJECT_TYPE, json_data)
-    
 
-    
     def get(self, meetingInviteeId):
         """Get details for a meetingInvitee, by ID.
 
@@ -209,8 +215,8 @@ def get(self, meetingInviteeId):
             meetingInviteeId(basestring): The meetingInvitee ID.
 
         Returns:
-            MeetingInvitee: A MeetingInvitee object with the details of the requested
-            meetingInvitee.
+            MeetingInvitee: A MeetingInvitee object with the details of the
+            requested meetingInvitee.
 
         Raises:
             TypeError: If the parameter types are incorrect.
@@ -220,13 +226,11 @@ def get(self, meetingInviteeId):
         check_type(meetingInviteeId, basestring)
 
         # API request
-        json_data = self._session.get(API_ENDPOINT + '/' + meetingInviteeId)
+        json_data = self._session.get(API_ENDPOINT + "/" + meetingInviteeId)
 
         # Return a membership object created from the response JSON data
         return self._object_factory(OBJECT_TYPE, json_data)
-    
 
-    
     def delete(self, meetingInviteeId):
         """Delete a meetingInvitee, by ID.
 
@@ -241,28 +245,31 @@ def delete(self, meetingInviteeId):
         check_type(meetingInviteeId, basestring)
 
         # API request
-        self._session.delete(API_ENDPOINT + '/' + meetingInviteeId)
-    
-
-    
-    def update(self, meetingInviteeId,
-                     email,
-                     displayName=None,
-                     coHost=None,
-                     hostEmail=None,
-                     sendEmail=None,
-                     panelist=None,
-                     **request_parameters):
+        self._session.delete(API_ENDPOINT + "/" + meetingInviteeId)
+
+    def update(
+        self,
+        meetingInviteeId,
+        email,
+        displayName=None,
+        coHost=None,
+        hostEmail=None,
+        sendEmail=None,
+        panelist=None,
+        **request_parameters,
+    ):
         """Update properties for a meetingInvitee, by ID.
 
         Args:
             meetingInviteeId(basestring): The meetingInvitee ID.
-            email (basestring): Email address for the meeting invitee
-            displayName (basestring): Display name of the meeting invitee
-            coHost (bool): CoHost status of the invitee
-            hostEmail (basestring): Email address for the meeting host (requires admin scope)
-            sendEmail (bool): If true, send an e-mail to the invitee
-            panelist (bool): Flag to indicate if the invitee is panelist or not
+            email (basestring): Email address for the meeting invitee.
+            displayName (basestring): Display name of the meeting invitee.
+            coHost (bool): Cohost status of the invitee.
+            hostEmail (basestring): Email address for the meeting host
+                (requires admin scope).
+            sendEmail (bool): If true, send an e-mail to the invitee.
+            panelist (bool): Flag to indicate if the invitee is panelist or
+                not.
             **request_parameters: Additional request parameters (provides
                 support for parameters that may be added in the future).
 
@@ -282,7 +289,7 @@ def update(self, meetingInviteeId,
         check_type(hostEmail, basestring, optional=True)
         check_type(sendEmail, bool, optional=True)
         check_type(panelist, bool, optional=True)
-        
+
         put_data = dict_from_items_with_values(
             request_parameters,
             email=email,
@@ -291,58 +298,55 @@ def update(self, meetingInviteeId,
             hostEmail=hostEmail,
             sendEmail=sendEmail,
             panelist=panelist,
-            
         )
 
-        
-
         # API request
-        json_data = self._session.put(API_ENDPOINT + '/' + meetingInviteeId,
-                                      json=put_data)
+        json_data = self._session.put(
+            API_ENDPOINT + "/" + meetingInviteeId, json=put_data
+        )
 
         # Return a membership object created from the response JSON data
         return self._object_factory(OBJECT_TYPE, json_data)
-    
-    
-    def bulk(self, meetingId, hostEmail=None, items=None, **request_parameters):
-      """ Bulk insert meeting invitees
-
-      Args:
-        meetingId(basestring): Id of the meeting the invitees should be added to.
-        hostEmail(basestring): Email of the meeting host.
-        items(list): List of invitees. Each invitee is a dict with email as the
-          required key and displayName, coHost, sendEmail and panelist as optional
-          properties.
-        **request_parameters: Additional request parameters (provides
-              support for parameters that may be added in the future).
-      
-      Returns:
-        GeneratorContainer: A GeneratorContainer which, when iterated,
-          yields the meetingInvitees returned by the Webex query.
-
-      Raises:
-        TypeError: If the parameter types are incorrect.
-        ApiError: If the Webex Teams cloud returns an error.
-      """
-      check_type(meetingId, basestring)
-      check_type(hostEmail, basestring, optional=True)
-      check_type(items, list, optional=True)
-      
-      post_data = dict_from_items_with_values(
-          request_parameters,
-          meetingId=meetingId,
-          items=items,
-          hostEmail=hostEmail,
-      )
-
-      # API request
-      json_data = self._session.put(API_ENDPOINT + '/bulkInsert',
-                                    json=post_data)
-
-      # Return an object created from the response JSON data
-      for itm in json_data['items']:
-        yield self._object_factory(OBJECT_TYPE, itm)
-
-
-      
-    
\ No newline at end of file
+
+    def bulk(
+        self, meetingId, hostEmail=None, items=None, **request_parameters
+    ):
+        """Bulk insert meeting invitees
+
+        Args:
+          meetingId(basestring): Id of the meeting the invitees should be added
+            to.
+          hostEmail(basestring): Email of the meeting host.
+          items(list): List of invitees. Each invitee is a dict with email as
+            the required key and displayName, coHost, sendEmail and panelist as
+            optional properties.
+          **request_parameters: Additional request parameters (provides
+                support for parameters that may be added in the future).
+
+        Returns:
+          GeneratorContainer: A GeneratorContainer which, when iterated,
+            yields the meetingInvitees returned by the Webex query.
+
+        Raises:
+          TypeError: If the parameter types are incorrect.
+          ApiError: If the Webex Teams cloud returns an error.
+        """
+        check_type(meetingId, basestring)
+        check_type(hostEmail, basestring, optional=True)
+        check_type(items, list, optional=True)
+
+        post_data = dict_from_items_with_values(
+            request_parameters,
+            meetingId=meetingId,
+            items=items,
+            hostEmail=hostEmail,
+        )
+
+        # API request
+        json_data = self._session.put(
+            API_ENDPOINT + "/bulkInsert", json=post_data
+        )
+
+        # Return an object created from the response JSON data
+        for itm in json_data["items"]:
+            yield self._object_factory(OBJECT_TYPE, itm)
diff --git a/webexteamssdk/api/meeting_registrants.py b/webexteamssdk/api/meeting_registrants.py
index a88ed34..70e4a8f 100644
--- a/webexteamssdk/api/meeting_registrants.py
+++ b/webexteamssdk/api/meeting_registrants.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex MeetingRegistrants API wrapper.
 
-Copyright (c) 2016-2022 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
@@ -42,8 +41,8 @@
 )
 
 
-API_ENDPOINT = 'meetings/{meetingId}/registrants'
-OBJECT_TYPE = 'meetingRegistrant'
+API_ENDPOINT = "meetings/{meetingId}/registrants"
+OBJECT_TYPE = "meetingRegistrant"
 
 
 class MeetingRegistrantsAPI(object):
@@ -55,7 +54,7 @@ class MeetingRegistrantsAPI(object):
     """
 
     def __init__(self, session, object_factory):
-        """Init a new MeetingRegistrantsAPI object with the provided RestSession.
+        """Init a new MeetingRegistrantsAPI object with the RestSession.
 
         Args:
             session(RestSession): The RESTful session object to be used for
@@ -71,18 +70,20 @@ def __init__(self, session, object_factory):
 
         self._session = session
         self._object_factory = object_factory
-    
-    @generator_container
-    def list(self, meetingId,
-                   max=None,
-                   hostEmail=None,
-                   current=None,
-                   email=None,
-                   registrationTimeFrom=None,
-                   registrationTimeTo=None,
-                   headers={},
-             **request_parameters):
 
+    @generator_container
+    def list(
+        self,
+        meetingId,
+        max=None,
+        hostEmail=None,
+        current=None,
+        email=None,
+        registrationTimeFrom=None,
+        registrationTimeTo=None,
+        headers=None,
+        **request_parameters,
+    ):
         """List meetingRegistrants.
 
         Use query parameters to filter the response.
@@ -99,12 +100,19 @@ def list(self, meetingId,
 
         Args:
             meetingId (basestring): Unique identifier for the meeting.
-            max (int): Limit the maximum number of registrants in the response, up to 100.
+            max (int): Limit the maximum number of registrants in the response,
+                up to 100.
             hostEmail (basestring): Email address for the meeting host.
-            current (bool): Whether or not to retrieve only the current scheduled meeting of the meeting series, i.e. the meeting ready to join or start or the upcoming meeting of the meeting series.
+            current (bool): Whether or not to retrieve only the current
+                scheduled meeting of the meeting series, i.e. the meeting ready
+                to join or start or the upcoming meeting of the meeting series.
             email (basestring): Registrant's email to filter registrants.
-            registrationTimeFrom (basestring): The time registrants register a meeting starts from the specified date and time (inclusive) in any ISO 8601 compliant format.
-            registrationTimeTo (basestring): The time registrants register a meeting before the specified date and time (exclusive) in any ISO 8601 compliant format.
+            registrationTimeFrom (basestring): The time registrants register a
+                meeting starts from the specified date and time (inclusive) in
+                any ISO 8601 compliant format.
+            registrationTimeTo (basestring): The time registrants register a
+                meeting before the specified date and time (exclusive) in any
+                ISO 8601 compliant format.
             headers(dict): Additional headers to be passed.
             **request_parameters: Additional request parameters (provides
                 support for parameters that may be added in the future).
@@ -125,7 +133,9 @@ def list(self, meetingId,
         check_type(email, basestring, optional=True)
         check_type(registrationTimeFrom, basestring, optional=True)
         check_type(registrationTimeTo, basestring, optional=True)
-        
+        check_type(headers, dict, optional=True)
+
+        headers = headers or {}
 
         params = dict_from_items_with_values(
             request_parameters,
@@ -135,12 +145,11 @@ def list(self, meetingId,
             email=email,
             registrationTimeFrom=registrationTimeFrom,
             registrationTimeTo=registrationTimeTo,
-            
         )
-        
+
         # Add URL parameters to the API endpoint
         request_url = API_ENDPOINT.format(meetingId=meetingId)
-        
+
         # API request - get items
 
         # Update headers
@@ -149,30 +158,32 @@ def list(self, meetingId,
         items = self._session.get_items(request_url, params=params)
 
         # Remove headers
-        for k, v in headers.items():
+        for k in headers.keys():
             del self._session.headers[k]
 
         # Yield membership objects created from the returned items JSON objects
         for item in items:
             yield self._object_factory(OBJECT_TYPE, item)
-    
-    
-    def create(self, meetingId,
-                     firstName,
-                     lastName,
-                     email,
-                     sendEmail=None,
-                     jobTitle=None,
-                     address1=None,
-                     address2=None,
-                     city=None,
-                     state=None,
-                     zipCode=None,
-                     countryRegion=None,
-                     workPhone=None,
-                     fax=None,
-                     customizedQuestions=None,
-                     **request_parameters):
+
+    def create(
+        self,
+        meetingId,
+        firstName,
+        lastName,
+        email,
+        sendEmail=None,
+        jobTitle=None,
+        address1=None,
+        address2=None,
+        city=None,
+        state=None,
+        zipCode=None,
+        countryRegion=None,
+        workPhone=None,
+        fax=None,
+        customizedQuestions=None,
+        **request_parameters,
+    ):
         """Create a meetingRegistrant.
 
         Args:
@@ -190,13 +201,14 @@ def create(self, meetingId,
             countryRegion (basestring): Registrant's country or region.
             workPhone (basestring): Registrant's work phone number.
             fax (basestring): Registrant's FAX number.
-            customizedQuestions (list): List of registrant's answers for customized questions,
+            customizedQuestions (list): List of registrant's answers for
+                customized questions,
             **request_parameters: Additional request parameters (provides
                 support for parameters that may be added in the future).
 
         Returns:
-            MeetingRegistrant: A MeetingRegistrant object with the details of the created
-            meetingRegistrant.
+            MeetingRegistrant: A MeetingRegistrant object with the details of
+                the created meetingRegistrant.
 
         Raises:
             TypeError: If the parameter types are incorrect.
@@ -218,7 +230,7 @@ def create(self, meetingId,
         check_type(workPhone, basestring, optional=True)
         check_type(fax, basestring, optional=True)
         check_type(customizedQuestions, list, optional=True)
-        
+
         post_data = dict_from_items_with_values(
             request_parameters,
             firstName=firstName,
@@ -235,21 +247,17 @@ def create(self, meetingId,
             workPhone=workPhone,
             fax=fax,
             customizedQuestions=customizedQuestions,
-            
         )
 
-        
         # Add URL parameters to the API endpoint
         request_url = API_ENDPOINT.format(meetingId=meetingId)
-        
+
         # API request
         json_data = self._session.post(request_url, json=post_data)
 
         # Return a membership object created from the response JSON data
         return self._object_factory(OBJECT_TYPE, json_data)
-    
 
-    
     def get(self, meetingId, meetingRegistrantId):
         """Get details for a meetingRegistrant, by ID.
 
@@ -258,8 +266,8 @@ def get(self, meetingId, meetingRegistrantId):
             meetingRegistrantId(basestring): The meetingRegistrant ID.
 
         Returns:
-            MeetingRegistrant: A MeetingRegistrant object with the details of the requested
-            meetingRegistrant.
+            MeetingRegistrant: A MeetingRegistrant object with the details of
+                the requested meetingRegistrant.
 
         Raises:
             TypeError: If the parameter types are incorrect.
@@ -271,15 +279,13 @@ def get(self, meetingId, meetingRegistrantId):
 
         # Add URL parameters to the API endpoint
         request_url = API_ENDPOINT.format(meetingId=meetingId)
-        
+
         # API request
-        json_data = self._session.get(request_url + '/' + meetingRegistrantId)
+        json_data = self._session.get(request_url + "/" + meetingRegistrantId)
 
         # Return a membership object created from the response JSON data
         return self._object_factory(OBJECT_TYPE, json_data)
-    
 
-    
     def delete(self, meetingId, meetingRegistrantId):
         """Delete a meetingRegistrant, by ID.
 
@@ -297,10 +303,6 @@ def delete(self, meetingId, meetingRegistrantId):
 
         # Add URL parameters to the API endpoint
         request_url = API_ENDPOINT.format(meetingId=meetingId)
-        
-        # API request
-        self._session.delete(request_url + '/' + meetingRegistrantId)
-    
 
-    
-    
\ No newline at end of file
+        # API request
+        self._session.delete(request_url + "/" + meetingRegistrantId)
diff --git a/webexteamssdk/api/meeting_templates.py b/webexteamssdk/api/meeting_templates.py
index bc14abb..0ebeff5 100644
--- a/webexteamssdk/api/meeting_templates.py
+++ b/webexteamssdk/api/meeting_templates.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex MeetingTemplates API wrapper.
 
-Copyright (c) 2016-2022 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
@@ -42,8 +41,8 @@
 )
 
 
-API_ENDPOINT = 'meetings/templates'
-OBJECT_TYPE = 'meetingTemplate'
+API_ENDPOINT = "meetings/templates"
+OBJECT_TYPE = "meetingTemplate"
 
 
 class MeetingTemplatesAPI(object):
@@ -71,17 +70,19 @@ def __init__(self, session, object_factory):
 
         self._session = session
         self._object_factory = object_factory
-    
-    @generator_container
-    def list(self, templateType=None,
-                   locale=None,
-                   isDefault=None,
-                   isStandard=None,
-                   hostEmail=None,
-                   siteUrl=None,
-                   headers={},
-             **request_parameters):
 
+    @generator_container
+    def list(
+        self,
+        templateType=None,
+        locale=None,
+        isDefault=None,
+        isStandard=None,
+        hostEmail=None,
+        siteUrl=None,
+        headers=None,
+        **request_parameters,
+    ):
         """List meetingTemplates.
 
         Use query parameters to filter the response.
@@ -97,11 +98,15 @@ def list(self, templateType=None,
         container.
 
         Args:
-            templateType (basestring): Meeting template types (meeting, webinar)
-            locale (basestring): Locale for the meeting template (i.e. en_US)
-            isDefault (bool): Flag to indicate if default or non-default meeting templates are returned
-            isStandard (bool): Flag to indicate if standard or non-standard meeting templates are returned
-            hostEmail (bool): Email address of a meeting host (Requires admin-level scope)
+            templateType (basestring): Meeting template types (meeting,
+                webinar).
+            locale (basestring): Locale for the meeting template (i.e. en_US).
+            isDefault (bool): Flag to indicate if default or non-default
+                meeting templates are returned.
+            isStandard (bool): Flag to indicate if standard or non-standard
+                meeting templates are returned.
+            hostEmail (bool): Email address of a meeting host (Requires
+                admin-level scope).
             siteUrl (bool): URL of the Webex site from which we are listing.
             headers(dict): Additional headers to be passed.
             **request_parameters: Additional request parameters (provides
@@ -122,7 +127,9 @@ def list(self, templateType=None,
         check_type(isStandard, bool, optional=True)
         check_type(hostEmail, bool, optional=True)
         check_type(siteUrl, bool, optional=True)
-        
+        check_type(headers, dict, optional=True)
+
+        headers = headers or {}
 
         params = dict_from_items_with_values(
             request_parameters,
@@ -132,9 +139,8 @@ def list(self, templateType=None,
             isStandard=isStandard,
             hostEmail=hostEmail,
             siteUrl=siteUrl,
-            
         )
-        
+
         # API request - get items
 
         # Update headers
@@ -143,16 +149,13 @@ def list(self, templateType=None,
         items = self._session.get_items(API_ENDPOINT, params=params)
 
         # Remove headers
-        for k, v in headers.items():
+        for k in headers.keys():
             del self._session.headers[k]
 
         # Yield membership objects created from the returned items JSON objects
         for item in items:
             yield self._object_factory(OBJECT_TYPE, item)
-    
-    
 
-    
     def get(self, meetingTemplateId):
         """Get details for a meetingTemplate, by ID.
 
@@ -160,8 +163,8 @@ def get(self, meetingTemplateId):
             meetingTemplateId(basestring): The meetingTemplate ID.
 
         Returns:
-            MeetingTemplate: A MeetingTemplate object with the details of the requested
-            meetingTemplate.
+            MeetingTemplate: A MeetingTemplate object with the details of the
+            requested meetingTemplate.
 
         Raises:
             TypeError: If the parameter types are incorrect.
@@ -171,12 +174,7 @@ def get(self, meetingTemplateId):
         check_type(meetingTemplateId, basestring)
 
         # API request
-        json_data = self._session.get(API_ENDPOINT + '/' + meetingTemplateId)
+        json_data = self._session.get(API_ENDPOINT + "/" + meetingTemplateId)
 
         # Return a membership object created from the response JSON data
         return self._object_factory(OBJECT_TYPE, json_data)
-    
-
-    
-
-    
\ No newline at end of file
diff --git a/webexteamssdk/api/meetings.py b/webexteamssdk/api/meetings.py
index f6f0baa..b9a534f 100644
--- a/webexteamssdk/api/meetings.py
+++ b/webexteamssdk/api/meetings.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Meetings API wrapper.
 
-Copyright (c) 2016-2022 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
@@ -42,8 +41,8 @@
 )
 
 
-API_ENDPOINT = 'meetings'
-OBJECT_TYPE = 'meeting'
+API_ENDPOINT = "meetings"
+OBJECT_TYPE = "meeting"
 
 
 class MeetingsAPI(object):
@@ -71,25 +70,27 @@ def __init__(self, session, object_factory):
 
         self._session = session
         self._object_factory = object_factory
-    
-    @generator_container
-    def list(self, meetingNumber=None,
-                   webLink=None,
-                   roomId=None,
-                   meetingType=None,
-                   state=None,
-                   scheduledType=None,
-                   participantEmail=None,
-                   current=None,
-                   from_=None,
-                   to=None,
-                   max=None,
-                   hostEmail=None,
-                   siteUrl=None,
-                   integrationTag=None,
-                   headers={},
-             **request_parameters):
 
+    @generator_container
+    def list(
+        self,
+        meetingNumber=None,
+        webLink=None,
+        roomId=None,
+        meetingType=None,
+        state=None,
+        scheduledType=None,
+        participantEmail=None,
+        current=None,
+        from_=None,
+        to=None,
+        max=None,
+        hostEmail=None,
+        siteUrl=None,
+        integrationTag=None,
+        headers=None,
+        **request_parameters,
+    ):
         """List meetings.
 
         Use query parameters to filter the response.
@@ -105,18 +106,23 @@ def list(self, meetingNumber=None,
         container.
 
         Args:
-            meetingNumber (basestring): Meeting number for the meeting objects being requested
-            webLink (basestring): URL encoded link to information page
+            meetingNumber (basestring): Meeting number for the meeting objects
+                being requested.
+            webLink (basestring): URL encoded link to information page.
             roomId (basestring): Associated teams space room ID.
-            meetingType (basestring): Type of the meeting (meetingSeries, scheduledMeeting, meeting).
-            state (basestring): 
-            scheduledType (basestring): Schedule type of this meeting (meeting, webinar, personalRoomMeeting)
+            meetingType (basestring): Type of the meeting (meetingSeries,
+                scheduledMeeting, meeting).
+            state (basestring):
+            scheduledType (basestring): Schedule type of this meeting (meeting,
+                webinar, personalRoomMeeting).
             participantEmail (basestring): E-Mail of a meeting participant.
-            current (bool): Flag to retrieve the current scheduled meeting of a series.
-            from_ (basestring): Start date and time in ISO 8601 format
-            to (basestring): To date and time in ISO 8601 format
+            current (bool): Flag to retrieve the current scheduled meeting of a
+                series.
+            from_ (basestring): Start date and time in ISO 8601 format.
+            to (basestring): To date and time in ISO 8601 format.
             max (int): Limit the number of meetings in response.
-            hostEmail (basestring): Email address for the meeting host (Needs admin-level scope).
+            hostEmail (basestring): Email address for the meeting host (Needs
+                admin-level scope).
             siteUrl (basestring): URL of the webex site.
             integrationTag (basestring): External tag set by integrations.
             headers(dict): Additional headers to be passed.
@@ -146,7 +152,9 @@ def list(self, meetingNumber=None,
         check_type(hostEmail, basestring, optional=True)
         check_type(siteUrl, basestring, optional=True)
         check_type(integrationTag, basestring, optional=True)
-        
+        check_type(headers, dict, optional=True)
+
+        headers = headers if headers is not None else {}
 
         params = dict_from_items_with_values(
             request_parameters,
@@ -164,14 +172,13 @@ def list(self, meetingNumber=None,
             hostEmail=hostEmail,
             siteUrl=siteUrl,
             integrationTag=integrationTag,
-            
         )
-        
+
         if from_:
-            params['from'] = params.pop("from_")
-        
+            params["from"] = params.pop("from_")
+
         request_url = API_ENDPOINT
-        
+
         # API request - get items
 
         # Update headers
@@ -180,94 +187,116 @@ def list(self, meetingNumber=None,
         items = self._session.get_items(request_url, params=params)
 
         # Remove headers
-        for k, v in headers.items():
+        for k in headers.keys():
             del self._session.headers[k]
 
         # Yield membership objects created from the returned items JSON objects
         for item in items:
             yield self._object_factory(OBJECT_TYPE, item)
-    
-    
-    def create(self, title,
-                     start,
-                     end,
-                     templateId=None,
-                     agenda=None,
-                     password=None,
-                     timezone=None,
-                     recurrence=None,
-                     enabledAutoRecordMeeting=None,
-                     allowAnyUserToBeCoHost=None,
-                     enabledJoinBeforeHost=None,
-                     enableConnectAudioBeforeHost=None,
-                     joinBeforeHostMinutes=None,
-                     excludePassword=None,
-                     publicMeeting=None,
-                     reminderTime=None,
-                     unlockedMeetingJoinSecurity=None,
-                     sessionTypeId=None,
-                     scheduledType=None,
-                     enabledWebcastView=None,
-                     panelistPassword=None,
-                     enableAutomaticLock=None,
-                     automaticLockMinutes=None,
-                     allowFirstUserToBeCoHost=None,
-                     allowAuthenticatedDevices=None,
-                     invitees=None,
-                     sendEmail=None,
-                     hostEmail=None,
-                     siteUrl=None,
-                     meetingOptions=None,
-                     registration=None,
-                     integrationTags=None,
-                     simultaneousInterpretation=None,
-                     enabledBreakoutSessions=None,
-                     breakoutSessions=None,
-                     **request_parameters):
+
+    def create(
+        self,
+        title,
+        start,
+        end,
+        templateId=None,
+        agenda=None,
+        password=None,
+        timezone=None,
+        recurrence=None,
+        enabledAutoRecordMeeting=None,
+        allowAnyUserToBeCoHost=None,
+        enabledJoinBeforeHost=None,
+        enableConnectAudioBeforeHost=None,
+        joinBeforeHostMinutes=None,
+        excludePassword=None,
+        publicMeeting=None,
+        reminderTime=None,
+        unlockedMeetingJoinSecurity=None,
+        sessionTypeId=None,
+        scheduledType=None,
+        enabledWebcastView=None,
+        panelistPassword=None,
+        enableAutomaticLock=None,
+        automaticLockMinutes=None,
+        allowFirstUserToBeCoHost=None,
+        allowAuthenticatedDevices=None,
+        invitees=None,
+        sendEmail=None,
+        hostEmail=None,
+        siteUrl=None,
+        meetingOptions=None,
+        registration=None,
+        integrationTags=None,
+        simultaneousInterpretation=None,
+        enabledBreakoutSessions=None,
+        breakoutSessions=None,
+        **request_parameters,
+    ):
         """Create a meeting.
 
         Args:
-            title (basestring): Title of the meeting
+            title (basestring): Title of the meeting.
             start (basestring): Start time of the meeting in ISO 8601.
             end (basestring): End time of the meeting in ISO 8601.
-            templateId (basestring): Unique identifier for meeting template
-            agenda (basestring): Meeting agenda (Maximum 1300 characters)
-            password (basestring): Password of the meeting
-            timezone (basestring): Time zone of start and end property in IANA time zone database format.
-            recurrence (basestring): Meeting recurrence according to RFC 2445
-            enabledAutoRecordMeeting (bool): Whether or not meeting is recorded automatically.
-            allowAnyUserToBeCoHost (bool): Allow any attendee with host account on site to become co host
-            enabledJoinBeforeHost (bool): Allow attendees to join before the host.
-            enableConnectAudioBeforeHost (bool): Allow attendees to connect audio before the host joins.
-            joinBeforeHostMinutes (int): Number of minutes attendees can join before the start time.
-            excludePassword (bool): Exclude meeting password from meeting invite emails.
-            publicMeeting (bool): Allow meeting to be listed on public calendar
-            reminderTime (int): Number of minutes before start time a reminder is send to the host
-            unlockedMeetingJoinSecurity (basestring): Join settings for uninvited people
-            sessionTypeId (basestring): Unique identifier for a meeting session type.
-            scheduledType (basestring): Type of meeting (regular, webinar, meeting in personal room)
-            enabledWebcastView (bool): Whether or not webcast view is enabled
-            panelistPassword (basestring): Password for panelists of a webinar meeting
-            enableAutomaticLock (bool): Whether or not to automatically lock the meeting after start.
-            automaticLockMinutes (int): Number of minutes for the meeting to be automatically locked.
-            allowFirstUserToBeCoHost (bool): Allow the first joiner with host account on the meeting site to be co host.
-            allowAuthenticatedDevices (bool): Whether or not to allow authenticated video devices in the meeting's organization to start or join the meeting
-            invitees (list): List of invitee objects
-            sendEmail (bool): Send an invite e-mail
-            hostEmail (basestring): Email address of the meeting host
-            siteUrl (basestring): Site URL for the meeting
-            meetingOptions (dict): Options for this meeting
+            templateId (basestring): Unique identifier for meeting template.
+            agenda (basestring): Meeting agenda (Maximum 1300 characters).
+            password (basestring): Password of the meeting.
+            timezone (basestring): Time zone of start and end property in
+                IANA time zone database format.
+            recurrence (basestring): Meeting recurrence according to RFC 2445.
+            enabledAutoRecordMeeting (bool): Whether or not meeting is
+                recorded automatically.
+            allowAnyUserToBeCoHost (bool): Allow any attendee with host
+                account on site to become cohost.
+            enabledJoinBeforeHost (bool): Allow attendees to join before the
+                host.
+            enableConnectAudioBeforeHost (bool): Allow attendees to connect
+                audio before the host joins.
+            joinBeforeHostMinutes (int): Number of minutes attendees can join
+                before the start time.
+            excludePassword (bool): Exclude meeting password from meeting
+                invite emails.
+            publicMeeting (bool): Allow meeting to be listed on public
+                calendar.
+            reminderTime (int): Number of minutes before start time a reminder
+                is send to the host.
+            unlockedMeetingJoinSecurity (basestring): Join settings for
+                uninvited people.
+            sessionTypeId (basestring): Unique identifier for a meeting
+                session type.
+            scheduledType (basestring): Type of meeting (regular, webinar,
+                meeting in personal room).
+            enabledWebcastView (bool): Whether or not webcast view is enabled.
+            panelistPassword (basestring): Password for panelists of a
+                webinar meeting.
+            enableAutomaticLock (bool): Whether or not to automatically lock
+                the meeting after start.
+            automaticLockMinutes (int): Number of minutes for the meeting to
+                be automatically locked.
+            allowFirstUserToBeCoHost (bool): Allow the first joiner with host
+                account on the meeting site to be cohost.
+            allowAuthenticatedDevices (bool): Whether or not to allow
+                authenticated video devices in the meeting's organization to
+                start or join the meeting.
+            invitees (list): List of invitee objects.
+            sendEmail (bool): Send an invite e-mail.
+            hostEmail (basestring): Email address of the meeting host.
+            siteUrl (basestring): Site URL for the meeting.
+            meetingOptions (dict): Options for this meeting.
             registration (dict): Meeting registration information.
-            integrationTags (list): List of external keys created by integrations
-            simultaneousInterpretation (dict): Simultaneous interpretation information for the meeting.
-            enabledBreakoutSessions (bool): Flag to enable breakout sessions in this meeting.
-            breakoutSessions (list): List of breakout sessions
+            integrationTags (list): List of external keys created by
+                integrations.
+            simultaneousInterpretation (dict): Simultaneous interpretation
+                information for the meeting.
+            enabledBreakoutSessions (bool): Flag to enable breakout sessions
+                in this meeting.
+            breakoutSessions (list): List of breakout sessions.
             **request_parameters: Additional request parameters (provides
                 support for parameters that may be added in the future).
 
         Returns:
-            Meeting: A Meeting object with the details of the created
-            meeting.
+            Meeting: A Meeting object with the details of the created meeting.
 
         Raises:
             TypeError: If the parameter types are incorrect.
@@ -309,7 +338,7 @@ def create(self, title,
         check_type(simultaneousInterpretation, dict, optional=True)
         check_type(enabledBreakoutSessions, bool, optional=True)
         check_type(breakoutSessions, list, optional=True)
-        
+
         post_data = dict_from_items_with_values(
             request_parameters,
             title=title,
@@ -347,20 +376,16 @@ def create(self, title,
             simultaneousInterpretation=simultaneousInterpretation,
             enabledBreakoutSessions=enabledBreakoutSessions,
             breakoutSessions=breakoutSessions,
-            
         )
 
-        
         request_url = API_ENDPOINT
-        
+
         # API request
         json_data = self._session.post(request_url, json=post_data)
 
         # Return a membership object created from the response JSON data
         return self._object_factory(OBJECT_TYPE, json_data)
-    
 
-    
     def get(self, meetingId):
         """Get details for a meeting, by ID.
 
@@ -378,15 +403,13 @@ def get(self, meetingId):
         """
         check_type(meetingId, basestring)
         request_url = API_ENDPOINT
-        
+
         # API request
-        json_data = self._session.get(request_url + '/' + meetingId)
+        json_data = self._session.get(request_url + "/" + meetingId)
 
         # Return a membership object created from the response JSON data
         return self._object_factory(OBJECT_TYPE, json_data)
-    
 
-    
     def delete(self, meetingId):
         """Delete a meeting, by ID.
 
@@ -400,78 +423,99 @@ def delete(self, meetingId):
         """
         check_type(meetingId, basestring)
         request_url = API_ENDPOINT
-        
+
         # API request
-        self._session.delete(request_url + '/' + meetingId)
-    
-
-    
-    def update(self, meetingId,
-                     title,
-                     password,
-                     start,
-                     end,
-                     agenda=None,
-                     timezone=None,
-                     recurrence=None,
-                     enabledAutoRecordMeeting=None,
-                     allowAnyUserToBeCoHost=None,
-                     enabledJoinBeforeHost=None,
-                     enableConnectAudioBeforeHost=None,
-                     joinBeforeHostMinutes=None,
-                     excludePassword=None,
-                     publicMeeting=None,
-                     reminderTime=None,
-                     unlockedMeetingJoinSecurity=None,
-                     sessionTypeId=None,
-                     scheduledType=None,
-                     enabledWebcastView=None,
-                     panelistPassword=None,
-                     enableAutomaticLock=None,
-                     automaticLockMinutes=None,
-                     allowFirstUserToBeCoHost=None,
-                     allowAuthenticatedDevices=None,
-                     sendEmail=None,
-                     hostEmail=None,
-                     siteUrl=None,
-                     meetingOptions=None,
-                     integrationTags=None,
-                     enabledBreakoutSessions=None,
-                     **request_parameters):
+        self._session.delete(request_url + "/" + meetingId)
+
+    def update(
+        self,
+        meetingId,
+        title,
+        password,
+        start,
+        end,
+        agenda=None,
+        timezone=None,
+        recurrence=None,
+        enabledAutoRecordMeeting=None,
+        allowAnyUserToBeCoHost=None,
+        enabledJoinBeforeHost=None,
+        enableConnectAudioBeforeHost=None,
+        joinBeforeHostMinutes=None,
+        excludePassword=None,
+        publicMeeting=None,
+        reminderTime=None,
+        unlockedMeetingJoinSecurity=None,
+        sessionTypeId=None,
+        scheduledType=None,
+        enabledWebcastView=None,
+        panelistPassword=None,
+        enableAutomaticLock=None,
+        automaticLockMinutes=None,
+        allowFirstUserToBeCoHost=None,
+        allowAuthenticatedDevices=None,
+        sendEmail=None,
+        hostEmail=None,
+        siteUrl=None,
+        meetingOptions=None,
+        integrationTags=None,
+        enabledBreakoutSessions=None,
+        **request_parameters,
+    ):
         """Update properties for a meeting, by ID.
 
         Args:
             meetingId(basestring): The meeting ID.
-            title (basestring): Title of the meeting
-            password (basestring): Password of the meeting
+            title (basestring): Title of the meeting.
+            password (basestring): Password of the meeting.
             start (basestring): Start time of the meeting in ISO 8601.
             end (basestring): End time of the meeting in ISO 8601.
-            agenda (basestring): Meeting agenda (Maximum 1300 characters)
-            timezone (basestring): Time zone of start and end property in IANA time zone database format.
-            recurrence (basestring): Meeting recurrence according to RFC 2445
-            enabledAutoRecordMeeting (bool): Whether or not meeting is recorded automatically.
-            allowAnyUserToBeCoHost (bool): Allow any attendee with host account on site to become co host
-            enabledJoinBeforeHost (bool): Allow attendees to join before the host.
-            enableConnectAudioBeforeHost (bool): Allow attendees to connect audio before the host joins.
-            joinBeforeHostMinutes (int): Number of minutes attendees can join before the start time.
-            excludePassword (bool): Exclude meeting password from meeting invite emails.
-            publicMeeting (bool): Allow meeting to be listed on public calendar
-            reminderTime (int): Number of minutes before start time a reminder is send to the host
-            unlockedMeetingJoinSecurity (basestring): Join settings for uninvited people
-            sessionTypeId (basestring): Unique identifier for a meeting session type.
-            scheduledType (basestring): Type of meeting (regular, webinar, meeting in personal room)
-            enabledWebcastView (bool): Whether or not webcast view is enabled
-            panelistPassword (basestring): Password for panelists of a webinar meeting
-            enableAutomaticLock (bool): Whether or not to automatically lock the meeting after start.
-            automaticLockMinutes (int): Number of minutes for the meeting to be automatically locked.
-            allowFirstUserToBeCoHost (bool): Allow the first joiner with host account on the meeting site to be co host.
-            allowAuthenticatedDevices (bool): Whether or not to allow authenticated video devices in the meeting's organization to start or join the meeting
-            sendEmail (bool): Send an invite e-mail
-            hostEmail (basestring): Email address of the meeting host
-            siteUrl (basestring): Site URL for the meeting
-            meetingOptions (dict): Options for this meeting
-            integrationTags (list): List of external keys created by integrations
-            enabledBreakoutSessions (bool): Flag to enable breakout sessions in this meeting.
+            agenda (basestring): Meeting agenda (Maximum 1300 characters).
+            timezone (basestring): Time zone of start and end property in IANA
+                time zone database format.
+            recurrence (basestring): Meeting recurrence according to RFC 2445.
+            enabledAutoRecordMeeting (bool): Whether or not meeting is recorded
+                automatically.
+            allowAnyUserToBeCoHost (bool): Allow any attendee with host account
+                on site to become cohost.
+            enabledJoinBeforeHost (bool): Allow attendees to join before the
+                host.
+            enableConnectAudioBeforeHost (bool): Allow attendees to connect
+                audio before the host joins.
+            joinBeforeHostMinutes (int): Number of minutes attendees can join
+                before the start time.
+            excludePassword (bool): Exclude meeting password from meeting
+                invite emails.
+            publicMeeting (bool): Allow meeting to be listed on public
+                calendar.
+            reminderTime (int): Number of minutes before start time a reminder
+                is send to the host.
+            unlockedMeetingJoinSecurity (basestring): Join settings for
+                uninvited people.
+            sessionTypeId (basestring): Unique identifier for a meeting session
+                type.
+            scheduledType (basestring): Type of meeting (regular, webinar,
+                meeting in personal room).
+            enabledWebcastView (bool): Whether or not webcast view is enabled.
+            panelistPassword (basestring): Password for panelists of a webinar
+                meeting.
+            enableAutomaticLock (bool): Whether or not to automatically lock
+                the meeting after start.
+            automaticLockMinutes (int): Number of minutes for the meeting to be
+                automatically locked.
+            allowFirstUserToBeCoHost (bool): Allow the first joiner with host
+                account on the meeting site to be cohost.
+            allowAuthenticatedDevices (bool): Whether or not to allow
+                authenticated video devices in the meeting's organization to
+                start or join the meeting.
+            sendEmail (bool): Send an invite e-mail.
+            hostEmail (basestring): Email address of the meeting host.
+            siteUrl (basestring): Site URL for the meeting.
+            meetingOptions (dict): Options for this meeting.
+            integrationTags (list): List of external keys created by
+                integrations.
+            enabledBreakoutSessions (bool): Flag to enable breakout sessions in
+                this meeting.
             **request_parameters: Additional request parameters (provides
                 support for parameters that may be added in the future).
 
@@ -515,7 +559,7 @@ def update(self, meetingId,
         check_type(meetingOptions, dict, optional=True)
         check_type(integrationTags, list, optional=True)
         check_type(enabledBreakoutSessions, bool, optional=True)
-        
+
         put_data = dict_from_items_with_values(
             request_parameters,
             title=title,
@@ -548,16 +592,14 @@ def update(self, meetingId,
             meetingOptions=meetingOptions,
             integrationTags=integrationTags,
             enabledBreakoutSessions=enabledBreakoutSessions,
-            
         )
-        
+
         request_url = API_ENDPOINT
-        
+
         # API request
-        json_data = self._session.put(request_url + '/' + meetingId,
-                                      json=put_data)
+        json_data = self._session.put(
+            request_url + "/" + meetingId, json=put_data
+        )
 
         # Return a membership object created from the response JSON data
         return self._object_factory(OBJECT_TYPE, json_data)
-    
-    
\ No newline at end of file
diff --git a/webexteamssdk/api/memberships.py b/webexteamssdk/api/memberships.py
index ced2652..8115680 100644
--- a/webexteamssdk/api/memberships.py
+++ b/webexteamssdk/api/memberships.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Memberships API wrapper.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
@@ -42,8 +41,8 @@
 )
 
 
-API_ENDPOINT = 'memberships'
-OBJECT_TYPE = 'membership'
+API_ENDPOINT = "memberships"
+OBJECT_TYPE = "membership"
 
 
 class MembershipsAPI(object):
@@ -73,8 +72,14 @@ def __init__(self, session, object_factory):
         self._object_factory = object_factory
 
     @generator_container
-    def list(self, roomId=None, personId=None, personEmail=None, max=None,
-             **request_parameters):
+    def list(
+        self,
+        roomId=None,
+        personId=None,
+        personEmail=None,
+        max=None,
+        **request_parameters,
+    ):
         """List room memberships.
 
         By default, lists memberships for rooms to which the authenticated user
@@ -135,8 +140,14 @@ def list(self, roomId=None, personId=None, personEmail=None, max=None,
         for item in items:
             yield self._object_factory(OBJECT_TYPE, item)
 
-    def create(self, roomId, personId=None, personEmail=None,
-               isModerator=False, **request_parameters):
+    def create(
+        self,
+        roomId,
+        personId=None,
+        personEmail=None,
+        isModerator=False,
+        **request_parameters,
+    ):
         """Add someone to a room by Person ID or email address.
 
         Add someone to a room by Person ID or email address; optionally
@@ -196,7 +207,7 @@ def get(self, membershipId):
         check_type(membershipId, basestring)
 
         # API request
-        json_data = self._session.get(API_ENDPOINT + '/' + membershipId)
+        json_data = self._session.get(API_ENDPOINT + "/" + membershipId)
 
         # Return a membership object created from the response JSON data
         return self._object_factory(OBJECT_TYPE, json_data)
@@ -228,8 +239,9 @@ def update(self, membershipId, isModerator=None, **request_parameters):
         )
 
         # API request
-        json_data = self._session.put(API_ENDPOINT + '/' + membershipId,
-                                      json=put_data)
+        json_data = self._session.put(
+            API_ENDPOINT + "/" + membershipId, json=put_data
+        )
 
         # Return a membership object created from the response JSON data
         return self._object_factory(OBJECT_TYPE, json_data)
@@ -248,4 +260,4 @@ def delete(self, membershipId):
         check_type(membershipId, basestring)
 
         # API request
-        self._session.delete(API_ENDPOINT + '/' + membershipId)
+        self._session.delete(API_ENDPOINT + "/" + membershipId)
diff --git a/webexteamssdk/api/messages.py b/webexteamssdk/api/messages.py
index 479cbce..daa02ea 100644
--- a/webexteamssdk/api/messages.py
+++ b/webexteamssdk/api/messages.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Messages API wrapper.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
@@ -39,13 +38,17 @@
 from ..generator_containers import generator_container
 from ..restsession import RestSession
 from ..utils import (
-    check_type, dict_from_items_with_values, is_local_file, is_web_url,
-    make_attachment, open_local_file,
+    check_type,
+    dict_from_items_with_values,
+    is_local_file,
+    is_web_url,
+    make_attachment,
+    open_local_file,
 )
 
 
-API_ENDPOINT = 'messages'
-OBJECT_TYPE = 'message'
+API_ENDPOINT = "messages"
+OBJECT_TYPE = "message"
 
 
 class MessagesAPI(object):
@@ -73,8 +76,16 @@ def __init__(self, session, object_factory):
         self._object_factory = object_factory
 
     @generator_container
-    def list(self, roomId, parentId=None, mentionedPeople=None, before=None,
-             beforeMessage=None, max=50, **request_parameters):
+    def list(
+        self,
+        roomId,
+        parentId=None,
+        mentionedPeople=None,
+        before=None,
+        beforeMessage=None,
+        max=50,
+        **request_parameters,
+    ):
         """Lists messages in a room.
 
         Each message will include content attachments if present.
@@ -139,8 +150,13 @@ def list(self, roomId, parentId=None, mentionedPeople=None, before=None,
             yield self._object_factory(OBJECT_TYPE, item)
 
     @generator_container
-    def list_direct(self, personId=None, personEmail=None, parentId=None,
-                    **request_parameters):
+    def list_direct(
+        self,
+        personId=None,
+        personEmail=None,
+        parentId=None,
+        **request_parameters,
+    ):
         """List all messages in a 1:1 (direct) room.
 
         Use the `personId` or `personEmail` query parameter to specify the
@@ -196,9 +212,18 @@ def list_direct(self, personId=None, personEmail=None, parentId=None,
         for item in items:
             yield self._object_factory(OBJECT_TYPE, item)
 
-    def create(self, roomId=None, parentId=None, toPersonId=None,
-               toPersonEmail=None, text=None, markdown=None, files=None,
-               attachments=None, **request_parameters):
+    def create(
+        self,
+        roomId=None,
+        parentId=None,
+        toPersonId=None,
+        toPersonEmail=None,
+        text=None,
+        markdown=None,
+        files=None,
+        attachments=None,
+        **request_parameters,
+    ):
         """Post a message to a room.
 
         The files parameter is a list, which accepts multiple values to allow
@@ -246,12 +271,14 @@ def create(self, roomId=None, parentId=None, toPersonId=None,
 
         if files:
             if len(files) > 1:
-                raise ValueError("The `files` parameter should be a list with "
-                                 "exactly one (1) item. The files parameter "
-                                 "is a list, which accepts multiple values to "
-                                 "allow for future expansion, but currently "
-                                 "only one file may be included with the "
-                                 "message.")
+                raise ValueError(
+                    "The `files` parameter should be a list with "
+                    "exactly one (1) item. The files parameter "
+                    "is a list, which accepts multiple values to "
+                    "allow for future expansion, but currently "
+                    "only one file may be included with the "
+                    "message."
+                )
             check_type(files[0], basestring)
         else:
             files = None
@@ -273,7 +300,7 @@ def create(self, roomId=None, parentId=None, toPersonId=None,
             markdown=markdown,
             files=files,
             attachments=attachments,
-            parentId=parentId
+            parentId=parentId,
         )
 
         # API request
@@ -284,18 +311,20 @@ def create(self, roomId=None, parentId=None, toPersonId=None,
         elif is_local_file(files[0]):
             # Multipart MIME post
             try:
-                post_data['files'] = open_local_file(files[0])
+                post_data["files"] = open_local_file(files[0])
                 multipart_data = MultipartEncoder(post_data)
-                headers = {'Content-type': multipart_data.content_type}
-                json_data = self._session.post(API_ENDPOINT,
-                                               headers=headers,
-                                               data=multipart_data)
+                headers = {"Content-type": multipart_data.content_type}
+                json_data = self._session.post(
+                    API_ENDPOINT, headers=headers, data=multipart_data
+                )
             finally:
-                post_data['files'].file_object.close()
+                post_data["files"].file_object.close()
 
         else:
-            raise ValueError("The `files` parameter does not contain a vaild "
-                             "URL or path to a local file.")
+            raise ValueError(
+                "The `files` parameter does not contain a vaild "
+                "URL or path to a local file."
+            )
 
         # Return a message object created from the response JSON data
         return self._object_factory(OBJECT_TYPE, json_data)
@@ -318,7 +347,7 @@ def get(self, messageId):
         check_type(messageId, basestring)
 
         # API request
-        json_data = self._session.get(API_ENDPOINT + '/' + messageId)
+        json_data = self._session.get(API_ENDPOINT + "/" + messageId)
 
         # Return a message object created from the response JSON data
         return self._object_factory(OBJECT_TYPE, json_data)
@@ -337,7 +366,7 @@ def delete(self, messageId):
         check_type(messageId, basestring)
 
         # API request
-        self._session.delete(API_ENDPOINT + '/' + messageId)
+        self._session.delete(API_ENDPOINT + "/" + messageId)
 
     def edit(self, messageId=None, roomId=None, text=None, markdown=None):
         """Edit a message.
@@ -367,7 +396,9 @@ def edit(self, messageId=None, roomId=None, text=None, markdown=None):
         )
 
         # API request
-        json_data = self._session.put(API_ENDPOINT + '/' + messageId, json=put_data)
+        json_data = self._session.put(
+            API_ENDPOINT + "/" + messageId, json=put_data
+        )
 
         # Return a message object created from the response JSON data
-        return self._object_factory(OBJECT_TYPE, json_data)
\ No newline at end of file
+        return self._object_factory(OBJECT_TYPE, json_data)
diff --git a/webexteamssdk/api/organizations.py b/webexteamssdk/api/organizations.py
index 0143671..9cefc64 100644
--- a/webexteamssdk/api/organizations.py
+++ b/webexteamssdk/api/organizations.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Organizations API wrapper.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
@@ -39,8 +38,8 @@
 from webexteamssdk.utils import check_type, dict_from_items_with_values
 
 
-API_ENDPOINT = 'organizations'
-OBJECT_TYPE = 'organization'
+API_ENDPOINT = "organizations"
+OBJECT_TYPE = "organization"
 
 
 class OrganizationsAPI(object):
@@ -88,8 +87,7 @@ def list(self, **request_parameters):
         """
         # API request - get items
         items = self._session.get_items(
-            API_ENDPOINT,
-            params=request_parameters
+            API_ENDPOINT, params=request_parameters
         )
 
         # Yield organization objects created from the returned JSON objects
@@ -114,7 +112,7 @@ def get(self, orgId):
         check_type(orgId, basestring)
 
         # API request
-        json_data = self._session.get(API_ENDPOINT + '/' + orgId)
+        json_data = self._session.get(API_ENDPOINT + "/" + orgId)
 
         # Return a organization object created from the returned JSON object
         return self._object_factory(OBJECT_TYPE, json_data)
diff --git a/webexteamssdk/api/people.py b/webexteamssdk/api/people.py
index 13ce40f..92c7c4f 100644
--- a/webexteamssdk/api/people.py
+++ b/webexteamssdk/api/people.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams People API wrapper.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
@@ -42,8 +41,8 @@
 )
 
 
-API_ENDPOINT = 'people'
-OBJECT_TYPE = 'person'
+API_ENDPOINT = "people"
+OBJECT_TYPE = "person"
 
 
 class PeopleAPI(object):
@@ -73,8 +72,15 @@ def __init__(self, session, object_factory):
         self._object_factory = object_factory
 
     @generator_container
-    def list(self, email=None, displayName=None, id=None, orgId=None, max=None,
-             **request_parameters):
+    def list(
+        self,
+        email=None,
+        displayName=None,
+        id=None,
+        orgId=None,
+        max=None,
+        **request_parameters,
+    ):
         """List people in your organization.
 
         For most users, either the `email` or `displayName` parameter is
@@ -140,15 +146,38 @@ def list(self, email=None, displayName=None, id=None, orgId=None, max=None,
         for item in items:
             yield self._object_factory(OBJECT_TYPE, item)
 
-    def create(self, emails, displayName=None, firstName=None, lastName=None,
-               avatar=None, orgId=None, roles=None, licenses=None,
-               **request_parameters):
+    def create(
+        self,
+        emails,
+        phoneNumbers=None,
+        extension=None,
+        locationId=None,
+        displayName=None,
+        firstName=None,
+        lastName=None,
+        avatar=None,
+        orgId=None,
+        roles=None,
+        licenses=None,
+        department=None,
+        manager=None,
+        managerId=None,
+        title=None,
+        addresses=None,
+        siteUrls=None,
+        callingData=None,
+        minResponse=None,
+        **request_parameters,
+    ):
         """Create a new user account for a given organization
 
         Only an admin can create a new user account.
 
         Args:
             emails(`list`): Email address(es) of the person (list of strings).
+            phoneNumbers(`list`): Phone numbers for the person.
+            extension(basestring): Webex Calling extension of the person.
+            locationId(basestring): The ID of the location for this person.
             displayName(basestring): Full name of the person.
             firstName(basestring): First name of the person.
             lastName(basestring): Last name of the person.
@@ -160,6 +189,19 @@ def create(self, emails, displayName=None, firstName=None, lastName=None,
             licenses(`list`): Licenses allocated to the person (list of
                 strings - containing the license IDs to be allocated to the
                 person).
+            department(basestring): The business department the user belongs
+                to.
+            manager(basestring): A manager identifier.
+            managerId(basestring): Person ID of the manager.
+            title(basestring): The person's title.
+            addresses(`list`): A person's addresses.
+            siteUrls(`list`): One or several site names where this user has an
+                attendee role.
+            callingData(bool): Include Webex Calling user details in the
+                response.
+            minResponse(bool): Set to true to improve performance by omitting
+                person details and returning only the ID in the response when
+                successful.
             **request_parameters: Additional request parameters (provides
                 support for parameters that may be added in the future).
 
@@ -172,6 +214,9 @@ def create(self, emails, displayName=None, firstName=None, lastName=None,
 
         """
         check_type(emails, list)
+        check_type(phoneNumbers, list, optional=True)
+        check_type(extension, basestring, optional=True)
+        check_type(locationId, basestring, optional=True)
         check_type(displayName, basestring, optional=True)
         check_type(firstName, basestring, optional=True)
         check_type(lastName, basestring, optional=True)
@@ -179,10 +224,21 @@ def create(self, emails, displayName=None, firstName=None, lastName=None,
         check_type(orgId, basestring, optional=True)
         check_type(roles, list, optional=True)
         check_type(licenses, list, optional=True)
+        check_type(department, basestring, optional=True)
+        check_type(manager, basestring, optional=True)
+        check_type(managerId, basestring, optional=True)
+        check_type(title, basestring, optional=True)
+        check_type(addresses, list, optional=True)
+        check_type(siteUrls, list, optional=True)
+        check_type(callingData, bool, optional=True)
+        check_type(minResponse, bool, optional=True)
 
         post_data = dict_from_items_with_values(
             request_parameters,
             emails=emails,
+            phoneNumbers=phoneNumbers,
+            extension=extension,
+            locationId=locationId,
             displayName=displayName,
             firstName=firstName,
             lastName=lastName,
@@ -190,10 +246,23 @@ def create(self, emails, displayName=None, firstName=None, lastName=None,
             orgId=orgId,
             roles=roles,
             licenses=licenses,
+            department=department,
+            manager=manager,
+            managerId=managerId,
+            title=title,
+            addresses=addresses,
+            siteUrls=siteUrls,
+        )
+
+        params = dict_from_items_with_values(
+            callingData=callingData,
+            minResponse=minResponse,
         )
 
         # API request
-        json_data = self._session.post(API_ENDPOINT, json=post_data)
+        json_data = self._session.post(
+            API_ENDPOINT, params=params, json=post_data
+        )
 
         # Return a person object created from the returned JSON object
         return self._object_factory(OBJECT_TYPE, json_data)
@@ -215,14 +284,24 @@ def get(self, personId):
         check_type(personId, basestring)
 
         # API request
-        json_data = self._session.get(API_ENDPOINT + '/' + personId)
+        json_data = self._session.get(API_ENDPOINT + "/" + personId)
 
         # Return a person object created from the response JSON data
         return self._object_factory(OBJECT_TYPE, json_data)
 
-    def update(self, personId, emails=None, displayName=None, firstName=None,
-               lastName=None, avatar=None, orgId=None, roles=None,
-               licenses=None, **request_parameters):
+    def update(
+        self,
+        personId,
+        emails=None,
+        displayName=None,
+        firstName=None,
+        lastName=None,
+        avatar=None,
+        orgId=None,
+        roles=None,
+        licenses=None,
+        **request_parameters,
+    ):
         """Update details for a person, by ID.
 
         Only an admin can update a person's details.
@@ -281,8 +360,9 @@ def update(self, personId, emails=None, displayName=None, firstName=None,
         )
 
         # API request
-        json_data = self._session.put(API_ENDPOINT + '/' + personId,
-                                      json=put_data)
+        json_data = self._session.put(
+            API_ENDPOINT + "/" + personId, json=put_data
+        )
 
         # Return a person object created from the returned JSON object
         return self._object_factory(OBJECT_TYPE, json_data)
@@ -303,7 +383,7 @@ def delete(self, personId):
         check_type(personId, basestring)
 
         # API request
-        self._session.delete(API_ENDPOINT + '/' + personId)
+        self._session.delete(API_ENDPOINT + "/" + personId)
 
     def me(self):
         """Get the details of the person accessing the API.
@@ -313,7 +393,7 @@ def me(self):
 
         """
         # API request
-        json_data = self._session.get(API_ENDPOINT + '/me')
+        json_data = self._session.get(API_ENDPOINT + "/me")
 
         # Return a person object created from the response JSON data
         return self._object_factory(OBJECT_TYPE, json_data)
diff --git a/webexteamssdk/api/recordings.py b/webexteamssdk/api/recordings.py
index 840a870..546c974 100644
--- a/webexteamssdk/api/recordings.py
+++ b/webexteamssdk/api/recordings.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Recordings API wrapper.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -21,6 +21,7 @@
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 """
+
 from __future__ import (
     absolute_import,
     division,
@@ -37,8 +38,9 @@
 
 from webexteamssdk.restsession import RestSession
 
-API_ENDPOINT = 'recordings'
-OBJECT_TYPE = 'recording'
+API_ENDPOINT = "recordings"
+OBJECT_TYPE = "recording"
+
 
 class RecordingsAPI(object):
     """Webex Teams Recordings API.
@@ -47,6 +49,7 @@ class RecordingsAPI(object):
     methods that return native Python objects.
 
     """
+
     def __init__(self, session, object_factory):
         """Init a new RecordingsAPI object with the provided RestSession.
 
@@ -64,14 +67,28 @@ def __init__(self, session, object_factory):
         self._object_factory = object_factory
 
     @generator_container
-    def list(self, max=None, _from=None, to=None, meetingId=None,
-             hostEmail=None, siteUrl=None, integrationTag=None, topic=None, format=None,
-             serviceType=None, **request_parameters):
+    def list(
+        self,
+        max=None,
+        _from=None,
+        to=None,
+        meetingId=None,
+        hostEmail=None,
+        siteUrl=None,
+        integrationTag=None,
+        topic=None,
+        format=None,
+        serviceType=None,
+        **request_parameters,
+    ):
         """Lists recordings.
-        You can specify a date range, a parent meeting ID and the maximum number of recordings to return.
 
-        Only recordings of meetings hosted by or shared with the authenticated user will be listed.
-        The list returned is sorted in descending order by the date and time that the recordings were created.
+        You can specify a date range, a parent meeting ID and the maximum
+        number of recordings to return.
+
+        Only recordings of meetings hosted by or shared with the authenticated
+        user will be listed. The list returned is sorted in descending order by
+        the date and time that the recordings were created.
 
         This method supports Webex Teams's implementation of RFC5988 Web
         Linking to provide pagination support.  It returns a generator
@@ -88,17 +105,19 @@ def list(self, max=None, _from=None, to=None, meetingId=None,
                 Teams service per request.
             _from(basestring): List recordings which occurred after a specific
                 date and time.
-            to(basestring): List recordings which occurred before a specific date
-                and time.
+            to(basestring): List recordings which occurred before a specific
+                date and time.
             meetingId(basestring): List recordings filtered by ID.
             hostEmail(basestring): Email address of meeting host.
-            siteUrl(basestring): URL of the Webex site which the API lists recordings from.
-            integrationTag(basestring): External key of the parent meeting created
-                by an integration application.
+            siteUrl(basestring): URL of the Webex site which the API lists
+                recordings from.
+            integrationTag(basestring): External key of the parent meeting
+                created by an integration application.
             topic(basestring): Recording's topic (case-insensitive).
-            format(basestring): Recording's format; if specified, it should be either
-                "MP4" or "ARF".
-            serviceType(basestring): Recording's service type; if specified, it should be either of:
+            format(basestring): Recording's format; if specified, it should be
+                either "MP4" or "ARF".
+            serviceType(basestring): Recording's service type; if specified, it
+                should be either of:
                     MeetingCenter,
                     EventCenter,
                     SupportCenter,
@@ -136,7 +155,7 @@ def list(self, max=None, _from=None, to=None, meetingId=None,
             integrationTag=integrationTag,
             topic=topic,
             format=format,
-            serviceType=serviceType
+            serviceType=serviceType,
         )
 
         items = self._session.get_items(API_ENDPOINT, params=params)
@@ -149,7 +168,8 @@ def get(self, recordingId, siteUrl=None, hostEmail=None):
 
         Args:
             recordingId(basestring): The ID of the recording to be retrieved.
-            siteUrl(basestring): URL of the Webex site which the API gets recordings from.
+            siteUrl(basestring): URL of the Webex site which the API gets
+                recordings from.
             hostEmail(basestring): Email address of meeting host.
 
         Returns:
@@ -166,11 +186,12 @@ def get(self, recordingId, siteUrl=None, hostEmail=None):
         check_type(hostEmail, basestring, optional=True)
 
         params = dict_from_items_with_values(
-            siteUrl=siteUrl,
-            hostEmail=hostEmail
+            siteUrl=siteUrl, hostEmail=hostEmail
         )
 
-        json_data = self._session.get(API_ENDPOINT+'/'+recordingId, params=params)
+        json_data = self._session.get(
+            API_ENDPOINT + "/" + recordingId, params=params
+        )
 
         return self._object_factory(OBJECT_TYPE, json_data)
 
@@ -179,7 +200,8 @@ def delete(self, recordingId, siteUrl=None, hostEmail=None):
 
         Args:
             recordingId(basestring): The ID of the recording to be deleted.
-            siteUrl(basestring): URL of the Webex site which the API deletes recording from.
+            siteUrl(basestring): URL of the Webex site which the API deletes
+                recording from.
             hostEmail(basestring): Email address of meeting host.
 
         Raises:
@@ -192,11 +214,7 @@ def delete(self, recordingId, siteUrl=None, hostEmail=None):
         check_type(hostEmail, basestring, optional=True)
 
         params = dict_from_items_with_values(
-            siteUrl=siteUrl,
-            hostEmail=hostEmail
+            siteUrl=siteUrl, hostEmail=hostEmail
         )
 
-        self._session.get(API_ENDPOINT+'/'+recordingId, params=params)
-
-
-
+        self._session.get(API_ENDPOINT + "/" + recordingId, params=params)
diff --git a/webexteamssdk/api/roles.py b/webexteamssdk/api/roles.py
index 1b0d142..540ba8d 100644
--- a/webexteamssdk/api/roles.py
+++ b/webexteamssdk/api/roles.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Roles API wrapper.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
@@ -42,8 +41,8 @@
 )
 
 
-API_ENDPOINT = 'roles'
-OBJECT_TYPE = 'role'
+API_ENDPOINT = "roles"
+OBJECT_TYPE = "role"
 
 
 class RolesAPI(object):
@@ -91,8 +90,7 @@ def list(self, **request_parameters):
         """
         # API request - get items
         items = self._session.get_items(
-            API_ENDPOINT,
-            params=request_parameters
+            API_ENDPOINT, params=request_parameters
         )
 
         # Yield role objects created from the returned JSON objects
@@ -116,7 +114,7 @@ def get(self, roleId):
         check_type(roleId, basestring)
 
         # API request
-        json_data = self._session.get(API_ENDPOINT + '/' + roleId)
+        json_data = self._session.get(API_ENDPOINT + "/" + roleId)
 
         # Return a role object created from the returned JSON object
         return self._object_factory(OBJECT_TYPE, json_data)
diff --git a/webexteamssdk/api/room_tabs.py b/webexteamssdk/api/room_tabs.py
index 9f153f5..5d92cbf 100644
--- a/webexteamssdk/api/room_tabs.py
+++ b/webexteamssdk/api/room_tabs.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Room Tabs API wrapper.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
@@ -42,8 +41,8 @@
 )
 
 
-API_ENDPOINT = 'room/tabs'
-OBJECT_TYPE = 'room_tab'
+API_ENDPOINT = "room/tabs"
+OBJECT_TYPE = "room_tab"
 
 
 class RoomTabsAPI(object):
@@ -74,8 +73,7 @@ def __init__(self, session, object_factory):
 
     @generator_container
     def list(self, roomId, **request_parameters):
-        """
-        Lists all Room Tabs of a room. roomId query parameter is required to retrieve the response.
+        """Lists all Room Tabs of a room.
 
         This method supports Webex Teams's implementation of RFC5988 Web
         Linking to provide pagination support.  It returns a generator
@@ -169,12 +167,14 @@ def get(self, roomTabId):
         check_type(roomTabId, basestring)
 
         # API request
-        json_data = self._session.get(API_ENDPOINT + '/' + roomTabId)
+        json_data = self._session.get(API_ENDPOINT + "/" + roomTabId)
 
         # Return a room object created from the response JSON data
         return self._object_factory(OBJECT_TYPE, json_data)
 
-    def update(self, roomTabId, roomId, contentUrl, displayName, **request_parameters):
+    def update(
+        self, roomTabId, roomId, contentUrl, displayName, **request_parameters
+    ):
         """Updates the content url of a Room Tab by ID.
 
         Args:
@@ -208,8 +208,9 @@ def update(self, roomTabId, roomId, contentUrl, displayName, **request_parameter
         )
 
         # API request
-        json_data = self._session.put(API_ENDPOINT + '/' + roomTabId,
-                                      json=put_data)
+        json_data = self._session.put(
+            API_ENDPOINT + "/" + roomTabId, json=put_data
+        )
 
         # Return a room object created from the response JSON data
         return self._object_factory(OBJECT_TYPE, json_data)
@@ -228,4 +229,4 @@ def delete(self, roomTabId):
         check_type(roomTabId, basestring)
 
         # API request
-        self._session.delete(API_ENDPOINT + '/' + roomTabId)
+        self._session.delete(API_ENDPOINT + "/" + roomTabId)
diff --git a/webexteamssdk/api/rooms.py b/webexteamssdk/api/rooms.py
index 0eec370..e866243 100644
--- a/webexteamssdk/api/rooms.py
+++ b/webexteamssdk/api/rooms.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Rooms API wrapper.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
@@ -42,8 +41,8 @@
 )
 
 
-API_ENDPOINT = 'rooms'
-OBJECT_TYPE = 'room'
+API_ENDPOINT = "rooms"
+OBJECT_TYPE = "room"
 
 
 class RoomsAPI(object):
@@ -73,8 +72,14 @@ def __init__(self, session, object_factory):
         self._object_factory = object_factory
 
     @generator_container
-    def list(self, teamId=None, type=None, sortBy=None, max=100,
-             **request_parameters):
+    def list(
+        self,
+        teamId=None,
+        type=None,
+        sortBy=None,
+        max=100,
+        **request_parameters,
+    ):
         """List rooms.
 
         By default, lists rooms to which the authenticated user belongs.
@@ -132,7 +137,17 @@ def list(self, teamId=None, type=None, sortBy=None, max=100,
         for item in items:
             yield self._object_factory(OBJECT_TYPE, item)
 
-    def create(self, title, teamId=None, **request_parameters):
+    def create(
+        self,
+        title,
+        teamId=None,
+        classificationId=None,
+        isLocked=None,
+        isPublic=None,
+        description=None,
+        isAnnouncementOnly=None,
+        **request_parameters,
+    ):
         """Create a room.
 
         The authenticated user is automatically added as a member of the room.
@@ -141,6 +156,15 @@ def create(self, title, teamId=None, **request_parameters):
             title(basestring): A user-friendly name for the room.
             teamId(basestring): The team ID with which this room is
                 associated.
+            classificationId(basestring): The classification ID for the room.
+            isLocked(bool): Set the space as locked/moderated and the creator
+                becomes a moderator.
+            isPublic(bool): The room is public and therefore discoverable
+                within the org. Anyone can find and join that room. When `true`
+                the description must be filled in.
+            description(basestring): The description of the space.
+            isAnnouncementOnly(bool): Sets the space into Announcement Mode or
+                clears the Announcement Mode (`false`).
             **request_parameters: Additional request parameters (provides
                 support for parameters that may be added in the future).
 
@@ -152,8 +176,13 @@ def create(self, title, teamId=None, **request_parameters):
             ApiError: If the Webex Teams cloud returns an error.
 
         """
-        check_type(title, basestring, optional=True)
+        check_type(title, basestring)
         check_type(teamId, basestring, optional=True)
+        check_type(classificationId, basestring, optional=True)
+        check_type(isLocked, bool, optional=True)
+        check_type(isPublic, bool, optional=True)
+        check_type(description, basestring, optional=True)
+        check_type(isAnnouncementOnly, bool, optional=True)
 
         post_data = dict_from_items_with_values(
             request_parameters,
@@ -184,7 +213,7 @@ def get(self, roomId):
         check_type(roomId, basestring)
 
         # API request
-        json_data = self._session.get(API_ENDPOINT + '/' + roomId)
+        json_data = self._session.get(API_ENDPOINT + "/" + roomId)
 
         # Return a room object created from the response JSON data
         return self._object_factory(OBJECT_TYPE, json_data)
@@ -209,18 +238,45 @@ def get_meeting_info(self, roomId):
 
         # API request
         json_data = self._session.get(
-            API_ENDPOINT + '/' + roomId + '/meetingInfo',
+            API_ENDPOINT + "/" + roomId + "/meetingInfo",
         )
 
         # Return a room meeting info object created from the response JSON data
         return self._object_factory("room_meeting_info", json_data)
 
-    def update(self, roomId, title, **request_parameters):
+    def update(
+        self,
+        roomId,
+        title,
+        classificationId=None,
+        teamId=None,
+        isLocked=None,
+        isPublic=None,
+        description=None,
+        isAnnouncementOnly=None,
+        isReadOnly=None,
+        **request_parameters,
+    ):
         """Update details for a room, by ID.
 
         Args:
             roomId(basestring): The room ID.
             title(basestring): A user-friendly name for the room.
+            classificationId(basestring): The classification ID for the room.
+            teamId(basestring): The teamId to which this space should be
+                assigned. Only unowned spaces can be assigned to a team.
+                Assignment between teams is unsupported.
+            isLocked(bool): Set the space as locked/moderated and the creator
+                becomes a moderator.
+            isPublic(bool): The room is public and therefore discoverable
+                within the org. Anyone can find and join that room. When `true`
+                the description must be filled in.
+            description(basestring): The description of the space.
+            isAnnouncementOnly(bool): Sets the space into Announcement Mode or
+                clears the Announcement Mode (`false`).
+            isReadOnly(bool): A compliance officer can set a direct room as
+                read-only, which will disallow any new information exchanges in
+                this space, while maintaining historical data.
             **request_parameters: Additional request parameters (provides
                 support for parameters that may be added in the future).
 
@@ -234,15 +290,30 @@ def update(self, roomId, title, **request_parameters):
         """
         check_type(roomId, basestring)
         check_type(title, basestring)
+        check_type(classificationId, basestring, optional=True)
+        check_type(teamId, basestring, optional=True)
+        check_type(isLocked, bool, optional=True)
+        check_type(isPublic, bool, optional=True)
+        check_type(description, basestring, optional=True)
+        check_type(isAnnouncementOnly, bool, optional=True)
+        check_type(isReadOnly, bool, optional=True)
 
         put_data = dict_from_items_with_values(
             request_parameters,
             title=title,
+            classificationId=classificationId,
+            teamId=teamId,
+            isLocked=isLocked,
+            isPublic=isPublic,
+            description=description,
+            isAnnouncementOnly=isAnnouncementOnly,
+            isReadOnly=isReadOnly,
         )
 
         # API request
-        json_data = self._session.put(API_ENDPOINT + '/' + roomId,
-                                      json=put_data)
+        json_data = self._session.put(
+            API_ENDPOINT + "/" + roomId, json=put_data
+        )
 
         # Return a room object created from the response JSON data
         return self._object_factory(OBJECT_TYPE, json_data)
@@ -261,4 +332,4 @@ def delete(self, roomId):
         check_type(roomId, basestring)
 
         # API request
-        self._session.delete(API_ENDPOINT + '/' + roomId)
+        self._session.delete(API_ENDPOINT + "/" + roomId)
diff --git a/webexteamssdk/api/team_memberships.py b/webexteamssdk/api/team_memberships.py
index b545314..67a2184 100644
--- a/webexteamssdk/api/team_memberships.py
+++ b/webexteamssdk/api/team_memberships.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Memberships API wrapper.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
@@ -42,8 +41,8 @@
 )
 
 
-API_ENDPOINT = 'team/memberships'
-OBJECT_TYPE = 'team_membership'
+API_ENDPOINT = "team/memberships"
+OBJECT_TYPE = "team_membership"
 
 
 class TeamMembershipsAPI(object):
@@ -119,8 +118,14 @@ def list(self, teamId, max=100, **request_parameters):
         for item in items:
             yield self._object_factory(OBJECT_TYPE, item)
 
-    def create(self, teamId, personId=None, personEmail=None,
-               isModerator=False, **request_parameters):
+    def create(
+        self,
+        teamId,
+        personId=None,
+        personEmail=None,
+        isModerator=False,
+        **request_parameters,
+    ):
         """Add someone to a team by Person ID or email address.
 
         Add someone to a team by Person ID or email address; optionally making
@@ -180,7 +185,7 @@ def get(self, membershipId):
         check_type(membershipId, basestring)
 
         # API request
-        json_data = self._session.get(API_ENDPOINT + '/' + membershipId)
+        json_data = self._session.get(API_ENDPOINT + "/" + membershipId)
 
         # Return a team membership object created from the response JSON data
         return self._object_factory(OBJECT_TYPE, json_data)
@@ -212,8 +217,9 @@ def update(self, membershipId, isModerator=None, **request_parameters):
         )
 
         # API request
-        json_data = self._session.put(API_ENDPOINT + '/' + membershipId,
-                                      json=put_data)
+        json_data = self._session.put(
+            API_ENDPOINT + "/" + membershipId, json=put_data
+        )
 
         # Return a team membership object created from the response JSON data
         return self._object_factory(OBJECT_TYPE, json_data)
@@ -232,4 +238,4 @@ def delete(self, membershipId):
         check_type(membershipId, basestring)
 
         # API request
-        self._session.delete(API_ENDPOINT + '/' + membershipId)
+        self._session.delete(API_ENDPOINT + "/" + membershipId)
diff --git a/webexteamssdk/api/teams.py b/webexteamssdk/api/teams.py
index 7a54506..a358b0d 100644
--- a/webexteamssdk/api/teams.py
+++ b/webexteamssdk/api/teams.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Teams-API wrapper.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
@@ -42,8 +41,8 @@
 )
 
 
-API_ENDPOINT = 'teams'
-OBJECT_TYPE = 'team'
+API_ENDPOINT = "teams"
+OBJECT_TYPE = "team"
 
 
 class TeamsAPI(object):
@@ -163,7 +162,7 @@ def get(self, teamId):
         check_type(teamId, basestring)
 
         # API request
-        json_data = self._session.get(API_ENDPOINT + '/' + teamId)
+        json_data = self._session.get(API_ENDPOINT + "/" + teamId)
 
         # Return a team object created from the response JSON data
         return self._object_factory(OBJECT_TYPE, json_data)
@@ -194,8 +193,9 @@ def update(self, teamId, name, **request_parameters):
         )
 
         # API request
-        json_data = self._session.put(API_ENDPOINT + '/' + teamId,
-                                      json=put_data)
+        json_data = self._session.put(
+            API_ENDPOINT + "/" + teamId, json=put_data
+        )
 
         # Return a team object created from the response JSON data
         return self._object_factory(OBJECT_TYPE, json_data)
@@ -214,4 +214,4 @@ def delete(self, teamId):
         check_type(teamId, basestring)
 
         # API request
-        self._session.delete(API_ENDPOINT + '/' + teamId)
+        self._session.delete(API_ENDPOINT + "/" + teamId)
diff --git a/webexteamssdk/api/webhooks.py b/webexteamssdk/api/webhooks.py
index f7401e9..5becad0 100644
--- a/webexteamssdk/api/webhooks.py
+++ b/webexteamssdk/api/webhooks.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Webhooks API wrapper.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
@@ -42,8 +41,8 @@
 )
 
 
-API_ENDPOINT = 'webhooks'
-OBJECT_TYPE = 'webhook'
+API_ENDPOINT = "webhooks"
+OBJECT_TYPE = "webhook"
 
 
 class WebhooksAPI(object):
@@ -115,8 +114,16 @@ def list(self, max=100, **request_parameters):
         for item in items:
             yield self._object_factory(OBJECT_TYPE, item)
 
-    def create(self, name, targetUrl, resource, event,
-               filter=None, secret=None, **request_parameters):
+    def create(
+        self,
+        name,
+        targetUrl,
+        resource,
+        event,
+        filter=None,
+        secret=None,
+        **request_parameters,
+    ):
         """Create a webhook.
 
         Args:
@@ -179,13 +186,14 @@ def get(self, webhookId):
         check_type(webhookId, basestring)
 
         # API request
-        json_data = self._session.get(API_ENDPOINT + '/' + webhookId)
+        json_data = self._session.get(API_ENDPOINT + "/" + webhookId)
 
         # Return a webhook object created from the response JSON data
         return self._object_factory(OBJECT_TYPE, json_data)
 
-    def update(self, webhookId, name=None, targetUrl=None,
-               **request_parameters):
+    def update(
+        self, webhookId, name=None, targetUrl=None, **request_parameters
+    ):
         """Update a webhook, by ID.
 
         Args:
@@ -216,8 +224,9 @@ def update(self, webhookId, name=None, targetUrl=None,
         )
 
         # API request
-        json_data = self._session.put(API_ENDPOINT + '/' + webhookId,
-                                      json=put_data)
+        json_data = self._session.put(
+            API_ENDPOINT + "/" + webhookId, json=put_data
+        )
 
         # Return a webhook object created from the response JSON data
         return self._object_factory(OBJECT_TYPE, json_data)
@@ -236,4 +245,4 @@ def delete(self, webhookId):
         check_type(webhookId, basestring)
 
         # API request
-        self._session.delete(API_ENDPOINT + '/' + webhookId)
+        self._session.delete(API_ENDPOINT + "/" + webhookId)
diff --git a/webexteamssdk/config.py b/webexteamssdk/config.py
index f7336d6..a1aa963 100644
--- a/webexteamssdk/config.py
+++ b/webexteamssdk/config.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Package configuration.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 # Package Constants
 DEFAULT_BASE_URL = "https://webexapis.com/v1/"
 
diff --git a/webexteamssdk/environment.py b/webexteamssdk/environment.py
index 6a68708..e09b9ed 100644
--- a/webexteamssdk/environment.py
+++ b/webexteamssdk/environment.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Package environment variables.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 import os
 import warnings
 
@@ -59,7 +58,7 @@ def _get_access_token():
                         new=ACCESS_TOKEN_ENVIRONMENT_VARIABLE,
                     )
                 )
-                warnings.warn(env_var_deprecation_warning)
+                warnings.warn(env_var_deprecation_warning, stacklevel=2)
                 return access_token
 
 
diff --git a/webexteamssdk/exceptions.py b/webexteamssdk/exceptions.py
index 5c573eb..589b932 100644
--- a/webexteamssdk/exceptions.py
+++ b/webexteamssdk/exceptions.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Package exceptions.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
@@ -43,16 +42,19 @@
 
 class webexteamssdkException(Exception):
     """Base class for all webexteamssdk package exceptions."""
+
     pass
 
 
 class webexteamssdkWarning(webexteamssdkException, Warning):
     """Base class for all webexteamssdk warnings."""
+
     pass
 
 
 class AccessTokenError(webexteamssdkException):
     """Raised when an incorrect Webex Teams Access Token has been provided."""
+
     pass
 
 
@@ -83,8 +85,10 @@ def __init__(self, response):
 
         self.details = None
         """The parsed JSON details from the API response."""
-        if "application/json" in \
-                self.response.headers.get("Content-Type", "").lower():
+        if (
+            "application/json"
+            in self.response.headers.get("Content-Type", "").lower()
+        ):
             try:
                 self.details = self.response.json()
             except ValueError:
@@ -94,8 +98,9 @@ def __init__(self, response):
         """The error message from the parsed API response."""
 
         self.tracking_id = (
-            self.details.get("trackingId") if self.details else None
-            or self.response.headers.get("trackingId")
+            self.details.get("trackingId")
+            if self.details
+            else None or self.response.headers.get("trackingId")
         )
         """The Webex Tracking ID from the response."""
 
@@ -104,8 +109,11 @@ def __init__(self, response):
                 status_code=self.status_code,
                 status=" " + self.status if self.status else "",
                 detail=self.message or self.description or "Unknown Error",
-                tracking_id=" [Tracking ID: " + self.tracking_id + "]"
-                            if self.tracking_id else "",
+                tracking_id=(
+                    " [Tracking ID: " + self.tracking_id + "]"
+                    if self.tracking_id
+                    else ""
+                ),
             )
         )
 
@@ -124,6 +132,7 @@ class ApiWarning(webexteamssdkWarning, ApiError):
 
     Several data attributes are available for inspection.
     """
+
     pass
 
 
@@ -138,7 +147,7 @@ def __init__(self, response):
         assert isinstance(response, requests.Response)
 
         # Extended exception attributes
-        self.retry_after = max(1, int(response.headers.get('Retry-After', 15)))
+        self.retry_after = max(1, int(response.headers.get("Retry-After", 15)))
         """The `Retry-After` time period (in seconds) provided by Webex Teams.
 
         Defaults to 15 seconds if the response `Retry-After` header isn't
@@ -155,9 +164,11 @@ class RateLimitWarning(ApiWarning, RateLimitError):
     Raised when a rate-limit exceeded message is received and the request will
     be retried.
     """
+
     pass
 
 
 class MalformedResponse(webexteamssdkException):
     """Raised when a malformed response is received from Webex Teams."""
+
     pass
diff --git a/webexteamssdk/generator_containers.py b/webexteamssdk/generator_containers.py
index 97a9309..c8d00f8 100644
--- a/webexteamssdk/generator_containers.py
+++ b/webexteamssdk/generator_containers.py
@@ -8,7 +8,7 @@
     generator_container: Function decorator for wrapping a generator function
         in a GeneratorContainer.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -29,7 +29,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
@@ -68,9 +67,7 @@ def __init__(self, generator_function, *args, **kwargs):
 
         if sys.version_info[0] < 3:
             self.arguments = inspect.getcallargs(
-                self.generator_function,
-                *args,
-                **kwargs
+                self.generator_function, *args, **kwargs
             )
         else:
             signature = inspect.signature(self.generator_function)
@@ -79,10 +76,10 @@ def __init__(self, generator_function, *args, **kwargs):
 
     def __repr__(self):
         """A string representation of this object."""
-        return '<GeneratorContainer {func_name}({arguments})>'.format(
+        return "<GeneratorContainer {func_name}({arguments})>".format(
             func_name=self.generator_function.__name__,
             arguments=", ".join(
-                str(key) + '=' + repr(value)
+                str(key) + "=" + repr(value)
                 for key, value in self.arguments.items()
             ),
         )
@@ -125,7 +122,7 @@ def __getitem__(self, item):
         """
         if isinstance(item, slice):
             arguments = self.arguments.copy()
-            arguments.setdefault('max', item.stop)
+            arguments.setdefault("max", item.stop)
             return islice(
                 self.generator_function(**arguments),
                 item.start,
@@ -133,8 +130,10 @@ def __getitem__(self, item):
                 item.step,
             )
         else:
-            raise IndexError("GeneratorContainers support slicing only. "
-                             "Indexing is not supported.")
+            raise IndexError(
+                "GeneratorContainers support slicing only. "
+                "Indexing is not supported."
+            )
 
 
 def generator_container(generator_function):
diff --git a/webexteamssdk/models/cards/__init__.py b/webexteamssdk/models/cards/__init__.py
index 5a9ef34..30c991c 100644
--- a/webexteamssdk/models/cards/__init__.py
+++ b/webexteamssdk/models/cards/__init__.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Adaptive Cards data models.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -25,13 +25,27 @@
 from .adaptive_card_component import AdaptiveCardComponent
 from .card import AdaptiveCard
 from .components import (
-    Choice, Column, Fact, Image, Media, MediaSource,
+    Choice,
+    Column,
+    Fact,
+    Image,
+    Media,
+    MediaSource,
     TextBlock,
 )
 from .container import ColumnSet, Container, FactSet, ImageSet
 from .inputs import Choices, Date, Number, Text, Time, Toggle
 from .options import (
-    BlockElementHeight, ChoiceInputStyle, Colors,
-    ContainerStyle, FontSize, FontWeight, HorizontalAlignment, ImageSize,
-    ImageStyle, Spacing, TextInputStyle, VerticalContentAlignment,
+    BlockElementHeight,
+    ChoiceInputStyle,
+    Colors,
+    ContainerStyle,
+    FontSize,
+    FontWeight,
+    HorizontalAlignment,
+    ImageSize,
+    ImageStyle,
+    Spacing,
+    TextInputStyle,
+    VerticalContentAlignment,
 )
diff --git a/webexteamssdk/models/cards/actions.py b/webexteamssdk/models/cards/actions.py
index a8bb42d..298d823 100644
--- a/webexteamssdk/models/cards/actions.py
+++ b/webexteamssdk/models/cards/actions.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Adaptive Card actions.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -27,6 +27,7 @@
 
 class OpenUrl(AdaptiveCardComponent):
     """Open URL Action."""
+
     type = "Action.OpenUrl"
 
     def __init__(self, url, title=None, iconURL=None):
@@ -36,12 +37,13 @@ def __init__(self, url, title=None, iconURL=None):
 
         super().__init__(
             serializable_properties=[],
-            simple_properties=['url', 'type', 'title', 'iconURL'],
+            simple_properties=["url", "type", "title", "iconURL"],
         )
 
 
 class Submit(AdaptiveCardComponent):
     """Submit Action."""
+
     type = "Action.Submit"
 
     def __init__(self, data=None, title=None, iconURL=None):
@@ -51,12 +53,13 @@ def __init__(self, data=None, title=None, iconURL=None):
 
         super().__init__(
             serializable_properties=[],
-            simple_properties=['data', 'title', 'iconURL', 'type'],
+            simple_properties=["data", "title", "iconURL", "type"],
         )
 
 
 class ShowCard(AdaptiveCardComponent):
     """Show Card Action."""
+
     type = "Action.ShowCard"
 
     def __init__(self, card=None, title=None, iconURL=None):
@@ -65,6 +68,6 @@ def __init__(self, card=None, title=None, iconURL=None):
         self.iconURL = iconURL
 
         super().__init__(
-            serializable_properties=['card'],
-            simple_properties=['title', 'type', 'iconURL'],
+            serializable_properties=["card"],
+            simple_properties=["title", "type", "iconURL"],
         )
diff --git a/webexteamssdk/models/cards/adaptive_card_component.py b/webexteamssdk/models/cards/adaptive_card_component.py
index ae405eb..c119bae 100644
--- a/webexteamssdk/models/cards/adaptive_card_component.py
+++ b/webexteamssdk/models/cards/adaptive_card_component.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Adaptive Card Component base class.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -38,6 +38,7 @@ class AdaptiveCardComponent:
       This includes lists of items (i.e. the 'body' field of the adaptive card)
       or single objects that also inherit from Serializable
     """
+
     def __init__(self, serializable_properties, simple_properties):
         """Initialize a serializable object.
 
diff --git a/webexteamssdk/models/cards/card.py b/webexteamssdk/models/cards/card.py
index 02e1499..01cae96 100644
--- a/webexteamssdk/models/cards/card.py
+++ b/webexteamssdk/models/cards/card.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Adaptive Card data model.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -33,12 +33,19 @@ class AdaptiveCard(AdaptiveCardComponent):
     Note: Webex Teams currently supports version 1.1 of adaptive cards and thus
     only features from that release are supported in this abstraction.
     """
+
     type = "AdaptiveCard"
     schema = "http://adaptivecards.io/schemas/adaptive-card.json"
     version = "1.1"
 
-    def __init__(self, body=None, actions=None, selectAction=None,
-                 fallbackText=None, lang=None):
+    def __init__(
+        self,
+        body=None,
+        actions=None,
+        selectAction=None,
+        fallbackText=None,
+        lang=None,
+    ):
         """Initialize a new Adaptive Card object.
 
         Args:
@@ -74,8 +81,8 @@ def __init__(self, body=None, actions=None, selectAction=None,
         self.lang = lang
 
         super().__init__(
-            serializable_properties=['body', 'actions', 'selectAction'],
-            simple_properties=['version', 'fallbackText', 'lang', 'type'],
+            serializable_properties=["body", "actions", "selectAction"],
+            simple_properties=["version", "fallbackText", "lang", "type"],
         )
 
     def to_dict(self):
diff --git a/webexteamssdk/models/cards/components.py b/webexteamssdk/models/cards/components.py
index 0db9509..804bbf9 100644
--- a/webexteamssdk/models/cards/components.py
+++ b/webexteamssdk/models/cards/components.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Adaptive Card components.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -24,7 +24,13 @@
 
 from .actions import OpenUrl, Submit
 from .adaptive_card_component import AdaptiveCardComponent
-from .options import BlockElementHeight, ImageSize, ImageStyle, Spacing, HorizontalAlignment
+from .options import (
+    BlockElementHeight,
+    ImageSize,
+    ImageStyle,
+    Spacing,
+    HorizontalAlignment,
+)
 from .utils import check_type
 
 
@@ -47,16 +53,25 @@ def __init__(self, mimeType, url):
 
         super().__init__(
             serializable_properties=[],
-            simple_properties=['mimeType', 'url'],
+            simple_properties=["mimeType", "url"],
         )
 
 
 class Media(AdaptiveCardComponent):
     """Adaptive Card Media component."""
+
     type = "Media"
 
-    def __init__(self, sources, poster=None, altText=None, height=None,
-                 separator=None, spacing=None, id=None):
+    def __init__(
+        self,
+        sources,
+        poster=None,
+        altText=None,
+        height=None,
+        separator=None,
+        spacing=None,
+        id=None,
+    ):
         """Initialize a new Media component.
 
         Args:
@@ -86,22 +101,39 @@ def __init__(self, sources, poster=None, altText=None, height=None,
         self.id = id
 
         super().__init__(
-            serializable_properties=['sources'],
+            serializable_properties=["sources"],
             simple_properties=[
-                'type', 'poster', 'altText', 'height', 'separator', 'spacing',
-                'id',
+                "type",
+                "poster",
+                "altText",
+                "height",
+                "separator",
+                "spacing",
+                "id",
             ],
         )
 
 
 class Image(AdaptiveCardComponent):
     """Adaptive Card Image component."""
+
     type = "Image"
 
-    def __init__(self, url, altText=None, backgroundColor=None, height=None,
-                 horizontalAlignment=None, selectAction=None, size=None,
-                 style=None, width=None, separator=None, spacing=None,
-                 id=None):
+    def __init__(
+        self,
+        url,
+        altText=None,
+        backgroundColor=None,
+        height=None,
+        horizontalAlignment=None,
+        selectAction=None,
+        size=None,
+        style=None,
+        width=None,
+        separator=None,
+        spacing=None,
+        id=None,
+    ):
         """Initialize a new image component.
 
         Args:
@@ -126,7 +158,9 @@ def __init__(self, url, altText=None, backgroundColor=None, height=None,
         check_type(altText, str, optional=True)
         check_type(backgroundColor, str, optional=True)
         check_type(height, (str, BlockElementHeight), optional=True)
-        check_type(horizontalAlignment, (str, HorizontalAlignment), optional=True)
+        check_type(
+            horizontalAlignment, (str, HorizontalAlignment), optional=True
+        )
         check_type(selectAction, (OpenUrl, Submit), optional=True)
         check_type(size, ImageSize, optional=True)
         check_type(style, ImageStyle, optional=True)
@@ -151,20 +185,42 @@ def __init__(self, url, altText=None, backgroundColor=None, height=None,
         super().__init__(
             serializable_properties=[],
             simple_properties=[
-                'type', 'url', 'altText', 'backgroundColor', 'height',
-                'horizontalAlignment', 'selectAction', 'size', 'style',
-                'width', 'separator', 'spacing', 'id',
+                "type",
+                "url",
+                "altText",
+                "backgroundColor",
+                "height",
+                "horizontalAlignment",
+                "selectAction",
+                "size",
+                "style",
+                "width",
+                "separator",
+                "spacing",
+                "id",
             ],
         )
 
 
 class TextBlock(AdaptiveCardComponent):
     """Adaptive Card Text Block component."""
+
     type = "TextBlock"
 
-    def __init__(self, text, color=None, horizontalAlignment=None,
-                 isSubtle=None, maxLines=None, size=None, weight=None,
-                 wrap=None, separator=None, spacing=None, id=None):
+    def __init__(
+        self,
+        text,
+        color=None,
+        horizontalAlignment=None,
+        isSubtle=None,
+        maxLines=None,
+        size=None,
+        weight=None,
+        wrap=None,
+        separator=None,
+        spacing=None,
+        id=None,
+    ):
         """Initialize a new TextBlock component."""
         # TODO: Document arguments
         self.text = text
@@ -182,20 +238,38 @@ def __init__(self, text, color=None, horizontalAlignment=None,
         super().__init__(
             serializable_properties=[],
             simple_properties=[
-                'type', 'text', 'color', 'horizontalAlignment', 'isSubtle',
-                'maxLines', 'size', 'weight', 'wrap', 'spacing', 'id',
-                'separator',
+                "type",
+                "text",
+                "color",
+                "horizontalAlignment",
+                "isSubtle",
+                "maxLines",
+                "size",
+                "weight",
+                "wrap",
+                "spacing",
+                "id",
+                "separator",
             ],
         )
 
 
 class Column(AdaptiveCardComponent):
     """Adaptive Card Column component."""
+
     type = "Column"
 
-    def __init__(self, items=None, separator=None, spacing=None,
-                 selectAction=None, style=None, verticalContentAlignment=None,
-                 width=None, id=None):
+    def __init__(
+        self,
+        items=None,
+        separator=None,
+        spacing=None,
+        selectAction=None,
+        style=None,
+        verticalContentAlignment=None,
+        width=None,
+        id=None,
+    ):
         """Initialize a new Column component."""
         # TODO: Document arguments
         self.items = items
@@ -208,10 +282,16 @@ def __init__(self, items=None, separator=None, spacing=None,
         self.id = id
 
         super().__init__(
-            serializable_properties=['items'],
+            serializable_properties=["items"],
             simple_properties=[
-                'type', 'separator', 'spacing', 'selectAction', 'style',
-                'verticalContentAlignment', 'width', 'id',
+                "type",
+                "separator",
+                "spacing",
+                "selectAction",
+                "style",
+                "verticalContentAlignment",
+                "width",
+                "id",
             ],
         )
 
@@ -227,7 +307,7 @@ def __init__(self, title, value):
 
         super().__init__(
             serializable_properties=[],
-            simple_properties=['title', 'value'],
+            simple_properties=["title", "value"],
         )
 
 
@@ -240,5 +320,5 @@ def __init__(self, title, value):
 
         super().__init__(
             serializable_properties=[],
-            simple_properties=['title', 'value'],
+            simple_properties=["title", "value"],
         )
diff --git a/webexteamssdk/models/cards/container.py b/webexteamssdk/models/cards/container.py
index 9798e45..fae112c 100644
--- a/webexteamssdk/models/cards/container.py
+++ b/webexteamssdk/models/cards/container.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Adaptive Card container data models.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -27,11 +27,20 @@
 
 class Container(AdaptiveCardComponent):
     """Adaptive Card Container component."""
+
     type = "Container"
 
-    def __init__(self, items, selectAction=None, style=None,
-                 verticalContentAlignment=None, height=None, separator=None,
-                 spacing=None, id=None):
+    def __init__(
+        self,
+        items,
+        selectAction=None,
+        style=None,
+        verticalContentAlignment=None,
+        height=None,
+        separator=None,
+        spacing=None,
+        id=None,
+    ):
         self.items = items
         self.selectAction = selectAction
         self.style = style
@@ -42,20 +51,34 @@ def __init__(self, items, selectAction=None, style=None,
         self.id = id
 
         super().__init__(
-            serializable_properties=['items'],
+            serializable_properties=["items"],
             simple_properties=[
-                'selectAction', 'style', 'verticalContentAlignment', 'height',
-                'separator', 'spacing', 'id', 'type',
+                "selectAction",
+                "style",
+                "verticalContentAlignment",
+                "height",
+                "separator",
+                "spacing",
+                "id",
+                "type",
             ],
         )
 
 
 class ColumnSet(AdaptiveCardComponent):
     """Adaptive Card Column Set component."""
+
     type = "ColumnSet"
 
-    def __init__(self, columns=None, selectAction=None, height=None,
-                 separator=None, spacing=None, id=None):
+    def __init__(
+        self,
+        columns=None,
+        selectAction=None,
+        height=None,
+        separator=None,
+        spacing=None,
+        id=None,
+    ):
         self.columns = columns
         self.selectAction = selectAction
         self.height = height
@@ -64,19 +87,26 @@ def __init__(self, columns=None, selectAction=None, height=None,
         self.id = id
 
         super().__init__(
-            serializable_properties=['columns'],
+            serializable_properties=["columns"],
             simple_properties=[
-                'selectAction', 'height', 'separator', 'spacing', 'id', 'type',
+                "selectAction",
+                "height",
+                "separator",
+                "spacing",
+                "id",
+                "type",
             ],
         )
 
 
 class FactSet(AdaptiveCardComponent):
     """Adaptive Card Fact Set component."""
+
     type = "FactSet"
 
-    def __init__(self, facts, height=None, separator=None, spacing=None,
-                 id=None):
+    def __init__(
+        self, facts, height=None, separator=None, spacing=None, id=None
+    ):
         self.facts = facts
         self.height = height
         self.separator = separator
@@ -84,19 +114,31 @@ def __init__(self, facts, height=None, separator=None, spacing=None,
         self.id = id
 
         super().__init__(
-            serializable_properties=['facts'],
+            serializable_properties=["facts"],
             simple_properties=[
-                'type', 'height', 'separator', 'id', 'spacing',
+                "type",
+                "height",
+                "separator",
+                "id",
+                "spacing",
             ],
         )
 
 
 class ImageSet(AdaptiveCardComponent):
     """Adaptive Card Image Set component."""
+
     type = "ImageSet"
 
-    def __init__(self, images, imageSize=None, height=None, separator=None,
-                 spacing=None, id=None):
+    def __init__(
+        self,
+        images,
+        imageSize=None,
+        height=None,
+        separator=None,
+        spacing=None,
+        id=None,
+    ):
         self.images = images
         self.imageSize = imageSize
         self.height = height
@@ -105,8 +147,13 @@ def __init__(self, images, imageSize=None, height=None, separator=None,
         self.id = id
 
         super().__init__(
-            serializable_properties=['images'],
+            serializable_properties=["images"],
             simple_properties=[
-                'imageSize', 'height', 'separator', 'spacing', 'id', 'type',
+                "imageSize",
+                "height",
+                "separator",
+                "spacing",
+                "id",
+                "type",
             ],
         )
diff --git a/webexteamssdk/models/cards/inputs.py b/webexteamssdk/models/cards/inputs.py
index 23f450d..441912d 100644
--- a/webexteamssdk/models/cards/inputs.py
+++ b/webexteamssdk/models/cards/inputs.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Access-Tokens API wrapper.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -27,11 +27,21 @@
 
 class Text(AdaptiveCardComponent):
     """Adaptive Card Text component."""
+
     type = "Input.Text"
 
-    def __init__(self, id, isMultiline=None, maxLength=None, placeholder=None,
-                 style=None, value=None, height=None, separator=None,
-                 spacing=None):
+    def __init__(
+        self,
+        id,
+        isMultiline=None,
+        maxLength=None,
+        placeholder=None,
+        style=None,
+        value=None,
+        height=None,
+        separator=None,
+        spacing=None,
+    ):
         self.id = id
         self.isMultiline = isMultiline
         self.maxLength = maxLength
@@ -45,18 +55,36 @@ def __init__(self, id, isMultiline=None, maxLength=None, placeholder=None,
         super().__init__(
             serializable_properties=[],
             simple_properties=[
-                'id', 'type', 'isMultiline', 'maxLength', 'placeholder',
-                'style', 'value', 'height', 'separator', 'spacing',
+                "id",
+                "type",
+                "isMultiline",
+                "maxLength",
+                "placeholder",
+                "style",
+                "value",
+                "height",
+                "separator",
+                "spacing",
             ],
         )
 
 
 class Number(AdaptiveCardComponent):
     """Adaptive Card Number component."""
+
     type = "Input.Number"
 
-    def __init__(self, id, max=None, min=None, placeholder=None, value=None,
-                 height=None, separator=None, spacing=None):
+    def __init__(
+        self,
+        id,
+        max=None,
+        min=None,
+        placeholder=None,
+        value=None,
+        height=None,
+        separator=None,
+        spacing=None,
+    ):
         self.id = id
         self.max = max
         self.min = min
@@ -69,18 +97,35 @@ def __init__(self, id, max=None, min=None, placeholder=None, value=None,
         super().__init__(
             serializable_properties=[],
             simple_properties=[
-                'type', 'id', 'max', 'min', 'placeholder', 'value', 'height',
-                'separator', 'spacing',
+                "type",
+                "id",
+                "max",
+                "min",
+                "placeholder",
+                "value",
+                "height",
+                "separator",
+                "spacing",
             ],
         )
 
 
 class Date(AdaptiveCardComponent):
     """Adaptive Card Date component."""
+
     type = "Input.Date"
 
-    def __init__(self, id, max=None, min=None, placeholder=None, value=None,
-                 height=None, separator=None, spacing=None):
+    def __init__(
+        self,
+        id,
+        max=None,
+        min=None,
+        placeholder=None,
+        value=None,
+        height=None,
+        separator=None,
+        spacing=None,
+    ):
         self.id = id
         self.max = max
         self.min = min
@@ -93,18 +138,35 @@ def __init__(self, id, max=None, min=None, placeholder=None, value=None,
         super().__init__(
             serializable_properties=[],
             simple_properties=[
-                'type', 'id', 'max', 'min', 'placeholder', 'value', 'height',
-                'separator', 'spacing',
+                "type",
+                "id",
+                "max",
+                "min",
+                "placeholder",
+                "value",
+                "height",
+                "separator",
+                "spacing",
             ],
         )
 
 
 class Time(AdaptiveCardComponent):
     """Adaptive Card Time component."""
+
     type = "Input.Time"
 
-    def __init__(self, id, max=None, min=None, placeholder=None, value=None,
-                 height=None, separator=None, spacing=None):
+    def __init__(
+        self,
+        id,
+        max=None,
+        min=None,
+        placeholder=None,
+        value=None,
+        height=None,
+        separator=None,
+        spacing=None,
+    ):
         self.id = id
         self.max = max
         self.min = min
@@ -117,18 +179,35 @@ def __init__(self, id, max=None, min=None, placeholder=None, value=None,
         super().__init__(
             serializable_properties=[],
             simple_properties=[
-                'id', 'type', 'max', 'min', 'placeholder', 'value', 'height',
-                'separator', 'spacing',
+                "id",
+                "type",
+                "max",
+                "min",
+                "placeholder",
+                "value",
+                "height",
+                "separator",
+                "spacing",
             ],
         )
 
 
 class Toggle(AdaptiveCardComponent):
     """Adaptive Card Toggle component."""
+
     type = "Input.Toggle"
 
-    def __init__(self, title, id, value=None, valueOff=None, valueOn=None,
-                 height=None, separator=None, spacing=None):
+    def __init__(
+        self,
+        title,
+        id,
+        value=None,
+        valueOff=None,
+        valueOn=None,
+        height=None,
+        separator=None,
+        spacing=None,
+    ):
         self.title = title
         self.id = id
         self.value = value
@@ -141,18 +220,35 @@ def __init__(self, title, id, value=None, valueOff=None, valueOn=None,
         super().__init__(
             serializable_properties=[],
             simple_properties=[
-                'type', 'id', 'title', 'value', 'valueOff', 'valueOn',
-                'height', 'separator', 'spacing',
+                "type",
+                "id",
+                "title",
+                "value",
+                "valueOff",
+                "valueOn",
+                "height",
+                "separator",
+                "spacing",
             ],
         )
 
 
 class Choices(AdaptiveCardComponent):
     """Adaptive Card Choice Set component."""
+
     type = "Input.ChoiceSet"
 
-    def __init__(self, choices, id, isMultiSelect=None, style=None, value=None,
-                 height=None, separator=None, spacing=None):
+    def __init__(
+        self,
+        choices,
+        id,
+        isMultiSelect=None,
+        style=None,
+        value=None,
+        height=None,
+        separator=None,
+        spacing=None,
+    ):
         self.choices = choices
         self.id = id
         self.isMultiSelect = isMultiSelect
@@ -163,9 +259,16 @@ def __init__(self, choices, id, isMultiSelect=None, style=None, value=None,
         self.spacing = spacing
 
         super().__init__(
-            serializable_properties=['choices'],
+            serializable_properties=["choices"],
             simple_properties=[
-                'id', 'type', 'isMultiSelect', 'style', 'value', 'height',
-                'separator', 'spacing',
+                "choices",
+                "id",
+                "type",
+                "isMultiSelect",
+                "style",
+                "value",
+                "height",
+                "separator",
+                "spacing",
             ],
         )
diff --git a/webexteamssdk/models/cards/options.py b/webexteamssdk/models/cards/options.py
index 5fa6691..f10d1e2 100644
--- a/webexteamssdk/models/cards/options.py
+++ b/webexteamssdk/models/cards/options.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Adaptive Card options.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
diff --git a/webexteamssdk/models/cards/utils.py b/webexteamssdk/models/cards/utils.py
index 78e7e95..60a7e44 100644
--- a/webexteamssdk/models/cards/utils.py
+++ b/webexteamssdk/models/cards/utils.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Access-Tokens API wrapper.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -60,7 +60,7 @@ def check_type(obj, acceptable_types, optional=False, is_list=False):
                     ),
                     none="or None" if optional else "",
                     o=obj,
-                    o_type=repr(type(obj).__name__)
+                    o_type=repr(type(obj).__name__),
                 )
             )
             raise TypeError(error_message)
@@ -76,7 +76,7 @@ def check_type(obj, acceptable_types, optional=False, is_list=False):
                         ),
                         none="or None" if optional else "",
                         o=o,
-                        o_type=repr(type(o).__name__)
+                        o_type=repr(type(o).__name__),
                     )
                 )
                 raise TypeError(error_message)
@@ -92,7 +92,7 @@ def check_type(obj, acceptable_types, optional=False, is_list=False):
                 types=", ".join([repr(t.__name__) for t in acceptable_types]),
                 none="or 'None'" if optional else "",
                 o=obj,
-                o_type=repr(type(obj).__name__)
+                o_type=repr(type(obj).__name__),
             )
         )
         raise TypeError(error_message)
diff --git a/webexteamssdk/models/dictionary.py b/webexteamssdk/models/dictionary.py
index 4105a72..8747882 100644
--- a/webexteamssdk/models/dictionary.py
+++ b/webexteamssdk/models/dictionary.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams data models.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
diff --git a/webexteamssdk/models/immutable.py b/webexteamssdk/models/immutable.py
index 2c77abb..ac0131c 100644
--- a/webexteamssdk/models/immutable.py
+++ b/webexteamssdk/models/immutable.py
@@ -8,7 +8,7 @@
 Python dictionary as a native Python object; providing attribute access using
 native dot-syntax (`object.attribute`).
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -30,8 +30,14 @@
 """
 
 from __future__ import (
-    absolute_import, absolute_import, division, division,
-    print_function, print_function, unicode_literals, unicode_literals,
+    absolute_import,
+    absolute_import,
+    division,
+    division,
+    print_function,
+    print_function,
+    unicode_literals,
+    unicode_literals,
 )
 
 from builtins import *
@@ -65,8 +71,10 @@
 from .mixins.meetings import MeetingBasicPropertiesMixin
 from .mixins.meeting_templates import MeetingTemplateBasicPropertiesMixin
 from .mixins.meeting_invitees import MeetingInviteeBasicPropertiesMixin
+
 from .mixins.meeting_registrants import MeetingRegistrantBasicPropertiesMixin
 
+
 class ImmutableData(object):
     """Model a Webex Teams JSON object as an immutable native Python object."""
 
@@ -111,8 +119,9 @@ def __getattr__(self, item):
                 return item_data
         else:
             raise AttributeError(
-                "'{}' object has no attribute '{}'"
-                "".format(self.__class__.__name__, item)
+                "'{}' object has no attribute '{}'" "".format(
+                    self.__class__.__name__, item
+                )
             )
 
     def __str__(self):
@@ -140,8 +149,7 @@ def _serialize(cls, data):
             # Freeze the elements of the dictionary, sort them, and return
             # them as a list of tuples
             key_value_tuples = [
-                (key, cls._serialize(value))
-                for key, value in data.items()
+                (key, cls._serialize(value)) for key, value in data.items()
             ]
             key_value_tuples.sort()
             return tuple(key_value_tuples)
@@ -156,8 +164,10 @@ def _freeze(self):
 
     def __eq__(self, other):
         """Determine if two objects are equal."""
-        return isinstance(other, self.__class__) \
+        return (
+            isinstance(other, self.__class__)
             and self._freeze() == other._freeze()
+        )
 
     def __hash__(self):
         """Hash the data object."""
@@ -187,8 +197,9 @@ class AccessToken(ImmutableData, AccessTokenBasicPropertiesMixin):
     """Webex Teams Access-Token data model."""
 
 
-class AdminAuditEventData(ImmutableData,
-                          AdminAuditEventDataBasicPropertiesMixin):
+class AdminAuditEventData(
+    ImmutableData, AdminAuditEventDataBasicPropertiesMixin
+):
     """Webex Teams Admin Audit Event Data object data model."""
 
 
@@ -198,7 +209,7 @@ class AdminAuditEvent(ImmutableData, AdminAuditEventBasicPropertiesMixin):
     @property
     def data(self):
         """The event resource data."""
-        return AdminAuditEventData(self._json_data.get('data'))
+        return AdminAuditEventData(self._json_data.get("data"))
 
 
 class AttachmentAction(ImmutableData, AttachmentActionBasicPropertiesMixin):
@@ -210,12 +221,12 @@ class Event(ImmutableData, EventBasicPropertiesMixin):
 
     @property
     def data(self):
-        """The event’s data representation.
+        """The event's data representation.
 
         This object will contain the event's resource, such as memberships or
         messages, at the time the event took place.
         """
-        return ImmutableData(self._json_data.get('data'))
+        return ImmutableData(self._json_data.get("data"))
 
 
 class License(ImmutableData, LicenseBasicPropertiesMixin):
@@ -272,7 +283,7 @@ class WebhookEvent(ImmutableData, WebhookEventBasicPropertiesMixin):
     @property
     def data(self):
         """The event resource data."""
-        return ImmutableData(self._json_data.get('data'))
+        return ImmutableData(self._json_data.get("data"))
 
 
 class GuestIssuerToken(ImmutableData, GuestIssuerTokenBasicPropertiesMixin):
@@ -282,17 +293,22 @@ class GuestIssuerToken(ImmutableData, GuestIssuerTokenBasicPropertiesMixin):
 class Recording(ImmutableData, RecordingBasicPropertiesMixin):
     """Webex Teams Recording data model"""
 
+
 class Meeting(ImmutableData, MeetingBasicPropertiesMixin):
     """Webex Meeting data model"""
 
+
 class MeetingTemplate(ImmutableData, MeetingTemplateBasicPropertiesMixin):
     """Webex MeetingTemplate data model"""
 
+
 class MeetingInvitee(ImmutableData, MeetingInviteeBasicPropertiesMixin):
-    """Webex MeetingInvitees data model"""
+    """Webex MeetingInvitee data model"""
+
 
 class MeetingRegistrant(ImmutableData, MeetingRegistrantBasicPropertiesMixin):
-    """Webex MeetingRegistrants data model"""
+    """Webex MeetingRegistrant data model"""
+
 
 immutable_data_models = defaultdict(
     lambda: ImmutableData,
@@ -318,7 +334,7 @@ class MeetingRegistrant(ImmutableData, MeetingRegistrantBasicPropertiesMixin):
     meeting=Meeting,
     meetingTemplate=MeetingTemplate,
     meetingInvitee=MeetingInvitee,
-    meetingRegistrant=MeetingRegistrant
+    meetingRegistrant=MeetingRegistrant,
 )
 
 
diff --git a/webexteamssdk/models/mixins/access_token.py b/webexteamssdk/models/mixins/access_token.py
index 17dee87..a32541a 100644
--- a/webexteamssdk/models/mixins/access_token.py
+++ b/webexteamssdk/models/mixins/access_token.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Access-Token data model.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
@@ -39,19 +38,19 @@ class AccessTokenBasicPropertiesMixin(object):
     @property
     def access_token(self):
         """Webex Teams access token."""
-        return self._json_data.get('access_token')
+        return self._json_data.get("access_token")
 
     @property
     def expires_in(self):
         """Access token expiry time (in seconds)."""
-        return self._json_data.get('expires_in')
+        return self._json_data.get("expires_in")
 
     @property
     def refresh_token(self):
         """Refresh token used to request a new/refreshed access token."""
-        return self._json_data.get('refresh_token')
+        return self._json_data.get("refresh_token")
 
     @property
     def refresh_token_expires_in(self):
         """Refresh token expiry time (in seconds)."""
-        return self._json_data.get('refresh_token_expires_in')
+        return self._json_data.get("refresh_token_expires_in")
diff --git a/webexteamssdk/models/mixins/admin_audit_event.py b/webexteamssdk/models/mixins/admin_audit_event.py
index be2c612..e0989fa 100644
--- a/webexteamssdk/models/mixins/admin_audit_event.py
+++ b/webexteamssdk/models/mixins/admin_audit_event.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Webhook-Event data model.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
@@ -41,77 +40,77 @@ class AdminAuditEventDataBasicPropertiesMixin(object):
     @property
     def actorOrgName(self):
         """The display name of the organization."""
-        return self._json_data.get('actorOrgName')
+        return self._json_data.get("actorOrgName")
 
     @property
     def targetName(self):
         """The name of the resource being acted upon."""
-        return self._json_data.get('targetName')
+        return self._json_data.get("targetName")
 
     @property
     def eventDescription(self):
         """A description for the event."""
-        return self._json_data.get('eventDescription')
+        return self._json_data.get("eventDescription")
 
     @property
     def actorName(self):
         """The name of the person who performed the action."""
-        return self._json_data.get('actorName')
+        return self._json_data.get("actorName")
 
     @property
     def actorEmail(self):
         """The email of the person who performed the action."""
-        return self._json_data.get('actorEmail')
+        return self._json_data.get("actorEmail")
 
     @property
     def adminRoles(self):
         """Admin roles for the person."""
-        return self._json_data.get('adminRoles')
+        return self._json_data.get("adminRoles")
 
     @property
     def trackingId(self):
         """A tracking identifier for the event."""
-        return self._json_data.get('trackingId')
+        return self._json_data.get("trackingId")
 
     @property
     def targetType(self):
         """The type of resource changed by the event."""
-        return self._json_data.get('targetType')
+        return self._json_data.get("targetType")
 
     @property
     def targetId(self):
         """The identifier for the resource changed by the event."""
-        return self._json_data.get('targetId')
+        return self._json_data.get("targetId")
 
     @property
     def eventCategory(self):
         """The category of resource changed by the event."""
-        return self._json_data.get('eventCategory')
+        return self._json_data.get("eventCategory")
 
     @property
     def actorUserAgent(self):
         """The browser user agent of the person who performed the action."""
-        return self._json_data.get('actorUserAgent')
+        return self._json_data.get("actorUserAgent")
 
     @property
     def actorIp(self):
         """The IP address of the person who performed the action."""
-        return self._json_data.get('actorIp')
+        return self._json_data.get("actorIp")
 
     @property
     def targetOrgId(self):
         """The orgId of the organization."""
-        return self._json_data.get('targetOrgId')
+        return self._json_data.get("targetOrgId")
 
     @property
     def actionText(self):
         """A more detailed description of the change made by the person."""
-        return self._json_data.get('actionText')
+        return self._json_data.get("actionText")
 
     @property
     def targetOrgName(self):
         """The name of the organization being acted upon."""
-        return self._json_data.get('targetOrgName')
+        return self._json_data.get("targetOrgName")
 
 
 class AdminAuditEventBasicPropertiesMixin(object):
@@ -120,22 +119,22 @@ class AdminAuditEventBasicPropertiesMixin(object):
     @property
     def id(self):
         """A unique identifier for the event."""
-        return self._json_data.get('id')
+        return self._json_data.get("id")
 
     @property
     def actorId(self):
         """The personId of the person who made the change."""
-        return self._json_data.get('actorId')
+        return self._json_data.get("actorId")
 
     @property
     def orgId(self):
         """The orgId of the person who made the change."""
-        return self._json_data.get('orgId')
+        return self._json_data.get("orgId")
 
     @property
     def created(self):
         """The date and time the event took place."""
-        created = self._json_data.get('created')
+        created = self._json_data.get("created")
         if created:
             return WebexTeamsDateTime.strptime(created)
         else:
diff --git a/webexteamssdk/models/mixins/attachment_action.py b/webexteamssdk/models/mixins/attachment_action.py
index 1bd2db4..c19262e 100644
--- a/webexteamssdk/models/mixins/attachment_action.py
+++ b/webexteamssdk/models/mixins/attachment_action.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Message data model.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
@@ -41,17 +40,17 @@ class AttachmentActionBasicPropertiesMixin(object):
     @property
     def id(self):
         """A unique identifier for the action."""
-        return self._json_data.get('id')
+        return self._json_data.get("id")
 
     @property
     def personId(self):
         """The ID of the person who performed the action."""
-        return self._json_data.get('personId')
+        return self._json_data.get("personId")
 
     @property
     def roomId(self):
         """The ID of the room the action was performed within."""
-        return self._json_data.get('roomId')
+        return self._json_data.get("roomId")
 
     @property
     def type(self):
@@ -60,22 +59,22 @@ def type(self):
         Attachment action enum:
             'submit': submit filled in inputs
         """
-        return self._json_data.get('type')
+        return self._json_data.get("type")
 
     @property
     def messageId(self):
         """The parent message the attachment action was performed on."""
-        return self._json_data.get('messageId')
+        return self._json_data.get("messageId")
 
     @property
     def inputs(self):
         """The attachment action's inputs"""
-        return self._json_data.get('inputs')
+        return self._json_data.get("inputs")
 
     @property
     def created(self):
         """The date and time the action was created."""
-        created = self._json_data.get('created')
+        created = self._json_data.get("created")
         if created:
             return WebexTeamsDateTime.strptime(created)
         else:
diff --git a/webexteamssdk/models/mixins/event.py b/webexteamssdk/models/mixins/event.py
index e086c39..8146886 100644
--- a/webexteamssdk/models/mixins/event.py
+++ b/webexteamssdk/models/mixins/event.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Event data model.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
@@ -41,7 +40,7 @@ class EventBasicPropertiesMixin(object):
     @property
     def id(self):
         """The unique identifier for the event."""
-        return self._json_data.get('id')
+        return self._json_data.get("id")
 
     @property
     def resource(self):
@@ -51,7 +50,7 @@ def resource(self):
             `messages`
             `memberships`
         """
-        return self._json_data.get('resource')
+        return self._json_data.get("resource")
 
     @property
     def type(self):
@@ -62,27 +61,27 @@ def type(self):
             `updated`
             `deleted`
         """
-        return self._json_data.get('type')
+        return self._json_data.get("type")
 
     @property
     def appId(self):
         """The ID of the application for the event."""
-        return self._json_data.get('appId')
+        return self._json_data.get("appId")
 
     @property
     def actorId(self):
         """The ID of the person who performed the action."""
-        return self._json_data.get('actorId')
+        return self._json_data.get("actorId")
 
     @property
     def orgId(self):
         """The ID of the organization for the event."""
-        return self._json_data.get('orgId')
+        return self._json_data.get("orgId")
 
     @property
     def created(self):
         """The date and time of the event."""
-        created = self._json_data.get('created')
+        created = self._json_data.get("created")
         if created:
             return WebexTeamsDateTime.strptime(created)
         else:
diff --git a/webexteamssdk/models/mixins/guest_issuer_token.py b/webexteamssdk/models/mixins/guest_issuer_token.py
index d354a13..5812584 100644
--- a/webexteamssdk/models/mixins/guest_issuer_token.py
+++ b/webexteamssdk/models/mixins/guest_issuer_token.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Guest-Issuer data model.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
diff --git a/webexteamssdk/models/mixins/license.py b/webexteamssdk/models/mixins/license.py
index f1c53ea..0ab203f 100644
--- a/webexteamssdk/models/mixins/license.py
+++ b/webexteamssdk/models/mixins/license.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams License data model.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
diff --git a/webexteamssdk/models/mixins/meeting_invitees.py b/webexteamssdk/models/mixins/meeting_invitees.py
index 2dc8818..5c21d1b 100644
--- a/webexteamssdk/models/mixins/meeting_invitees.py
+++ b/webexteamssdk/models/mixins/meeting_invitees.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex MeetingInvitees data model.
 
-Copyright (c) 2016-2022 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -32,37 +32,35 @@
 from builtins import *
 
 
-
 class MeetingInviteeBasicPropertiesMixin(object):
     """MeetingInvitee basic properties."""
-    
+
     @property
     def id(self):
         """Unique id for the meeting invitee"""
         return self._json_data.get("id")
-    
+
     @property
     def email(self):
         """Email address for the meeting invitee"""
         return self._json_data.get("email")
-    
+
     @property
     def displayName(self):
         """Display name of the meeting invitee"""
         return self._json_data.get("displayName")
-    
+
     @property
     def coHost(self):
         """CoHost status of the invitee"""
         return self._json_data.get("coHost")
-    
+
     @property
     def meetingId(self):
         """Unique id for the meeting that the invitee is part of"""
         return self._json_data.get("meetingId")
-    
+
     @property
     def panelist(self):
         """Flag to indicate if the invitee is panelist or not"""
         return self._json_data.get("panelist")
-    
\ No newline at end of file
diff --git a/webexteamssdk/models/mixins/meeting_registrants.py b/webexteamssdk/models/mixins/meeting_registrants.py
index f44d4ab..4ab4bfe 100644
--- a/webexteamssdk/models/mixins/meeting_registrants.py
+++ b/webexteamssdk/models/mixins/meeting_registrants.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex MeetingRegistrants data model.
 
-Copyright (c) 2016-2022 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -32,102 +32,100 @@
 from builtins import *
 
 
-
 class MeetingRegistrantBasicPropertiesMixin(object):
     """MeetingRegistrant basic properties."""
-    
+
     @property
     def registrantId(self):
         """New registrant's ID."""
         return self._json_data.get("registrantId")
-    
+
     @property
     def status(self):
         """New registrant's status."""
         return self._json_data.get("status")
-    
+
     @property
     def firstName(self):
         """Registrant's first name."""
         return self._json_data.get("firstName")
-    
+
     @property
     def lastName(self):
         """Registrant's last name."""
         return self._json_data.get("lastName")
-    
+
     @property
     def email(self):
         """Registrant's email."""
         return self._json_data.get("email")
-    
+
     @property
     def jobTitle(self):
         """Registrant's job title."""
         return self._json_data.get("jobTitle")
-    
+
     @property
     def companyName(self):
         """Registrant's company."""
         return self._json_data.get("companyName")
-    
+
     @property
     def address1(self):
         """Registrant's first address line."""
         return self._json_data.get("address1")
-    
+
     @property
     def address2(self):
         """Registrant's second address line."""
         return self._json_data.get("address2")
-    
+
     @property
     def city(self):
         """Registrant's city name."""
         return self._json_data.get("city")
-    
+
     @property
     def state(self):
         """Registrant's state."""
         return self._json_data.get("state")
-    
+
     @property
     def zipCode(self):
         """Registrant's postal code."""
         return self._json_data.get("zipCode")
-    
+
     @property
     def countryRegion(self):
         """Registrant's country or region."""
         return self._json_data.get("countryRegion")
-    
+
     @property
     def workPhone(self):
         """Registrant's work phone number."""
         return self._json_data.get("workPhone")
-    
+
     @property
     def fax(self):
         """Registrant's FAX number."""
         return self._json_data.get("fax")
-    
+
     @property
     def registrationTime(self):
         """Registrant's registration time."""
         return self._json_data.get("registrationTime")
-    
+
     @property
     def customizedQuestions(self):
         """List of registrant's answers for customized questions,"""
         return self._json_data.get("customizedQuestions")
-    
+
     @property
     def sourceId(self):
         """Registrant's source id."""
         return self._json_data.get("sourceId")
-    
+
     @property
     def registrationId(self):
         """Registrant's registration ID."""
         return self._json_data.get("registrationId")
-    
\ No newline at end of file
diff --git a/webexteamssdk/models/mixins/meeting_templates.py b/webexteamssdk/models/mixins/meeting_templates.py
index d1b8751..70f5e45 100644
--- a/webexteamssdk/models/mixins/meeting_templates.py
+++ b/webexteamssdk/models/mixins/meeting_templates.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex MeetingTemplates data model.
 
-Copyright (c) 2016-2022 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -32,47 +32,50 @@
 from builtins import *
 
 
-
 class MeetingTemplateBasicPropertiesMixin(object):
     """MeetingTemplate basic properties."""
-    
+
     @property
     def id(self):
         """Unique id for meeting template"""
         return self._json_data.get("id")
-    
+
     @property
     def name(self):
         """Name of the meeting template"""
         return self._json_data.get("name")
-    
+
     @property
     def locale(self):
         """Locale for the meeting template"""
         return self._json_data.get("locale")
-    
+
     @property
     def siteUrl(self):
         """Site URL for the meeting template"""
         return self._json_data.get("siteUrl")
-    
+
     @property
     def templateType(self):
         """Type of the meeting template (meeting, webinar)"""
         return self._json_data.get("templateType")
-    
+
     @property
     def isDefault(self):
         """Whether or not the meeting template is a default template"""
         return self._json_data.get("isDefault")
-    
+
     @property
     def isStandard(self):
         """Whether or not the meeting template is a standard template"""
         return self._json_data.get("isStandard")
-    
+
     @property
     def meeting(self):
-        """Meeting object which is used to create a meeting by the meeting template. Please note that the meeting object should be used to create a meeting immediately."""
+        """Meeting object which is used as a template to create a meeting.
+
+        Meeting object which is used to create a meeting by the meeting
+        template. Please note that the meeting object should be used to create
+        a meeting immediately.
+        """
         return self._json_data.get("meeting")
-    
\ No newline at end of file
diff --git a/webexteamssdk/models/mixins/meetings.py b/webexteamssdk/models/mixins/meetings.py
index 5255f13..67b7cda 100644
--- a/webexteamssdk/models/mixins/meetings.py
+++ b/webexteamssdk/models/mixins/meetings.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Meetings data model.
 
-Copyright (c) 2016-2022 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -32,232 +32,255 @@
 from builtins import *
 
 
-
 class MeetingBasicPropertiesMixin(object):
     """Meeting basic properties."""
-    
+
     @property
     def id(self):
-        """Unique identifier for the meeting"""
+        """Unique identifier for the meeting."""
         return self._json_data.get("id")
-    
+
     @property
     def meetingNumber(self):
-        """Meeting number (of series, scheduled meeting or instance)"""
+        """Meeting number (of series, scheduled meeting, or instance)."""
         return self._json_data.get("meetingNumber")
-    
+
     @property
     def title(self):
-        """Title of the meeting"""
+        """Title of the meeting."""
         return self._json_data.get("title")
-    
+
     @property
     def agenda(self):
-        """Meeting agenda (Maximum 1300 characters)"""
+        """Meeting agenda (Maximum 1300 characters)."""
         return self._json_data.get("agenda")
-    
+
     @property
     def password(self):
-        """Password of the meeting"""
+        """Password of the meeting."""
         return self._json_data.get("password")
-    
+
     @property
     def phoneAndVideoSystemPassword(self):
-        """8-digit numeric password to join via phone/device"""
+        """Eight (8) digit numeric password to join via phone/device."""
         return self._json_data.get("phoneAndVideoSystemPassword")
-    
+
     @property
     def meetingType(self):
-        """Type of this meeting (Values: meetingSeries, scheduledMeeting, meeting)"""
+        """Type of meeting.
+
+        Values: `meetingSeries`, `scheduledMeeting`, `meeting`
+        """
         return self._json_data.get("meetingType")
-    
+
     @property
     def state(self):
-        """State of the meeting (Values: active, scheduled, ready, lobby, inProgress, ended, missed, expired)"""
+        """Meeting state.
+
+        Values: `active`, `scheduled`, `ready`, `lobby`, `inProgress`, `ended`,
+            `missed`, `expired`
+        """
         return self._json_data.get("state")
-    
+
     @property
     def timezone(self):
-        """Time zone of start and end property in IANA time zone database format."""
+        """Time zone.
+
+        Time zone of start and end property in IANA time zone database format.
+        """
         return self._json_data.get("timezone")
-    
+
     @property
     def start(self):
         """Start time of the meeting in ISO 8601."""
         return self._json_data.get("start")
-    
+
     @property
     def end(self):
         """End time of the meeting in ISO 8601."""
         return self._json_data.get("end")
-    
+
     @property
     def recurrence(self):
         """Meeting recurrence according to RFC 2445"""
         return self._json_data.get("recurrence")
-    
+
     @property
     def hostUserId(self):
         """Unique id of the meeting host."""
         return self._json_data.get("hostUserId")
-    
+
     @property
     def hostDisplayName(self):
         """Display name for the meeting host"""
         return self._json_data.get("hostDisplayName")
-    
+
     @property
     def hostEmail(self):
         """Email address of the meeting host"""
         return self._json_data.get("hostEmail")
-    
+
     @property
     def hostKey(self):
         """Key for joining the meeting as host"""
         return self._json_data.get("hostKey")
-    
+
     @property
     def siteUrl(self):
         """Site URL for the meeting"""
         return self._json_data.get("siteUrl")
-    
+
     @property
     def webLink(self):
         """Link to a meeting information page that launches the client"""
         return self._json_data.get("webLink")
-    
+
     @property
     def registerLink(self):
-        """Link to a page where attendees can register for the webinar. Only applies for webinars."""
+        """Link to a page where attendees can register for the webinar.
+
+        Only applies for webinars.
+        """
         return self._json_data.get("registerLink")
-    
+
     @property
     def sipAddress(self):
         """SIP address for callback from a video system"""
         return self._json_data.get("sipAddress")
-    
+
     @property
     def dialInIpAddress(self):
         """IP address for callback from video system."""
         return self._json_data.get("dialInIpAddress")
-    
+
     @property
     def roomId(self):
         """Room ID of the associated webex space. Only in space meetings."""
         return self._json_data.get("roomId")
-    
+
     @property
     def enabledAutoRecordMeeting(self):
         """Whether or not meeting is recorded automatically."""
         return self._json_data.get("enabledAutoRecordMeeting")
-    
+
     @property
     def allowAnyUserToBeCoHost(self):
-        """Allow any attendee with host account on site to become co host"""
+        """Allow any attendee with host account on site to become cohost"""
         return self._json_data.get("allowAnyUserToBeCoHost")
-    
+
     @property
     def enabledJoinBeforeHost(self):
         """Allow attendees to join before the host."""
         return self._json_data.get("enabledJoinBeforeHost")
-    
+
     @property
     def enableConnectAudioBeforeHost(self):
         """Allow attendees to connect audio before the host joins."""
         return self._json_data.get("enableConnectAudioBeforeHost")
-    
+
     @property
     def joinBeforeHostMinutes(self):
         """Number of minutes attendees can join before the start time."""
         return self._json_data.get("joinBeforeHostMinutes")
-    
+
     @property
     def excludePassword(self):
         """Exclude meeting password from meeting invite emails."""
         return self._json_data.get("excludePassword")
-    
+
     @property
     def publicMeeting(self):
         """Allow meeting to be listed on public calendar"""
         return self._json_data.get("publicMeeting")
-    
+
     @property
     def reminderTime(self):
-        """Number of minutes before start time a reminder is send to the host"""
+        """Number of minutes before start time to send reminder to the host."""
         return self._json_data.get("reminderTime")
-    
+
     @property
     def unlockedMeetingJoinSecurity(self):
-        """Join settings for uninvited people"""
+        """Join settings for uninvited people."""
         return self._json_data.get("unlockedMeetingJoinSecurity")
-    
+
     @property
     def sessionTypeId(self):
         """Unique identifier for a meeting session type."""
         return self._json_data.get("sessionTypeId")
-    
+
     @property
     def scheduledType(self):
-        """Type of meeting (regular, webinar, meeting in personal room)"""
+        """Type of meeting (regular, webinar, meeting in personal room)."""
         return self._json_data.get("scheduledType")
-    
+
     @property
     def enabledWebcastView(self):
-        """Whether or not webcast view is enabled"""
+        """Whether or not webcast view is enabled."""
         return self._json_data.get("enabledWebcastView")
-    
+
     @property
     def panelistPassword(self):
-        """Password for panelists of a webinar meeting"""
+        """Password for panelists of a webinar meeting."""
         return self._json_data.get("panelistPassword")
-    
+
     @property
     def phoneAndVideoSystemPanelistPassword(self):
-        """8-digit numeric panelist pasword for phone/device usage"""
+        """Eight (8) digit numeric panelist password for phone/device usage."""
         return self._json_data.get("phoneAndVideoSystemPanelistPassword")
-    
+
     @property
     def enableAutomaticLock(self):
         """Whether or not to automatically lock the meeting after start."""
         return self._json_data.get("enableAutomaticLock")
-    
+
     @property
     def automaticLockMinutes(self):
         """Number of minutes for the meeting to be automatically locked."""
         return self._json_data.get("automaticLockMinutes")
-    
+
     @property
     def allowFirstUserToBeCoHost(self):
-        """Allow the first joiner with host account on the meeting site to be co host."""
+        """Allow first organization member to join to cohost the meeting.
+
+        Allow the first joiner with host account on the meeting site to be
+        cohost.
+        """
         return self._json_data.get("allowFirstUserToBeCoHost")
-    
+
     @property
     def allowAuthenticatedDevices(self):
-        """Whether or not to allow authenticated video devices in the meeting's organization to start or join the meeting"""
+        """Allow authenticated video devices to start or join the meeting.
+
+        Whether or not to allow authenticated video devices in the meeting's
+        organization to start or join the meeting.
+        """
         return self._json_data.get("allowAuthenticatedDevices")
-    
+
     @property
     def telephony(self):
-        """Information for callbacks from a meeting to phone or for joining via phone."""
+        """Telephony information used to join the meeting from a phone.
+
+        Information for callbacks from a meeting to phone or for joining via
+        phone.
+        """
         return self._json_data.get("telephony")
-    
+
     @property
     def meetingOptions(self):
-        """Options for this meeting"""
+        """Options for this meeting."""
         return self._json_data.get("meetingOptions")
-    
+
     @property
     def registration(self):
         """Meeting registration information."""
         return self._json_data.get("registration")
-    
+
     @property
     def integrationTags(self):
-        """List of external keys created by integrations"""
+        """List of external keys created by integrations."""
         return self._json_data.get("integrationTags")
-    
+
     @property
     def simultaneousInterpretation(self):
         """Simultaneous interpretation information for the meeting."""
         return self._json_data.get("simultaneousInterpretation")
-    
\ No newline at end of file
diff --git a/webexteamssdk/models/mixins/membership.py b/webexteamssdk/models/mixins/membership.py
index f1ac31d..57bb846 100644
--- a/webexteamssdk/models/mixins/membership.py
+++ b/webexteamssdk/models/mixins/membership.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Membership data model.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
@@ -43,37 +42,37 @@ class MembershipBasicPropertiesMixin(object):
     @property
     def id(self):
         """A unique identifier for the membership."""
-        return self._json_data.get('id')
+        return self._json_data.get("id")
 
     @property
     def roomId(self):
         """The room ID."""
-        return self._json_data.get('roomId')
+        return self._json_data.get("roomId")
 
     @property
     def personId(self):
         """The person ID."""
-        return self._json_data.get('personId')
+        return self._json_data.get("personId")
 
     @property
     def personEmail(self):
         """The email address of the person."""
-        return self._json_data.get('personEmail')
+        return self._json_data.get("personEmail")
 
     @property
     def personDisplayName(self):
         """The display name of the person."""
-        return self._json_data.get('personDisplayName')
+        return self._json_data.get("personDisplayName")
 
     @property
     def personOrgId(self):
         """The organization ID of the person."""
-        return self._json_data.get('personOrgId')
+        return self._json_data.get("personOrgId")
 
     @property
     def isModerator(self):
         """Whether or not the participant is a room moderator."""
-        return self._json_data.get('isModerator')
+        return self._json_data.get("isModerator")
 
     @property
     def isMonitor(self):
@@ -81,13 +80,14 @@ def isMonitor(self):
         warnings.warn(
             "The `isMonitor` attribute has been deprecated.",
             DeprecationWarning,
+            stacklevel=1,
         )
-        return self._json_data.get('isMonitor')
+        return self._json_data.get("isMonitor")
 
     @property
     def created(self):
         """The date and time when the membership was created."""
-        created = self._json_data.get('created')
+        created = self._json_data.get("created")
         if created:
             return WebexTeamsDateTime.strptime(created)
         else:
diff --git a/webexteamssdk/models/mixins/message.py b/webexteamssdk/models/mixins/message.py
index e8cc768..9a74bae 100644
--- a/webexteamssdk/models/mixins/message.py
+++ b/webexteamssdk/models/mixins/message.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Message data model.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
diff --git a/webexteamssdk/models/mixins/organization.py b/webexteamssdk/models/mixins/organization.py
index 8f46dd5..8cd3c82 100644
--- a/webexteamssdk/models/mixins/organization.py
+++ b/webexteamssdk/models/mixins/organization.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Organization data model.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
@@ -41,17 +40,17 @@ class OrganizationBasicPropertiesMixin(object):
     @property
     def id(self):
         """A unique identifier for the organization."""
-        return self._json_data.get('id')
+        return self._json_data.get("id")
 
     @property
     def displayName(self):
         """Full name of the organization."""
-        return self._json_data.get('displayName')
+        return self._json_data.get("displayName")
 
     @property
     def created(self):
         """The date and time the organization was created."""
-        created = self._json_data.get('created')
+        created = self._json_data.get("created")
         if created:
             return WebexTeamsDateTime.strptime(created)
         else:
diff --git a/webexteamssdk/models/mixins/person.py b/webexteamssdk/models/mixins/person.py
index c9f5616..cb8f179 100644
--- a/webexteamssdk/models/mixins/person.py
+++ b/webexteamssdk/models/mixins/person.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Person data model.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
@@ -48,10 +47,21 @@ def emails(self):
         """The email addresses of the person."""
         return self._json_data.get("emails")
 
+    @property
     def phoneNumbers(self):
         """Phone numbers for the person."""
         return self._json_data.get("phoneNumbers")
 
+    @property
+    def extension(self):
+        """The Webex Calling extension for the person."""
+        return self._json_data.get("extension")
+
+    @property
+    def locationId(self):
+        """The location ID for the person."""
+        return self._json_data.get("locationId")
+
     @property
     def displayName(self):
         """The full name of the person."""
@@ -88,15 +98,43 @@ def orgId(self):
 
     @property
     def roles(self):
-        """An array of role strings representing the roles to which this
-        person belongs. """
+        """List of roles for the person.
+
+        An list of role strings representing the roles to which this
+        person belongs.
+        """
         return self._json_data.get("roles")
 
     @property
     def licenses(self):
-        """An array of license strings allocated to this person."""
+        """An list of license strings allocated to this person."""
         return self._json_data.get("licenses")
 
+    @property
+    def department(self):
+        """The business department the user belongs to."""
+        return self._json_data.get("department")
+
+    @property
+    def manager(self):
+        """A manager identifier."""
+        return self._json_data.get("manager")
+
+    @property
+    def managerId(self):
+        """Person ID of the manager."""
+        return self._json_data.get("managerId")
+
+    @property
+    def title(self):
+        """The person's title."""
+        return self._json_data.get("title")
+
+    @property
+    def addresses(self):
+        """A person's addresses."""
+        return self._json_data.get("addresses")
+
     @property
     def created(self):
         """The date and time the person was created."""
@@ -127,13 +165,32 @@ def timezone(self):
     @property
     def lastActivity(self):
         """The date and time of the person"s last activity within Webex
-        Teams. """
+        Teams."""
         last_activity = self._json_data.get("lastActivity")
         if last_activity:
             return WebexTeamsDateTime.strptime(last_activity)
         else:
             return None
 
+    @property
+    def siteUrls(self):
+        """One or several site names where this user has a role."""
+        return self._json_data.get("siteUrls")
+
+    @property
+    def sipAddresses(self):
+        """The user's SIP addresses."""
+        return self._json_data.get("sipAddresses")
+
+    @property
+    def xmppFederationJid(self):
+        """XMPP federation identifier.
+
+        Identifier for intra-domain federation with other XMPP based messenger
+        systems.
+        """
+        return self._json_data.get("xmppFederationJid")
+
     @property
     def status(self):
         """The current presence status of the person.
@@ -158,7 +215,7 @@ def status(self):
 
             `presenting`: The user is sharing content
 
-            `unknown`: The user’s status could not be determined
+            `unknown`: The user's status could not be determined
         """
         return self._json_data.get("status")
 
diff --git a/webexteamssdk/models/mixins/recording.py b/webexteamssdk/models/mixins/recording.py
index ac80dbd..8b73128 100644
--- a/webexteamssdk/models/mixins/recording.py
+++ b/webexteamssdk/models/mixins/recording.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Recording data model.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
@@ -45,27 +44,42 @@ def id(self):
 
     @property
     def meetingId(self):
-        """Unique identifier for the parent ended meeting instance which the recording belongs to."""
+        """Meeting identifier for the meeting instance.
+
+        Unique identifier for the parent ended meeting instance that the
+        recording belongs to.
+        """
         return self._json_data.get("meetingId")
 
     @property
     def scheduledMeetingId(self):
-        """Unique identifier for the parent scheduled meeting which the recording belongs to."""
+        """Meeting identifier for the scheduled meeting.
+
+        Unique identifier for the parent scheduled meeting which the recording
+        belongs to.
+        """
         return self._json_data.get("scheduledMeetingId")
 
     @property
     def topic(self):
-        """The recording's topic."""
+        """The recording topic."""
         return self._json_data.get("topic")
 
     @property
     def meetingSeriesId(self):
-        """Unique identifier for the parent meeting series which the recording belongs to."""
+        """Meeting series identifier.
+
+        Unique identifier for the parent meeting series which the recording
+        belongs to.
+        """
         return self._json_data.get("meetingSeriesId")
 
     @property
     def createTime(self):
-        """The date and time recording was created in ISO 8601 compliant format."""
+        """Recording creation time.
+
+        The date and time recording was created in ISO 8601 compliant format.
+        """
         created = self._json_data.get("createTime")
         if created:
             return WebexTeamsDateTime.strptime(created)
@@ -124,5 +138,9 @@ def shareToMe(self):
 
     @property
     def integrationTags(self):
-        """External keys of the parent meeting created by an integration application."""
+        """Integration tags.
+
+        External keys of the parent meeting created by an integration
+        application.
+        """
         return self._json_data.get("integrationTags")
diff --git a/webexteamssdk/models/mixins/role.py b/webexteamssdk/models/mixins/role.py
index 95767b1..83465a8 100644
--- a/webexteamssdk/models/mixins/role.py
+++ b/webexteamssdk/models/mixins/role.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Role data model.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
@@ -39,9 +38,9 @@ class RoleBasicPropertiesMixin(object):
     @property
     def id(self):
         """A unique identifier for the role."""
-        return self._json_data.get('id')
+        return self._json_data.get("id")
 
     @property
     def name(self):
         """The name of the role."""
-        return self._json_data.get('name')
+        return self._json_data.get("name")
diff --git a/webexteamssdk/models/mixins/room.py b/webexteamssdk/models/mixins/room.py
index 5c0e526..6d01db2 100644
--- a/webexteamssdk/models/mixins/room.py
+++ b/webexteamssdk/models/mixins/room.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Room data model.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
diff --git a/webexteamssdk/models/mixins/room_meeting_info.py b/webexteamssdk/models/mixins/room_meeting_info.py
index 28ba87c..7a3aa3e 100644
--- a/webexteamssdk/models/mixins/room_meeting_info.py
+++ b/webexteamssdk/models/mixins/room_meeting_info.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Room Meeting Info data model.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
diff --git a/webexteamssdk/models/mixins/room_tab.py b/webexteamssdk/models/mixins/room_tab.py
index 49f9619..8116cf1 100644
--- a/webexteamssdk/models/mixins/room_tab.py
+++ b/webexteamssdk/models/mixins/room_tab.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Room data model.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
diff --git a/webexteamssdk/models/mixins/team.py b/webexteamssdk/models/mixins/team.py
index 8ce60e3..906767a 100644
--- a/webexteamssdk/models/mixins/team.py
+++ b/webexteamssdk/models/mixins/team.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Team data model.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
@@ -41,22 +40,22 @@ class TeamBasicPropertiesMixin(object):
     @property
     def id(self):
         """A unique identifier for the team."""
-        return self._json_data.get('id')
+        return self._json_data.get("id")
 
     @property
     def name(self):
         """A user-friendly name for the team."""
-        return self._json_data.get('name')
+        return self._json_data.get("name")
 
     @property
     def creatorId(self):
         """The ID of the person who created the team."""
-        return self._json_data.get('creatorId')
+        return self._json_data.get("creatorId")
 
     @property
     def created(self):
         """The date and time the team was created."""
-        created = self._json_data.get('created')
+        created = self._json_data.get("created")
         if created:
             return WebexTeamsDateTime.strptime(created)
         else:
diff --git a/webexteamssdk/models/mixins/team_membership.py b/webexteamssdk/models/mixins/team_membership.py
index 9820260..fcf2afd 100644
--- a/webexteamssdk/models/mixins/team_membership.py
+++ b/webexteamssdk/models/mixins/team_membership.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Team-Membership data model.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
@@ -41,42 +40,42 @@ class TeamMembershipBasicPropertiesMixin(object):
     @property
     def id(self):
         """A unique identifier for the team membership."""
-        return self._json_data.get('id')
+        return self._json_data.get("id")
 
     @property
     def teamId(self):
         """The team ID."""
-        return self._json_data.get('teamId')
+        return self._json_data.get("teamId")
 
     @property
     def personId(self):
         """The person ID."""
-        return self._json_data.get('personId')
+        return self._json_data.get("personId")
 
     @property
     def personEmail(self):
         """The email address of the person."""
-        return self._json_data.get('personEmail')
+        return self._json_data.get("personEmail")
 
     @property
     def personDisplayName(self):
         """The display name of the person."""
-        return self._json_data.get('personDisplayName')
+        return self._json_data.get("personDisplayName")
 
     @property
     def personOrgId(self):
         """The organization ID of the person."""
-        return self._json_data.get('personOrgId')
+        return self._json_data.get("personOrgId")
 
     @property
     def isModerator(self):
         """Whether or not the participant is a team moderator."""
-        return self._json_data.get('isModerator')
+        return self._json_data.get("isModerator")
 
     @property
     def created(self):
         """The date and time when the team membership was created."""
-        created = self._json_data.get('created')
+        created = self._json_data.get("created")
         if created:
             return WebexTeamsDateTime.strptime(created)
         else:
diff --git a/webexteamssdk/models/mixins/webhook.py b/webexteamssdk/models/mixins/webhook.py
index a3d3b26..670b82c 100644
--- a/webexteamssdk/models/mixins/webhook.py
+++ b/webexteamssdk/models/mixins/webhook.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Webhook data model.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
@@ -41,17 +40,17 @@ class WebhookBasicPropertiesMixin(object):
     @property
     def id(self):
         """A unique identifier for the webhook."""
-        return self._json_data.get('id')
+        return self._json_data.get("id")
 
     @property
     def name(self):
         """A user-friendly name for the webhook."""
-        return self._json_data.get('name')
+        return self._json_data.get("name")
 
     @property
     def targetUrl(self):
         """The URL that receives POST requests for each event."""
-        return self._json_data.get('targetUrl')
+        return self._json_data.get("targetUrl")
 
     @property
     def resource(self):
@@ -66,7 +65,7 @@ def resource(self):
             `messages`: The Messages resource
             `rooms`: The Rooms resource
         """
-        return self._json_data.get('resource')
+        return self._json_data.get("resource")
 
     @property
     def event(self):
@@ -78,32 +77,32 @@ def event(self):
             `updated`: An object was updated
             `deleted`: An object was deleted
         """
-        return self._json_data.get('event')
+        return self._json_data.get("event")
 
     @property
     def filter(self):
         """The filter that defines the webhook scope."""
-        return self._json_data.get('filter')
+        return self._json_data.get("filter")
 
     @property
     def secret(self):
         """The secret used to generate payload signature."""
-        return self._json_data.get('secret')
+        return self._json_data.get("secret")
 
     @property
     def orgId(self):
         """The ID of the organization that owns the webhook."""
-        return self._json_data.get('orgId')
+        return self._json_data.get("orgId")
 
     @property
     def createdBy(self):
         """The ID of the person that created the webhook."""
-        return self._json_data.get('createdBy')
+        return self._json_data.get("createdBy")
 
     @property
     def appId(self):
         """The ID of the application that created the webhook."""
-        return self._json_data.get('appId')
+        return self._json_data.get("appId")
 
     @property
     def ownedBy(self):
@@ -118,7 +117,7 @@ def ownedBy(self):
             `org`
             `creator`
         """
-        return self._json_data.get('ownedBy')
+        return self._json_data.get("ownedBy")
 
     @property
     def status(self):
@@ -128,12 +127,12 @@ def status(self):
             `active`: The webhook is active
             `inactive`: The webhook is inactive
         """
-        return self._json_data.get('status')
+        return self._json_data.get("status")
 
     @property
     def created(self):
         """The date and time the webhook was created."""
-        created = self._json_data.get('created')
+        created = self._json_data.get("created")
         if created:
             return WebexTeamsDateTime.strptime(created)
         else:
diff --git a/webexteamssdk/models/mixins/webhook_event.py b/webexteamssdk/models/mixins/webhook_event.py
index d4207ad..d56fb6a 100644
--- a/webexteamssdk/models/mixins/webhook_event.py
+++ b/webexteamssdk/models/mixins/webhook_event.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Webhook-Event data model.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
@@ -39,12 +38,12 @@ class WebhookEventBasicPropertiesMixin(object):
     @property
     def id(self):
         """A unique identifier for the webhook."""
-        return self._json_data.get('id')
+        return self._json_data.get("id")
 
     @property
     def name(self):
         """A user-friendly name for the webhook."""
-        return self._json_data.get('name')
+        return self._json_data.get("name")
 
     @property
     def resource(self):
@@ -58,7 +57,7 @@ def resource(self):
             `messages`: The Messages resource
             `rooms`: The Rooms resource
         """
-        return self._json_data.get('resource')
+        return self._json_data.get("resource")
 
     @property
     def event(self):
@@ -69,27 +68,27 @@ def event(self):
             `updated`: An object was updated
             `deleted`: An object was deleted
         """
-        return self._json_data.get('event')
+        return self._json_data.get("event")
 
     @property
     def filter(self):
         """The filter that defines the webhook scope."""
-        return self._json_data.get('filter')
+        return self._json_data.get("filter")
 
     @property
     def orgId(self):
         """The ID of the organization that owns the webhook."""
-        return self._json_data.get('orgId')
+        return self._json_data.get("orgId")
 
     @property
     def createdBy(self):
         """The ID of the person that created the webhook."""
-        return self._json_data.get('createdBy')
+        return self._json_data.get("createdBy")
 
     @property
     def appId(self):
         """The ID of the application that created the webhook."""
-        return self._json_data.get('appId')
+        return self._json_data.get("appId")
 
     @property
     def ownedBy(self):
@@ -104,7 +103,7 @@ def ownedBy(self):
             `org`
             `creator`
         """
-        return self._json_data.get('ownedBy')
+        return self._json_data.get("ownedBy")
 
     @property
     def status(self):
@@ -114,9 +113,9 @@ def status(self):
             `active`: The webhook is active
             `inactive`: The webhook is inactive
         """
-        return self._json_data.get('status')
+        return self._json_data.get("status")
 
     @property
     def actorId(self):
         """The ID of the person that caused the webhook to be sent."""
-        return self._json_data.get('actorId')
+        return self._json_data.get("actorId")
diff --git a/webexteamssdk/models/simple.py b/webexteamssdk/models/simple.py
index 44140b1..5de5473 100644
--- a/webexteamssdk/models/simple.py
+++ b/webexteamssdk/models/simple.py
@@ -8,7 +8,7 @@
 Python dictionary as a native Python object; providing attribute access using
 native dot-syntax.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -29,7 +29,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
diff --git a/webexteamssdk/response_codes.py b/webexteamssdk/response_codes.py
index 5706b9e..bc5315d 100644
--- a/webexteamssdk/response_codes.py
+++ b/webexteamssdk/response_codes.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Webex Teams Response Codes.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
@@ -37,38 +36,33 @@
     400: "The request was invalid or cannot be otherwise served.",
     401: "Authentication credentials were missing or incorrect.",
     403: "The request is understood, but it has been refused or access is not "
-         "allowed.",
+    "allowed.",
     404: "The URI requested is invalid or the resource requested, such as a "
-         "user, does not exist. Also returned when the requested format is "
-         "not supported by the requested method.",
+    "user, does not exist. Also returned when the requested format is "
+    "not supported by the requested method.",
     405: "The request was made to a resource using an HTTP request method "
-         "that is not supported.",
+    "that is not supported.",
     409: "The request could not be processed because it conflicts with some "
-         "established rule of the system. For example, a person may not be "
-         "added to a room more than once.",
+    "established rule of the system. For example, a person may not be "
+    "added to a room more than once.",
     410: "The requested resource is no longer available.",
     415: "The request was made to a resource without specifying a media type "
-         "or used a media type that is not supported.",
+    "or used a media type that is not supported.",
     423: "The requested resource is temporarily unavailable. A `Retry-After` "
-         "header may be present that specifies how many seconds you need to "
-         "wait before attempting the request again.",
+    "header may be present that specifies how many seconds you need to "
+    "wait before attempting the request again.",
     429: "Too many requests have been sent in a given amount of time and the "
-         "request has been rate limited. A `Retry-After` header should be "
-         "present that specifies how many seconds you need to wait before a "
-         "successful request can be made.",
+    "request has been rate limited. A `Retry-After` header should be "
+    "present that specifies how many seconds you need to wait before a "
+    "successful request can be made.",
     500: "Something went wrong on the server. If the issue persists, feel "
-         "free to contact the Webex Developer Support team "
-         "(https://developer.webex.com/support).",
+    "free to contact the Webex Developer Support team "
+    "(https://developer.webex.com/support).",
     502: "The server received an invalid response from an upstream server "
-         "while processing the request. Try again later.",
-    503: "Server is overloaded with requests. Try again later."
+    "while processing the request. Try again later.",
+    503: "Server is overloaded with requests. Try again later.",
 }
 
 RATE_LIMIT_RESPONSE_CODE = 429
 
-EXPECTED_RESPONSE_CODE = {
-    "GET": 200,
-    "POST": 200,
-    "PUT": 200,
-    "DELETE": 204
-}
+EXPECTED_RESPONSE_CODE = {"GET": 200, "POST": 200, "PUT": 200, "DELETE": 204}
diff --git a/webexteamssdk/restsession.py b/webexteamssdk/restsession.py
index 86aa0d5..8274f89 100644
--- a/webexteamssdk/restsession.py
+++ b/webexteamssdk/restsession.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """RestSession class for creating connections to the Webex Teams APIs.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
@@ -33,6 +32,7 @@
 from builtins import *
 
 from future import standard_library
+
 standard_library.install_aliases()
 
 import json
@@ -52,7 +52,10 @@
 from .exceptions import MalformedResponse, RateLimitError, RateLimitWarning
 from .response_codes import EXPECTED_RESPONSE_CODE
 from .utils import (
-    check_response_code, check_type, extract_and_parse_json, validate_base_url,
+    check_response_code,
+    check_type,
+    extract_and_parse_json,
+    validate_base_url,
 )
 
 
@@ -94,12 +97,16 @@ def _fix_next_url(next_url, params):
         query_list = parsed_url.query.split("&")
         if "max=null" in query_list:
             query_list.remove("max=null")
-            warnings.warn("`max=null` still present in next-URL returned "
-                          "from Webex Teams", RuntimeWarning)
+            warnings.warn(
+                "`max=null` still present in next-URL returned "
+                "from Webex Teams",
+                RuntimeWarning,
+                stacklevel=1,
+            )
         if params:
             for k, v in params.items():
-                if not any(p.startswith('{}='.format(k)) for p in query_list):
-                    query_list.append('{}={}'.format(k, v))
+                if not any(p.startswith("{}=".format(k)) for p in query_list):
+                    query_list.append("{}={}".format(k, v))
         new_query = "&".join(query_list)
         parsed_url = list(parsed_url)
         parsed_url[4] = new_query
@@ -179,13 +186,17 @@ def user_agent(be_geo_id=None, caller=None):
 class RestSession(object):
     """RESTful HTTP session class for making calls to the Webex Teams APIs."""
 
-    def __init__(self, access_token, base_url,
-                 single_request_timeout=DEFAULT_SINGLE_REQUEST_TIMEOUT,
-                 wait_on_rate_limit=DEFAULT_WAIT_ON_RATE_LIMIT,
-                 proxies=None,
-                 be_geo_id=None,
-                 caller=None,
-                 disable_ssl_verify=False):
+    def __init__(
+        self,
+        access_token,
+        base_url,
+        single_request_timeout=DEFAULT_SINGLE_REQUEST_TIMEOUT,
+        wait_on_rate_limit=DEFAULT_WAIT_ON_RATE_LIMIT,
+        proxies=None,
+        be_geo_id=None,
+        caller=None,
+        disable_ssl_verify=False,
+    ):
         """Initialize a new RestSession object.
 
         Args:
@@ -239,11 +250,13 @@ def __init__(self, access_token, base_url,
             self._req_session.proxies.update(proxies)
 
         # Update the HTTP headers for the session
-        self.update_headers({
-            "Authorization": "Bearer " + access_token,
-            "Content-type": "application/json;charset=utf-8",
-            "User-Agent": user_agent(be_geo_id=be_geo_id, caller=caller),
-        })
+        self.update_headers(
+            {
+                "Authorization": "Bearer " + access_token,
+                "Content-type": "application/json;charset=utf-8",
+                "User-Agent": user_agent(be_geo_id=be_geo_id, caller=caller),
+            }
+        )
 
     @property
     def base_url(self):
@@ -362,7 +375,7 @@ def request(self, method, url, erc, **kwargs):
                 # Catch rate-limit errors
                 # Wait and retry if automatic rate-limit handling is enabled
                 if self.wait_on_rate_limit:
-                    warnings.warn(RateLimitWarning(response))
+                    warnings.warn(RateLimitWarning(response), stacklevel=1)
                     time.sleep(e.retry_after)
                     continue
                 else:
@@ -472,8 +485,11 @@ def get_items(self, url, params=None, **kwargs):
             items = json_page.get("items")
 
             if items is None:
-                error_message = "'items' key not found in JSON data: " \
-                                "{!r}".format(json_page)
+                error_message = (
+                    "'items' key not found in JSON data: " "{!r}".format(
+                        json_page
+                    )
+                )
                 raise MalformedResponse(error_message)
 
             else:
@@ -501,8 +517,9 @@ def post(self, url, json=None, data=None, **kwargs):
         # Expected response code
         erc = kwargs.pop("erc", EXPECTED_RESPONSE_CODE["POST"])
 
-        response = self.request("POST", url, erc, json=json, data=data,
-                                **kwargs)
+        response = self.request(
+            "POST", url, erc, json=json, data=data, **kwargs
+        )
         return extract_and_parse_json(response)
 
     def put(self, url, json=None, data=None, **kwargs):
@@ -526,8 +543,9 @@ def put(self, url, json=None, data=None, **kwargs):
         # Expected response code
         erc = kwargs.pop("erc", EXPECTED_RESPONSE_CODE["PUT"])
 
-        response = self.request("PUT", url, erc, json=json, data=data,
-                                **kwargs)
+        response = self.request(
+            "PUT", url, erc, json=json, data=data, **kwargs
+        )
         return extract_and_parse_json(response)
 
     def delete(self, url, **kwargs):
diff --git a/webexteamssdk/utils.py b/webexteamssdk/utils.py
index f22c8bb..b77176b 100644
--- a/webexteamssdk/utils.py
+++ b/webexteamssdk/utils.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Package helper functions and classes.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 from __future__ import (
     absolute_import,
     division,
@@ -49,13 +48,15 @@
 
 from .config import WEBEX_TEAMS_DATETIME_FORMAT
 from .exceptions import (
-    ApiError, RateLimitError,
+    ApiError,
+    RateLimitError,
 )
 from .response_codes import RATE_LIMIT_RESPONSE_CODE
 
 
-EncodableFile = namedtuple('EncodableFile',
-                           ['file_name', 'file_object', 'content_type'])
+EncodableFile = namedtuple(
+    "EncodableFile", ["file_name", "file_object", "content_type"]
+)
 
 
 def to_unicode(string):
@@ -63,12 +64,12 @@ def to_unicode(string):
     assert isinstance(string, basestring)
     if sys.version_info[0] >= 3:
         if isinstance(string, bytes):
-            return string.decode('utf-8')
+            return string.decode("utf-8")
         else:
             return string
     else:
         if isinstance(string, str):
-            return string.decode('utf-8')
+            return string.decode("utf-8")
         else:
             return string
 
@@ -78,12 +79,12 @@ def to_bytes(string):
     assert isinstance(string, basestring)
     if sys.version_info[0] >= 3:
         if isinstance(string, str):
-            return string.encode('utf-8')
+            return string.encode("utf-8")
         else:
             return string
     else:
         if isinstance(string, unicode):
-            return string.encode('utf-8')
+            return string.encode("utf-8")
         else:
             return string
 
@@ -94,8 +95,10 @@ def validate_base_url(base_url):
     if parsed_url.scheme and parsed_url.netloc:
         return parsed_url.geturl()
     else:
-        error_message = "base_url must contain a valid scheme (protocol " \
-                        "specifier) and network location (hostname)"
+        error_message = (
+            "base_url must contain a valid scheme (protocol "
+            "specifier) and network location (hostname)"
+        )
         raise ValueError(error_message)
 
 
@@ -104,12 +107,9 @@ def is_web_url(string):
     assert isinstance(string, basestring)
     parsed_url = urllib.parse.urlparse(string)
     return (
-        (
-            parsed_url.scheme.lower() == 'http'
-            or parsed_url.scheme.lower() == 'https'
-        )
-        and parsed_url.netloc
-    )
+        parsed_url.scheme.lower() == "http"
+        or parsed_url.scheme.lower() == "https"
+    ) and parsed_url.netloc
 
 
 def is_local_file(string):
@@ -123,11 +123,11 @@ def open_local_file(file_path):
     assert isinstance(file_path, basestring)
     assert is_local_file(file_path)
     file_name = os.path.basename(file_path)
-    file_object = open(file_path, 'rb')
-    content_type = mimetypes.guess_type(file_name)[0] or 'text/plain'
-    return EncodableFile(file_name=file_name,
-                         file_object=file_object,
-                         content_type=content_type)
+    file_object = open(file_path, "rb")
+    content_type = mimetypes.guess_type(file_name)[0] or "text/plain"
+    return EncodableFile(
+        file_name=file_name, file_object=file_object, content_type=content_type
+    )
 
 
 def check_type(obj, acceptable_types, optional=False):
@@ -164,7 +164,7 @@ def check_type(obj, acceptable_types, optional=False):
                 types=", ".join([repr(t.__name__) for t in acceptable_types]),
                 none="or 'None'" if optional else "",
                 obj=obj,
-                obj_type=repr(type(obj).__name__)
+                obj_type=repr(type(obj).__name__),
             )
         )
         raise TypeError(error_message)
@@ -213,7 +213,7 @@ def check_response_code(response, expected_response_code):
         ApiError: If the requests.response.status_code does not match the
             provided expected response code (erc).
 
-     """
+    """
     if response.status_code == expected_response_code:
         pass
     elif response.status_code == RATE_LIMIT_RESPONSE_CODE:
@@ -262,17 +262,17 @@ def json_dict(json_data):
 
 def make_attachment(card):
     """Given a card, makes a card attachment by attaching the correct
-       content type and content.
+     content type and content.
 
-      Args:
-        card(AdaptiveCard): Adaptive Card object that should be attached
+    Args:
+      card(AdaptiveCard): Adaptive Card object that should be attached
 
-      Returns:
-        A Python dictionary containing the card attachment dictionary
+    Returns:
+      A Python dictionary containing the card attachment dictionary
     """
     attachment = {
         "contentType": "application/vnd.microsoft.card.adaptive",
-        "content": card.to_dict()
+        "content": card.to_dict(),
     }
 
     return attachment
@@ -301,9 +301,11 @@ class WebexTeamsDateTime(datetime):
     @classmethod
     def strptime(cls, date_string, format=WEBEX_TEAMS_DATETIME_FORMAT):
         """strptime with the Webex Teams DateTime format as the default."""
-        return super(WebexTeamsDateTime, cls).strptime(
-            date_string, format
-        ).replace(tzinfo=ZuluTimeZone())
+        return (
+            super(WebexTeamsDateTime, cls)
+            .strptime(date_string, format)
+            .replace(tzinfo=ZuluTimeZone())
+        )
 
     def strftime(self, fmt=WEBEX_TEAMS_DATETIME_FORMAT):
         """strftime with the Webex Teams DateTime format as the default."""
@@ -314,10 +316,12 @@ def __str__(self):
         if self.tzinfo:
             dt = self.astimezone(ZuluTimeZone())
         else:
-            warnings.warn(UserWarning(
-                "Datetime {} does not have an associated timezone; assuming it"
-                "should be UTC/Zulu.".format(repr(self))
-            ))
+            warnings.warn(
+                "Datetime {} does not have an associated timezone; "
+                "assuming it should be UTC/Zulu.".format(repr(self)),
+                category=UserWarning,
+                stacklevel=2,
+            )
             dt = self.replace(tzinfo=ZuluTimeZone())
 
         return dt.strftime("%Y-%m-%dT%H:%M:%S.{:0=3}%Z").format(


Test patch:
diff --git a/pytest.ini b/pytest.ini
index a4071d6..5969799 100644
--- a/pytest.ini
+++ b/pytest.ini
@@ -2,3 +2,4 @@
 addopts = --strict-markers
 markers =
     slow: marks tests as slow (deselect with '-m "not slow"')
+    manual: marks tests as manual (deselect with '-m "not manual"')
diff --git a/script/test b/script/test
index 68a22c1..fe9f6a7 100755
--- a/script/test
+++ b/script/test
@@ -1,7 +1,7 @@
 #!/usr/bin/env bash
 # Run the project's test suite(s).
 #
-# Copyright (c) 2016-2020 Cisco and/or its affiliates.
+# Copyright (c) 2016-2024 Cisco and/or its affiliates.
 # License: MIT
 
 
@@ -10,7 +10,7 @@ default=true
 
 
 # Process Script Arguments
-for i in ${@}; do
+for i in "${@}"; do
     case ${i} in
         lint)
         lint=true
@@ -27,6 +27,11 @@ for i in ${@}; do
         default=
         ;;
 
+        manual)
+        slow=true
+        default=
+        ;;
+
         *)
         echo "Unknown argument: $i"
         exit 1
@@ -47,12 +52,18 @@ fi
 
 # Run the test suite
 if [ ${default} ] || [ ${tests} ]; then
-    echo "==> Running the test suite (excluding slow tests)"
-    py.test -s -m "not slow"
+    echo "==> Running the test suite (excluding slow and manual tests)"
+    pytest -s -m "not slow and not manual"
 fi
 
-# Run the rate-limit tests
+# Run the slow tests
 if [ ${slow} ]; then
     echo "==> Running the slow tests"
-    py.test -s -m "slow"
+    pytest -s -m "slow"
+fi
+
+# Run the slow tests
+if [ ${manual} ]; then
+    echo "==> Running the manual tests"
+    pytest -s -m "manual"
 fi
diff --git a/tests/api/__init__.py b/tests/api/__init__.py
index f905136..3f49ea1 100644
--- a/tests/api/__init__.py
+++ b/tests/api/__init__.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """WebexTeamsAPI fixtures and tests.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -42,8 +42,10 @@
 from webexteamssdk.api.teams import TeamsAPI
 from webexteamssdk.api.webhooks import WebhooksAPI
 from webexteamssdk.config import (
-    ACCESS_TOKEN_ENVIRONMENT_VARIABLE, DEFAULT_BASE_URL,
-    DEFAULT_SINGLE_REQUEST_TIMEOUT, DEFAULT_WAIT_ON_RATE_LIMIT,
+    ACCESS_TOKEN_ENVIRONMENT_VARIABLE,
+    DEFAULT_BASE_URL,
+    DEFAULT_SINGLE_REQUEST_TIMEOUT,
+    DEFAULT_WAIT_ON_RATE_LIMIT,
 )
 from webexteamssdk.api.recordings import RecordingsAPI
 
@@ -54,6 +56,7 @@
 
 # Fixtures
 
+
 @pytest.fixture(scope="session")
 def access_token():
     if WEBEX_TOKEN_KEEPER_URL:
@@ -84,6 +87,7 @@ def api(access_token):
 
 # Test creating WebexTeamsAPI objects
 
+
 @pytest.mark.usefixtures("unset_access_token")
 def test_create_without_an_access_token():
     with pytest.raises(webexteamssdk.AccessTokenError):
@@ -97,9 +101,7 @@ def test_create_with_access_token_environment_variable():
 
 @pytest.mark.usefixtures("unset_access_token")
 def test_create_with_access_token_argument(access_token):
-    connection_object = webexteamssdk.WebexTeamsAPI(
-        access_token=access_token
-    )
+    connection_object = webexteamssdk.WebexTeamsAPI(access_token=access_token)
     assert isinstance(connection_object, webexteamssdk.WebexTeamsAPI)
 
 
@@ -119,8 +121,10 @@ def test_custom_base_url():
 @pytest.mark.usefixtures("access_token")
 def test_default_single_request_timeout():
     connection_object = webexteamssdk.WebexTeamsAPI()
-    assert connection_object.single_request_timeout == \
-        DEFAULT_SINGLE_REQUEST_TIMEOUT
+    assert (
+        connection_object.single_request_timeout
+        == DEFAULT_SINGLE_REQUEST_TIMEOUT
+    )
 
 
 @pytest.mark.usefixtures("access_token")
@@ -135,8 +139,7 @@ def test_custom_single_request_timeout():
 @pytest.mark.usefixtures("access_token")
 def test_default_wait_on_rate_limit():
     connection_object = webexteamssdk.WebexTeamsAPI()
-    assert connection_object.wait_on_rate_limit == \
-        DEFAULT_WAIT_ON_RATE_LIMIT
+    assert connection_object.wait_on_rate_limit == DEFAULT_WAIT_ON_RATE_LIMIT
 
 
 @pytest.mark.usefixtures("access_token")
@@ -144,8 +147,7 @@ def test_non_default_wait_on_rate_limit():
     connection_object = webexteamssdk.WebexTeamsAPI(
         wait_on_rate_limit=not DEFAULT_WAIT_ON_RATE_LIMIT
     )
-    assert connection_object.wait_on_rate_limit != \
-        DEFAULT_WAIT_ON_RATE_LIMIT
+    assert connection_object.wait_on_rate_limit != DEFAULT_WAIT_ON_RATE_LIMIT
 
 
 # Test creation of component API objects
@@ -202,4 +204,4 @@ def test_webhooks_api_object_creation(api):
 
 
 def test_recordings_api_object_creation(api):
-    assert isinstance(api.recordings, RecordingsAPI)
\ No newline at end of file
+    assert isinstance(api.recordings, RecordingsAPI)
diff --git a/tests/api/test_admin_audit_events.py b/tests/api/test_admin_audit_events.py
index 7601ffc..87a5710 100644
--- a/tests/api/test_admin_audit_events.py
+++ b/tests/api/test_admin_audit_events.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """WebexTeamsAPI Admin Audit Events API fixtures and tests.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -23,26 +23,24 @@
 """
 
 import itertools
+from datetime import timedelta, timezone
 
 import pytest
 
 import webexteamssdk
 
 
-from_datetime_string = str(
-    webexteamssdk.WebexTeamsDateTime(2018, 1, 1, 0, 0, 0, 0),
-)
-
-to_datetime_string = str(
-    webexteamssdk.WebexTeamsDateTime.utcnow(),
-)
+to_datetime = webexteamssdk.WebexTeamsDateTime.now(tz=timezone.utc)
+from_datetime = to_datetime - timedelta(days=364)
 
 
 # Helper Functions
 
+
 def is_valid_admin_audit_event(obj):
-    return isinstance(obj, webexteamssdk.AdminAuditEvent) \
-        and obj.id is not None
+    return (
+        isinstance(obj, webexteamssdk.AdminAuditEvent) and obj.id is not None
+    )
 
 
 def are_valid_admin_audit_events(iterable):
@@ -51,19 +49,23 @@ def are_valid_admin_audit_events(iterable):
 
 # Fixtures
 
+
 @pytest.fixture(scope="session")
 def admin_audit_events(api, me):
-    three_events = list(api.admin_audit_events.list(
-        orgId=me.orgId,
-        _from=from_datetime_string,
-        to=to_datetime_string,
-    )[:3])
+    three_events = list(
+        api.admin_audit_events.list(
+            orgId=me.orgId,
+            _from=str(from_datetime),
+            to=str(to_datetime),
+        )[:3]
+    )
     assert len(three_events) == 3
     return three_events
 
 
 # Tests
 
+
 def test_list_admin_audit_events(api, admin_audit_events):
     assert are_valid_admin_audit_events(admin_audit_events)
 
@@ -75,7 +77,6 @@ def test_list_admin_audit_events_by_actor_id(api, admin_audit_events):
     assert all([event.actorId == actor_id for event in actor_events])
 
 
-@pytest.mark.xfail  # TODO: Returned link headers are malformed on the endpoint
 def test_list_events_with_paging(api, me, admin_audit_events):
     page_size = 1
     pages = 3
@@ -83,8 +84,8 @@ def test_list_events_with_paging(api, me, admin_audit_events):
     assert len(admin_audit_events) >= num_events
     events_gen = api.admin_audit_events.list(
         orgId=me.orgId,
-        _from=from_datetime_string,
-        to=to_datetime_string,
+        _from=str(from_datetime),
+        to=str(to_datetime),
         max=page_size,
     )
     events_list = list(itertools.islice(events_gen, num_events))
diff --git a/tests/api/test_attachment_actions.py b/tests/api/test_attachment_actions.py
index f8366f4..2da38b8 100644
--- a/tests/api/test_attachment_actions.py
+++ b/tests/api/test_attachment_actions.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """WebexTeamsAPI Messages API fixtures and tests.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -39,8 +39,9 @@
 
 # Helper Functions
 def is_valid_attachment_action(obj):
-    return isinstance(obj, webexteamssdk.AttachmentAction) \
-        and obj.id is not None
+    return (
+        isinstance(obj, webexteamssdk.AttachmentAction) and obj.id is not None
+    )
 
 
 # Fixtures
@@ -70,7 +71,7 @@ def attachment_action_create(api, test_people, attachment_actions_card):
         inputs={
             "Name": person.displayName,
             "Email": person.emails[0],
-        }
+        },
     )
 
     yield attachment_action
diff --git a/tests/api/test_events.py b/tests/api/test_events.py
index a09d587..8fd3919 100644
--- a/tests/api/test_events.py
+++ b/tests/api/test_events.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """WebexTeamsAPI Events API fixtures and tests.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -31,6 +31,7 @@
 
 # Helper Functions
 
+
 def is_valid_event(obj):
     return isinstance(obj, webexteamssdk.Event) and obj.id is not None
 
@@ -41,6 +42,7 @@ def are_valid_events(iterable):
 
 # Fixtures
 
+
 @pytest.fixture(scope="session")
 def events(api, group_room_messages, direct_messages):
     five_events = list(api.events.list()[:5])
@@ -50,6 +52,7 @@ def events(api, group_room_messages, direct_messages):
 
 # Tests
 
+
 def test_list_events(api, events):
     assert are_valid_events(events)
 
diff --git a/tests/api/test_guest_issuer.py b/tests/api/test_guest_issuer.py
index f361c1c..df27632 100644
--- a/tests/api/test_guest_issuer.py
+++ b/tests/api/test_guest_issuer.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """WebexTeamsAPI Licenses API fixtures and tests.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -24,6 +24,7 @@
 
 import os
 import time
+import pytest
 
 import webexteamssdk
 
@@ -34,16 +35,27 @@
     "WEBEX_TEAMS_GUEST_ISSUER_SECRET"
 )
 
+if WEBEX_TEAMS_GUEST_ISSUER_ID is None or not WEBEX_TEAMS_GUEST_ISSUER_SECRET:
+    pytest.skip(
+        "Required WEBEX_TEAMS_GUEST_ISSUER_ID and/or "
+        "WEBEX_TEAMS_GUEST_ISSUER_SECRET environment variables are not set.",
+        allow_module_level=True,
+    )
+
 
 # Helper Functions
 
+
 def is_valid_guest_issuer_token(obj):
-    return (isinstance(obj, webexteamssdk.GuestIssuerToken)
-            and obj.token is not None)
+    return (
+        isinstance(obj, webexteamssdk.GuestIssuerToken)
+        and obj.token is not None
+    )
 
 
 # Tests
 
+
 def test_get_guest_issuer_token(api):
     guest_issuer_token = api.guest_issuer.create(
         sub="test-guest-user",
@@ -52,4 +64,5 @@ def test_get_guest_issuer_token(api):
         exp=str(int(time.time()) + TOKEN_EXPIRATION_SECONDS),
         secret=WEBEX_TEAMS_GUEST_ISSUER_SECRET,
     )
+
     assert is_valid_guest_issuer_token(guest_issuer_token)
diff --git a/tests/api/test_licenses.py b/tests/api/test_licenses.py
index c7e6b62..82a5e44 100644
--- a/tests/api/test_licenses.py
+++ b/tests/api/test_licenses.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """WebexTeamsAPI Licenses API fixtures and tests.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -29,6 +29,7 @@
 
 # Helper Functions
 
+
 def is_valid_license(obj):
     return isinstance(obj, webexteamssdk.License) and obj.id is not None
 
@@ -39,6 +40,7 @@ def are_valid_licenses(iterable):
 
 # Fixtures
 
+
 @pytest.fixture(scope="session")
 def licenses_list(api, me):
     return list(api.licenses.list(orgId=me.orgId))
@@ -51,6 +53,7 @@ def licenses_dict(licenses_list):
 
 # Tests
 
+
 def test_list_licenses(licenses_list):
     assert are_valid_licenses(licenses_list)
 
diff --git a/tests/api/test_meeting_registrants.py b/tests/api/test_meeting_registrants.py
index 7774c56..d125352 100644
--- a/tests/api/test_meeting_registrants.py
+++ b/tests/api/test_meeting_registrants.py
@@ -31,25 +31,31 @@
 
 # Helper Functions
 
+
 def is_valid_registrant(obj):
-    return isinstance(obj, webexteamssdk.MeetingRegistrant) and obj.id is not None
+    return (
+        isinstance(obj, webexteamssdk.MeetingRegistrant) and obj.id is not None
+    )
+
 
 def get_start_end_time():
     now = datetime.datetime.now()
-    start = (now + datetime.timedelta(days=1)).strftime('%Y-%m-%dT%H:%M:%S')    # tomorrow same time
-    end = (now + datetime.timedelta(days=1, hours=1)).strftime('%Y-%m-%dT%H:%M:%S') # tomorrow 1 hour later
-    return {'start': start, 'end': end}
-
+    start = (now + datetime.timedelta(days=1)).strftime(
+        "%Y-%m-%dT%H:%M:%S"
+    )  # tomorrow same time
+    end = (now + datetime.timedelta(days=1, hours=1)).strftime(
+        "%Y-%m-%dT%H:%M:%S"
+    )  # tomorrow 1 hour later
+    return {"start": start, "end": end}
 
 
 # Fixtures
 
+
 @pytest.fixture(scope="session")
 def meeting(api):
-
     meeting = api.meetings.create(
-        title=create_string("Meeting"),
-        **get_start_end_time()
+        title=create_string("Meeting"), **get_start_end_time()
     )
 
     yield meeting
@@ -59,18 +65,19 @@ def meeting(api):
     except webexteamssdk.ApiError:
         pass
 
+
 @pytest.fixture(scope="session")
 def webinar(api):
     webinar = api.meetings.create(
         title=create_string("Webinar"),
         scheduledType="webinar",
         registration={
-            'autoAcceptRequest': True,
-            'requireFirstName': True,
-            'requireLastName': True,
-            'requireEmail': True
+            "autoAcceptRequest": True,
+            "requireFirstName": True,
+            "requireLastName": True,
+            "requireEmail": True,
         },
-        **get_start_end_time()
+        **get_start_end_time(),
     )
 
     yield webinar
@@ -80,13 +87,14 @@ def webinar(api):
     except webexteamssdk.ApiError:
         pass
 
+
 @pytest.fixture(scope="session")
 def registrant(api, webinar):
     registrant = api.meeting_registrants.create(
         webinar.id,
         firstName=create_string("FirstName"),
         lastName=create_string("LastName"),
-        email="someone@example.com"
+        email="someone@example.com",
     )
 
     yield registrant
@@ -94,11 +102,12 @@ def registrant(api, webinar):
     try:
         api.meeting_registrants.delete(webinar.id, registrant.id)
     except webexteamssdk.ApiError:
-        pass    
+        pass
 
 
 # Tests
 
+
 def test_register_for_meeting(api, meeting):
     # it is expected that registration does not work for a plain meeting
     with pytest.raises(webexteamssdk.ApiError) as ex_info:
@@ -106,22 +115,30 @@ def test_register_for_meeting(api, meeting):
             meeting.id,
             firstName=create_string("FirstName"),
             lastName=create_string("LastName"),
-            email="someone@example.com"
+            email="someone@example.com",
         )
     assert ex_info.value.status_code == 400
-    assert ex_info.value.response.json()['errors'][0]['description'] == "Registration is not supported for this meeting series."
+    assert (
+        ex_info.value.response.json()["errors"][0]["description"]
+        == "Registration is not supported for this meeting series."
+    )
 
 
 def test_register_for_webinar(api, registrant):
     assert is_valid_registrant(registrant)
 
+
 def test_get_registrant(api, webinar, registrant):
-    assert is_valid_registrant(api.meeting_registrants.get(webinar.id, registrant.id))    
+    assert is_valid_registrant(
+        api.meeting_registrants.get(webinar.id, registrant.id)
+    )
+
 
 def test_list_registrants(api, webinar, registrant):
     registrants_list = list(api.meeting_registrants.list(webinar.id))
     assert len(registrants_list) > 0
     assert registrant.id in [item.id for item in registrants_list]
 
+
 def test_unregister(api, webinar, registrant):
-    api.meeting_registrants.delete(webinar.id, registrant.id)
\ No newline at end of file
+    api.meeting_registrants.delete(webinar.id, registrant.id)
diff --git a/tests/api/test_meetings.py b/tests/api/test_meetings.py
index 576fbc4..09e795c 100644
--- a/tests/api/test_meetings.py
+++ b/tests/api/test_meetings.py
@@ -31,25 +31,29 @@
 
 # Helper Functions
 
+
 def is_valid_meeting(obj):
     return isinstance(obj, webexteamssdk.Meeting) and obj.id is not None
 
+
 def get_start_end_time():
     now = datetime.datetime.now()
-    start = (now + datetime.timedelta(days=1)).strftime('%Y-%m-%dT%H:%M:%S')    # tomorrow same time
-    end = (now + datetime.timedelta(days=1, hours=1)).strftime('%Y-%m-%dT%H:%M:%S') # tomorrow 1 hour later
-    return {'start': start, 'end': end}
-
+    start = (now + datetime.timedelta(days=1)).strftime(
+        "%Y-%m-%dT%H:%M:%S"
+    )  # tomorrow same time
+    end = (now + datetime.timedelta(days=1, hours=1)).strftime(
+        "%Y-%m-%dT%H:%M:%S"
+    )  # tomorrow 1 hour later
+    return {"start": start, "end": end}
 
 
 # Fixtures
 
+
 @pytest.fixture(scope="session")
 def meeting(api):
-
     meeting = api.meetings.create(
-        title=create_string("Meeting"),
-        **get_start_end_time()
+        title=create_string("Meeting"), **get_start_end_time()
     )
 
     yield meeting
@@ -59,12 +63,13 @@ def meeting(api):
     except webexteamssdk.ApiError:
         pass
 
+
 @pytest.fixture(scope="session")
 def webinar(api):
     webinar = api.meetings.create(
         title=create_string("Webinar"),
         scheduledType="webinar",
-        **get_start_end_time()
+        **get_start_end_time(),
     )
 
     yield webinar
@@ -77,16 +82,23 @@ def webinar(api):
 
 # Tests
 
+
 def test_create_meeting(meeting):
     assert is_valid_meeting(meeting)
 
+
 def test_create_webinar(webinar):
     assert is_valid_meeting(webinar)
     assert webinar.scheduledType == "webinar"
 
+
 def test_get_meeting(api, meeting, webinar):
     assert is_valid_meeting(api.meetings.get(meeting.id))
-    assert is_valid_meeting(api.meetings.get(webinar.id)) and api.meetings.get(webinar.id).scheduledType == "webinar"
+    assert (
+        is_valid_meeting(api.meetings.get(webinar.id))
+        and api.meetings.get(webinar.id).scheduledType == "webinar"
+    )
+
 
 def test_list_meetings(api, meeting, webinar):
     meetings_list = list(api.meetings.list())
@@ -95,6 +107,7 @@ def test_list_meetings(api, meeting, webinar):
     assert meeting.id in all_ids
     assert webinar.id in all_ids
 
+
 def test_update_meeting_title(api, meeting):
     new_title = create_string("Updates Meeting")
     updated_meeting = api.meetings.update(
@@ -102,10 +115,11 @@ def test_update_meeting_title(api, meeting):
         title=new_title,
         password=meeting.password,
         start=meeting.start,
-        end=meeting.end
+        end=meeting.end,
     )
     assert is_valid_meeting(updated_meeting)
     assert updated_meeting.title == new_title
 
+
 def test_delete_meeting(api, meeting):
-    api.meetings.delete(meeting.id)
\ No newline at end of file
+    api.meetings.delete(meeting.id)
diff --git a/tests/api/test_memberships.py b/tests/api/test_memberships.py
index 88cfa31..33c5a91 100644
--- a/tests/api/test_memberships.py
+++ b/tests/api/test_memberships.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """WebexTeamsAPI Memberships API fixtures and tests.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -31,9 +31,12 @@
 
 # Helper Functions
 
+
 def is_valid_membership(membership):
-    return isinstance(membership, webexteamssdk.Membership) \
+    return (
+        isinstance(membership, webexteamssdk.Membership)
         and membership.id is not None
+    )
 
 
 def are_valid_memberships(iterable):
@@ -43,6 +46,7 @@ def are_valid_memberships(iterable):
 
 # Fixtures
 
+
 @pytest.fixture(scope="session")
 def my_memberships(api, group_room, team_room, direct_rooms):
     return list(api.memberships.list())
@@ -58,24 +62,20 @@ def my_group_room_membership(api, group_room, me):
 
 
 @pytest.fixture(scope="session")
-def group_room_moderator(api, my_group_room_membership):
-    if my_group_room_membership.isModerator:
-        return True
-    else:
-        updated_membership = api.memberships.update(
-            membershipId=my_group_room_membership.id,
-            isModerator=True,
-        )
+def my_moderated_group_room_membership(api, moderated_group_room, me):
+    memberships = list(
+        api.memberships.list(roomId=moderated_group_room.id, personId=me.id)
+    )
 
-        if updated_membership.isModerator:
-            return True
+    assert len(memberships) == 1
+    membership = memberships[0]
+    assert membership.isModerator
 
-    pytest.fail("Unable to make test account a Room Moderator")
+    return membership
 
 
 @pytest.fixture(scope="session")
-def membership_person_added_by_email(api, group_room, test_people,
-                                     group_room_moderator):
+def membership_person_added_by_email(api, group_room, test_people):
     person = test_people["member_added_by_email"]
     membership = api.memberships.create(
         roomId=group_room.id,
@@ -88,8 +88,7 @@ def membership_person_added_by_email(api, group_room, test_people,
 
 
 @pytest.fixture(scope="session")
-def membership_person_added_by_id(api, group_room, test_people,
-                                  group_room_moderator):
+def membership_person_added_by_id(api, group_room, test_people):
     person = test_people["member_added_by_id"]
     membership = api.memberships.create(
         roomId=group_room.id,
@@ -102,11 +101,12 @@ def membership_person_added_by_id(api, group_room, test_people,
 
 
 @pytest.fixture(scope="session")
-def membership_moderator_added_by_email(api, group_room, test_people,
-                                        group_room_moderator):
+def membership_moderator_added_by_email(
+    api, moderated_group_room, test_people
+):
     person = test_people["moderator_added_by_email"]
     membership = api.memberships.create(
-        roomId=group_room.id,
+        roomId=moderated_group_room.id,
         personEmail=person.emails[0],
         isModerator=True,
     )
@@ -117,11 +117,10 @@ def membership_moderator_added_by_email(api, group_room, test_people,
 
 
 @pytest.fixture(scope="session")
-def membership_moderator_added_by_id(api, group_room, test_people,
-                                     group_room_moderator):
+def membership_moderator_added_by_id(api, moderated_group_room, test_people):
     person = test_people["moderator_added_by_id"]
     membership = api.memberships.create(
-        roomId=group_room.id,
+        roomId=moderated_group_room.id,
         personId=person.id,
         isModerator=True,
     )
@@ -132,15 +131,24 @@ def membership_moderator_added_by_id(api, group_room, test_people,
 
 
 @pytest.fixture(scope="session")
-def additional_group_room_memberships(membership_person_added_by_email,
-                                      membership_person_added_by_id,
-                                      membership_moderator_added_by_email,
-                                      membership_moderator_added_by_id):
+def additional_group_room_memberships(
+    membership_person_added_by_email,
+    membership_person_added_by_id,
+):
     return [
         membership_person_added_by_email,
         membership_person_added_by_id,
+    ]
+
+
+@pytest.fixture(scope="session")
+def additional_moderated_group_room_memberships(
+    membership_moderator_added_by_email,
+    membership_moderator_added_by_id,
+):
+    return [
         membership_moderator_added_by_email,
-        membership_moderator_added_by_id
+        membership_moderator_added_by_id,
     ]
 
 
@@ -151,6 +159,7 @@ def group_room_with_members(group_room, additional_group_room_memberships):
 
 # Tests
 
+
 def test_list_memberships(my_memberships):
     assert len(my_memberships) >= 3
     assert are_valid_memberships(my_memberships)
@@ -168,69 +177,66 @@ def test_list_memberships_with_paging(api, add_rooms, my_memberships):
     assert are_valid_memberships(memberships_list)
 
 
-@pytest.mark.xfail  # TODO: Resolve test account issues
-def test_filter_room_memberships_by_person_email(api, test_people,
-                                                 group_room_with_members):
+def test_filter_room_memberships_by_person_email(
+    api, test_people, group_room_with_members
+):
     person = test_people["member_added_by_email"]
-    memberships = list(api.memberships.list(
-        roomId=group_room_with_members.id,
-        personEmail=person.emails[0],
-    ))
+    memberships = list(
+        api.memberships.list(
+            roomId=group_room_with_members.id,
+            personEmail=person.emails[0],
+        )
+    )
     assert len(memberships) == 1
     membership = memberships[0]
     assert is_valid_membership(membership)
     assert membership.roomId == group_room_with_members.id
 
 
-@pytest.mark.xfail  # TODO: Resolve test account issues
-def test_filter_room_memberships_by_person_id(api, test_people,
-                                              group_room_with_members):
+def test_filter_room_memberships_by_person_id(
+    api, test_people, group_room_with_members
+):
     person = test_people["member_added_by_id"]
-    memberships = list(api.memberships.list(
-        roomId=group_room_with_members.id,
-        personId=person.id,
-    ))
+    memberships = list(
+        api.memberships.list(
+            roomId=group_room_with_members.id,
+            personId=person.id,
+        )
+    )
     assert len(memberships) == 1
     membership = memberships[0]
     assert is_valid_membership(membership)
     assert membership.roomId == group_room_with_members.id
 
 
-@pytest.mark.xfail  # TODO: Resolve test account issues
 def test_list_room_memberships(api, group_room_with_members):
     memberships = list(api.memberships.list(group_room_with_members.id))
     assert len(memberships) > 1
     assert are_valid_memberships(memberships)
 
 
-@pytest.mark.xfail  # TODO: Resolve test account issues
 def test_create_membership_by_email(membership_person_added_by_email):
     assert is_valid_membership(membership_person_added_by_email)
 
 
-@pytest.mark.xfail  # TODO: Resolve test account issues
 def test_create_membership_by_person_id(membership_person_added_by_id):
     assert is_valid_membership(membership_person_added_by_id)
 
 
-@pytest.mark.xfail  # TODO: Resolve test account issues
 def test_create_moderator_by_email(membership_moderator_added_by_email):
     assert is_valid_membership(membership_moderator_added_by_email)
 
 
-@pytest.mark.xfail  # TODO: Resolve test account issues
 def test_create_moderator_by_person_id(membership_moderator_added_by_id):
     assert is_valid_membership(membership_moderator_added_by_id)
 
 
-@pytest.mark.xfail  # TODO: Resolve test account issues
 def test_get_membership_details(api, membership_person_added_by_id):
     membership_id = membership_person_added_by_id.id
     details = api.memberships.get(membership_id)
     assert is_valid_membership(details)
 
 
-@pytest.mark.xfail  # TODO: Resolve test account issues
 def test_update_membership_make_moderator(api, membership_person_added_by_id):
     assert not membership_person_added_by_id.isModerator
     updated_membership = api.memberships.update(
diff --git a/tests/api/test_messages.py b/tests/api/test_messages.py
index 590e623..c1b4426 100644
--- a/tests/api/test_messages.py
+++ b/tests/api/test_messages.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """WebexTeamsAPI Messages API fixtures and tests.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -176,9 +176,7 @@ def group_room_markdown_message(
 def group_room_message_with_file_by_url(group_room, send_group_room_message):
     text = "File posted via URL"
     return send_group_room_message(
-        room_id=group_room.id,
-        text=text,
-        files=[WEBEX_TEAMS_TEST_FILE_URL]
+        room_id=group_room.id, text=text, files=[WEBEX_TEAMS_TEST_FILE_URL]
     )
 
 
@@ -244,6 +242,7 @@ def direct_messages(
 
 # Tests
 
+
 def test_list_all_messages(group_room_messages):
     assert len(group_room_messages) >= 1
     assert are_valid_messages(group_room_messages)
@@ -260,28 +259,38 @@ def test_list_messages_with_paging(api, group_room, group_room_messages):
     assert are_valid_messages(messages_list)
 
 
-def test_list_messages_before_datetime(api, group_room,
-                                       group_room_markdown_message):
-    message_list = list(api.messages.list(
-        roomId=group_room.id,
-        before=str(group_room_markdown_message.created),
-    ))
+def test_list_messages_before_datetime(
+    api, group_room, group_room_markdown_message
+):
+    message_list = list(
+        api.messages.list(
+            roomId=group_room.id,
+            before=str(group_room_markdown_message.created),
+        )
+    )
     assert len(message_list) >= 1
     assert are_valid_messages(message_list)
 
 
-def test_list_messages_before_message_with_id(api, group_room,
-                                              group_room_markdown_message):
-    message_list = list(api.messages.list(
-        roomId=group_room.id,
-        beforeMessage=group_room_markdown_message.id,
-    ))
+def test_list_messages_before_message_with_id(
+    api, group_room, group_room_markdown_message
+):
+    message_list = list(
+        api.messages.list(
+            roomId=group_room.id,
+            beforeMessage=group_room_markdown_message.id,
+        )
+    )
     assert len(message_list) >= 1
     assert are_valid_messages(message_list)
 
 
-def test_list_messages_mentioning_me(api, group_room,
-                                     group_room_markdown_message):
+@pytest.mark.xfail(
+    reason="API Error: The API is not returning the expected results"
+)
+def test_list_messages_mentioning_me(
+    api, group_room, group_room_markdown_message
+):
     messages = api.messages.list(group_room.id, mentionedPeople="me")
     messages_list = list(messages)
     assert len(messages_list) >= 1
@@ -293,7 +302,7 @@ def test_create_direct_messages_by_email(direct_message_by_person_email):
 
 
 def test_reply_to_direct_message_by_person_email(
-    direct_message_reply_by_person_email
+    direct_message_reply_by_person_email,
 ):
     assert is_valid_message(direct_message_reply_by_person_email)
 
@@ -309,7 +318,7 @@ def test_create_direct_messages_by_id(direct_message_by_person_id):
 
 
 def test_reply_to_direct_message_by_person_id(
-    direct_message_reply_by_person_id
+    direct_message_reply_by_person_id,
 ):
     assert is_valid_message(direct_message_reply_by_person_id)
 
@@ -321,8 +330,9 @@ def test_list_direct_messages_by_person_id(api, direct_message_by_person_id):
     assert are_valid_messages(messages)
 
 
-def test_list_direct_messages_by_person_email(api,
-                                              direct_message_by_person_email):
+def test_list_direct_messages_by_person_email(
+    api, direct_message_by_person_email
+):
     messages = api.messages.list_direct(
         personEmail=direct_message_by_person_email.toPersonEmail,
     )
@@ -346,7 +356,8 @@ def test_post_file_by_url(group_room_message_with_file_by_url):
 
 
 def test_post_file_by_local_upload(
-        group_room_message_with_file_by_local_upload):
+    group_room_message_with_file_by_local_upload,
+):
     assert is_valid_message(group_room_message_with_file_by_local_upload)
 
 
@@ -360,11 +371,10 @@ def test_delete_message(api, group_room, send_group_room_message):
     message = api.messages.create(group_room.id, text=text)
     assert is_valid_message(message)
     api.messages.delete(message.id)
-    with pytest.raises(webexteamssdk.ApiError):
-        api.messages.get(message.id)
 
-def test_delete_message(api, group_room):
+
+def test_edit_message(api, group_room):
     text = create_string("Edit this Message")
     message = api.messages.create(group_room.id, text=text)
     text = create_string("Message Edited")
-    assert text == api.messages.edit( message.id, group_room.id, text).text
\ No newline at end of file
+    assert text == api.messages.edit(message.id, group_room.id, text).text
diff --git a/tests/api/test_organizations.py b/tests/api/test_organizations.py
index b00e52a..a4966a9 100644
--- a/tests/api/test_organizations.py
+++ b/tests/api/test_organizations.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """WebexTeamsAPI Organizations API fixtures and tests.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -29,6 +29,7 @@
 
 # Helper Functions
 
+
 def is_valid_organization(obj):
     return isinstance(obj, webexteamssdk.Organization) and obj.id is not None
 
@@ -39,6 +40,7 @@ def are_valid_organizations(iterable):
 
 # Fixtures
 
+
 @pytest.fixture(scope="session")
 def organizations_list(api):
     return list(api.organizations.list())
@@ -46,6 +48,7 @@ def organizations_list(api):
 
 # Tests
 
+
 def test_list_organizations(organizations_list):
     assert are_valid_organizations(organizations_list)
 
diff --git a/tests/api/test_people.py b/tests/api/test_people.py
index 99e3a39..a118a00 100644
--- a/tests/api/test_people.py
+++ b/tests/api/test_people.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """WebexTeamsAPI People API fixtures and tests.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -31,6 +31,7 @@
 
 # Helper Functions
 
+
 def get_person_by_email(api, email):
     list_of_people = list(api.people.list(email=email))
     if list_of_people:
@@ -61,6 +62,7 @@ def are_valid_people(iterable):
 
 # Fixtures
 
+
 @pytest.fixture(scope="session")
 def me(api):
     return api.people.me()
@@ -68,7 +70,6 @@ def me(api):
 
 @pytest.fixture(scope="session")
 def get_test_person(api, get_new_email_address, me, licenses_dict):
-
     def inner_function():
         person_email = get_new_email_address()
         person = get_person_by_email(api, person_email)
@@ -81,7 +82,9 @@ def inner_function():
                 firstName="webexteamssdk",
                 lastName="webexteamssdk",
                 orgId=me.orgId,
-                licenses=[licenses_dict["Messaging"].id],
+                licenses=[licenses_dict["Advanced Messaging"].id],
+                callingData=True,
+                minResponse=False,
             )
             return person
 
@@ -153,7 +156,7 @@ def temp_person(api, get_random_email_address, me, licenses_dict):
         firstName="webexteamssdk",
         lastName="webexteamssdk",
         orgId=me.orgId,
-        licenses=[licenses_dict["Messaging"].id],
+        licenses=[licenses_dict["Advanced Messaging"].id],
     )
 
     yield person
@@ -174,6 +177,7 @@ def people_in_group_room(api, group_room_memberships):
 
 # Tests
 
+
 def test_list_people_by_email(api, test_people):
     email = test_people["not_a_member"].emails[0]
     list_of_people = list(api.people.list(email=email))
@@ -191,20 +195,24 @@ def test_list_people_by_display_name(api, test_people):
 def test_list_people_by_id(api, test_people):
     person_id = test_people["not_a_member"].id
     list_of_people = list(api.people.list(id=person_id))
-    assert len(list_of_people) >= 1
+    assert len(list_of_people) == 1
     assert are_valid_people(list_of_people)
 
 
-@pytest.mark.xfail  # TODO: Resolve test account issues
-def test_list_people_with_paging(api, test_people,
-                                 additional_group_room_memberships):
+def test_list_people_with_paging(
+    api,
+    test_people,
+    additional_group_room_memberships,
+    additional_moderated_group_room_memberships,
+):
     page_size = 1
     pages = 3
     num_people = pages * page_size
     assert test_people.len() >= num_people
-    display_name = test_people["not_a_member"].displayName
-    people = api.people.list(displayName=display_name, max=page_size)
+
+    people = api.people.list(max=page_size)
     people_list = list(itertools.islice(people, num_people))
+
     assert len(people_list) == num_people
     assert are_valid_people(people_list)
 
diff --git a/tests/api/test_recordings.py b/tests/api/test_recordings.py
index a846460..fc58971 100644
--- a/tests/api/test_recordings.py
+++ b/tests/api/test_recordings.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """WebexTeamsAPI Recordings API fixtures and tests.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -24,18 +24,14 @@
 
 import itertools
 import os
+from datetime import timedelta, timezone
 
 import pytest
 
 import webexteamssdk
 
-from_datetime_string = str(
-    webexteamssdk.WebexTeamsDateTime(2022, 1, 1, 0, 0, 0, 0),
-)
-
-to_datetime_string = str(
-    webexteamssdk.WebexTeamsDateTime.utcnow(),
-)
+to_datetime = webexteamssdk.WebexTeamsDateTime.now(tz=timezone.utc)
+from_datetime = to_datetime - timedelta(days=364)
 
 
 # Helper Functions
@@ -50,7 +46,9 @@ def are_valid_recording(iterable):
 # Fixtures
 @pytest.fixture(scope="session")
 def list_recordings(api):
-    return list(api.recordings.list(_from=from_datetime_string, to=to_datetime_string))
+    return list(
+        api.recordings.list(_from=str(from_datetime), to=str(to_datetime))
+    )
 
 
 @pytest.fixture(scope="session")
@@ -60,14 +58,22 @@ def recording_id(api, list_recordings):
 
 
 # Tests
+# We cannot create recordings programmatically, so we cannot automate testing
+# of the Recordings API - we can only manually test the API after manually
+# creating recordings.
+
+
+@pytest.mark.manual
 def test_recording_list(list_recordings):
     assert len(list_recordings) > 0
     assert are_valid_recording(list_recordings)
 
 
+@pytest.mark.manual
 def test_recording_detail(recording_id):
     assert is_valid_recording(recording_id)
 
 
+@pytest.mark.manual
 def test_delete_recording(api, recording_id):
     api.recordings.delete(recording_id)
diff --git a/tests/api/test_roles.py b/tests/api/test_roles.py
index 7c26236..097fbee 100644
--- a/tests/api/test_roles.py
+++ b/tests/api/test_roles.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """WebexTeamsAPI Roles API fixtures and tests.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -29,6 +29,7 @@
 
 # Helper Functions
 
+
 def is_valid_role(obj):
     return isinstance(obj, webexteamssdk.Role) and obj.id is not None
 
@@ -39,6 +40,7 @@ def are_valid_roles(iterable):
 
 # Fixtures
 
+
 @pytest.fixture(scope="session")
 def roles_list(api):
     return list(api.roles.list())
@@ -51,6 +53,7 @@ def roles_dict(roles_list):
 
 # Tests
 
+
 def test_list_roles(roles_list):
     assert are_valid_roles(roles_list)
 
diff --git a/tests/api/test_room_tabs.py b/tests/api/test_room_tabs.py
index 4bc196c..609efa1 100644
--- a/tests/api/test_room_tabs.py
+++ b/tests/api/test_room_tabs.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """WebexTeamsAPI Rooms API fixtures and tests.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -23,15 +23,25 @@
 """
 
 import itertools
+import os
 
 import pytest
 
 import webexteamssdk
 from tests.utils import create_string
 
+WEBEX_TEAMS_TEST_FILE_URL = os.environ.get("WEBEX_TEAMS_TEST_FILE_URL")
+
+if not WEBEX_TEAMS_TEST_FILE_URL:
+    pytest.skip(
+        "WEBEX_TEAMS_TEST_FILE_URL environment variable is not set.",
+        allow_module_level=True,
+    )
+
 
 # Helper Functions
 
+
 def is_valid_room_tab(obj):
     return isinstance(obj, webexteamssdk.RoomTab) and obj.id is not None
 
@@ -41,132 +51,63 @@ def are_valid_room_tabs(iterable):
 
 
 # Fixtures
-
 @pytest.fixture(scope="session")
-def group_room(api):
-    room = api.rooms.create(title=create_string("Group Room"))
-
-    yield room
-
-    api.rooms.delete(room.id)
-
-
-@pytest.fixture(scope="session")
-def direct_rooms(api, direct_messages):
-    return [
-        api.rooms.get(message.roomId)
-        for message in direct_messages
-    ]
-
-
-@pytest.fixture(scope="session")
-def team_room(api, team):
-    team_room = api.rooms.create(
-        title=create_string("Team Room"),
-        teamId=team.id,
+def room_tab(api, group_room):
+    room_tab = api.room_tabs.create(
+        roomId=group_room.id,
+        contentUrl=WEBEX_TEAMS_TEST_FILE_URL,
+        displayName=create_string("RoomTab"),
     )
 
-    yield team_room
+    yield room_tab
 
-    api.rooms.delete(team_room.id)
+    api.room_tabs.delete(room_tab.id)
 
 
-@pytest.fixture(scope="session")
-def list_of_rooms(api, group_room, direct_rooms, team_room):
-    return list(api.rooms.list())
-
-
-@pytest.fixture
-def temp_room(api):
-    room = api.rooms.create(title=create_string("Temp Room"))
+@pytest.fixture()
+def temp_room_tab(api, group_room):
+    temp_room_tab = api.room_tabs.create(
+        roomId=group_room.id,
+        contentUrl=WEBEX_TEAMS_TEST_FILE_URL,
+        displayName=create_string("RoomTab"),
+    )
 
-    yield room
+    yield temp_room_tab
 
     try:
-        api.rooms.delete(room.id)
+        api.room_tabs.delete(temp_room_tab.id)
     except webexteamssdk.ApiError:
         pass
 
 
-@pytest.fixture
-def add_rooms(api):
-    rooms = []
-
-    def inner(num_rooms):
-        for i in range(num_rooms):
-            rooms.append(api.rooms.create(create_string("Additional Room")))
-        return rooms
-
-    yield inner
-
-    for room in rooms:
-        try:
-            api.rooms.delete(room.id)
-        except webexteamssdk.ApiError:
-            pass
-
-
 # Tests
 
-def test_list_all_room_tabs(list_of_room_tabs):
-    assert len(list_of_room_tabs) > 0
-    assert are_valid_room_tabs(list_of_room_tabs)
-
-
-# def test_list_rooms_with_paging(api, list_of_rooms, add_rooms):
-#     page_size = 1
-#     pages = 3
-#     num_rooms = pages * page_size
-#     if len(list_of_rooms) < num_rooms:
-#         add_rooms(num_rooms - len(list_of_rooms))
-#     rooms = api.rooms.list(max=page_size)
-#     rooms_list = list(itertools.islice(rooms, num_rooms))
-#     assert len(rooms_list) == num_rooms
-#     assert are_valid_rooms(rooms_list)
-
-
-# def test_list_group_rooms(api, group_room):
-#     group_rooms_list = list(api.rooms.list(type='group'))
-#     assert len(group_rooms_list) > 0
-#     assert are_valid_rooms(group_rooms_list)
 
+def test_list_all_room_tabs(api, group_room, room_tab):
+    all_room_tabs = list(api.room_tabs.list(roomId=group_room.id))
+    assert len(all_room_tabs) > 0
+    assert are_valid_room_tabs(all_room_tabs)
 
-# def test_list_team_rooms(api, team, team_room):
-#     team_rooms_list = list(api.rooms.list(teamId=team.id))
-#     assert len(team_rooms_list) > 0
-#     assert are_valid_rooms(team_rooms_list)
 
+def test_create_room_tab(room_tab):
+    assert is_valid_room_tab(room_tab)
 
-# def test_list_direct_rooms(api, direct_rooms):
-#     direct_rooms_list = list(api.rooms.list(type='direct'))
-#     assert len(direct_rooms_list) > 0
-#     assert are_valid_rooms(direct_rooms_list)
 
+def test_get_room_tab(api, room_tab):
+    assert is_valid_room_tab(api.room_tabs.get(room_tab.id))
 
-# def test_create_group_room(group_room):
-#     assert is_valid_room(group_room)
 
-
-# def test_create_team_room(team_room):
-#     assert is_valid_room(team_room)
-
-
-# def test_get_room_details(api, group_room):
-#     room = api.rooms.get(group_room.id)
-#     assert is_valid_room(room)
-
-
-# def test_get_room_meeting_info(api, group_room):
-#     room_meeting_info = api.rooms.get_meeting_info(group_room.id)
-#     assert is_valid_room_meeting_info(room_meeting_info)
-
-
-# def test_update_room_title(api, group_room):
-#     new_title = create_string("Updated Group Room")
-#     room = api.rooms.update(group_room.id, title=new_title)
-#     assert is_valid_room(room)
-#     assert room.title == new_title
+def test_update_room_tab(api, group_room, room_tab):
+    new_display_name = create_string("RoomTab")
+    updated_room_tab = api.room_tabs.update(
+        roomTabId=room_tab.id,
+        roomId=group_room.id,
+        contentUrl=room_tab.contentUrl,
+        displayName=new_display_name,
+    )
+    assert is_valid_room_tab(updated_room_tab)
+    assert updated_room_tab.displayName == new_display_name
 
 
-# def test_delete_room(api, temp_room):
-#     api.rooms.delete(temp_room.id)
+def test_delete_room_tab(api, temp_room_tab):
+    api.room_tabs.delete(temp_room_tab.id)
diff --git a/tests/api/test_rooms.py b/tests/api/test_rooms.py
index 4e403fb..1256260 100644
--- a/tests/api/test_rooms.py
+++ b/tests/api/test_rooms.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """WebexTeamsAPI Rooms API fixtures and tests.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -32,13 +32,16 @@
 
 # Helper Functions
 
+
 def is_valid_room(obj):
     return isinstance(obj, webexteamssdk.Room) and obj.id is not None
 
 
 def is_valid_room_meeting_info(obj):
-    return (isinstance(obj, webexteamssdk.RoomMeetingInfo)
-            and obj.roomId is not None)
+    return (
+        isinstance(obj, webexteamssdk.RoomMeetingInfo)
+        and obj.roomId is not None
+    )
 
 
 def are_valid_rooms(iterable):
@@ -47,6 +50,7 @@ def are_valid_rooms(iterable):
 
 # Fixtures
 
+
 @pytest.fixture(scope="session")
 def group_room(api):
     room = api.rooms.create(title=create_string("Group Room"))
@@ -56,12 +60,21 @@ def group_room(api):
     api.rooms.delete(room.id)
 
 
+@pytest.fixture(scope="session")
+def moderated_group_room(api):
+    room = api.rooms.create(
+        title=create_string("Moderated Group Room"),
+        isLocked=True,
+    )
+
+    yield room
+
+    api.rooms.delete(room.id)
+
+
 @pytest.fixture(scope="session")
 def direct_rooms(api, direct_messages):
-    return [
-        api.rooms.get(message.roomId)
-        for message in direct_messages
-    ]
+    return [api.rooms.get(message.roomId) for message in direct_messages]
 
 
 @pytest.fixture(scope="session")
@@ -98,7 +111,7 @@ def add_rooms(api):
     rooms = []
 
     def inner(num_rooms):
-        for i in range(num_rooms):
+        for _ in range(num_rooms):
             rooms.append(api.rooms.create(create_string("Additional Room")))
         return rooms
 
@@ -113,6 +126,7 @@ def inner(num_rooms):
 
 # Tests
 
+
 def test_list_all_rooms(list_of_rooms):
     assert len(list_of_rooms) > 0
     assert are_valid_rooms(list_of_rooms)
@@ -131,7 +145,7 @@ def test_list_rooms_with_paging(api, list_of_rooms, add_rooms):
 
 
 def test_list_group_rooms(api, group_room):
-    group_rooms_list = list(api.rooms.list(type='group'))
+    group_rooms_list = list(api.rooms.list(type="group"))
     assert len(group_rooms_list) > 0
     assert are_valid_rooms(group_rooms_list)
 
@@ -143,7 +157,7 @@ def test_list_team_rooms(api, team, team_room):
 
 
 def test_list_direct_rooms(api, direct_rooms):
-    direct_rooms_list = list(api.rooms.list(type='direct'))
+    direct_rooms_list = list(api.rooms.list(type="direct"))
     assert len(direct_rooms_list) > 0
     assert are_valid_rooms(direct_rooms_list)
 
diff --git a/tests/api/test_teammemberships.py b/tests/api/test_teammemberships.py
index 7f79393..694014a 100644
--- a/tests/api/test_teammemberships.py
+++ b/tests/api/test_teammemberships.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """WebexTeamsAPI Team Memberships API fixtures and tests.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -31,9 +31,12 @@
 
 # Helper Functions
 
+
 def is_valid_team_membership(membership):
-    return isinstance(membership, webexteamssdk.TeamMembership) \
+    return (
+        isinstance(membership, webexteamssdk.TeamMembership)
         and membership.id is not None
+    )
 
 
 def are_valid_team_memberships(iterable):
@@ -43,6 +46,7 @@ def are_valid_team_memberships(iterable):
 
 # Fixtures
 
+
 @pytest.fixture(scope="session")
 def my_team_membership(api, me, team):
     team_memberships = api.team_memberships.list(team.id)
@@ -122,15 +126,17 @@ def team_moderator_added_by_id(api, team, test_people, team_moderator):
 
 
 @pytest.fixture(scope="session")
-def additional_team_memberships(team_member_added_by_email,
-                                team_member_added_by_id,
-                                team_moderator_added_by_email,
-                                team_moderator_added_by_id):
+def additional_team_memberships(
+    team_member_added_by_email,
+    team_member_added_by_id,
+    team_moderator_added_by_email,
+    team_moderator_added_by_id,
+):
     return [
         team_member_added_by_email,
         team_member_added_by_id,
         team_moderator_added_by_email,
-        team_moderator_added_by_id
+        team_moderator_added_by_id,
     ]
 
 
@@ -141,6 +147,7 @@ def team_with_members(team, additional_team_memberships):
 
 # Tests
 
+
 def test_list_team_memberships(api, team_with_members):
     team_memberships = list(api.team_memberships.list(team_with_members.id))
     assert len(team_memberships) > 1
diff --git a/tests/api/test_teams.py b/tests/api/test_teams.py
index d737cde..0aceaff 100644
--- a/tests/api/test_teams.py
+++ b/tests/api/test_teams.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """WebexTeamsAPI Team API fixtures and tests.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -32,6 +32,7 @@
 
 # Helper Functions
 
+
 def is_valid_team(obj):
     return isinstance(obj, webexteamssdk.Team) and obj.id is not None
 
@@ -42,6 +43,7 @@ def are_valid_teams(iterable):
 
 # Fixtures
 
+
 @pytest.fixture(scope="session")
 def team(api):
     team = api.teams.create(create_string("Team"))
@@ -73,7 +75,7 @@ def add_teams(api):
     teams = []
 
     def inner(num_teams):
-        for i in range(num_teams):
+        for _ in range(num_teams):
             teams.append(api.teams.create(create_string("Additional Team")))
         return teams
 
@@ -88,6 +90,7 @@ def inner(num_teams):
 
 # Tests
 
+
 def test_list_teams(teams_list):
     assert len(teams_list) > 0
     assert are_valid_teams(teams_list)
diff --git a/tests/conftest.py b/tests/conftest.py
index b7af2e0..b88d9a2 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """pytest configuration and top-level fixtures.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -30,27 +30,28 @@
 import pytest
 
 from tests.environment import (
-    WEBEX_TEAMS_TEST_DOMAIN, WEBEX_TEAMS_TEST_FILE_URL,
+    WEBEX_TEAMS_TEST_DOMAIN,
+    WEBEX_TEAMS_TEST_FILE_URL,
     WEBEX_TEAMS_TEST_ID_START,
 )
 from tests.utils import download_file
 
 
 pytest_plugins = [
-    'tests.test_webexteamssdk',
-    'tests.api',
-    'tests.api.test_attachment_actions',
-    'tests.api.test_licenses',
-    'tests.api.test_memberships',
-    'tests.api.test_messages',
-    'tests.api.test_organizations',
-    'tests.api.test_people',
-    'tests.api.test_roles',
-    'tests.api.test_rooms',
-    'tests.api.test_teammemberships',
-    'tests.api.test_teams',
+    "tests.test_webexteamssdk",
+    "tests.api",
+    "tests.api.test_attachment_actions",
+    "tests.api.test_licenses",
+    "tests.api.test_memberships",
+    "tests.api.test_messages",
+    "tests.api.test_organizations",
+    "tests.api.test_people",
+    "tests.api.test_roles",
+    "tests.api.test_rooms",
+    "tests.api.test_teammemberships",
+    "tests.api.test_teams",
     "tests.api.test_events",
-    "tests.api.test_recordings"
+    "tests.api.test_recordings",
 ]
 
 email_template = string.Template("test${number}@" + WEBEX_TEAMS_TEST_DOMAIN)
@@ -67,6 +68,7 @@ def new_email_generator():
 
 # pytest Fixtures
 
+
 @pytest.fixture(scope="session")
 def temp_directory():
     directory_abs_path = tempfile.mkdtemp()
diff --git a/tests/environment.py b/tests/environment.py
index 721edf6..8d818bd 100644
--- a/tests/environment.py
+++ b/tests/environment.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Test suite environment variables.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -48,9 +48,13 @@
     )
 
 WEBEX_TEAMS_TEST_STRING_PREFIX = os.getenv(
-    "WEBEX_TEAMS_TEST_STRING_PREFIX", default="webexteamssdk py.test",
+    "WEBEX_TEAMS_TEST_STRING_PREFIX",
+    default="webexteamssdk pytest",
 )
 
-WEBEX_TEAMS_TEST_STRING_TEMPLATE = string.Template(os.getenv(
-    "WEBEX_TEAMS_TEST_STRING_TEMPLATE", default="$prefix $item [$datetime]",
-))
+WEBEX_TEAMS_TEST_STRING_TEMPLATE = string.Template(
+    os.getenv(
+        "WEBEX_TEAMS_TEST_STRING_TEMPLATE",
+        default="$prefix $item [$datetime]",
+    )
+)
diff --git a/tests/test_restsession.py b/tests/test_restsession.py
index 47b6ad4..2aa748c 100644
--- a/tests/test_restsession.py
+++ b/tests/test_restsession.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """webexteamssdk/restsession.py Fixtures & Tests
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
 SOFTWARE.
 """
 
-
 import logging
 import warnings
 
diff --git a/tests/test_webexteamssdk.py b/tests/test_webexteamssdk.py
index fbe2586..1637ee1 100644
--- a/tests/test_webexteamssdk.py
+++ b/tests/test_webexteamssdk.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Test suite for the community-developed Python SDK for the Webex Teams APIs.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
diff --git a/tests/utils.py b/tests/utils.py
index 36bb3f3..1f83578 100644
--- a/tests/utils.py
+++ b/tests/utils.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Test utilities, helper functions, and classes.
 
-Copyright (c) 2016-2020 Cisco and/or its affiliates.
+Copyright (c) 2016-2024 Cisco and/or its affiliates.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -28,7 +28,8 @@
 import requests
 
 from tests.environment import (
-    WEBEX_TEAMS_TEST_STRING_PREFIX, WEBEX_TEAMS_TEST_STRING_TEMPLATE,
+    WEBEX_TEAMS_TEST_STRING_PREFIX,
+    WEBEX_TEAMS_TEST_STRING_TEMPLATE,
 )
 
 
@@ -37,7 +38,7 @@ def create_string(item):
     return WEBEX_TEAMS_TEST_STRING_TEMPLATE.substitute(
         prefix=WEBEX_TEAMS_TEST_STRING_PREFIX,
         item=item,
-        datetime=str(datetime.datetime.now())
+        datetime=str(datetime.datetime.now()),
     )
 
 
@@ -45,13 +46,15 @@ def download_file(url, local_directory, local_filename=None):
     """Download a file from a remote URL to a local directory."""
     # http://stackoverflow.com/questions/16694907/
     # how-to-download-large-file-in-python-with-requests-py
-    local_filename = local_filename if local_filename \
-        else url.split('/')[-1]
-    local_path = os.path.normpath(os.path.join(
-        local_directory, local_filename,
-    ))
+    local_filename = local_filename if local_filename else url.split("/")[-1]
+    local_path = os.path.normpath(
+        os.path.join(
+            local_directory,
+            local_filename,
+        )
+    )
     response = requests.get(url, stream=True)
-    with open(local_path, 'wb') as f:
+    with open(local_path, "wb") as f:
         for chunk in response.iter_content(chunk_size=1024):
             if chunk:
                 f.write(chunk)