Repository: codemagic-ci-cd/cli-tools (language: python)

Issue:
Resolve default locale from applicaiton test information
Actions `app-store-connect publish` and `app-store-connect beta-build-localizations create` defined a hardcoded default value `en-US` for `--locale` option. However, not all application entries in App Store Connect have `en-US` as the primary localization, which makes this decision kind or arbitrary. In order to better suit actual user needs and make the tool more user-friendly, omit default value entirely and when adding testing/what's new notes to build, find out what the application's primary test information locale is, and reuse that value.

Additionally, beta build localization resource is automatically created for default locale soon after the build itself is submitted to App Store Connect. In that case we just need to modify the resource. To better accomodate such case, make `app-store-connect beta-build-localizations create` a little less strict by allowing also locales as input that already have this resource. In this case just modify existing resource instead of failing the create request with `409` response.

Altogether new usage is as follows:
```bash
$ app-store-connect beta-build-localizations create b48608c6-47f2-439e-9d77-951390a4be89 --whats-new 'Exciting new features'
Using application Banaan Codemagic primary locale en-GB for beta build localization
Modify Beta Build Localization 4d4fe826-7b13-4096-afe3-cbe76098ce3b
Successfully modified Beta Build Localization 4d4fe826-7b13-4096-afe3-cbe76098ce3b
-- Beta Build Localization --
Id: 4d4fe826-7b13-4096-afe3-cbe76098ce3b
Type: betaBuildLocalizations
Locale: en-GB
Whats new: Exciting new features
```




Discussion / hints:

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 574bbe9b..32b85f79 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,19 @@
+Version 0.8.4
+-------------
+
+**Features**
+
+- Remove default value from `--locale` option for actions `app-store-connect beta-build-localizations create` and `app-store-connect publish`. In case it is not provided, resolve the default locale value from related application's primary test information.
+- Make `app-store-connect beta-build-localizations create` more forgiving and allow the cases when beta build localization already exists for the locale. On such occasions just update the resource.
+
+**Development / Docs**
+
+- Update `app-store-connect publish` action docs.
+- Update `app-store-connect beta-build-localizations create` action docs.
+- Do not use runtime enum definition generation during argument parsing.
+- Fix error messages for invalid enumeration values.
+- Update [requests](https://docs.python-requests.org/en/master/) dependency requirement from version 2.22.0 to 2.25.1.
+
 Version 0.8.3
 -------------
 
diff --git a/Pipfile b/Pipfile
index 26585bf6..d2b8047f 100644
--- a/Pipfile
+++ b/Pipfile
@@ -18,11 +18,12 @@ flake8 = "*"
 flake8-commas = "*"
 flake8-quotes = "*"
 pep8-naming = "*"
+types-requests = "*"
 
 [packages]
 pyopenssl = "~=19.0"
 pyjwt = "~=2.0"
-requests = "~=2.22.0"
+requests = "~=2.25"
 cryptography = "~=3.3"
 oauth2client = "~=4.1.3"
 google-api-python-client = "~=1.7.12"
diff --git a/Pipfile.lock b/Pipfile.lock
index 537bca08..29b41e08 100644
--- a/Pipfile.lock
+++ b/Pipfile.lock
@@ -1,7 +1,7 @@
 {
     "_meta": {
         "hash": {
-            "sha256": "83460069319eca5ae15750c60a9ce295b7a7bba4bfd8cacc03159b47a189ef04"
+            "sha256": "b80d972c649860a53c983dea1f7e33a9f05cfa23a9adbdb790297d3a9fb52690"
         },
         "pipfile-spec": 6,
         "requires": {
@@ -18,30 +18,39 @@
     "default": {
         "cachetools": {
             "hashes": [
-                "sha256:1d9d5f567be80f7c07d765e21b814326d78c61eb0c3a637dffc0e5d1796cb2e2",
-                "sha256:f469e29e7aa4cff64d8de4aad95ce76de8ea1125a16c68e0d93f65c3c3dc92e9"
+                "sha256:2cc0b89715337ab6dbba85b5b50effe2b0c74e035d83ee8ed637cf52f12ae001",
+                "sha256:61b5ed1e22a0924aed1d23b478f37e8d52549ff8a961de2909c69bf950020cff"
             ],
             "markers": "python_version ~= '3.5'",
-            "version": "==4.2.1"
+            "version": "==4.2.2"
         },
         "certifi": {
             "hashes": [
-                "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c",
-                "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"
+                "sha256:2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee",
+                "sha256:50b1e4f8446b06f41be7dd6338db18e0990601dce795c2b1686458aa7e8fa7d8"
             ],
-            "version": "==2020.12.5"
+            "version": "==2021.5.30"
         },
         "cffi": {
             "hashes": [
                 "sha256:005a36f41773e148deac64b08f233873a4d0c18b053d37da83f6af4d9087b813",
+                "sha256:04c468b622ed31d408fea2346bec5bbffba2cc44226302a0de1ade9f5ea3d373",
+                "sha256:06d7cd1abac2ffd92e65c0609661866709b4b2d82dd15f611e602b9b188b0b69",
+                "sha256:06db6321b7a68b2bd6df96d08a5adadc1fa0e8f419226e25b2a5fbf6ccc7350f",
                 "sha256:0857f0ae312d855239a55c81ef453ee8fd24136eaba8e87a2eceba644c0d4c06",
+                "sha256:0f861a89e0043afec2a51fd177a567005847973be86f709bbb044d7f42fc4e05",
                 "sha256:1071534bbbf8cbb31b498d5d9db0f274f2f7a865adca4ae429e147ba40f73dea",
                 "sha256:158d0d15119b4b7ff6b926536763dc0714313aa59e320ddf787502c70c4d4bee",
+                "sha256:1bf1ac1984eaa7675ca8d5745a8cb87ef7abecb5592178406e55858d411eadc0",
                 "sha256:1f436816fc868b098b0d63b8920de7d208c90a67212546d02f84fe78a9c26396",
+                "sha256:24a570cd11895b60829e941f2613a4f79df1a27344cbbb82164ef2e0116f09c7",
+                "sha256:24ec4ff2c5c0c8f9c6b87d5bb53555bf267e1e6f70e52e5a9740d32861d36b6f",
                 "sha256:2894f2df484ff56d717bead0a5c2abb6b9d2bf26d6960c4604d5c48bbc30ee73",
                 "sha256:29314480e958fd8aab22e4a58b355b629c59bf5f2ac2492b61e3dc06d8c7a315",
+                "sha256:293e7ea41280cb28c6fcaaa0b1aa1f533b8ce060b9e701d78511e1e6c4a1de76",
                 "sha256:34eff4b97f3d982fb93e2831e6750127d1355a923ebaeeb565407b3d2f8d41a1",
                 "sha256:35f27e6eb43380fa080dccf676dece30bef72e4a67617ffda586641cd4508d49",
+                "sha256:3c3f39fa737542161d8b0d680df2ec249334cd70a8f420f71c9304bd83c3cbed",
                 "sha256:3d3dd4c9e559eb172ecf00a2a7517e97d1e96de2a5e610bd9b68cea3925b4892",
                 "sha256:43e0b9d9e2c9e5d152946b9c5fe062c151614b262fda2e7b201204de0b99e482",
                 "sha256:48e1c69bbacfc3d932221851b39d49e81567a4d4aac3b21258d9c24578280058",
@@ -49,6 +58,7 @@
                 "sha256:58e3f59d583d413809d60779492342801d6e82fefb89c86a38e040c16883be53",
                 "sha256:5de7970188bb46b7bf9858eb6890aad302577a5f6f75091fd7cdd3ef13ef3045",
                 "sha256:65fa59693c62cf06e45ddbb822165394a288edce9e276647f0046e1ec26920f3",
+                "sha256:681d07b0d1e3c462dd15585ef5e33cb021321588bebd910124ef4f4fb71aef55",
                 "sha256:69e395c24fc60aad6bb4fa7e583698ea6cc684648e1ffb7fe85e3c1ca131a7d5",
                 "sha256:6c97d7350133666fbb5cf4abdc1178c812cb205dc6f41d174a7b0f18fb93337e",
                 "sha256:6e4714cc64f474e4d6e37cfff31a814b509a35cb17de4fb1999907575684479c",
@@ -66,8 +76,10 @@
                 "sha256:b85eb46a81787c50650f2392b9b4ef23e1f126313b9e0e9013b35c15e4288e2e",
                 "sha256:bb89f306e5da99f4d922728ddcd6f7fcebb3241fc40edebcb7284d7514741991",
                 "sha256:cbde590d4faaa07c72bf979734738f328d239913ba3e043b1e98fe9a39f8b2b6",
+                "sha256:cc5a8e069b9ebfa22e26d0e6b97d6f9781302fe7f4f2b8776c3e1daea35f1adc",
                 "sha256:cd2868886d547469123fadc46eac7ea5253ea7fcb139f12e1dfc2bbd406427d1",
                 "sha256:d42b11d692e11b6634f7613ad8df5d6d5f8875f5d48939520d351007b3c13406",
+                "sha256:df5052c5d867c1ea0b311fb7c3cd28b19df469c056f7fdcfe88c7473aa63e333",
                 "sha256:f2d45f97ab6bb54753eab54fffe75aaf3de4ff2341c9daee1987ee1837636f1d",
                 "sha256:fd78e5fee591709f32ef6edb9a015b4aa1a5022598e36227500c8f4e02328d9c"
             ],
@@ -75,28 +87,29 @@
         },
         "chardet": {
             "hashes": [
-                "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
-                "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
+                "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa",
+                "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"
             ],
-            "version": "==3.0.4"
+            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
+            "version": "==4.0.0"
         },
         "cryptography": {
             "hashes": [
-                "sha256:066bc53f052dfeda2f2d7c195cf16fb3e5ff13e1b6b7415b468514b40b381a5b",
-                "sha256:0923ba600d00718d63a3976f23cab19aef10c1765038945628cd9be047ad0336",
-                "sha256:2d32223e5b0ee02943f32b19245b61a62db83a882f0e76cc564e1cec60d48f87",
-                "sha256:4169a27b818de4a1860720108b55a2801f32b6ae79e7f99c00d79f2a2822eeb7",
-                "sha256:57ad77d32917bc55299b16d3b996ffa42a1c73c6cfa829b14043c561288d2799",
-                "sha256:5ecf2bcb34d17415e89b546dbb44e73080f747e504273e4d4987630493cded1b",
-                "sha256:600cf9bfe75e96d965509a4c0b2b183f74a4fa6f5331dcb40fb7b77b7c2484df",
-                "sha256:66b57a9ca4b3221d51b237094b0303843b914b7d5afd4349970bb26518e350b0",
-                "sha256:93cfe5b7ff006de13e1e89830810ecbd014791b042cbe5eec253be11ac2b28f3",
-                "sha256:9e98b452132963678e3ac6c73f7010fe53adf72209a32854d55690acac3f6724",
-                "sha256:df186fcbf86dc1ce56305becb8434e4b6b7504bc724b71ad7a3239e0c9d14ef2",
-                "sha256:fec7fb46b10da10d9e1d078d1ff8ed9e05ae14f431fdbd11145edd0550b9a964"
+                "sha256:0f1212a66329c80d68aeeb39b8a16d54ef57071bf22ff4e521657b27372e327d",
+                "sha256:1e056c28420c072c5e3cb36e2b23ee55e260cb04eee08f702e0edfec3fb51959",
+                "sha256:240f5c21aef0b73f40bb9f78d2caff73186700bf1bc6b94285699aff98cc16c6",
+                "sha256:26965837447f9c82f1855e0bc8bc4fb910240b6e0d16a664bb722df3b5b06873",
+                "sha256:37340614f8a5d2fb9aeea67fd159bfe4f5f4ed535b1090ce8ec428b2f15a11f2",
+                "sha256:3d10de8116d25649631977cb37da6cbdd2d6fa0e0281d014a5b7d337255ca713",
+                "sha256:3d8427734c781ea5f1b41d6589c293089704d4759e34597dce91014ac125aad1",
+                "sha256:7ec5d3b029f5fa2b179325908b9cd93db28ab7b85bb6c1db56b10e0b54235177",
+                "sha256:8e56e16617872b0957d1c9742a3f94b43533447fd78321514abbe7db216aa250",
+                "sha256:de4e5f7f68220d92b7637fc99847475b59154b7a1b3868fb7385337af54ac9ca",
+                "sha256:eb8cc2afe8b05acbd84a43905832ec78e7b3873fb124ca190f574dca7389a87d",
+                "sha256:ee77aa129f481be46f8d92a1a7db57269a2f23052d5f2433b4621bb457081cc9"
             ],
             "index": "pypi",
-            "version": "==3.4.6"
+            "version": "==3.4.7"
         },
         "google-api-python-client": {
             "hashes": [
@@ -108,11 +121,11 @@
         },
         "google-auth": {
             "hashes": [
-                "sha256:9bd436d19ab047001a1340720d2b629eb96dd503258c524921ec2af3ee88a80e",
-                "sha256:dcaba3aa9d4e0e96fd945bf25a86b6f878fcb05770b67adbeb50a63ca4d28a5e"
+                "sha256:b3a67fa9ba5b768861dacf374c2135eb09fa14a0e40c851c3b8ea7abe6fc8fef",
+                "sha256:e34e5f5de5610b202f9b40ebd9f8b27571d5c5537db9afed3a72b2db5a345039"
             ],
             "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
-            "version": "==1.28.0"
+            "version": "==1.32.0"
         },
         "google-auth-httplib2": {
             "hashes": [
@@ -123,18 +136,19 @@
         },
         "httplib2": {
             "hashes": [
-                "sha256:749c32603f9bf16c1277f59531d502e8f1c2ca19901ae653b49c4ed698f0820e",
-                "sha256:e0d428dad43c72dbce7d163b7753ffc7a39c097e6788ef10f4198db69b92f08e"
+                "sha256:0b12617eeca7433d4c396a100eaecfa4b08ee99aa881e6df6e257a7aad5d533d",
+                "sha256:2ad195faf9faf079723f6714926e9a9061f694d07724b846658ce08d40f522b4"
             ],
             "index": "pypi",
-            "version": "==0.19.0"
+            "version": "==0.19.1"
         },
         "idna": {
             "hashes": [
-                "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407",
-                "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"
+                "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6",
+                "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"
             ],
-            "version": "==2.8"
+            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
+            "version": "==2.10"
         },
         "oauth2client": {
             "hashes": [
@@ -190,11 +204,11 @@
         },
         "pyjwt": {
             "hashes": [
-                "sha256:a5c70a06e1f33d81ef25eecd50d50bd30e34de1ca8b2b9fa3fe0daaabcf69bf7",
-                "sha256:b70b15f89dc69b993d8a8d32c299032d5355c82f9b5b7e851d1a6d706dffe847"
+                "sha256:934d73fbba91b0483d3857d1aff50e96b2a892384ee2c17417ed3203f173fca1",
+                "sha256:fba44e7898bbca160a2b2b501f492824fc8382485d3a6f11ba5d0c1937ce6130"
             ],
             "index": "pypi",
-            "version": "==2.0.1"
+            "version": "==2.1.0"
         },
         "pyopenssl": {
             "hashes": [
@@ -214,11 +228,11 @@
         },
         "requests": {
             "hashes": [
-                "sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4",
-                "sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31"
+                "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804",
+                "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"
             ],
             "index": "pypi",
-            "version": "==2.22.0"
+            "version": "==2.25.1"
         },
         "rsa": {
             "hashes": [
@@ -230,11 +244,11 @@
         },
         "six": {
             "hashes": [
-                "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259",
-                "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"
+                "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
+                "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
             ],
             "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
-            "version": "==1.15.0"
+            "version": "==1.16.0"
         },
         "uritemplate": {
             "hashes": [
@@ -246,11 +260,11 @@
         },
         "urllib3": {
             "hashes": [
-                "sha256:8d7eaa5a82a1cac232164990f04874c594c9453ec55eef02eab885aa02fc17a2",
-                "sha256:f5321fbe4bf3fefa0efd0bfe7fb14e90909eb62a48ccda331726b4319897dd5e"
+                "sha256:753a0374df26658f99d826cfe40394a686d05985786d946fbe4165b5148f5a7c",
+                "sha256:a7acd0977125325f516bda9735fa7142b909a8d01e8b2e4c8108d0984e6e0098"
             ],
             "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'",
-            "version": "==1.25.11"
+            "version": "==1.26.5"
         }
     },
     "develop": {
@@ -271,27 +285,27 @@
         },
         "astroid": {
             "hashes": [
-                "sha256:21d735aab248253531bb0f1e1e6d068f0ee23533e18ae8a6171ff892b98297cf",
-                "sha256:cfc35498ee64017be059ceffab0a25bedf7548ab76f2bea691c5565896e7128d"
+                "sha256:4db03ab5fc3340cf619dbc25e42c2cc3755154ce6009469766d7143d1fc2ee4e",
+                "sha256:8a398dfce302c13f14bab13e2b14fe385d32b73f4e4853b9bdfb64598baa1975"
             ],
-            "markers": "python_version >= '3.6'",
-            "version": "==2.5.1"
+            "markers": "python_version ~= '3.6'",
+            "version": "==2.5.6"
         },
         "attrs": {
             "hashes": [
-                "sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6",
-                "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"
+                "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1",
+                "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"
             ],
-            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
-            "version": "==20.3.0"
+            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
+            "version": "==21.2.0"
         },
         "autopep8": {
             "hashes": [
-                "sha256:5454e6e9a3d02aae38f866eec0d9a7de4ab9f93c10a273fb0340f3d6d09f7514",
-                "sha256:f01b06a6808bc31698db907761e5890eb2295e287af53f6693b39ce55454034a"
+                "sha256:276ced7e9e3cb22e5d7c14748384a5cf5d9002257c0ed50c0e075b68011bb6d0",
+                "sha256:aa213493c30dcdac99537249ee65b24af0b2c29f2e83cd8b3f68760441ed0db9"
             ],
             "index": "pypi",
-            "version": "==1.5.6"
+            "version": "==1.5.7"
         },
         "backcall": {
             "hashes": [
@@ -310,17 +324,18 @@
         },
         "certifi": {
             "hashes": [
-                "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c",
-                "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"
+                "sha256:2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee",
+                "sha256:50b1e4f8446b06f41be7dd6338db18e0990601dce795c2b1686458aa7e8fa7d8"
             ],
-            "version": "==2020.12.5"
+            "version": "==2021.5.30"
         },
         "chardet": {
             "hashes": [
-                "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
-                "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
+                "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa",
+                "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"
             ],
-            "version": "==3.0.4"
+            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
+            "version": "==4.0.0"
         },
         "colorama": {
             "hashes": [
@@ -390,25 +405,26 @@
         },
         "decorator": {
             "hashes": [
-                "sha256:41fa54c2a0cc4ba648be4fd43cff00aedf5b9465c9bf18d64325bc225f08f760",
-                "sha256:e3a62f0520172440ca0dcc823749319382e377f37f140a0b99ef45fecb84bfe7"
+                "sha256:6e5c199c16f7a9f0e3a61a4a54b3d27e7dad0dbdde92b944426cb20914376323",
+                "sha256:72ecfba4320a893c53f9706bebb2d55c270c1e51a28789361aa93e4a21319ed5"
             ],
-            "version": "==4.4.2"
+            "markers": "python_version >= '3.5'",
+            "version": "==5.0.9"
         },
         "distlib": {
             "hashes": [
-                "sha256:8c09de2c67b3e7deef7184574fc060ab8a793e7adbb183d942c389c8b13c52fb",
-                "sha256:edf6116872c863e1aa9d5bb7cb5e05a022c519a4594dc703843343a9ddd9bff1"
+                "sha256:106fef6dc37dd8c0e2c0a60d3fca3e77460a48907f335fa28420463a6f799736",
+                "sha256:23e223426b28491b1ced97dc3bbe183027419dfc7982b4fa2f05d5f3ff10711c"
             ],
-            "version": "==0.3.1"
+            "version": "==0.3.2"
         },
         "docutils": {
             "hashes": [
-                "sha256:0c5b78adfbf7762415433f5515cd5c9e762339e23369dbe8000d84a4bf4ab3af",
-                "sha256:c2de3a60e9e7d07be26b7f2b00ca0309c207e06c100f9cc2a94931fc75a478fc"
+                "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125",
+                "sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61"
             ],
             "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
-            "version": "==0.16"
+            "version": "==0.17.1"
         },
         "filelock": {
             "hashes": [
@@ -419,11 +435,11 @@
         },
         "flake8": {
             "hashes": [
-                "sha256:12d05ab02614b6aee8df7c36b97d1a3b2372761222b19b58621355e82acddcff",
-                "sha256:78873e372b12b093da7b5e5ed302e8ad9e988b38b063b61ad937f26ca58fc5f0"
+                "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b",
+                "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"
             ],
             "index": "pypi",
-            "version": "==3.9.0"
+            "version": "==3.9.2"
         },
         "flake8-commas": {
             "hashes": [
@@ -449,18 +465,19 @@
         },
         "idna": {
             "hashes": [
-                "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407",
-                "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"
+                "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6",
+                "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"
             ],
-            "version": "==2.8"
+            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
+            "version": "==2.10"
         },
         "importlib-metadata": {
             "hashes": [
-                "sha256:742add720a20d0467df2f444ae41704000f50e1234f46174b51f9c6031a1bd71",
-                "sha256:b74159469b464a99cb8cc3e21973e4d96e05d3024d337313fedb618a6e86e6f4"
+                "sha256:833b26fb89d5de469b24a390e9df088d4e52e4ba33b01dc5e0e4f41b81a16c00",
+                "sha256:b142cc1dd1342f31ff04bb7d022492b09920cb64fed867cd3ea6f80fe3ebd139"
             ],
             "markers": "python_version < '3.8'",
-            "version": "==3.7.3"
+            "version": "==4.5.0"
         },
         "iniconfig": {
             "hashes": [
@@ -471,18 +488,18 @@
         },
         "ipdb": {
             "hashes": [
-                "sha256:178c367a61c1039e44e17c56fcc4a6e7dc11b33561261382d419b6ddb4401810"
+                "sha256:951bd9a64731c444fd907a5ce268543020086a697f6be08f7cc2c9a752a278c5"
             ],
             "index": "pypi",
-            "version": "==0.13.7"
+            "version": "==0.13.9"
         },
         "ipython": {
             "hashes": [
-                "sha256:04323f72d5b85b606330b6d7e2dc8d2683ad46c3905e955aa96ecc7a99388e70",
-                "sha256:34207ffb2f653bced2bc8e3756c1db86e7d93e44ed049daae9814fed66d408ec"
+                "sha256:9bc24a99f5d19721fb8a2d1408908e9c0520a17fff2233ffe82620847f17f1b6",
+                "sha256:d513e93327cf8657d6467c81f1f894adc125334ffe0e4ddd1abbb1c78d828703"
             ],
             "markers": "python_version >= '3.7'",
-            "version": "==7.21.0"
+            "version": "==7.24.1"
         },
         "ipython-genutils": {
             "hashes": [
@@ -493,11 +510,11 @@
         },
         "isort": {
             "hashes": [
-                "sha256:c729845434366216d320e936b8ad6f9d681aab72dc7cbc2d51bedc3582f3ad1e",
-                "sha256:fff4f0c04e1825522ce6949973e83110a6e907750cd92d128b0d14aaaadbffdc"
+                "sha256:83510593e07e433b77bd5bff0f6f607dbafa06d1a89022616f02d8b699cfcd56",
+                "sha256:8e2c107091cfec7286bc0f68a547d0ba4c094d460b732075b6fba674f1035c0c"
             ],
             "index": "pypi",
-            "version": "==5.7.0"
+            "version": "==5.9.1"
         },
         "jedi": {
             "hashes": [
@@ -509,41 +526,47 @@
         },
         "keyring": {
             "hashes": [
-                "sha256:237ff44888ba9b3918a7dcb55c8f1db909c95b6f071bfb46c6918f33f453a68a",
-                "sha256:29f407fd5509c014a6086f17338c70215c8d1ab42d5d49e0254273bc0a64bbfc"
+                "sha256:045703609dd3fccfcdb27da201684278823b72af515aedec1a8515719a038cb8",
+                "sha256:8f607d7d1cc502c43a932a275a56fe47db50271904513a379d39df1af277ac48"
             ],
             "markers": "python_version >= '3.6'",
-            "version": "==23.0.0"
+            "version": "==23.0.1"
         },
         "lazy-object-proxy": {
             "hashes": [
-                "sha256:1d33d6f789697f401b75ce08e73b1de567b947740f768376631079290118ad39",
-                "sha256:2f2de8f8ac0be3e40d17730e0600619d35c78c13a099ea91ef7fb4ad944ce694",
-                "sha256:3782931963dc89e0e9a0ae4348b44762e868ea280e4f8c233b537852a8996ab9",
-                "sha256:37d9c34b96cca6787fe014aeb651217944a967a5b165e2cacb6b858d2997ab84",
-                "sha256:38c3865bd220bd983fcaa9aa11462619e84a71233bafd9c880f7b1cb753ca7fa",
-                "sha256:429c4d1862f3fc37cd56304d880f2eae5bd0da83bdef889f3bd66458aac49128",
-                "sha256:522b7c94b524389f4a4094c4bf04c2b02228454ddd17c1a9b2801fac1d754871",
-                "sha256:57fb5c5504ddd45ed420b5b6461a78f58cbb0c1b0cbd9cd5a43ad30a4a3ee4d0",
-                "sha256:5944a9b95e97de1980c65f03b79b356f30a43de48682b8bdd90aa5089f0ec1f4",
-                "sha256:6f4e5e68b7af950ed7fdb594b3f19a0014a3ace0fedb86acb896e140ffb24302",
-                "sha256:71a1ef23f22fa8437974b2d60fedb947c99a957ad625f83f43fd3de70f77f458",
-                "sha256:8a44e9901c0555f95ac401377032f6e6af66d8fc1fbfad77a7a8b1a826e0b93c",
-                "sha256:b6577f15d5516d7d209c1a8cde23062c0f10625f19e8dc9fb59268859778d7d7",
-                "sha256:c8fe2d6ff0ff583784039d0255ea7da076efd08507f2be6f68583b0da32e3afb",
-                "sha256:cadfa2c2cf54d35d13dc8d231253b7985b97d629ab9ca6e7d672c35539d38163",
-                "sha256:cd1bdace1a8762534e9a36c073cd54e97d517a17d69a17985961265be6d22847",
-                "sha256:ddbdcd10eb999d7ab292677f588b658372aadb9a52790f82484a37127a390108",
-                "sha256:e7273c64bccfd9310e9601b8f4511d84730239516bada26a0c9846c9697617ef",
-                "sha256:e7428977763150b4cf83255625a80a23dfdc94d43be7791ce90799d446b4e26f",
-                "sha256:e960e8be509e8d6d618300a6c189555c24efde63e85acaf0b14b2cd1ac743315",
-                "sha256:ecb5dd5990cec6e7f5c9c1124a37cb2c710c6d69b0c1a5c4aa4b35eba0ada068",
-                "sha256:ef3f5e288aa57b73b034ce9c1f1ac753d968f9069cd0742d1d69c698a0167166",
-                "sha256:fa5b2dee0e231fa4ad117be114251bdfe6afe39213bd629d43deb117b6a6c40a",
-                "sha256:fa7fb7973c622b9e725bee1db569d2c2ee64d2f9a089201c5e8185d482c7352d"
+                "sha256:17e0967ba374fc24141738c69736da90e94419338fd4c7c7bef01ee26b339653",
+                "sha256:1fee665d2638491f4d6e55bd483e15ef21f6c8c2095f235fef72601021e64f61",
+                "sha256:22ddd618cefe54305df49e4c069fa65715be4ad0e78e8d252a33debf00f6ede2",
+                "sha256:24a5045889cc2729033b3e604d496c2b6f588c754f7a62027ad4437a7ecc4837",
+                "sha256:410283732af311b51b837894fa2f24f2c0039aa7f220135192b38fcc42bd43d3",
+                "sha256:4732c765372bd78a2d6b2150a6e99d00a78ec963375f236979c0626b97ed8e43",
+                "sha256:489000d368377571c6f982fba6497f2aa13c6d1facc40660963da62f5c379726",
+                "sha256:4f60460e9f1eb632584c9685bccea152f4ac2130e299784dbaf9fae9f49891b3",
+                "sha256:5743a5ab42ae40caa8421b320ebf3a998f89c85cdc8376d6b2e00bd12bd1b587",
+                "sha256:85fb7608121fd5621cc4377a8961d0b32ccf84a7285b4f1d21988b2eae2868e8",
+                "sha256:9698110e36e2df951c7c36b6729e96429c9c32b3331989ef19976592c5f3c77a",
+                "sha256:9d397bf41caad3f489e10774667310d73cb9c4258e9aed94b9ec734b34b495fd",
+                "sha256:b579f8acbf2bdd9ea200b1d5dea36abd93cabf56cf626ab9c744a432e15c815f",
+                "sha256:b865b01a2e7f96db0c5d12cfea590f98d8c5ba64ad222300d93ce6ff9138bcad",
+                "sha256:bf34e368e8dd976423396555078def5cfc3039ebc6fc06d1ae2c5a65eebbcde4",
+                "sha256:c6938967f8528b3668622a9ed3b31d145fab161a32f5891ea7b84f6b790be05b",
+                "sha256:d1c2676e3d840852a2de7c7d5d76407c772927addff8d742b9808fe0afccebdf",
+                "sha256:d7124f52f3bd259f510651450e18e0fd081ed82f3c08541dffc7b94b883aa981",
+                "sha256:d900d949b707778696fdf01036f58c9876a0d8bfe116e8d220cfd4b15f14e741",
+                "sha256:ebfd274dcd5133e0afae738e6d9da4323c3eb021b3e13052d8cbd0e457b1256e",
+                "sha256:ed361bb83436f117f9917d282a456f9e5009ea12fd6de8742d1a4752c3017e93",
+                "sha256:f5144c75445ae3ca2057faac03fda5a902eff196702b0a24daf1d6ce0650514b"
             ],
-            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
-            "version": "==1.5.2"
+            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
+            "version": "==1.6.0"
+        },
+        "matplotlib-inline": {
+            "hashes": [
+                "sha256:5cf1176f554abb4fa98cb362aa2b55c500147e4bdbb07e3fda359143e1da0811",
+                "sha256:f41d5ff73c9f5385775d5c0bc13b424535c8402fe70ea8210f93e11f3683993e"
+            ],
+            "markers": "python_version >= '3.5'",
+            "version": "==0.1.2"
         },
         "mccabe": {
             "hashes": [
@@ -561,31 +584,32 @@
         },
         "mypy": {
             "hashes": [
-                "sha256:0d0a87c0e7e3a9becdfbe936c981d32e5ee0ccda3e0f07e1ef2c3d1a817cf73e",
-                "sha256:25adde9b862f8f9aac9d2d11971f226bd4c8fbaa89fb76bdadb267ef22d10064",
-                "sha256:28fb5479c494b1bab244620685e2eb3c3f988d71fd5d64cc753195e8ed53df7c",
-                "sha256:2f9b3407c58347a452fc0736861593e105139b905cca7d097e413453a1d650b4",
-                "sha256:33f159443db0829d16f0a8d83d94df3109bb6dd801975fe86bacb9bf71628e97",
-                "sha256:3f2aca7f68580dc2508289c729bd49ee929a436208d2b2b6aab15745a70a57df",
-                "sha256:499c798053cdebcaa916eef8cd733e5584b5909f789de856b482cd7d069bdad8",
-                "sha256:4eec37370483331d13514c3f55f446fc5248d6373e7029a29ecb7b7494851e7a",
-                "sha256:552a815579aa1e995f39fd05dde6cd378e191b063f031f2acfe73ce9fb7f9e56",
-                "sha256:5873888fff1c7cf5b71efbe80e0e73153fe9212fafdf8e44adfe4c20ec9f82d7",
-                "sha256:61a3d5b97955422964be6b3baf05ff2ce7f26f52c85dd88db11d5e03e146a3a6",
-                "sha256:674e822aa665b9fd75130c6c5f5ed9564a38c6cea6a6432ce47eafb68ee578c5",
-                "sha256:7ce3175801d0ae5fdfa79b4f0cfed08807af4d075b402b7e294e6aa72af9aa2a",
-                "sha256:9743c91088d396c1a5a3c9978354b61b0382b4e3c440ce83cf77994a43e8c521",
-                "sha256:9f94aac67a2045ec719ffe6111df543bac7874cee01f41928f6969756e030564",
-                "sha256:a26f8ec704e5a7423c8824d425086705e381b4f1dfdef6e3a1edab7ba174ec49",
-                "sha256:abf7e0c3cf117c44d9285cc6128856106183938c68fd4944763003decdcfeb66",
-                "sha256:b09669bcda124e83708f34a94606e01b614fa71931d356c1f1a5297ba11f110a",
-                "sha256:cd07039aa5df222037005b08fbbfd69b3ab0b0bd7a07d7906de75ae52c4e3119",
-                "sha256:d23e0ea196702d918b60c8288561e722bf437d82cb7ef2edcd98cfa38905d506",
-                "sha256:d65cc1df038ef55a99e617431f0553cd77763869eebdf9042403e16089fe746c",
-                "sha256:d7da2e1d5f558c37d6e8c1246f1aec1e7349e4913d8fb3cb289a35de573fe2eb"
+                "sha256:0190fb77e93ce971954c9e54ea61de2802065174e5e990c9d4c1d0f54fbeeca2",
+                "sha256:0756529da2dd4d53d26096b7969ce0a47997123261a5432b48cc6848a2cb0bd4",
+                "sha256:2f9fedc1f186697fda191e634ac1d02f03d4c260212ccb018fabbb6d4b03eee8",
+                "sha256:353aac2ce41ddeaf7599f1c73fed2b75750bef3b44b6ad12985a991bc002a0da",
+                "sha256:3f12705eabdd274b98f676e3e5a89f247ea86dc1af48a2d5a2b080abac4e1243",
+                "sha256:4efc67b9b3e2fddbe395700f91d5b8deb5980bfaaccb77b306310bd0b9e002eb",
+                "sha256:517e7528d1be7e187a5db7f0a3e479747307c1b897d9706b1c662014faba3116",
+                "sha256:68a098c104ae2b75e946b107ef69dd8398d54cb52ad57580dfb9fc78f7f997f0",
+                "sha256:746e0b0101b8efec34902810047f26a8c80e1efbb4fc554956d848c05ef85d76",
+                "sha256:8be7bbd091886bde9fcafed8dd089a766fa76eb223135fe5c9e9798f78023a20",
+                "sha256:9236c21194fde5df1b4d8ebc2ef2c1f2a5dc7f18bcbea54274937cae2e20a01c",
+                "sha256:9ef5355eaaf7a23ab157c21a44c614365238a7bdb3552ec3b80c393697d974e1",
+                "sha256:9f1d74eeb3f58c7bd3f3f92b8f63cb1678466a55e2c4612bf36909105d0724ab",
+                "sha256:a26d0e53e90815c765f91966442775cf03b8a7514a4e960de7b5320208b07269",
+                "sha256:ae94c31bb556ddb2310e4f913b706696ccbd43c62d3331cd3511caef466871d2",
+                "sha256:b5ba1f0d5f9087e03bf5958c28d421a03a4c1ad260bf81556195dffeccd979c4",
+                "sha256:b5dfcd22c6bab08dfeded8d5b44bdcb68c6f1ab261861e35c470b89074f78a70",
+                "sha256:cd01c599cf9f897b6b6c6b5d8b182557fb7d99326bcdf5d449a0fbbb4ccee4b9",
+                "sha256:e89880168c67cf4fde4506b80ee42f1537ad66ad366c101d388b3fd7d7ce2afd",
+                "sha256:ebe2bc9cb638475f5d39068d2dbe8ae1d605bb8d8d3ff281c695df1670ab3987",
+                "sha256:f89bfda7f0f66b789792ab64ce0978e4a991a0e4dd6197349d0767b0f1095b21",
+                "sha256:fc4d63da57ef0e8cd4ab45131f3fe5c286ce7dd7f032650d0fbc239c6190e167",
+                "sha256:fd634bc17b1e2d6ce716f0e43446d0d61cdadb1efcad5c56ca211c22b246ebc8"
             ],
             "index": "pypi",
-            "version": "==0.812"
+            "version": "==0.902"
         },
         "mypy-extensions": {
             "hashes": [
@@ -604,11 +628,11 @@
         },
         "parso": {
             "hashes": [
-                "sha256:15b00182f472319383252c18d5913b69269590616c947747bc50bf4ac768f410",
-                "sha256:8519430ad07087d4c997fda3a7918f7cfa27cb58972a8c89c2a0295a1c940e9e"
+                "sha256:12b83492c6239ce32ff5eed6d3639d6a536170723c6f3f1506869f1ace413398",
+                "sha256:a8c4922db71e4fdb90e0d0bc6e50f9b273d3397925e5e60a717e719201778d22"
             ],
             "markers": "python_version >= '3.6'",
-            "version": "==0.8.1"
+            "version": "==0.8.2"
         },
         "pep8-naming": {
             "hashes": [
@@ -635,11 +659,11 @@
         },
         "pipenv": {
             "hashes": [
-                "sha256:4ab2f60742184d851ac44b9e1d423afe71dc2ea7a68bde07eb890c8b4ce5a420",
-                "sha256:8253fe6f9cfb3791a54da8a0571f73c918cb3457dd908684c1800a13a06ec4c1"
+                "sha256:05958fadcd70b2de6a27542fcd2bd72dd5c59c6d35307fdac3e06361fb06e30e",
+                "sha256:d180f5be4775c552fd5e69ae18a9d6099d9dafb462efe54f11c72cb5f4d5e977"
             ],
             "index": "pypi",
-            "version": "==2020.11.15"
+            "version": "==2021.5.29"
         },
         "pkginfo": {
             "hashes": [
@@ -658,11 +682,11 @@
         },
         "prompt-toolkit": {
             "hashes": [
-                "sha256:4cea7d09e46723885cb8bc54678175453e5071e9449821dce6f017b1d1fbfc1a",
-                "sha256:9397a7162cf45449147ad6042fa37983a081b8a73363a5253dd4072666333137"
+                "sha256:08360ee3a3148bdb5163621709ee322ec34fc4375099afa4bbf751e9b7b7fa4f",
+                "sha256:7089d8d2938043508aa9420ec18ce0922885304cddae87fb96eebca942299f88"
             ],
             "markers": "python_full_version >= '3.6.1'",
-            "version": "==3.0.17"
+            "version": "==3.0.19"
         },
         "ptyprocess": {
             "hashes": [
@@ -689,27 +713,27 @@
         },
         "pyflakes": {
             "hashes": [
-                "sha256:910208209dcea632721cb58363d0f72913d9e8cf64dc6f8ae2e02a3609aba40d",
-                "sha256:e59fd8e750e588358f1b8885e5a4751203a0516e0ee6d34811089ac294c8806f"
+                "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3",
+                "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"
             ],
             "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
-            "version": "==2.3.0"
+            "version": "==2.3.1"
         },
         "pygments": {
             "hashes": [
-                "sha256:2656e1a6edcdabf4275f9a3640db59fd5de107d88e8663c5d4e9a0fa62f77f94",
-                "sha256:534ef71d539ae97d4c3a4cf7d6f110f214b0e687e92f9cb9d2a3b0d3101289c8"
+                "sha256:a18f47b506a429f6f4b9df81bb02beab9ca21d0a5fee38ed15aef65f0545519f",
+                "sha256:d66e804411278594d764fc69ec36ec13d9ae9147193a1740cd34d272ca383b8e"
             ],
             "markers": "python_version >= '3.5'",
-            "version": "==2.8.1"
+            "version": "==2.9.0"
         },
         "pylint": {
             "hashes": [
-                "sha256:0e21d3b80b96740909d77206d741aa3ce0b06b41be375d92e1f3244a274c1f8a",
-                "sha256:d09b0b07ba06bcdff463958f53f23df25e740ecd81895f7d2699ec04bbd8dc3b"
+                "sha256:0a049c5d47b629d9070c3932d13bff482b12119b6a241a93bc460b0be16953c8",
+                "sha256:792b38ff30903884e4a9eab814ee3523731abd3c463f3ba48d7b627e87013484"
             ],
             "index": "pypi",
-            "version": "==2.7.2"
+            "version": "==2.8.3"
         },
         "pyparsing": {
             "hashes": [
@@ -721,19 +745,19 @@
         },
         "pytest": {
             "hashes": [
-                "sha256:9d1edf9e7d0b84d72ea3dbcdfd22b35fb543a5e8f2a60092dd578936bf63d7f9",
-                "sha256:b574b57423e818210672e07ca1fa90aaf194a4f63f3ab909a2c67ebb22913839"
+                "sha256:50bcad0a0b9c5a72c8e4e7c9855a3ad496ca6a881a3641b4260605450772c54b",
+                "sha256:91ef2131a9bd6be8f76f1f08eac5c5317221d6ad1e143ae03894b862e8976890"
             ],
             "index": "pypi",
-            "version": "==6.2.2"
+            "version": "==6.2.4"
         },
         "pytest-cov": {
             "hashes": [
-                "sha256:359952d9d39b9f822d9d29324483e7ba04a3a17dd7d05aa6beb7ea01e359e5f7",
-                "sha256:bdb9fdb0b85a7cc825269a4c56b48ccaa5c7e365054b6038772c32ddcdc969da"
+                "sha256:261bb9e47e65bd099c89c3edf92972865210c36813f80ede5277dceb77a4a62a",
+                "sha256:261ceeb8c227b726249b376b8526b600f38667ee314f910353fa318caa01f4d7"
             ],
             "index": "pypi",
-            "version": "==2.11.1"
+            "version": "==2.12.1"
         },
         "readme-renderer": {
             "hashes": [
@@ -744,11 +768,11 @@
         },
         "requests": {
             "hashes": [
-                "sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4",
-                "sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31"
+                "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804",
+                "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"
             ],
             "index": "pypi",
-            "version": "==2.22.0"
+            "version": "==2.25.1"
         },
         "requests-toolbelt": {
             "hashes": [
@@ -759,18 +783,18 @@
         },
         "rfc3986": {
             "hashes": [
-                "sha256:112398da31a3344dc25dbf477d8df6cb34f9278a94fee2625d89e4514be8bb9d",
-                "sha256:af9147e9aceda37c91a05f4deb128d4b4b49d6b199775fd2d2927768abdc8f50"
+                "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835",
+                "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97"
             ],
-            "version": "==1.4.0"
+            "version": "==1.5.0"
         },
         "six": {
             "hashes": [
-                "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259",
-                "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"
+                "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
+                "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
             ],
             "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
-            "version": "==1.15.0"
+            "version": "==1.16.0"
         },
         "toml": {
             "hashes": [
@@ -782,11 +806,11 @@
         },
         "tqdm": {
             "hashes": [
-                "sha256:9fdf349068d047d4cfbe24862c425883af1db29bcddf4b0eeb2524f6fbdb23c7",
-                "sha256:d666ae29164da3e517fcf125e41d4fe96e5bb375cd87ff9763f6b38b5592fe33"
+                "sha256:24be966933e942be5f074c29755a95b315c69a91f839a29139bf26ffffe2d3fd",
+                "sha256:aa0c29f03f298951ac6318f7c8ce584e48fa22ec26396e6411e43d038243bdb2"
             ],
             "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
-            "version": "==4.59.0"
+            "version": "==4.61.1"
         },
         "traitlets": {
             "hashes": [
@@ -806,64 +830,72 @@
         },
         "typed-ast": {
             "hashes": [
-                "sha256:07d49388d5bf7e863f7fa2f124b1b1d89d8aa0e2f7812faff0a5658c01c59aa1",
-                "sha256:14bf1522cdee369e8f5581238edac09150c765ec1cb33615855889cf33dcb92d",
-                "sha256:240296b27397e4e37874abb1df2a608a92df85cf3e2a04d0d4d61055c8305ba6",
-                "sha256:36d829b31ab67d6fcb30e185ec996e1f72b892255a745d3a82138c97d21ed1cd",
-                "sha256:37f48d46d733d57cc70fd5f30572d11ab8ed92da6e6b28e024e4a3edfb456e37",
-                "sha256:4c790331247081ea7c632a76d5b2a265e6d325ecd3179d06e9cf8d46d90dd151",
-                "sha256:5dcfc2e264bd8a1db8b11a892bd1647154ce03eeba94b461effe68790d8b8e07",
-                "sha256:7147e2a76c75f0f64c4319886e7639e490fee87c9d25cb1d4faef1d8cf83a440",
-                "sha256:7703620125e4fb79b64aa52427ec192822e9f45d37d4b6625ab37ef403e1df70",
-                "sha256:8368f83e93c7156ccd40e49a783a6a6850ca25b556c0fa0240ed0f659d2fe496",
-                "sha256:84aa6223d71012c68d577c83f4e7db50d11d6b1399a9c779046d75e24bed74ea",
-                "sha256:85f95aa97a35bdb2f2f7d10ec5bbdac0aeb9dafdaf88e17492da0504de2e6400",
-                "sha256:8db0e856712f79c45956da0c9a40ca4246abc3485ae0d7ecc86a20f5e4c09abc",
-                "sha256:9044ef2df88d7f33692ae3f18d3be63dec69c4fb1b5a4a9ac950f9b4ba571606",
-                "sha256:963c80b583b0661918718b095e02303d8078950b26cc00b5e5ea9ababe0de1fc",
-                "sha256:987f15737aba2ab5f3928c617ccf1ce412e2e321c77ab16ca5a293e7bbffd581",
-                "sha256:9ec45db0c766f196ae629e509f059ff05fc3148f9ffd28f3cfe75d4afb485412",
-                "sha256:9fc0b3cb5d1720e7141d103cf4819aea239f7d136acf9ee4a69b047b7986175a",
-                "sha256:a2c927c49f2029291fbabd673d51a2180038f8cd5a5b2f290f78c4516be48be2",
-                "sha256:a38878a223bdd37c9709d07cd357bb79f4c760b29210e14ad0fb395294583787",
-                "sha256:b4fcdcfa302538f70929eb7b392f536a237cbe2ed9cba88e3bf5027b39f5f77f",
-                "sha256:c0c74e5579af4b977c8b932f40a5464764b2f86681327410aa028a22d2f54937",
-                "sha256:c1c876fd795b36126f773db9cbb393f19808edd2637e00fd6caba0e25f2c7b64",
-                "sha256:c9aadc4924d4b5799112837b226160428524a9a45f830e0d0f184b19e4090487",
-                "sha256:cc7b98bf58167b7f2db91a4327da24fb93368838eb84a44c472283778fc2446b",
-                "sha256:cf54cfa843f297991b7388c281cb3855d911137223c6b6d2dd82a47ae5125a41",
-                "sha256:d003156bb6a59cda9050e983441b7fa2487f7800d76bdc065566b7d728b4581a",
-                "sha256:d175297e9533d8d37437abc14e8a83cbc68af93cc9c1c59c2c292ec59a0697a3",
-                "sha256:d746a437cdbca200622385305aedd9aef68e8a645e385cc483bdc5e488f07166",
-                "sha256:e683e409e5c45d5c9082dc1daf13f6374300806240719f95dc783d1fc942af10"
+                "sha256:01ae5f73431d21eead5015997ab41afa53aa1fbe252f9da060be5dad2c730ace",
+                "sha256:067a74454df670dcaa4e59349a2e5c81e567d8d65458d480a5b3dfecec08c5ff",
+                "sha256:0fb71b8c643187d7492c1f8352f2c15b4c4af3f6338f21681d3681b3dc31a266",
+                "sha256:1b3ead4a96c9101bef08f9f7d1217c096f31667617b58de957f690c92378b528",
+                "sha256:2068531575a125b87a41802130fa7e29f26c09a2833fea68d9a40cf33902eba6",
+                "sha256:209596a4ec71d990d71d5e0d312ac935d86930e6eecff6ccc7007fe54d703808",
+                "sha256:2c726c276d09fc5c414693a2de063f521052d9ea7c240ce553316f70656c84d4",
+                "sha256:398e44cd480f4d2b7ee8d98385ca104e35c81525dd98c519acff1b79bdaac363",
+                "sha256:52b1eb8c83f178ab787f3a4283f68258525f8d70f778a2f6dd54d3b5e5fb4341",
+                "sha256:5feca99c17af94057417d744607b82dd0a664fd5e4ca98061480fd8b14b18d04",
+                "sha256:7538e495704e2ccda9b234b82423a4038f324f3a10c43bc088a1636180f11a41",
+                "sha256:760ad187b1041a154f0e4d0f6aae3e40fdb51d6de16e5c99aedadd9246450e9e",
+                "sha256:777a26c84bea6cd934422ac2e3b78863a37017618b6e5c08f92ef69853e765d3",
+                "sha256:95431a26309a21874005845c21118c83991c63ea800dd44843e42a916aec5899",
+                "sha256:9ad2c92ec681e02baf81fdfa056fe0d818645efa9af1f1cd5fd6f1bd2bdfd805",
+                "sha256:9c6d1a54552b5330bc657b7ef0eae25d00ba7ffe85d9ea8ae6540d2197a3788c",
+                "sha256:aee0c1256be6c07bd3e1263ff920c325b59849dc95392a05f258bb9b259cf39c",
+                "sha256:af3d4a73793725138d6b334d9d247ce7e5f084d96284ed23f22ee626a7b88e39",
+                "sha256:b36b4f3920103a25e1d5d024d155c504080959582b928e91cb608a65c3a49e1a",
+                "sha256:b9574c6f03f685070d859e75c7f9eeca02d6933273b5e69572e5ff9d5e3931c3",
+                "sha256:bff6ad71c81b3bba8fa35f0f1921fb24ff4476235a6e94a26ada2e54370e6da7",
+                "sha256:c190f0899e9f9f8b6b7863debfb739abcb21a5c054f911ca3596d12b8a4c4c7f",
+                "sha256:c907f561b1e83e93fad565bac5ba9c22d96a54e7ea0267c708bffe863cbe4075",
+                "sha256:cae53c389825d3b46fb37538441f75d6aecc4174f615d048321b716df2757fb0",
+                "sha256:dd4a21253f42b8d2b48410cb31fe501d32f8b9fbeb1f55063ad102fe9c425e40",
+                "sha256:dde816ca9dac1d9c01dd504ea5967821606f02e510438120091b84e852367428",
+                "sha256:f2362f3cb0f3172c42938946dbc5b7843c2a28aec307c49100c8b38764eb6927",
+                "sha256:f328adcfebed9f11301eaedfa48e15bdece9b519fb27e6a8c01aa52a17ec31b3",
+                "sha256:f8afcf15cc511ada719a88e013cec87c11aff7b91f019295eb4530f96fe5ef2f",
+                "sha256:fb1bbeac803adea29cedd70781399c99138358c26d05fcbd23c13016b7f5ec65"
             ],
             "markers": "python_version < '3.8' and implementation_name == 'cpython'",
-            "version": "==1.4.2"
+            "version": "==1.4.3"
+        },
+        "types-requests": {
+            "hashes": [
+                "sha256:ee0d0c507210141b7d5b8639cc43eaa726084178775db2a5fb06fbf85c185808",
+                "sha256:fa5c1e5e832ff6193507d8da7e1159281383908ee193a2f4b37bc08140b51844"
+            ],
+            "index": "pypi",
+            "version": "==2.25.0"
         },
         "typing-extensions": {
             "hashes": [
-                "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918",
-                "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c",
-                "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"
+                "sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497",
+                "sha256:50b6f157849174217d0656f99dc82fe932884fb250826c18350e159ec6cdf342",
+                "sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84"
             ],
             "markers": "python_version < '3.8'",
-            "version": "==3.7.4.3"
+            "version": "==3.10.0.0"
         },
         "urllib3": {
             "hashes": [
-                "sha256:8d7eaa5a82a1cac232164990f04874c594c9453ec55eef02eab885aa02fc17a2",
-                "sha256:f5321fbe4bf3fefa0efd0bfe7fb14e90909eb62a48ccda331726b4319897dd5e"
+                "sha256:753a0374df26658f99d826cfe40394a686d05985786d946fbe4165b5148f5a7c",
+                "sha256:a7acd0977125325f516bda9735fa7142b909a8d01e8b2e4c8108d0984e6e0098"
             ],
             "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'",
-            "version": "==1.25.11"
+            "version": "==1.26.5"
         },
         "virtualenv": {
             "hashes": [
-                "sha256:49ec4eb4c224c6f7dd81bb6d0a28a09ecae5894f4e593c89b0db0885f565a107",
-                "sha256:83f95875d382c7abafe06bd2a4cdd1b363e1bb77e02f155ebe8ac082a916b37c"
+                "sha256:14fdf849f80dbb29a4eb6caa9875d476ee2a5cf76a5f5415fa2f1606010ab467",
+                "sha256:2b0126166ea7c9c3661f5b8e06773d28f83322de7a3ff7d06f0aed18c9de6a76"
             ],
             "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
-            "version": "==20.4.3"
+            "version": "==20.4.7"
         },
         "virtualenv-clone": {
             "hashes": [
diff --git a/docs/app-store-connect/beta-build-localizations.md b/docs/app-store-connect/beta-build-localizations.md
index f55e29d1..cda8f4db 100644
--- a/docs/app-store-connect/beta-build-localizations.md
+++ b/docs/app-store-connect/beta-build-localizations.md
@@ -76,7 +76,7 @@ Enable verbose logging for commands
 
 |Action|Description|
 | :--- | :--- |
-|[`create`](beta-build-localizations/create.md)|Create a beta build localization|
+|[`create`](beta-build-localizations/create.md)|Create a beta build localization if it doesn't exist or update existing         beta build localization for specified locale|
 |[`delete`](beta-build-localizations/delete.md)|Delete a beta build localization|
 |[`get`](beta-build-localizations/get.md)|Get beta build localization|
 |[`list`](beta-build-localizations/list.md)|List beta build localizations|
diff --git a/docs/app-store-connect/beta-build-localizations/create.md b/docs/app-store-connect/beta-build-localizations/create.md
index ab47746f..857527de 100644
--- a/docs/app-store-connect/beta-build-localizations/create.md
+++ b/docs/app-store-connect/beta-build-localizations/create.md
@@ -3,7 +3,7 @@ create
 ======
 
 
-**Create a beta build localization**
+**Create a beta build localization if it doesn't exist or update existing         beta build localization for specified locale**
 ### Usage
 ```bash
 app-store-connect beta-build-localizations create [-h] [--log-stream STREAM] [--no-color] [--version] [-s] [-v]
@@ -14,9 +14,9 @@ app-store-connect beta-build-localizations create [-h] [--log-stream STREAM] [--
     [--private-key PRIVATE_KEY]
     [--certificates-dir CERTIFICATES_DIRECTORY]
     [--profiles-dir PROFILES_DIRECTORY]
+    [--locale LOCALE_DEFAULT]
     [--whats-new WHATS_NEW]
     BUILD_ID_RESOURCE_ID
-    --locale LOCALE
 ```
 ### Required arguments for action `create`
 
@@ -24,12 +24,12 @@ app-store-connect beta-build-localizations create [-h] [--log-stream STREAM] [--
 
 
 Alphanumeric ID value of the Build
-##### `--locale, -l=da | de-DE | el | en-AU | en-CA | en-GB | en-US | es-ES | es-MX | fi | fr-CA | fr-FR | id | it | ja | ko | ms | nl-NL | no | pt-BR | pt-PT | ru | sv | th | tr | vi | zh-Hans | zh-Hant`
+### Optional arguments for action `create`
 
+##### `--locale, -l=da | de-DE | el | en-AU | en-CA | en-GB | en-US | es-ES | es-MX | fi | fr-CA | fr-FR | id | it | ja | ko | ms | nl-NL | no | pt-BR | pt-PT | ru | sv | th | tr | vi | zh-Hans | zh-Hant`
 
-The locale code name for displaying localized "What's new" content in TestFlight. Learn more from https://developer.apple.com/documentation/appstoreconnectapi/betabuildlocalizationcreaterequest/data/attributes
-### Optional arguments for action `create`
 
+The locale code name for displaying localized "What's new" content in TestFlight. In case not provided, application's primary locale from test information is used instead. Learn more from https://developer.apple.com/documentation/appstoreconnectapi/betabuildlocalizationcreaterequest/data/attributes
 ##### `--whats-new, -n=WHATS_NEW`
 
 
diff --git a/docs/app-store-connect/publish.md b/docs/app-store-connect/publish.md
index 7bdee3b6..d615e756 100644
--- a/docs/app-store-connect/publish.md
+++ b/docs/app-store-connect/publish.md
@@ -18,7 +18,7 @@ app-store-connect publish [-h] [--log-stream STREAM] [--no-color] [--version] [-
     [--apple-id APPLE_ID]
     [--password APP_SPECIFIC_PASSWORD]
     [--testflight]
-    [--locale LOCALE_OPTIONAL_WITH_DEFAULT]
+    [--locale LOCALE_DEFAULT]
     [--whats-new WHATS_NEW]
     [--skip-package-validation]
     [--max-build-processing-wait MAX_BUILD_PROCESSING_WAIT]
@@ -44,7 +44,7 @@ Submit an app for Testflight beta app review to allow external testing
 ##### `--locale, -l=da | de-DE | el | en-AU | en-CA | en-GB | en-US | es-ES | es-MX | fi | fr-CA | fr-FR | id | it | ja | ko | ms | nl-NL | no | pt-BR | pt-PT | ru | sv | th | tr | vi | zh-Hans | zh-Hant`
 
 
-The locale code name for displaying localized "What's new" content in TestFlight. Learn more from https://developer.apple.com/documentation/appstoreconnectapi/betabuildlocalizationcreaterequest/data/attributes. Default:&nbsp;`en-US`
+The locale code name for displaying localized "What's new" content in TestFlight. In case not provided, application's primary locale from test information is used instead. Learn more from https://developer.apple.com/documentation/appstoreconnectapi/betabuildlocalizationcreaterequest/data/attributes
 ##### `--whats-new, -n=WHATS_NEW`
 
 
diff --git a/setup.py b/setup.py
index 59f5c540..8e298b57 100644
--- a/setup.py
+++ b/setup.py
@@ -31,7 +31,7 @@
         'oauth2client>=4.1.3',
         'PyJWT>=2.0.0,<3',
         'pyopenssl>=19.0',
-        'requests>=2.22.0',
+        'requests>=2.25.1',
     ],
     extras_require={
         'dev': ['pytest'],
diff --git a/src/codemagic/__version__.py b/src/codemagic/__version__.py
index de9825af..5023b016 100644
--- a/src/codemagic/__version__.py
+++ b/src/codemagic/__version__.py
@@ -1,5 +1,5 @@
 __title__ = 'codemagic-cli-tools'
 __description__ = 'CLI tools used in Codemagic builds'
-__version__ = '0.8.3'
+__version__ = '0.8.4'
 __url__ = 'https://github.com/codemagic-ci-cd/cli-tools'
 __licence__ = 'GNU General Public License v3.0'
diff --git a/src/codemagic/apple/resources/beta_app_localization.py b/src/codemagic/apple/resources/beta_app_localization.py
index 76a1ebbf..64d2d045 100644
--- a/src/codemagic/apple/resources/beta_app_localization.py
+++ b/src/codemagic/apple/resources/beta_app_localization.py
@@ -22,6 +22,10 @@ class Attributes(Resource.Attributes):
         privacyPolicyUrl: Optional[str]
         tvOsPrivacyPolicy: Optional[str]
 
+        def __post_init__(self):
+            if isinstance(self.locale, str):
+                self.locale = Locale(self.locale)
+
     @dataclass
     class Relationships(Resource.Relationships):
         app: Relationship
diff --git a/src/codemagic/apple/resources/beta_app_review_submission.py b/src/codemagic/apple/resources/beta_app_review_submission.py
index c0c2c94c..a7c64b3a 100644
--- a/src/codemagic/apple/resources/beta_app_review_submission.py
+++ b/src/codemagic/apple/resources/beta_app_review_submission.py
@@ -16,6 +16,10 @@ class BetaAppReviewSubmission(Resource):
     class Attributes(Resource.Attributes):
         betaReviewState: BetaReviewState
 
+        def __post_init__(self):
+            if isinstance(self.betaReviewState, str):
+                self.betaReviewState = BetaReviewState(self.betaReviewState)
+
     @dataclass
     class Relationships(Resource.Relationships):
         build: Relationship
diff --git a/src/codemagic/apple/resources/enums.py b/src/codemagic/apple/resources/enums.py
index 72f72dee..ac5271d2 100644
--- a/src/codemagic/apple/resources/enums.py
+++ b/src/codemagic/apple/resources/enums.py
@@ -6,7 +6,7 @@
 from codemagic.utilities import log
 
 
-class _ResourceEnumMeta(enum.EnumMeta):
+class ResourceEnumMeta(enum.EnumMeta):
     """
     Custom metaclass for Resource enumerations to accommodate the cases when
     App Store Connect API returns such a value that our definitions do not describe.
@@ -17,23 +17,30 @@ class _ResourceEnumMeta(enum.EnumMeta):
     fails unexpectedly, which is not desirable.
     """
 
+    graceful_fallback = True
+
     def __call__(cls, value, *args, **kwargs):  # noqa: N805
         try:
             return super().__call__(value, *args, **kwargs)
         except ValueError as ve:
+            if not cls.graceful_fallback:
+                raise
             logger = log.get_logger(cls, log_to_stream=False)
             logger.warning('Undefined Resource enumeration: %s', ve)
-            enum_class = _ResourceEnum(f'Graceful{cls.__name__}', {value: value})
-            return enum_class(value)
+            try:
+                enum_class = ResourceEnum(f'Graceful{cls.__name__}', {value: value})
+                return enum_class(value)
+            except TypeError:
+                raise ve
 
 
-class _ResourceEnum(enum.Enum, metaclass=_ResourceEnumMeta):
+class ResourceEnum(enum.Enum, metaclass=ResourceEnumMeta):
 
     def __str__(self):
         return str(self.value)
 
 
-class AppStoreState(_ResourceEnum):
+class AppStoreState(ResourceEnum):
     DEVELOPER_REMOVED_FROM_SALE = 'DEVELOPER_REMOVED_FROM_SALE'
     DEVELOPER_REJECTED = 'DEVELOPER_REJECTED'
     IN_REVIEW = 'IN_REVIEW'
@@ -53,28 +60,28 @@ class AppStoreState(_ResourceEnum):
     REPLACED_WITH_NEW_VERSION = 'REPLACED_WITH_NEW_VERSION'
 
 
-class BetaReviewState(_ResourceEnum):
+class BetaReviewState(ResourceEnum):
     APPROVED = 'APPROVED'
     IN_REVIEW = 'IN_REVIEW'
     REJECTED = 'REJECTED'
     WAITING_FOR_REVIEW = 'WAITING_FOR_REVIEW'
 
 
-class BuildProcessingState(_ResourceEnum):
+class BuildProcessingState(ResourceEnum):
     PROCESSING = 'PROCESSING'
     FAILED = 'FAILED'
     INVALID = 'INVALID'
     VALID = 'VALID'
 
 
-class BundleIdPlatform(_ResourceEnum):
+class BundleIdPlatform(ResourceEnum):
     IOS = 'IOS'
     MAC_OS = 'MAC_OS'
     UNIVERSAL = 'UNIVERSAL'
     SERVICES = 'SERVICES'
 
 
-class CapabilityOptionKey(_ResourceEnum):
+class CapabilityOptionKey(ResourceEnum):
     XCODE_5 = 'XCODE_5'
     XCODE_6 = 'XCODE_6'
     COMPLETE_PROTECTION = 'COMPLETE_PROTECTION'
@@ -82,18 +89,18 @@ class CapabilityOptionKey(_ResourceEnum):
     PROTECTED_UNTIL_FIRST_USER_AUTH = 'PROTECTED_UNTIL_FIRST_USER_AUTH'
 
 
-class CapabilitySettingAllowedInstance(_ResourceEnum):
+class CapabilitySettingAllowedInstance(ResourceEnum):
     ENTRY = 'ENTRY'
     SINGLE = 'SINGLE'
     MULTIPLE = 'MULTIPLE'
 
 
-class CapabilitySettingKey(_ResourceEnum):
+class CapabilitySettingKey(ResourceEnum):
     ICLOUD_VERSION = 'ICLOUD_VERSION'
     DATA_PROTECTION_PERMISSION_LEVEL = 'DATA_PROTECTION_PERMISSION_LEVEL'
 
 
-class CapabilityType(_ResourceEnum):
+class CapabilityType(ResourceEnum):
     ACCESS_WIFI_INFORMATION = 'ACCESS_WIFI_INFORMATION'
     APP_GROUPS = 'APP_GROUPS'
     APPLE_PAY = 'APPLE_PAY'
@@ -119,7 +126,7 @@ class CapabilityType(_ResourceEnum):
     WIRELESS_ACCESSORY_CONFIGURATION = 'WIRELESS_ACCESSORY_CONFIGURATION'
 
 
-class CertificateType(_ResourceEnum):
+class CertificateType(ResourceEnum):
     DEVELOPER_ID_APPLICATION = 'DEVELOPER_ID_APPLICATION'
     DEVELOPER_ID_KEXT = 'DEVELOPER_ID_KEXT'
     DEVELOPMENT = 'DEVELOPMENT'
@@ -152,12 +159,12 @@ def from_profile_type(cls, profile_type: ProfileType) -> Optional[CertificateTyp
             raise ValueError(f'Certificate type for profile type {profile_type} is unknown')
 
 
-class ContentRightsDeclaration(_ResourceEnum):
+class ContentRightsDeclaration(ResourceEnum):
     DOES_NOT_USE_THIRD_PARTY_CONTENT = 'DOES_NOT_USE_THIRD_PARTY_CONTENT'
     USES_THIRD_PARTY_CONTENT = 'USES_THIRD_PARTY_CONTENT'
 
 
-class DeviceClass(_ResourceEnum):
+class DeviceClass(ResourceEnum):
     APPLE_TV = 'APPLE_TV'
     APPLE_WATCH = 'APPLE_WATCH'
     IPAD = 'IPAD'
@@ -166,24 +173,24 @@ class DeviceClass(_ResourceEnum):
     MAC = 'MAC'
 
 
-class DeviceStatus(_ResourceEnum):
+class DeviceStatus(ResourceEnum):
     DISABLED = 'DISABLED'
     ENABLED = 'ENABLED'
 
 
-class Platform(_ResourceEnum):
+class Platform(ResourceEnum):
     IOS = 'IOS'
     MAC_OS = 'MAC_OS'
     TV_OS = 'TV_OS'
 
 
-class ProfileState(_ResourceEnum):
+class ProfileState(ResourceEnum):
     ACTIVE = 'ACTIVE'
     INVALID = 'INVALID'
     EXPIRED = 'EXPIRED'  # Undocumented Profile State
 
 
-class ProfileType(_ResourceEnum):
+class ProfileType(ResourceEnum):
     IOS_APP_ADHOC = 'IOS_APP_ADHOC'
     IOS_APP_DEVELOPMENT = 'IOS_APP_DEVELOPMENT'
     IOS_APP_INHOUSE = 'IOS_APP_INHOUSE'
@@ -218,13 +225,13 @@ def devices_allowed(self) -> bool:
         return self.is_development_type or self.is_ad_hoc_type
 
 
-class ReleaseType(_ResourceEnum):
+class ReleaseType(ResourceEnum):
     MANUAL = 'MANUAL'
     AFTER_APPROVAL = 'AFTER_APPROVAL'
     SCHEDULED = 'SCHEDULED'
 
 
-class ResourceType(_ResourceEnum):
+class ResourceType(ResourceEnum):
     APPS = 'apps'
     APP_STORE_VERSIONS = 'appStoreVersions'
     APP_STORE_VERSION_SUBMISSIONS = 'appStoreVersionSubmissions'
@@ -241,7 +248,7 @@ class ResourceType(_ResourceEnum):
     PROFILES = 'profiles'
 
 
-class Locale(_ResourceEnum):
+class Locale(ResourceEnum):
     """
     Referenced in https://developer.apple.com/documentation/appstoreconnectapi/betaapplocalization/attributes#discussion
     """
diff --git a/src/codemagic/cli/cli_app.py b/src/codemagic/cli/cli_app.py
index a29a1788..4bd14e93 100644
--- a/src/codemagic/cli/cli_app.py
+++ b/src/codemagic/cli/cli_app.py
@@ -166,11 +166,25 @@ def show_version(cls):
     def is_cli_invocation(cls) -> bool:
         return os.environ.get('_CLI_INVOCATION') == 'true'
 
+    @classmethod
+    def _resolve_cli_invocation_arg(cls):
+        from codemagic.apple.resources.enums import ResourceEnumMeta
+
+        parser = cls._setup_cli_options()
+        # Turn off graceful enumeration fallback to get proper error messages
+        ResourceEnumMeta.graceful_fallback = False
+        try:
+            args = parser.parse_args()
+        finally:
+            ResourceEnumMeta.graceful_fallback = True
+
+        return parser, args
+
     @classmethod
     def invoke_cli(cls) -> NoReturn:
         os.environ['_CLI_INVOCATION'] = 'true'
-        parser = cls._setup_cli_options()
-        args = parser.parse_args()
+
+        parser, args = cls._resolve_cli_invocation_arg()
         cls._setup_logging(args)
 
         cls._log_cli_invoke_started()
diff --git a/src/codemagic/google_play/resources/enums.py b/src/codemagic/google_play/resources/enums.py
index 646409ab..c3961863 100644
--- a/src/codemagic/google_play/resources/enums.py
+++ b/src/codemagic/google_play/resources/enums.py
@@ -1,19 +1,19 @@
 import enum
 
 
-class _ResourceEnum(enum.Enum):
+class ResourceEnum(enum.Enum):
     def __str__(self):
         return str(self.value)
 
 
-class TrackName(_ResourceEnum):
+class TrackName(ResourceEnum):
     INTERNAL = 'internal'
     ALPHA = 'alpha'
     BETA = 'beta'
     PRODUCTION = 'production'
 
 
-class ReleaseStatus(_ResourceEnum):
+class ReleaseStatus(ResourceEnum):
     STATUS_UNSPECIFIED = 'statusUnspecified'
     DRAFT = 'draft'
     IN_PROGRESS = 'inProgress'
diff --git a/src/codemagic/tools/_app_store_connect/abstract_base_action.py b/src/codemagic/tools/_app_store_connect/abstract_base_action.py
index d3cb51e5..e4d3c6d9 100644
--- a/src/codemagic/tools/_app_store_connect/abstract_base_action.py
+++ b/src/codemagic/tools/_app_store_connect/abstract_base_action.py
@@ -48,7 +48,7 @@ def create_beta_app_review_submission(
     def create_beta_build_localization(
             self,
             build_id: ResourceId,
-            locale: Locale,
+            locale: Optional[Locale],
             whats_new: Optional[Types.WhatsNewArgument] = None,
             should_print: bool = True) -> BetaBuildLocalization:
         ...
diff --git a/src/codemagic/tools/_app_store_connect/action_groups/beta_build_localizations_action_group.py b/src/codemagic/tools/_app_store_connect/action_groups/beta_build_localizations_action_group.py
index cb226585..ae5bd974 100644
--- a/src/codemagic/tools/_app_store_connect/action_groups/beta_build_localizations_action_group.py
+++ b/src/codemagic/tools/_app_store_connect/action_groups/beta_build_localizations_action_group.py
@@ -5,6 +5,7 @@
 from typing import Optional
 
 from codemagic import cli
+from codemagic.apple import AppStoreConnectApiError
 from codemagic.apple.app_store_connect.versioning import BetaBuildLocalizations
 from codemagic.apple.resources import BetaBuildLocalization
 from codemagic.apple.resources import Locale
@@ -49,25 +50,46 @@ def list_beta_build_localizations(
 
     @cli.action('create',
                 BuildArgument.BUILD_ID_RESOURCE_ID,
-                BuildArgument.LOCALE,
+                BuildArgument.LOCALE_DEFAULT,
                 BuildArgument.WHATS_NEW,
                 action_group=AppStoreConnectActionGroup.BETA_BUILDS_LOCALIZATIONS)
     def create_beta_build_localization(
             self,
             build_id: ResourceId,
-            locale: Locale,
+            locale: Optional[Locale] = None,
             whats_new: Optional[Types.WhatsNewArgument] = None,
             should_print: bool = True) -> BetaBuildLocalization:
         """
-        Create a beta build localization
+        Create a beta build localization if it doesn't exist or update existing
+        beta build localization for specified locale
         """
-        return self._create_resource(
-            self.api_client.beta_build_localizations,
-            should_print,
-            build=build_id,
-            locale=locale,
-            whats_new=whats_new.value if whats_new else None,
-        )
+        if locale is None:
+            app = self.api_client.builds.read_app(build_id)
+            locale = self._get_application_default_locale(app.id)
+            msg_template = 'Using application %s primary locale %s for beta build localization'
+            self.logger.info(msg_template, app.attributes.name, locale.value)
+
+        beta_localizations_filter = BetaBuildLocalizations.Filter(build=build_id, locale=locale)
+        try:
+            beta_build_localizations = self.api_client.beta_build_localizations.list(beta_localizations_filter)
+        except AppStoreConnectApiError:
+            beta_build_localizations = []
+
+        # The notes are automatically created for default locale some time after the build is
+        # submitted to App Store Connect. In that case we just need to modify the resource.
+        # Otherwise, either when the resource is not created yet, or we are working with non-default
+        # locales, we need to create the BetaBuildLocalization resource by ourselves.
+        if not beta_build_localizations:
+            return self._create_resource(
+                self.api_client.beta_build_localizations,
+                should_print,
+                build=build_id,
+                locale=locale,
+                whats_new=whats_new.value if whats_new else None,
+            )
+        else:
+            beta_build_localization = beta_build_localizations[0]
+            return self.update_beta_build_localization(beta_build_localization.id, whats_new)
 
     @cli.action('delete',
                 BuildArgument.BETA_BUILD_LOCALIZATION_ID_RESOURCE_ID,
@@ -98,3 +120,8 @@ def update_beta_build_localization(
             should_print,
             whats_new=whats_new.value if whats_new else None,
         )
+
+    def _get_application_default_locale(self, app_id: ResourceId) -> Locale:
+        beta_app_localizations = self.api_client.apps.list_beta_app_localizations(app_id)
+        default_beta_app_localization = beta_app_localizations[0]
+        return default_beta_app_localization.attributes.locale
diff --git a/src/codemagic/tools/_app_store_connect/actions/publish_action.py b/src/codemagic/tools/_app_store_connect/actions/publish_action.py
index b7bce72a..98db9742 100644
--- a/src/codemagic/tools/_app_store_connect/actions/publish_action.py
+++ b/src/codemagic/tools/_app_store_connect/actions/publish_action.py
@@ -36,7 +36,7 @@ class PublishAction(AbstractBaseAction, metaclass=ABCMeta):
                 PublishArgument.APPLE_ID,
                 PublishArgument.APP_SPECIFIC_PASSWORD,
                 PublishArgument.SUBMIT_TO_TESTFLIGHT,
-                BuildArgument.LOCALE_OPTIONAL_WITH_DEFAULT,
+                BuildArgument.LOCALE_DEFAULT,
                 BuildArgument.WHATS_NEW,
                 PublishArgument.SKIP_PACKAGE_VALIDATION,
                 PublishArgument.MAX_BUILD_PROCESSING_WAIT,
@@ -46,7 +46,7 @@ def publish(self,
                 apple_id: Optional[str] = None,
                 app_specific_password: Optional[Types.AppSpecificPassword] = None,
                 submit_to_testflight: Optional[bool] = None,
-                locale: Locale = BuildArgument.LOCALE_OPTIONAL_WITH_DEFAULT.get_default(),
+                locale: Optional[Locale] = None,
                 whats_new: Optional[Types.WhatsNewArgument] = None,
                 skip_package_validation: Optional[bool] = None,
                 max_build_processing_wait: Optional[Types.MaxBuildProcessingWait] = None) -> None:
@@ -115,7 +115,7 @@ def _publish_application_package(
     def _submit_build_to_testflight(
         self,
         ipa: Ipa,
-        locale: Locale,
+        locale: Optional[Locale],
         whats_new: Optional[Types.WhatsNewArgument],
         max_processing_minutes: int,
     ):
@@ -123,7 +123,7 @@ def _submit_build_to_testflight(
         app = self._get_uploaded_build_application(ipa)
         build, pre_release_version = self._get_uploaded_build(app, ipa)
 
-        if locale and whats_new:
+        if whats_new:
             self.create_beta_build_localization(build.id, locale, whats_new)
 
         self._assert_app_has_testflight_information(app)
diff --git a/src/codemagic/tools/_app_store_connect/arguments.py b/src/codemagic/tools/_app_store_connect/arguments.py
index fab3b40d..7378fc6c 100644
--- a/src/codemagic/tools/_app_store_connect/arguments.py
+++ b/src/codemagic/tools/_app_store_connect/arguments.py
@@ -360,7 +360,7 @@ class BuildArgument(cli.Argument):
         type=ResourceId,
         description='Alphanumeric ID value of the Beta Build Localization',
     )
-    LOCALE = cli.ArgumentProperties(
+    LOCALE_OPTIONAL = cli.ArgumentProperties(
         key='locale',
         flags=('--locale', '-l'),
         type=Locale,
@@ -370,19 +370,18 @@ class BuildArgument(cli.Argument):
             'betabuildlocalizationcreaterequest/data/attributes'
         ),
         argparse_kwargs={
-            'required': True,
+            'required': False,
             'choices': list(Locale),
         },
     )
-    LOCALE_OPTIONAL = LOCALE.duplicate(argparse_kwargs={
-        'required': False,
-        'choices': list(Locale),
-    })
-    LOCALE_OPTIONAL_WITH_DEFAULT = LOCALE.duplicate(argparse_kwargs={
-        'required': False,
-        'choices': list(Locale),
-        'default': Locale('en-US'),
-    })
+    LOCALE_DEFAULT = LOCALE_OPTIONAL.duplicate(
+        description=(
+            'The locale code name for displaying localized "What\'s new" content in TestFlight. '
+            "In case not provided, application's primary locale from test information is used instead. "
+            'Learn more from https://developer.apple.com/documentation/appstoreconnectapi/'
+            'betabuildlocalizationcreaterequest/data/attributes'
+        ),
+    )
     WHATS_NEW = cli.ArgumentProperties(
         key='whats_new',
         flags=('--whats-new', '-n'),


Test patch:
diff --git a/tests/apple/resources/enums/test_resource_enum.py b/tests/apple/resources/enums/test_resource_enum.py
new file mode 100644
index 00000000..d694d3c6
--- /dev/null
+++ b/tests/apple/resources/enums/test_resource_enum.py
@@ -0,0 +1,38 @@
+import pytest
+
+from codemagic.apple.resources.enums import ResourceEnum
+from codemagic.apple.resources.enums import ResourceEnumMeta
+
+
+class MockEnum(ResourceEnum):
+    A = 'A'
+    B = 'B'
+
+
+@pytest.mark.parametrize('enum_value', MockEnum.__members__.keys())
+def test_resource_enum(enum_value):
+    mock_enum = MockEnum(enum_value)
+    assert isinstance(mock_enum, MockEnum)
+    assert mock_enum.value == enum_value
+
+
+@pytest.mark.parametrize('enum_value', ('C', 'D', 'Lorem ipsum'))
+def test_resource_enum_graceful_fallback_on_strings(enum_value):
+    mock_enum = MockEnum(enum_value)
+    assert not isinstance(mock_enum, MockEnum)
+    assert MockEnum.__name__ in mock_enum.__class__.__name__
+    assert mock_enum.value == enum_value
+
+
+@pytest.mark.parametrize('enum_value', ((1, 2), 3.5, None, 4, 5, [], {}))
+def test_resource_enum_graceful_fallback_invalid_inputs(enum_value):
+    with pytest.raises(ValueError):
+        MockEnum(enum_value)
+
+
+@pytest.mark.parametrize('enum_value', ('C', 'D', 'Lorem ipsum'))
+def test_resource_enum_graceful_fallback_disabled(enum_value):
+    ResourceEnumMeta.graceful_fallback = False
+    with pytest.raises(ValueError):
+        MockEnum(enum_value)
+    ResourceEnumMeta.graceful_fallback = True