2023-03-28T18:58:21,766 Created temporary directory: /tmp/pip-ephem-wheel-cache-8_7o7pn7 2023-03-28T18:58:21,772 Created temporary directory: /tmp/pip-build-tracker-qum1lirg 2023-03-28T18:58:21,772 Initialized build tracking at /tmp/pip-build-tracker-qum1lirg 2023-03-28T18:58:21,773 Created build tracker: /tmp/pip-build-tracker-qum1lirg 2023-03-28T18:58:21,773 Entered build tracker: /tmp/pip-build-tracker-qum1lirg 2023-03-28T18:58:21,774 Created temporary directory: /tmp/pip-wheel-t__xeeom 2023-03-28T18:58:21,790 DEPRECATION: --no-binary currently disables reading from the cache of locally built wheels. In the future --no-binary will not influence the wheel cache. pip 23.1 will enforce this behaviour change. A possible replacement is to use the --no-cache-dir option. You can use the flag --use-feature=no-binary-enable-wheel-cache to test the upcoming behaviour. Discussion can be found at https://github.com/pypa/pip/issues/11453 2023-03-28T18:58:21,795 Created temporary directory: /tmp/pip-ephem-wheel-cache-1gszi275 2023-03-28T18:58:21,848 Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple 2023-03-28T18:58:21,855 2 location(s) to search for versions of kcapi: 2023-03-28T18:58:21,855 * https://pypi.org/simple/kcapi/ 2023-03-28T18:58:21,855 * https://www.piwheels.org/simple/kcapi/ 2023-03-28T18:58:21,856 Fetching project page and analyzing links: https://pypi.org/simple/kcapi/ 2023-03-28T18:58:21,857 Getting page https://pypi.org/simple/kcapi/ 2023-03-28T18:58:21,861 Found index url https://pypi.org/simple 2023-03-28T18:58:22,113 Fetched page https://pypi.org/simple/kcapi/ as application/vnd.pypi.simple.v1+json 2023-03-28T18:58:22,152 Skipping link: No binaries permitted for kcapi: https://files.pythonhosted.org/packages/fe/61/d57d94be65a50a1014c2ed202e673e5ac9fbef0f7f7d43914746d535aea8/kcapi-1.0.0-py3-none-any.whl (from https://pypi.org/simple/kcapi/) 2023-03-28T18:58:22,153 Found link https://files.pythonhosted.org/packages/d7/ed/43ecaf3e1d762621a64ca8d0553c9de713253e8ec1292d8f483a2d7c294f/kcapi-1.0.0.tar.gz (from https://pypi.org/simple/kcapi/), version: 1.0.0 2023-03-28T18:58:22,153 Found link https://files.pythonhosted.org/packages/70/9a/2e2289a63d3b6afeae17ff67193b7e8bb48371c9fc606957d447480e383c/kcapi-1.0.2.tar.gz (from https://pypi.org/simple/kcapi/), version: 1.0.2 2023-03-28T18:58:22,154 Found link https://files.pythonhosted.org/packages/2f/80/d814a0fb02fc43a9ec0d6b1ea3e5c3493031681c0ebe0234ce05727deb82/kcapi-1.0.3.tar.gz (from https://pypi.org/simple/kcapi/), version: 1.0.3 2023-03-28T18:58:22,155 Found link https://files.pythonhosted.org/packages/97/e5/767619252ee850a6443fe924a71964d12a0b20c909934e6f6455f5151137/kcapi-1.0.4.tar.gz (from https://pypi.org/simple/kcapi/), version: 1.0.4 2023-03-28T18:58:22,155 Skipping link: No binaries permitted for kcapi: https://files.pythonhosted.org/packages/4f/06/bdd41625a1c13eb4e0b5762ac6276ad4f0dd6a4e0739b13e66f5036681b5/kcapi-1.0.5-py3-none-any.whl (from https://pypi.org/simple/kcapi/) 2023-03-28T18:58:22,156 Found link https://files.pythonhosted.org/packages/f5/cd/19cd710df1e816590591582cb6a27ee0ae948c1e36147ae612959e64bc7d/kcapi-1.0.5.tar.gz (from https://pypi.org/simple/kcapi/), version: 1.0.5 2023-03-28T18:58:22,157 Skipping link: No binaries permitted for kcapi: https://files.pythonhosted.org/packages/bb/40/3c8b8608213310402c01a2184a52b23eaa7f6f3f640416c740a9a8555e91/kcapi-1.0.6-py3-none-any.whl (from https://pypi.org/simple/kcapi/) 2023-03-28T18:58:22,157 Found link https://files.pythonhosted.org/packages/83/fb/ec933f5b3bfc6b5889f0349f45c6d74325e13ac0e6e6be1d646e9bee7be3/kcapi-1.0.6.tar.gz (from https://pypi.org/simple/kcapi/), version: 1.0.6 2023-03-28T18:58:22,158 Skipping link: No binaries permitted for kcapi: https://files.pythonhosted.org/packages/53/a5/1feb11338e349753f4c1d6912e907ba724035ab639a56b4f586e1a4a3d4a/kcapi-1.0.7-py3-none-any.whl (from https://pypi.org/simple/kcapi/) 2023-03-28T18:58:22,158 Found link https://files.pythonhosted.org/packages/28/69/c0df24544d2096c8f2357b9e9f6fb341f7ca9dd063dc589312cd09896b10/kcapi-1.0.7.tar.gz (from https://pypi.org/simple/kcapi/), version: 1.0.7 2023-03-28T18:58:22,159 Skipping link: No binaries permitted for kcapi: https://files.pythonhosted.org/packages/ca/49/80e31ca96f3c04f76515b17f1e5f6471ca27cd4bfbd00623066cabc151d5/kcapi-1.0.9-py3-none-any.whl (from https://pypi.org/simple/kcapi/) 2023-03-28T18:58:22,160 Found link https://files.pythonhosted.org/packages/a7/28/818a144c7c42722d387cea76fdc5fbff26604c74fcb72ad8c5f7ebadf11f/kcapi-1.0.9.tar.gz (from https://pypi.org/simple/kcapi/), version: 1.0.9 2023-03-28T18:58:22,160 Skipping link: No binaries permitted for kcapi: https://files.pythonhosted.org/packages/a4/79/b0aed12fefbe0bff4f0a65578e9cebcbf37ab1d1cc178369a1b3936fe836/kcapi-1.0.10-py3-none-any.whl (from https://pypi.org/simple/kcapi/) 2023-03-28T18:58:22,161 Found link https://files.pythonhosted.org/packages/6a/e5/9fca6bab7c3b146e911dff58031166ba4acffa81a251443b30adb5dd1886/kcapi-1.0.10.tar.gz (from https://pypi.org/simple/kcapi/), version: 1.0.10 2023-03-28T18:58:22,162 Skipping link: No binaries permitted for kcapi: https://files.pythonhosted.org/packages/70/40/57a3bda2f194b908ef614d11517297abbe73ff82d904947b3ffc88ad27d6/kcapi-1.0.11-py3-none-any.whl (from https://pypi.org/simple/kcapi/) 2023-03-28T18:58:22,162 Found link https://files.pythonhosted.org/packages/a9/58/33a02045e2667c55d49f866c0f3477de7703cdfd1c22108755452552e350/kcapi-1.0.11.tar.gz (from https://pypi.org/simple/kcapi/), version: 1.0.11 2023-03-28T18:58:22,163 Skipping link: No binaries permitted for kcapi: https://files.pythonhosted.org/packages/a5/16/8c90471ddbc4e674f05737fc8ad6f4cb03ef2fe88ecc42135c8c3892c184/kcapi-1.0.12-py3-none-any.whl (from https://pypi.org/simple/kcapi/) 2023-03-28T18:58:22,163 Found link https://files.pythonhosted.org/packages/ac/89/b1da9d37864ff1458fda3804dd3c8ef94ab6f812c3b4f9973d37f62015dd/kcapi-1.0.12.tar.gz (from https://pypi.org/simple/kcapi/), version: 1.0.12 2023-03-28T18:58:22,164 Skipping link: No binaries permitted for kcapi: https://files.pythonhosted.org/packages/bb/23/960eab7abc37745ec9a40f95bdf3dcd960f1b69e523468426093fc5bc5f4/kcapi-1.0.13-py3-none-any.whl (from https://pypi.org/simple/kcapi/) 2023-03-28T18:58:22,165 Found link https://files.pythonhosted.org/packages/90/d3/bbc83594cadf9869bb736955a0ceecf5626362faa3f1994bac27d87e4ceb/kcapi-1.0.13.tar.gz (from https://pypi.org/simple/kcapi/), version: 1.0.13 2023-03-28T18:58:22,165 Skipping link: No binaries permitted for kcapi: https://files.pythonhosted.org/packages/2c/d5/2ca6251dd28ff1cb262af6fccc9390ccb4a0745ce8295dc9a7da9214d90b/kcapi-1.0.14-py3-none-any.whl (from https://pypi.org/simple/kcapi/) 2023-03-28T18:58:22,166 Found link https://files.pythonhosted.org/packages/2b/27/73d30f5f344e55a16fcd75a5f733cd3542af70000ee1774186903dcb97a7/kcapi-1.0.14.tar.gz (from https://pypi.org/simple/kcapi/), version: 1.0.14 2023-03-28T18:58:22,166 Skipping link: No binaries permitted for kcapi: https://files.pythonhosted.org/packages/4c/a3/0bcad506f648f0b36e295dbd656b23adf5e2a323488bf96ca5813152f601/kcapi-1.0.15-py3-none-any.whl (from https://pypi.org/simple/kcapi/) 2023-03-28T18:58:22,167 Found link https://files.pythonhosted.org/packages/a0/59/a921380fb88a77db58379f620b0b00671fbd76fa8c8a70340b7fc40edb82/kcapi-1.0.15.tar.gz (from https://pypi.org/simple/kcapi/), version: 1.0.15 2023-03-28T18:58:22,168 Skipping link: No binaries permitted for kcapi: https://files.pythonhosted.org/packages/ef/d0/d179a2c27b3f4774af71ccbc24788d643b830cbf427383974f2c78e5d3fd/kcapi-1.0.16-py3-none-any.whl (from https://pypi.org/simple/kcapi/) 2023-03-28T18:58:22,168 Found link https://files.pythonhosted.org/packages/46/84/ab28c64d473dd65dec14d06f7d7e205f26e448cc97d65319e2159998b6be/kcapi-1.0.16.tar.gz (from https://pypi.org/simple/kcapi/), version: 1.0.16 2023-03-28T18:58:22,169 Skipping link: No binaries permitted for kcapi: https://files.pythonhosted.org/packages/3a/73/63ad5e21ffc77dd9885b3e5d11f693c6247ef20e5acd345850959b6d00d8/kcapi-1.0.17-py3-none-any.whl (from https://pypi.org/simple/kcapi/) 2023-03-28T18:58:22,169 Found link https://files.pythonhosted.org/packages/eb/34/4b410431eb9e2925fbee8a6e8a00a9b3cf0ca209273ad6ba34f19c406934/kcapi-1.0.17.tar.gz (from https://pypi.org/simple/kcapi/), version: 1.0.17 2023-03-28T18:58:22,170 Skipping link: No binaries permitted for kcapi: https://files.pythonhosted.org/packages/3c/22/9dc68a9cd6f3de8e9ba253d958f66710fd9f9c94a41dc77c59479015a97c/kcapi-1.0.18-py3-none-any.whl (from https://pypi.org/simple/kcapi/) 2023-03-28T18:58:22,171 Found link https://files.pythonhosted.org/packages/96/32/22e6b4cbf63d0839a3bb369b8b9e42be1967c44370db7e3471a72443717d/kcapi-1.0.18.tar.gz (from https://pypi.org/simple/kcapi/), version: 1.0.18 2023-03-28T18:58:22,171 Skipping link: No binaries permitted for kcapi: https://files.pythonhosted.org/packages/09/06/10fe3291d45e784f9bc9359c2862642badc8bcf3f2c20a55148021093d5f/kcapi-1.0.19-py3-none-any.whl (from https://pypi.org/simple/kcapi/) 2023-03-28T18:58:22,172 Found link https://files.pythonhosted.org/packages/42/e4/8c2e1dc05838ad92a54cdd52dccd74aa345cac2e5d4ab5ad62da8f5a94cd/kcapi-1.0.19.tar.gz (from https://pypi.org/simple/kcapi/), version: 1.0.19 2023-03-28T18:58:22,172 Skipping link: No binaries permitted for kcapi: https://files.pythonhosted.org/packages/18/07/a94a730319f58c906181d295e9e0ed7cc582100379cef9238d938734e281/kcapi-1.0.20-py3-none-any.whl (from https://pypi.org/simple/kcapi/) 2023-03-28T18:58:22,173 Found link https://files.pythonhosted.org/packages/d0/9d/e2aa53c33acc556e6425e13dc15bf8a0aeffafd455844bf6210546a2a04b/kcapi-1.0.20.tar.gz (from https://pypi.org/simple/kcapi/), version: 1.0.20 2023-03-28T18:58:22,174 Skipping link: No binaries permitted for kcapi: https://files.pythonhosted.org/packages/eb/52/5e7c5d8e16fd9f2e3abcfd1c724d9c478a0758354261810877b3122370fe/kcapi-1.0.21-py3-none-any.whl (from https://pypi.org/simple/kcapi/) 2023-03-28T18:58:22,174 Found link https://files.pythonhosted.org/packages/8c/04/fe04a01f92e1061db4f8c42a1a49f5c78ac2fa2f5ea406b87abf3b5b5a96/kcapi-1.0.21.tar.gz (from https://pypi.org/simple/kcapi/), version: 1.0.21 2023-03-28T18:58:22,175 Skipping link: No binaries permitted for kcapi: https://files.pythonhosted.org/packages/8f/eb/8b160cd1568abbd3d52d64234e1799a85153c908e22f8a6f2fbf3d731906/kcapi-1.0.22-py3-none-any.whl (from https://pypi.org/simple/kcapi/) 2023-03-28T18:58:22,175 Found link https://files.pythonhosted.org/packages/d6/ff/4a3930939ddf3234b39b7c8490b83e224665f76501e6b005bc1f83dfe493/kcapi-1.0.22.tar.gz (from https://pypi.org/simple/kcapi/), version: 1.0.22 2023-03-28T18:58:22,176 Skipping link: No binaries permitted for kcapi: https://files.pythonhosted.org/packages/1f/20/c3824e3d4a204d619b2e034e72bd72a319aadd0fd5ac418a47c10d270d0c/kcapi-1.0.23-py3-none-any.whl (from https://pypi.org/simple/kcapi/) 2023-03-28T18:58:22,177 Found link https://files.pythonhosted.org/packages/dd/9e/6d444e67a64a409c129a27f408ef63100908f792881120519f93bfe96703/kcapi-1.0.23.tar.gz (from https://pypi.org/simple/kcapi/), version: 1.0.23 2023-03-28T18:58:22,177 Skipping link: No binaries permitted for kcapi: https://files.pythonhosted.org/packages/14/fe/72caff19b79147c782f510fee43320f511cfdaa67414c7cef8ec93f1b1a1/kcapi-1.0.24-py3-none-any.whl (from https://pypi.org/simple/kcapi/) 2023-03-28T18:58:22,178 Found link https://files.pythonhosted.org/packages/0f/03/9d049da100ed1c9591899be2bece3d91d93fe0e35559aabb45ca2f85d4da/kcapi-1.0.24.tar.gz (from https://pypi.org/simple/kcapi/), version: 1.0.24 2023-03-28T18:58:22,178 Skipping link: No binaries permitted for kcapi: https://files.pythonhosted.org/packages/fa/da/7189711585ade0c749f3c29b3d6fc075a43a9ae4b92f2045a7e0b11e105f/kcapi-1.0.25-py3-none-any.whl (from https://pypi.org/simple/kcapi/) 2023-03-28T18:58:22,179 Found link https://files.pythonhosted.org/packages/e1/ca/a4cfd4e60124f494bbf64a914cb4a9d6510dbbfdd95cb8d93d5cd3c16d7f/kcapi-1.0.25.tar.gz (from https://pypi.org/simple/kcapi/), version: 1.0.25 2023-03-28T18:58:22,180 Skipping link: No binaries permitted for kcapi: https://files.pythonhosted.org/packages/f3/5b/0a370b20df0b5e93b8a38b28ba868995f041664ad3b7280528e9051709d0/kcapi-1.0.26-py3-none-any.whl (from https://pypi.org/simple/kcapi/) 2023-03-28T18:58:22,180 Found link https://files.pythonhosted.org/packages/fb/7f/aca42d0eccd93b3e36b8d72de58082e486cf69844724b29703d7e7daffa5/kcapi-1.0.26.tar.gz (from https://pypi.org/simple/kcapi/), version: 1.0.26 2023-03-28T18:58:22,181 Skipping link: No binaries permitted for kcapi: https://files.pythonhosted.org/packages/88/b5/46621cd83c72ea1ad21a3a5a223994a64af96989967d964fe5ff036e549a/kcapi-1.0.27-py3-none-any.whl (from https://pypi.org/simple/kcapi/) 2023-03-28T18:58:22,182 Found link https://files.pythonhosted.org/packages/8d/0d/8654b5713e04420e3b5142894084eedeb53e5c258343801d34659f8fd690/kcapi-1.0.27.tar.gz (from https://pypi.org/simple/kcapi/), version: 1.0.27 2023-03-28T18:58:22,182 Skipping link: No binaries permitted for kcapi: https://files.pythonhosted.org/packages/1a/18/aad9259e541e28016fadb65707ca786a7fd6d56cdaf8c83d4ac845b0ecc2/kcapi-1.0.28-py3-none-any.whl (from https://pypi.org/simple/kcapi/) 2023-03-28T18:58:22,183 Found link https://files.pythonhosted.org/packages/15/f9/624eac07bb7d49bbc7d47598f3ef8c06334f4e570b93b6a9c25dd3b6d906/kcapi-1.0.28.tar.gz (from https://pypi.org/simple/kcapi/), version: 1.0.28 2023-03-28T18:58:22,183 Skipping link: No binaries permitted for kcapi: https://files.pythonhosted.org/packages/12/7e/fa4af57020e242ecd4d5c4f928c5b8405f77543cb393b4dc83bb00e6da75/kcapi-1.0.29-py3-none-any.whl (from https://pypi.org/simple/kcapi/) 2023-03-28T18:58:22,184 Found link https://files.pythonhosted.org/packages/6e/de/c7b841d3d8a0bc670e0f9d84725bb6382a5e9feea6c8e557001bae7f29d7/kcapi-1.0.29.tar.gz (from https://pypi.org/simple/kcapi/), version: 1.0.29 2023-03-28T18:58:22,184 Skipping link: No binaries permitted for kcapi: https://files.pythonhosted.org/packages/4b/ce/324f74f48f75fa15652240588fabeb91d9becaa5bcb6a0ee608a244a9b7f/kcapi-1.0.30-py3-none-any.whl (from https://pypi.org/simple/kcapi/) 2023-03-28T18:58:22,185 Found link https://files.pythonhosted.org/packages/37/89/662e07532293aa575e543298097bad2db86f6651f7a1bb6f0ef8304daaa1/kcapi-1.0.30.tar.gz (from https://pypi.org/simple/kcapi/), version: 1.0.30 2023-03-28T18:58:22,186 Skipping link: No binaries permitted for kcapi: https://files.pythonhosted.org/packages/c2/bd/15bfa3b4afe35c98135463b772d6591ad1414119bc1e362048e23342f7b6/kcapi-1.0.31-py3-none-any.whl (from https://pypi.org/simple/kcapi/) 2023-03-28T18:58:22,186 Found link https://files.pythonhosted.org/packages/a0/2a/38ab39c6053d4cad65d3515630d648db4ba734a8f70cdea2b332f9b8c081/kcapi-1.0.31.tar.gz (from https://pypi.org/simple/kcapi/), version: 1.0.31 2023-03-28T18:58:22,187 Skipping link: No binaries permitted for kcapi: https://files.pythonhosted.org/packages/57/21/78a15f9be5919e4e80a0796034c04affef4251d0856a3c75fe49e513b088/kcapi-1.0.32-py3-none-any.whl (from https://pypi.org/simple/kcapi/) 2023-03-28T18:58:22,187 Found link https://files.pythonhosted.org/packages/07/7b/ea76757e44b69d8a7404a2451d450192e5ca44c8736db4223058594fe304/kcapi-1.0.32.tar.gz (from https://pypi.org/simple/kcapi/), version: 1.0.32 2023-03-28T18:58:22,188 Skipping link: No binaries permitted for kcapi: https://files.pythonhosted.org/packages/c5/c4/397623892ddafbb444ff2ab3628ddb6ad07b75e7dffe466c771a5130d4d6/kcapi-1.0.33-py3-none-any.whl (from https://pypi.org/simple/kcapi/) 2023-03-28T18:58:22,189 Found link https://files.pythonhosted.org/packages/21/ac/021fd9acf50c6626f186a495c9c0a534667db5d1b91c0f35b79edc385a25/kcapi-1.0.33.tar.gz (from https://pypi.org/simple/kcapi/), version: 1.0.33 2023-03-28T18:58:22,189 Skipping link: No binaries permitted for kcapi: https://files.pythonhosted.org/packages/23/d1/7b0319fe33e2bf44533d7b2a707d177e661c2d4effba255149134aaca5fe/kcapi-1.0.34-py3-none-any.whl (from https://pypi.org/simple/kcapi/) 2023-03-28T18:58:22,190 Found link https://files.pythonhosted.org/packages/b0/63/a27e3935beabcea1bcb2a0d270bf9dac48af67e58c2e8b7247159755048c/kcapi-1.0.34.tar.gz (from https://pypi.org/simple/kcapi/), version: 1.0.34 2023-03-28T18:58:22,190 Skipping link: No binaries permitted for kcapi: https://files.pythonhosted.org/packages/ee/1d/d59839b3fb8020655b9b9acb6e7aa8d3b12223cc545dec14f6d75450309f/kcapi-1.0.35-py3-none-any.whl (from https://pypi.org/simple/kcapi/) 2023-03-28T18:58:22,191 Found link https://files.pythonhosted.org/packages/2c/be/9e294775a4e9328d65fa3c2674d225464ca323e6415f01d38c228a0969e0/kcapi-1.0.35.tar.gz (from https://pypi.org/simple/kcapi/), version: 1.0.35 2023-03-28T18:58:22,192 Skipping link: No binaries permitted for kcapi: https://files.pythonhosted.org/packages/08/46/64a9387fb58fb52d9dad0b0ad8e83704d11bea4ba6183a5135b7d30d0709/kcapi-1.0.36-py3-none-any.whl (from https://pypi.org/simple/kcapi/) 2023-03-28T18:58:22,192 Found link https://files.pythonhosted.org/packages/e3/6c/ece8e7bb3b0f596a457d80331eeec8da672000dd353b5bff5cefdbdee468/kcapi-1.0.36.tar.gz (from https://pypi.org/simple/kcapi/), version: 1.0.36 2023-03-28T18:58:22,193 Skipping link: No binaries permitted for kcapi: https://files.pythonhosted.org/packages/15/5f/914b0d9f7fec361ac75566bd8878b4921e7f551ca81d8c09884c6cadf839/kcapi-1.0.37-py3-none-any.whl (from https://pypi.org/simple/kcapi/) 2023-03-28T18:58:22,193 Found link https://files.pythonhosted.org/packages/14/4d/e4e25a73e39ada4512c9bfa61a0ed8677ab70424a4313f9a2ebe9aedeccc/kcapi-1.0.37.tar.gz (from https://pypi.org/simple/kcapi/), version: 1.0.37 2023-03-28T18:58:22,194 Skipping link: No binaries permitted for kcapi: https://files.pythonhosted.org/packages/b7/88/08e2f23cb1e25c3ba49d6dae731e0be58791cc56fd171f4ecf2364ef81ff/kcapi-1.0.38-py3-none-any.whl (from https://pypi.org/simple/kcapi/) 2023-03-28T18:58:22,195 Found link https://files.pythonhosted.org/packages/9a/e8/876322d7f03424608f0b73cd01d72dacc217e7ed69269800798dbd4dd5f8/kcapi-1.0.38.tar.gz (from https://pypi.org/simple/kcapi/), version: 1.0.38 2023-03-28T18:58:22,195 Skipping link: No binaries permitted for kcapi: https://files.pythonhosted.org/packages/64/52/ea84f1f6dd5a74ffeb60bb0824945aff317b3369a0c5cb64ff2840be6432/kcapi-1.0.39-py3-none-any.whl (from https://pypi.org/simple/kcapi/) 2023-03-28T18:58:22,196 Found link https://files.pythonhosted.org/packages/29/d7/a4f3d9455a8520922edf4f38c632869956308c4e13103d2e6238b064070b/kcapi-1.0.39.tar.gz (from https://pypi.org/simple/kcapi/), version: 1.0.39 2023-03-28T18:58:22,196 Skipping link: No binaries permitted for kcapi: https://files.pythonhosted.org/packages/72/f9/3670972b7cdaed14d7803f8adb97652dc858120d05caa5fa76904e5c7314/kcapi-1.0.40-py3-none-any.whl (from https://pypi.org/simple/kcapi/) 2023-03-28T18:58:22,197 Found link https://files.pythonhosted.org/packages/d9/a9/6a2c0777b85007557cdc2e60593508ce81b09b212be411a4d508770d84ff/kcapi-1.0.40.tar.gz (from https://pypi.org/simple/kcapi/), version: 1.0.40 2023-03-28T18:58:22,198 Skipping link: No binaries permitted for kcapi: https://files.pythonhosted.org/packages/87/6c/aa3843af9c3fad57b81030036e6a0922f405eee5631c698cdf57ef2e715d/kcapi-1.1.0-py3-none-any.whl (from https://pypi.org/simple/kcapi/) (requires-python:>=3.7) 2023-03-28T18:58:22,199 Found link https://files.pythonhosted.org/packages/a0/7b/835a85b6268ae6f56b5a8fe1f6c88e6a27ef7fd4d150d43c0a3d49c42a60/kcapi-1.1.0.tar.gz (from https://pypi.org/simple/kcapi/) (requires-python:>=3.7), version: 1.1.0 2023-03-28T18:58:22,200 Skipping link: No binaries permitted for kcapi: https://files.pythonhosted.org/packages/30/c6/9d8066e8fd22232a72b0d56b7d24872a6a725a7e877e317dae5db53634d0/kcapi-1.1.1-py3-none-any.whl (from https://pypi.org/simple/kcapi/) (requires-python:>=3.7) 2023-03-28T18:58:22,201 Found link https://files.pythonhosted.org/packages/eb/9e/32217926fbc7593b45f3f1e72da114e93d4e0c09085fba916c1f5e15ff17/kcapi-1.1.1.tar.gz (from https://pypi.org/simple/kcapi/) (requires-python:>=3.7), version: 1.1.1 2023-03-28T18:58:22,202 Skipping link: No binaries permitted for kcapi: https://files.pythonhosted.org/packages/ad/5b/e6c2ea3cd49c2a4fc737dfbe6879683f1292d4597771fa2cd8f8e0c3b16b/kcapi-1.1.2-py3-none-any.whl (from https://pypi.org/simple/kcapi/) (requires-python:>=3.7) 2023-03-28T18:58:22,203 Found link https://files.pythonhosted.org/packages/3a/5c/6e2c1bc7a1f8491defe6f325cf28756f5e13e327cc21d0d1079e226a149d/kcapi-1.1.2.tar.gz (from https://pypi.org/simple/kcapi/) (requires-python:>=3.7), version: 1.1.2 2023-03-28T18:58:22,204 Fetching project page and analyzing links: https://www.piwheels.org/simple/kcapi/ 2023-03-28T18:58:22,205 Getting page https://www.piwheels.org/simple/kcapi/ 2023-03-28T18:58:22,207 Found index url https://www.piwheels.org/simple 2023-03-28T18:58:22,425 Fetched page https://www.piwheels.org/simple/kcapi/ as text/html 2023-03-28T18:58:22,456 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.1.1-py3-none-any.whl#sha256=c7b20c8e05ba72b52f5d01568ecdae532c5817a48cda4c2608718098e698a70f (from https://www.piwheels.org/simple/kcapi/) (requires-python:>=3.7) 2023-03-28T18:58:22,457 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.1.0-py3-none-any.whl#sha256=ccde2d8b4b76f64029d43b382dcd01133cff2dd5850d869b6f3c6d02e348fd92 (from https://www.piwheels.org/simple/kcapi/) (requires-python:>=3.7) 2023-03-28T18:58:22,457 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.0.40-py3-none-any.whl#sha256=c49e51fc581fde48bf05df339d7c24df132c994ba4e52e2f910a7e16844e4fd3 (from https://www.piwheels.org/simple/kcapi/) 2023-03-28T18:58:22,458 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.0.39-py3-none-any.whl#sha256=faf227e9bfcdc2cc683651d8ea29d01186b07f5a30f91d2785ceb2c3032cde18 (from https://www.piwheels.org/simple/kcapi/) 2023-03-28T18:58:22,458 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.0.38-py3-none-any.whl#sha256=cf2ce95e372d8c87da8890e3f3d226499e8b7bf51f65bac2e769ad09dc2abaae (from https://www.piwheels.org/simple/kcapi/) 2023-03-28T18:58:22,459 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.0.37-py3-none-any.whl#sha256=f0de139174bc9ca61685f2fc269b8bf0c472a16bb18ade9f92f51b10a14cce00 (from https://www.piwheels.org/simple/kcapi/) 2023-03-28T18:58:22,459 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.0.36-py3-none-any.whl#sha256=837f64f6357692a342719775e587396e8c515b8b49f2017906bdd954b9d396c0 (from https://www.piwheels.org/simple/kcapi/) 2023-03-28T18:58:22,460 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.0.35-py3-none-any.whl#sha256=7ef763450c19a60b4d674e441038ee117ccd38bb62af53a072a7c40a060795f7 (from https://www.piwheels.org/simple/kcapi/) 2023-03-28T18:58:22,460 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.0.34-py3-none-any.whl#sha256=d3b9c02a70263a59937e7a90d3d27a9a152564f4b569a5095146f3463b8cd6ab (from https://www.piwheels.org/simple/kcapi/) 2023-03-28T18:58:22,461 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.0.33-py3-none-any.whl#sha256=5758c508fa5471b469347095d1949051759984b8251c843aa7c9721c1ee3e7ee (from https://www.piwheels.org/simple/kcapi/) 2023-03-28T18:58:22,461 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.0.32-py3-none-any.whl#sha256=480c46e7cf86e1c84cf6861eb9c65032e139deac04a6d43d1747618859b72d5d (from https://www.piwheels.org/simple/kcapi/) 2023-03-28T18:58:22,462 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.0.31-py3-none-any.whl#sha256=373484189eafeef555043024d2927e40ea01f4e5ce0278bdd0e739f7a7b75ed1 (from https://www.piwheels.org/simple/kcapi/) 2023-03-28T18:58:22,462 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.0.30-py3-none-any.whl#sha256=84da506963bc9b27d61c715d68f47959add70294511af26db623efc0575f73aa (from https://www.piwheels.org/simple/kcapi/) 2023-03-28T18:58:22,463 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.0.29-py3-none-any.whl#sha256=045e658b3cca53934fa42e1371dec9042d74ee234f212adf61730bf587115269 (from https://www.piwheels.org/simple/kcapi/) 2023-03-28T18:58:22,463 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.0.28-py3-none-any.whl#sha256=94c95ae7af64f4ed14d735660771890f99f9437f528c10c92c632fb065486d3f (from https://www.piwheels.org/simple/kcapi/) 2023-03-28T18:58:22,464 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.0.27-py3-none-any.whl#sha256=e4f0c383acb709bcc77462afcbecc25e70416f8d1a46c21d74b49b5ae1d09eeb (from https://www.piwheels.org/simple/kcapi/) 2023-03-28T18:58:22,464 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.0.26-py3-none-any.whl#sha256=0ce0d022d288f2aee98dea3c05684fc0f1a82693329c6352f2af27b25aabf393 (from https://www.piwheels.org/simple/kcapi/) 2023-03-28T18:58:22,465 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.0.25-py3-none-any.whl#sha256=85507540050db30a723e1c9465cb6e68de12237892406b93bfdc5db38826f037 (from https://www.piwheels.org/simple/kcapi/) 2023-03-28T18:58:22,465 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.0.24-py3-none-any.whl#sha256=b96b8194724fddbf8f2a12aa374818110d735d9b55f398c93f12371a7aa6d3a9 (from https://www.piwheels.org/simple/kcapi/) 2023-03-28T18:58:22,466 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.0.23-py3-none-any.whl#sha256=b2facc6f505b65ba82e780b575df898caf88230e0a73f441e29cca70551bde11 (from https://www.piwheels.org/simple/kcapi/) 2023-03-28T18:58:22,466 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.0.22-py3-none-any.whl#sha256=d410c086052699aa7f9358a776ac61a2ebfca82e7db561de0ce6c49a103d674a (from https://www.piwheels.org/simple/kcapi/) 2023-03-28T18:58:22,467 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.0.21-py3-none-any.whl#sha256=12b53868de02ea95cfa6a667a5e66060c4bf818fe74b67a19c8ed98495b8ceef (from https://www.piwheels.org/simple/kcapi/) 2023-03-28T18:58:22,467 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.0.20-py3-none-any.whl#sha256=c6384e994b517eece705456ee590c9e003607c9195db48e6522e366aab600ee3 (from https://www.piwheels.org/simple/kcapi/) 2023-03-28T18:58:22,468 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.0.19-py3-none-any.whl#sha256=436c3d81572a2d1aa927228b69781358819c730c93a6c3126139b7a848f03e9c (from https://www.piwheels.org/simple/kcapi/) 2023-03-28T18:58:22,468 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.0.18-py3-none-any.whl#sha256=cd6968d1046f446d0f4a2efcc389997a1345e9ab7c4a7d0b2de4b9f8bc375bc4 (from https://www.piwheels.org/simple/kcapi/) 2023-03-28T18:58:22,469 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.0.17-py3-none-any.whl#sha256=78c22022a5f23c2584f53bbcf2a83b3915a4e08ec5d2be68fb44d36e24c0ecf9 (from https://www.piwheels.org/simple/kcapi/) 2023-03-28T18:58:22,469 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.0.16-py3-none-any.whl#sha256=b6fce6163707e7b9cad69fd658ed5548381c21ed0507acff69c6e5bc79bbead6 (from https://www.piwheels.org/simple/kcapi/) 2023-03-28T18:58:22,470 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.0.15-py3-none-any.whl#sha256=25771422c3cdfb33d470ae6917ae34f934ee2747477af3b496734c058ab1b013 (from https://www.piwheels.org/simple/kcapi/) 2023-03-28T18:58:22,470 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.0.14-py3-none-any.whl#sha256=844b45ed55d3a1a9af6e9bf84ee4ab971bbd65ff58e9adbb5d94a9e52ad36dde (from https://www.piwheels.org/simple/kcapi/) 2023-03-28T18:58:22,471 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.0.13-py3-none-any.whl#sha256=93ca2e1acc8e050988c72787488ab710ef009337cde5f929fa52e14e5c1d115d (from https://www.piwheels.org/simple/kcapi/) 2023-03-28T18:58:22,471 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.0.12-py3-none-any.whl#sha256=e8fb9263ab405a6ed0042f0017b3ce4b6ef6fb9d18aa5d9a3697469d2955fd23 (from https://www.piwheels.org/simple/kcapi/) 2023-03-28T18:58:22,472 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.0.11-py3-none-any.whl#sha256=97b7813ee46b5843eba2c8feb3e1bb961024f8d81c51db81c42cd9b6e1eb0afe (from https://www.piwheels.org/simple/kcapi/) 2023-03-28T18:58:22,473 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.0.10-py3-none-any.whl#sha256=b4ddd372ae9ff07c606c2c1bc4ea1310cc7e1c4b5aac772dacf907e4902a1e5d (from https://www.piwheels.org/simple/kcapi/) 2023-03-28T18:58:22,473 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.0.9-py3-none-any.whl#sha256=1159266c8378d1c8a7f6dce17b504a4734d04cffaccc54c683f6dbc96c7aa621 (from https://www.piwheels.org/simple/kcapi/) 2023-03-28T18:58:22,474 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.0.7-py3-none-any.whl#sha256=fb60e2bf658a94ff0068d495636120deb6f55c8ad1f74c5f9cf29663d6281356 (from https://www.piwheels.org/simple/kcapi/) 2023-03-28T18:58:22,474 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.0.6-py3-none-any.whl#sha256=3a9df1b4f5d479048716a982a35f82796bba575cc00e8184911f3e15e1ffa96b (from https://www.piwheels.org/simple/kcapi/) 2023-03-28T18:58:22,475 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.0.5-py3-none-any.whl#sha256=e1087c1b31b55917e9757afc45b1796d85d26e5d4c7c8a58e434cbf30d496786 (from https://www.piwheels.org/simple/kcapi/) 2023-03-28T18:58:22,475 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.0.4-py3-none-any.whl#sha256=2631ce086b30abcfed2a4c5e54731376e4741ad7bf81d7aac31c8b990d828729 (from https://www.piwheels.org/simple/kcapi/) 2023-03-28T18:58:22,476 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.0.3-py3-none-any.whl#sha256=943d407d9c85f2c871447d476cfd95498ca2646921bb11f6ed0bcc24e9a6ad1a (from https://www.piwheels.org/simple/kcapi/) 2023-03-28T18:58:22,476 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.0.2-py3-none-any.whl#sha256=70ff41a5daf726b308976eb09038d43a9e228b3184675c5bca4cb7333fc580c1 (from https://www.piwheels.org/simple/kcapi/) 2023-03-28T18:58:22,477 Skipping link: No binaries permitted for kcapi: https://www.piwheels.org/simple/kcapi/kcapi-1.0.0-py3-none-any.whl#sha256=be845358aac1a2757ac5e334f6a284c3eeaf67bb6fbf9eae956b584e9f158d00 (from https://www.piwheels.org/simple/kcapi/) 2023-03-28T18:58:22,477 Skipping link: not a file: https://www.piwheels.org/simple/kcapi/ 2023-03-28T18:58:22,478 Skipping link: not a file: https://pypi.org/simple/kcapi/ 2023-03-28T18:58:22,525 Given no hashes to check 1 links for project 'kcapi': discarding no candidates 2023-03-28T18:58:22,555 Collecting kcapi==1.1.2 2023-03-28T18:58:22,560 Created temporary directory: /tmp/pip-unpack-ktpcvlyu 2023-03-28T18:58:22,786 Downloading kcapi-1.1.2.tar.gz (31 kB) 2023-03-28T18:58:23,005 Added kcapi==1.1.2 from https://files.pythonhosted.org/packages/3a/5c/6e2c1bc7a1f8491defe6f325cf28756f5e13e327cc21d0d1079e226a149d/kcapi-1.1.2.tar.gz to build tracker '/tmp/pip-build-tracker-qum1lirg' 2023-03-28T18:58:23,014 Created temporary directory: /tmp/pip-build-env-x3jrkter 2023-03-28T18:58:23,035 Installing build dependencies: started 2023-03-28T18:58:23,037 Running command pip subprocess to install build dependencies 2023-03-28T18:58:25,791 Using pip 23.0.1 from /usr/local/lib/python3.7/dist-packages/pip (python 3.7) 2023-03-28T18:58:27,022 DEPRECATION: --no-binary currently disables reading from the cache of locally built wheels. In the future --no-binary will not influence the wheel cache. pip 23.1 will enforce this behaviour change. A possible replacement is to use the --no-cache-dir option. You can use the flag --use-feature=no-binary-enable-wheel-cache to test the upcoming behaviour. Discussion can be found at https://github.com/pypa/pip/issues/11453 2023-03-28T18:58:27,079 Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple 2023-03-28T18:58:30,965 Collecting setuptools>=61.0 2023-03-28T18:58:31,243 Using cached https://www.piwheels.org/simple/setuptools/setuptools-67.6.1-py3-none-any.whl (1.1 MB) 2023-03-28T18:58:36,384 Installing collected packages: setuptools 2023-03-28T18:58:40,640 Successfully installed setuptools-67.6.1 2023-03-28T18:58:41,582 Installing build dependencies: finished with status 'done' 2023-03-28T18:58:41,594 Getting requirements to build wheel: started 2023-03-28T18:58:41,596 Running command Getting requirements to build wheel 2023-03-28T18:58:42,865 /tmp/pip-build-env-x3jrkter/overlay/lib/python3.7/site-packages/setuptools/config/_apply_pyprojecttoml.py:103: _WouldIgnoreField: 'readme' defined outside of `pyproject.toml` would be ignored. 2023-03-28T18:58:42,866 !! 2023-03-28T18:58:42,867 ########################################################################## 2023-03-28T18:58:42,867 # configuration would be ignored/result in error due to `pyproject.toml` # 2023-03-28T18:58:42,868 ########################################################################## 2023-03-28T18:58:42,869 The following seems to be defined outside of `pyproject.toml`: 2023-03-28T18:58:42,870 `readme = '# Keycloak API\n\nPython module to automate Keycloak or Red Hat Single Sign-On (RHSSO) configuration.\n\n## How To Install\n\n```sh\npip install kcapi\n```\n\n\n## Testing\n\nTo run the test you would need a Keycloak instance, you can run one locally or in the [cloud]( https://developers.redhat.com/developer-sandbox/get-started) then you just have to follow this steps: \n\n```shell script\npython3.10 -m venv .venv\nsource .venv/bin/activate\npip install requests\n\n# Setup SSO server - go to https://developers.redhat.com/developer-sandbox/get-started,\n# launch sandbox environment, +Add, select some "Red Hat Single Sign-On..." template.\nexport KC_USER=admin\nexport KC_PASSWORD=admin_password\nexport KC_REALM=myrealm # do not use master realm, it cannot be removed\nexport KC_ENDPOINT=https://my-first-sso-me-me-dev.apps.sandbox.x8i5.p1.openshiftapps.com\n\npython -m unittest\n```\n\n\n## API\n\n### OpenID\n\nThis class takes care of OpenID login using [password owner credentials](https://datatracker.ietf.org/doc/html/rfc6749#section-1.3.3) flow.\n\n\n#### Constructor\n\n```python\nfrom rhsso import OpenID\n\noid_client = OpenID({\n "client_id": "admin-cli",\n "username": USER,\n "password": PASSWORD,\n "grant_type":"password",\n "realm" : "master"\n }, endpoint)\n```\n\n- **client_id**: Client Identifier in Keycloak.\n- **username**: Login username for the Realm.\n- **password**: Login password for the Realm.\n- **grant_type**: The grant type you want to use (usually ``password``).\n- **endpoint**: A Keycloak or RHSSO URL endpoint, something like: ``https://my_keycloak.com``. \n\n\n#### Methods\n\n##### getToken\n\nThis will initiate a session with the Keycloak server and will return a OpenID token back.\n\n```python\noid_client.getToken() #glTeDLlmmpLYoAAUMcFQqNOMjw5dA\n```\n\n##### createAdminClient\n\nThis static method should be used in order to access the master Realm in Keycloak.\n\n```python\n oidc = OpenID.createAdminClient(self.USER, self.PASSWORD)\n oidc.getToken() #glTeDLlmmpLYoAAUMcFQqNOMjw5dA\n```\n### Keycloak\n\nThis class builds all the Keycloak configuration REST resources by using REST conventions we can target the majority of Keycloak services.\n\n#### Constructor\n\n```Python\nkc = Keycloak(token, self.ENDPOINT)\n```\n\nThe constructor takes two parameters:\n\n- **token**: A token with enough priviledge to perform the desired operation.\n- **endpoint**: A Keycloak or RHSSO URL endpoint, something like: ``https://my_keycloak.com``. \n\n\n#### Methods\n\n#### build\nThis methods build a REST client (capabilities detailed below) targeting a specific Keycloak REST resource.\n\n```python\ngroups = kc.build(\'groups\', \'my_realm\')\n\n# Create a group called DC\nstate = groups.create({"name": "DC"}).isOk()\n\n```\n> In this example we build the \'groups\' API for ``my_realm`` Realm.\n\n##### Supported Resources\n\nHere is a quick list of supported resources:\n\n- **users**: [users API](https://access.redhat.com/webassets/avalon/d/red-hat-single-sign-on/version-7.0.0/restapi/#_create_a_new_user).\n- **clients**: [client API](https://access.redhat.com/webassets/avalon/d/red-hat-single-sign-on/version-7.0.0/restapi/#_create_a_new_client). \n- **groups**: [groups API](https://access.redhat.com/documentation/en-us/red_hat_single_sign-on/7.0/html/server_administration_guide/groups).\n- **roles**: [roles API](https://access.redhat.com/webassets/avalon/d/red-hat-single-sign-on/version-7.0.0/restapi/#_create_a_new_role_for_the_realm_or_client_2)\n- **identity-provider**: [identity provider API](https://access.redhat.com/webassets/avalon/d/red-hat-single-sign-on/version-7.0.0/restapi/#_get_identity_providers)\n\n\n> As long as you find a REST endpoint that follow the standard you can use this method to build a client around it, an example of this is the non well documented ``components`` endpoint.\n\n- **components**: This API allows you configure things like [user federation](https://access.redhat.com/documentation/en-us/red_hat_single_sign-on/7.0/html/server_administration_guide/user-storage-federation) or [Realm keys](https://access.redhat.com/documentation/en-us/red_hat_single_sign-on/7.2/html/server_administration_guide/admin_permissions#realm_keys).\n\n- **authentication**: Provide access to built-in and/or custom authentication flows.\n
\n\n#### admin\nSimilar to the ``build`` method but the client points to the ``master`` realm, allowing us operation such as realm creation.\n\n```python\n main_realm = kc.admin()\n\n # Creates a realm called my_realm\n main_realm.create({"enabled": "true", "id": my_realm, "realm": my_realm})\n```\n\n\n### REST API\n\nWhen you use the ``build`` or ``admin`` methods you will get back a **REST** class pointing to the Keycloak resource, keep in mind that this class don\'t check that the resource is valid, this is done to keep it flexible and to make it easy to adapt to new Keycloak REST API changes in the future. \n\n#### Usage\n\nIn order to create one you need to ``build`` method we have used before:\n\n```python\nbatman = {\n "enabled":\'true\',\n "attributes":{},\n "username":"batman",\n "firstName":"Bruce",\n "lastName":"Wayne",\n "emailVerified":""\n}\n\nusers = kc.build(\'users\', \'DC\')\n\n# Create a user called batman in DC\nstate = users.create(batman).isOk()\n```\n\n#### Methods\n\nFollowing the example above lets see the methods we have starting with the usual CRUD methods:\n\n#### create\n\nThis method ``POST`` a dictionary into any given resource:\n\n```python\nbatman = {\n "enabled":\'true\',\n "attributes":{},\n "username":"batman",\n "firstName":"Bruce",\n "lastName":"Wayne",\n "emailVerified":""\n}\n\nstate = users.create(batman).isOk()\n```\n\n- **dictionary**: Dictionary with the fields we want to POST to the server.\n\n\n\n\n#### update\n\nThis method performs a ``PUT`` on the resource.\n\n```python\nbatman_update = {\n "firstName":"Bruno",\n "emailVerified": True\n}\n\nid = \'bf81a9d9-811f-4807-bd69-3d74eecbe9f4\'\n\nstate = users.update(id, batman_update).isOk()\n```\n- **id**: Id of the resource in Keycloak.\n- **dictionary**: Dictionary representing the updated fields. \n\n#### remove\nThis method sends a ``DELETE`` to the pointed resource.\n\n```python\nbatman_update = {\n "firstName":"Bruno",\n "emailVerified": True\n}\n\nid = \'bf81a9d9-811f-4807-bd69-3d74eecbe9f4\'\n\nstate = users.remove(id).isOk()\n```\n- **id**: Id of the resource in Keycloak.\n- **dictionary**: Dictionary representing the updated fields. \n\n\n#### get\nSend a ``GET`` request to retrieve a specific Keycloak resource.\n\n```python\nid = \'bf81a9d9-811f-4807-bd69-3d74eecbe9f4\'\n\nuser = users.get(id).response()\n```\n\n#### all\n\nReturn all objects of a particular resource type.\n\n```Python\nusers = kc.build(\'users\', \'DC\')\n\n# Create a user called batman in DC\nuser_list = users.all() #\xa0[ {id:\'xxx-yyy\', username: \'batman\', ...} ] \n```\n#### findFirst\nFinds a resource by passing an arbitrary key/value pair.\n\n```Python\nusers = kc.build(\'users\', \'DC\')\n\nusers.findFirst({"key":"username", "value": \'batman\'})\n```\n\n#### exist\nCheck if a resource matching the provided ``id`` exists:\n```Python\nusers = kc.build(\'users\', \'DC\')\nid = \'bf81a9d9-811f-4807-bd69-3d74eecbe9f4\'\n\nusers.exists(id) #True\n```\n\n#### existByKV\nCheck if a resource matching the provided key/value pair, exists.\n\n\n```Python\nusers = kc.build(\'users\', \'DC\')\n\nusers.existByKV("username", \'batman\') #False\n```\n\n\n### ResponseHandler\n\nEach **CRUD** method returns a ``ResponseHandler`` class with the following methods.\n\n#### Methods\n\n\n#### response\nreturns the requests [response object](https://docs.python-requests.org/en/latest/api/#requests.Response).\n\n```Python\nusers.update(id, batman_update).response().status_code #HTTP 201\n```\n\n\n#### isOk\n\nReturn ``True`` if the request complete successfully otherwise it will raise an exception.\n\n```Python\nstate = users.update(id, batman_update).isOk() # Return True here.\n```\n\n#### verify\n\nDoes the same as ``isOk`` but it allow you to chain more methods.\n\n```python\nbatman_update = {\n "firstName":"Bruno",\n "emailVerified": True\n}\n\nid = \'bf81a9d9-811f-4807-bd69-3d74eecbe9f4\'\n\ncookies = users.update(id, batman_update).verify().response().cookies # Get cookies.\n```\n\n\n## Specialisations\n\n### Realms \n\n### KeycloakCaches \n\nThis class handles the Keycloak caches. \n\n#### Instantiation \n\n```python\n# Creates a REST API instance target the Realms API. \nrealms = kc.build(\'realms\', \'my_realm\') \n\n# Gets the cache Realms cache API. \ncaches = realms.caches(self.REALM)\n```\n\n#### clearUserCache \nThis method tells Keycloak to clear the user cache.\n\n```python\ncaches.clearUserCache()\n```\n\n\n#### clearRealmCache \nThis method tells Keycloak to clear the realm cache.\n\n```python\ncaches.clearRealmCache()\n```\n\n\n#### clearKeyCache \nThis method tells Keycloak to clear the external public key cache for clients and identity providers.\n\n```python\ncaches.clearKeyCache()\n```\n\n> For more information on how this caches works follow this [link](https://access.redhat.com/documentation/en-us/red_hat_single_sign-on/7.0/html/server_installation_and_configuration_guide/server_cache_configuration).\n\n\n### Users\n\n#### updateCredentials\n\nUpdate user credentials.\n\n```js\nuser_credentials = {\n \'temporary\': False,\n \'value\':\'12345\'\n}\n\nstate = users.updateCredentials(user_info, user_credentials).isOk() # Updated user password.\n```\nWhere:\n- **temporary**: Boolean where if ``True`` provide a temporary password just for the first login. \n- **value**: String with the password.\n\n\n#### joinGroup\n\nAdd a user into a existing [group](https://access.redhat.com/documentation/en-us/red_hat_single_sign-on/7.0/html/server_administration_guide/groups).\n\nFirst we need a group:\n```python\ndef createDCGroup():\n group = kc.build(\'groups\', \'heroes\')\n return group.create({"name": "DC"}).isOk()\n```\n\nThen we can join the group the following way:\n\n```python\n createDCGroup()\n\n users = kc.build(\'users\', \'heroes\')\n user = {"key": "username", "value": "batman"}\n group = {"key": "name", "value": "DC"}\n\n users.joinGroup(user, group).isOk()\n```\n\n> The API works by matching the first occurrence between the provided ``key/value`` for the two resources (User and Group), this can help in various situation for example if we want to target the user by ``uuid``.\n\n\nUsing ``uuid`` as user identifier.\n\n```python\n createDCGroup()\n\n users = kc.build(\'users\', \'heroes\')\n user = {"key": "uuid", "value": "23e4567-e89b-..."}\n group = {"key": "name", "value": "DC"}\n\n users.joinGroup(user, group).isOk()\n```\n\nOr we want to use the group ``id``:\n\n```python\n user = {"key": "uuid", "value": "23e4567-e89b-..."}\n group = {"key": "id", "value": "f8d91722-a1f0-45e..."}\n\n users.joinGroup(user, group).isOk()\n```\n> If the field criteria don\'t return a unique value, the first entry in the list will be used.\n#### leaveGroup\n\nRemove a user from a group.\n\n```python\n createDCGroup()\n\n users = kc.build(\'users\', \'heroes\')\n user = {"key": "username", "value": "batman"}\n group = {"key": "uuid", "value": "123e4567-e89b-..."}\n\n users.leaveGroup(user, group).isOk()\n\n user = {"key": "uuid", "value": "12d3-a456-4"}\n group = {"key": "id", "value": "123e4567-e89b-..."}\n\n users.leaveGroup(user, group).isOk()\n\n```\n\n> The same rules for ``key/value`` discussed above also applies here.\n\n\n### Groups\n\nTo manage the relationship between realm level [roles](keycloak.org/docs/latest/server_admin/#assigning-permissions-and-access-using-roles-and-groups) and groups, we can use the **RealmsRolesMapping**.\n\nTo get an instance of this class you need to instantiate the ``group`` resource class:\n\n```Python\ngroups = kc.build(\'groups\', \'heroes\')\n```\n\nAnd use the method ``realmRoles`` passing a valid [group dictionary](https://access.redhat.com/webassets/avalon/d/red-hat-single-sign-on/version-7.0.0/restapi/#_grouprepresentation):\n\n```python\nrealmsRoles = groups.realmRoles({"key":"name", "value":\'DC\'})\n```\n\nThen we get a class with following methods:\n\n#### add\n\nAdd a list of existing roles to a group.\n\n```python\ndef makeRoles(self):\n roles = kc.build(\'roles\', self.realm)\n lvl1 = roles.create({"name": "level-1"}).isOk()\n lvl2 = roles.create({"name": "level-2"}).isOk()\n return lvl1 and lvl2\n\n\nif makeRoles():\n realmsRoles = groups.realmRoles({"key":"name", "value":\'DC\'})\n realmsRoles.add(["level-1", "level-2"])\n```\n\n#### remove\nRemove a list of associated roles from a group.\n\n```python\nrealmsRoles = groups.realmRoles({"key":"name", "value":\'DC\'})\nrealmsRoles.remove(["level-1", "level-2"])\n```\n\n\n## Roles \n\n\n#### composite\nIn Keycloak we can map roles to other roles, this method allow you to do just that. \n\n```python\nrole_watch = self.kc.build(\'roles\', \'my-realm\').find(\'watch\')\nadded = role_watch.add_composite(\'view\')\n```'` 2023-03-28T18:58:42,871 According to the spec (see the link below), however, setuptools CANNOT 2023-03-28T18:58:42,871 consider this value unless 'readme' is listed as `dynamic`. 2023-03-28T18:58:42,872 https://packaging.python.org/en/latest/specifications/declaring-project-metadata/ 2023-03-28T18:58:42,872 For the time being, `setuptools` will still consider the given value (as a 2023-03-28T18:58:42,872 **transitional** measure), but please note that future releases of setuptools will 2023-03-28T18:58:42,873 follow strictly the standard. 2023-03-28T18:58:42,873 To prevent this warning, you can list 'readme' under `dynamic` or alternatively 2023-03-28T18:58:42,874 remove the `[project]` table from your file and rely entirely on other means of 2023-03-28T18:58:42,874 configuration. 2023-03-28T18:58:42,875 !! 2023-03-28T18:58:42,876 warnings.warn(msg, _WouldIgnoreField) 2023-03-28T18:58:43,420 running egg_info 2023-03-28T18:58:43,430 writing kcapi.egg-info/PKG-INFO 2023-03-28T18:58:43,435 writing dependency_links to kcapi.egg-info/dependency_links.txt 2023-03-28T18:58:43,440 writing requirements to kcapi.egg-info/requires.txt 2023-03-28T18:58:43,442 writing top-level names to kcapi.egg-info/top_level.txt 2023-03-28T18:58:43,484 reading manifest file 'kcapi.egg-info/SOURCES.txt' 2023-03-28T18:58:43,489 adding license file 'LICENSE' 2023-03-28T18:58:43,498 writing manifest file 'kcapi.egg-info/SOURCES.txt' 2023-03-28T18:58:43,502 /tmp/pip-build-env-x3jrkter/overlay/lib/python3.7/site-packages/setuptools/config/_apply_pyprojecttoml.py:103: _WouldIgnoreField: 'license' defined outside of `pyproject.toml` would be ignored. 2023-03-28T18:58:43,503 !! 2023-03-28T18:58:43,507 ########################################################################## 2023-03-28T18:58:43,507 # configuration would be ignored/result in error due to `pyproject.toml` # 2023-03-28T18:58:43,508 ########################################################################## 2023-03-28T18:58:43,509 The following seems to be defined outside of `pyproject.toml`: 2023-03-28T18:58:43,510 `license = 'MIT'` 2023-03-28T18:58:43,511 According to the spec (see the link below), however, setuptools CANNOT 2023-03-28T18:58:43,511 consider this value unless 'license' is listed as `dynamic`. 2023-03-28T18:58:43,512 https://packaging.python.org/en/latest/specifications/declaring-project-metadata/ 2023-03-28T18:58:43,513 For the time being, `setuptools` will still consider the given value (as a 2023-03-28T18:58:43,514 **transitional** measure), but please note that future releases of setuptools will 2023-03-28T18:58:43,514 follow strictly the standard. 2023-03-28T18:58:43,515 To prevent this warning, you can list 'license' under `dynamic` or alternatively 2023-03-28T18:58:43,516 remove the `[project]` table from your file and rely entirely on other means of 2023-03-28T18:58:43,516 configuration. 2023-03-28T18:58:43,517 !! 2023-03-28T18:58:43,518 warnings.warn(msg, _WouldIgnoreField) 2023-03-28T18:58:43,519 /tmp/pip-build-env-x3jrkter/overlay/lib/python3.7/site-packages/setuptools/config/_apply_pyprojecttoml.py:103: _WouldIgnoreField: 'dependencies' defined outside of `pyproject.toml` would be ignored. 2023-03-28T18:58:43,519 !! 2023-03-28T18:58:43,520 ########################################################################## 2023-03-28T18:58:43,521 # configuration would be ignored/result in error due to `pyproject.toml` # 2023-03-28T18:58:43,521 ########################################################################## 2023-03-28T18:58:43,522 The following seems to be defined outside of `pyproject.toml`: 2023-03-28T18:58:43,523 `dependencies = ['requests']` 2023-03-28T18:58:43,523 According to the spec (see the link below), however, setuptools CANNOT 2023-03-28T18:58:43,524 consider this value unless 'dependencies' is listed as `dynamic`. 2023-03-28T18:58:43,525 https://packaging.python.org/en/latest/specifications/declaring-project-metadata/ 2023-03-28T18:58:43,525 For the time being, `setuptools` will still consider the given value (as a 2023-03-28T18:58:43,526 **transitional** measure), but please note that future releases of setuptools will 2023-03-28T18:58:43,527 follow strictly the standard. 2023-03-28T18:58:43,527 To prevent this warning, you can list 'dependencies' under `dynamic` or alternatively 2023-03-28T18:58:43,528 remove the `[project]` table from your file and rely entirely on other means of 2023-03-28T18:58:43,528 configuration. 2023-03-28T18:58:43,530 !! 2023-03-28T18:58:43,531 warnings.warn(msg, _WouldIgnoreField) 2023-03-28T18:58:43,671 Getting requirements to build wheel: finished with status 'done' 2023-03-28T18:58:43,696 Installing backend dependencies: started 2023-03-28T18:58:43,698 Running command pip subprocess to install backend dependencies 2023-03-28T18:58:46,463 Using pip 23.0.1 from /usr/local/lib/python3.7/dist-packages/pip (python 3.7) 2023-03-28T18:58:47,690 DEPRECATION: --no-binary currently disables reading from the cache of locally built wheels. In the future --no-binary will not influence the wheel cache. pip 23.1 will enforce this behaviour change. A possible replacement is to use the --no-cache-dir option. You can use the flag --use-feature=no-binary-enable-wheel-cache to test the upcoming behaviour. Discussion can be found at https://github.com/pypa/pip/issues/11453 2023-03-28T18:58:47,747 Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple 2023-03-28T18:58:48,613 Collecting wheel 2023-03-28T18:58:48,654 Using cached https://www.piwheels.org/simple/wheel/wheel-0.40.0-py3-none-any.whl (64 kB) 2023-03-28T18:58:52,930 Installing collected packages: wheel 2023-03-28T18:58:53,392 Creating /tmp/pip-build-env-x3jrkter/normal/bin 2023-03-28T18:58:53,396 changing mode of /tmp/pip-build-env-x3jrkter/normal/bin/wheel to 755 2023-03-28T18:58:53,423 Successfully installed wheel-0.40.0 2023-03-28T18:58:54,292 Installing backend dependencies: finished with status 'done' 2023-03-28T18:58:54,298 Created temporary directory: /tmp/pip-modern-metadata-b6foc47u 2023-03-28T18:58:54,307 Preparing metadata (pyproject.toml): started 2023-03-28T18:58:54,309 Running command Preparing metadata (pyproject.toml) 2023-03-28T18:58:55,547 /tmp/pip-build-env-x3jrkter/overlay/lib/python3.7/site-packages/setuptools/config/_apply_pyprojecttoml.py:103: _WouldIgnoreField: 'readme' defined outside of `pyproject.toml` would be ignored. 2023-03-28T18:58:55,548 !! 2023-03-28T18:58:55,549 ########################################################################## 2023-03-28T18:58:55,550 # configuration would be ignored/result in error due to `pyproject.toml` # 2023-03-28T18:58:55,550 ########################################################################## 2023-03-28T18:58:55,551 The following seems to be defined outside of `pyproject.toml`: 2023-03-28T18:58:55,551 `readme = '# Keycloak API\n\nPython module to automate Keycloak or Red Hat Single Sign-On (RHSSO) configuration.\n\n## How To Install\n\n```sh\npip install kcapi\n```\n\n\n## Testing\n\nTo run the test you would need a Keycloak instance, you can run one locally or in the [cloud]( https://developers.redhat.com/developer-sandbox/get-started) then you just have to follow this steps: \n\n```shell script\npython3.10 -m venv .venv\nsource .venv/bin/activate\npip install requests\n\n# Setup SSO server - go to https://developers.redhat.com/developer-sandbox/get-started,\n# launch sandbox environment, +Add, select some "Red Hat Single Sign-On..." template.\nexport KC_USER=admin\nexport KC_PASSWORD=admin_password\nexport KC_REALM=myrealm # do not use master realm, it cannot be removed\nexport KC_ENDPOINT=https://my-first-sso-me-me-dev.apps.sandbox.x8i5.p1.openshiftapps.com\n\npython -m unittest\n```\n\n\n## API\n\n### OpenID\n\nThis class takes care of OpenID login using [password owner credentials](https://datatracker.ietf.org/doc/html/rfc6749#section-1.3.3) flow.\n\n\n#### Constructor\n\n```python\nfrom rhsso import OpenID\n\noid_client = OpenID({\n "client_id": "admin-cli",\n "username": USER,\n "password": PASSWORD,\n "grant_type":"password",\n "realm" : "master"\n }, endpoint)\n```\n\n- **client_id**: Client Identifier in Keycloak.\n- **username**: Login username for the Realm.\n- **password**: Login password for the Realm.\n- **grant_type**: The grant type you want to use (usually ``password``).\n- **endpoint**: A Keycloak or RHSSO URL endpoint, something like: ``https://my_keycloak.com``. \n\n\n#### Methods\n\n##### getToken\n\nThis will initiate a session with the Keycloak server and will return a OpenID token back.\n\n```python\noid_client.getToken() #glTeDLlmmpLYoAAUMcFQqNOMjw5dA\n```\n\n##### createAdminClient\n\nThis static method should be used in order to access the master Realm in Keycloak.\n\n```python\n oidc = OpenID.createAdminClient(self.USER, self.PASSWORD)\n oidc.getToken() #glTeDLlmmpLYoAAUMcFQqNOMjw5dA\n```\n### Keycloak\n\nThis class builds all the Keycloak configuration REST resources by using REST conventions we can target the majority of Keycloak services.\n\n#### Constructor\n\n```Python\nkc = Keycloak(token, self.ENDPOINT)\n```\n\nThe constructor takes two parameters:\n\n- **token**: A token with enough priviledge to perform the desired operation.\n- **endpoint**: A Keycloak or RHSSO URL endpoint, something like: ``https://my_keycloak.com``. \n\n\n#### Methods\n\n#### build\nThis methods build a REST client (capabilities detailed below) targeting a specific Keycloak REST resource.\n\n```python\ngroups = kc.build(\'groups\', \'my_realm\')\n\n# Create a group called DC\nstate = groups.create({"name": "DC"}).isOk()\n\n```\n> In this example we build the \'groups\' API for ``my_realm`` Realm.\n\n##### Supported Resources\n\nHere is a quick list of supported resources:\n\n- **users**: [users API](https://access.redhat.com/webassets/avalon/d/red-hat-single-sign-on/version-7.0.0/restapi/#_create_a_new_user).\n- **clients**: [client API](https://access.redhat.com/webassets/avalon/d/red-hat-single-sign-on/version-7.0.0/restapi/#_create_a_new_client). \n- **groups**: [groups API](https://access.redhat.com/documentation/en-us/red_hat_single_sign-on/7.0/html/server_administration_guide/groups).\n- **roles**: [roles API](https://access.redhat.com/webassets/avalon/d/red-hat-single-sign-on/version-7.0.0/restapi/#_create_a_new_role_for_the_realm_or_client_2)\n- **identity-provider**: [identity provider API](https://access.redhat.com/webassets/avalon/d/red-hat-single-sign-on/version-7.0.0/restapi/#_get_identity_providers)\n\n\n> As long as you find a REST endpoint that follow the standard you can use this method to build a client around it, an example of this is the non well documented ``components`` endpoint.\n\n- **components**: This API allows you configure things like [user federation](https://access.redhat.com/documentation/en-us/red_hat_single_sign-on/7.0/html/server_administration_guide/user-storage-federation) or [Realm keys](https://access.redhat.com/documentation/en-us/red_hat_single_sign-on/7.2/html/server_administration_guide/admin_permissions#realm_keys).\n\n- **authentication**: Provide access to built-in and/or custom authentication flows.\n
\n\n#### admin\nSimilar to the ``build`` method but the client points to the ``master`` realm, allowing us operation such as realm creation.\n\n```python\n main_realm = kc.admin()\n\n # Creates a realm called my_realm\n main_realm.create({"enabled": "true", "id": my_realm, "realm": my_realm})\n```\n\n\n### REST API\n\nWhen you use the ``build`` or ``admin`` methods you will get back a **REST** class pointing to the Keycloak resource, keep in mind that this class don\'t check that the resource is valid, this is done to keep it flexible and to make it easy to adapt to new Keycloak REST API changes in the future. \n\n#### Usage\n\nIn order to create one you need to ``build`` method we have used before:\n\n```python\nbatman = {\n "enabled":\'true\',\n "attributes":{},\n "username":"batman",\n "firstName":"Bruce",\n "lastName":"Wayne",\n "emailVerified":""\n}\n\nusers = kc.build(\'users\', \'DC\')\n\n# Create a user called batman in DC\nstate = users.create(batman).isOk()\n```\n\n#### Methods\n\nFollowing the example above lets see the methods we have starting with the usual CRUD methods:\n\n#### create\n\nThis method ``POST`` a dictionary into any given resource:\n\n```python\nbatman = {\n "enabled":\'true\',\n "attributes":{},\n "username":"batman",\n "firstName":"Bruce",\n "lastName":"Wayne",\n "emailVerified":""\n}\n\nstate = users.create(batman).isOk()\n```\n\n- **dictionary**: Dictionary with the fields we want to POST to the server.\n\n\n\n\n#### update\n\nThis method performs a ``PUT`` on the resource.\n\n```python\nbatman_update = {\n "firstName":"Bruno",\n "emailVerified": True\n}\n\nid = \'bf81a9d9-811f-4807-bd69-3d74eecbe9f4\'\n\nstate = users.update(id, batman_update).isOk()\n```\n- **id**: Id of the resource in Keycloak.\n- **dictionary**: Dictionary representing the updated fields. \n\n#### remove\nThis method sends a ``DELETE`` to the pointed resource.\n\n```python\nbatman_update = {\n "firstName":"Bruno",\n "emailVerified": True\n}\n\nid = \'bf81a9d9-811f-4807-bd69-3d74eecbe9f4\'\n\nstate = users.remove(id).isOk()\n```\n- **id**: Id of the resource in Keycloak.\n- **dictionary**: Dictionary representing the updated fields. \n\n\n#### get\nSend a ``GET`` request to retrieve a specific Keycloak resource.\n\n```python\nid = \'bf81a9d9-811f-4807-bd69-3d74eecbe9f4\'\n\nuser = users.get(id).response()\n```\n\n#### all\n\nReturn all objects of a particular resource type.\n\n```Python\nusers = kc.build(\'users\', \'DC\')\n\n# Create a user called batman in DC\nuser_list = users.all() #\xa0[ {id:\'xxx-yyy\', username: \'batman\', ...} ] \n```\n#### findFirst\nFinds a resource by passing an arbitrary key/value pair.\n\n```Python\nusers = kc.build(\'users\', \'DC\')\n\nusers.findFirst({"key":"username", "value": \'batman\'})\n```\n\n#### exist\nCheck if a resource matching the provided ``id`` exists:\n```Python\nusers = kc.build(\'users\', \'DC\')\nid = \'bf81a9d9-811f-4807-bd69-3d74eecbe9f4\'\n\nusers.exists(id) #True\n```\n\n#### existByKV\nCheck if a resource matching the provided key/value pair, exists.\n\n\n```Python\nusers = kc.build(\'users\', \'DC\')\n\nusers.existByKV("username", \'batman\') #False\n```\n\n\n### ResponseHandler\n\nEach **CRUD** method returns a ``ResponseHandler`` class with the following methods.\n\n#### Methods\n\n\n#### response\nreturns the requests [response object](https://docs.python-requests.org/en/latest/api/#requests.Response).\n\n```Python\nusers.update(id, batman_update).response().status_code #HTTP 201\n```\n\n\n#### isOk\n\nReturn ``True`` if the request complete successfully otherwise it will raise an exception.\n\n```Python\nstate = users.update(id, batman_update).isOk() # Return True here.\n```\n\n#### verify\n\nDoes the same as ``isOk`` but it allow you to chain more methods.\n\n```python\nbatman_update = {\n "firstName":"Bruno",\n "emailVerified": True\n}\n\nid = \'bf81a9d9-811f-4807-bd69-3d74eecbe9f4\'\n\ncookies = users.update(id, batman_update).verify().response().cookies # Get cookies.\n```\n\n\n## Specialisations\n\n### Realms \n\n### KeycloakCaches \n\nThis class handles the Keycloak caches. \n\n#### Instantiation \n\n```python\n# Creates a REST API instance target the Realms API. \nrealms = kc.build(\'realms\', \'my_realm\') \n\n# Gets the cache Realms cache API. \ncaches = realms.caches(self.REALM)\n```\n\n#### clearUserCache \nThis method tells Keycloak to clear the user cache.\n\n```python\ncaches.clearUserCache()\n```\n\n\n#### clearRealmCache \nThis method tells Keycloak to clear the realm cache.\n\n```python\ncaches.clearRealmCache()\n```\n\n\n#### clearKeyCache \nThis method tells Keycloak to clear the external public key cache for clients and identity providers.\n\n```python\ncaches.clearKeyCache()\n```\n\n> For more information on how this caches works follow this [link](https://access.redhat.com/documentation/en-us/red_hat_single_sign-on/7.0/html/server_installation_and_configuration_guide/server_cache_configuration).\n\n\n### Users\n\n#### updateCredentials\n\nUpdate user credentials.\n\n```js\nuser_credentials = {\n \'temporary\': False,\n \'value\':\'12345\'\n}\n\nstate = users.updateCredentials(user_info, user_credentials).isOk() # Updated user password.\n```\nWhere:\n- **temporary**: Boolean where if ``True`` provide a temporary password just for the first login. \n- **value**: String with the password.\n\n\n#### joinGroup\n\nAdd a user into a existing [group](https://access.redhat.com/documentation/en-us/red_hat_single_sign-on/7.0/html/server_administration_guide/groups).\n\nFirst we need a group:\n```python\ndef createDCGroup():\n group = kc.build(\'groups\', \'heroes\')\n return group.create({"name": "DC"}).isOk()\n```\n\nThen we can join the group the following way:\n\n```python\n createDCGroup()\n\n users = kc.build(\'users\', \'heroes\')\n user = {"key": "username", "value": "batman"}\n group = {"key": "name", "value": "DC"}\n\n users.joinGroup(user, group).isOk()\n```\n\n> The API works by matching the first occurrence between the provided ``key/value`` for the two resources (User and Group), this can help in various situation for example if we want to target the user by ``uuid``.\n\n\nUsing ``uuid`` as user identifier.\n\n```python\n createDCGroup()\n\n users = kc.build(\'users\', \'heroes\')\n user = {"key": "uuid", "value": "23e4567-e89b-..."}\n group = {"key": "name", "value": "DC"}\n\n users.joinGroup(user, group).isOk()\n```\n\nOr we want to use the group ``id``:\n\n```python\n user = {"key": "uuid", "value": "23e4567-e89b-..."}\n group = {"key": "id", "value": "f8d91722-a1f0-45e..."}\n\n users.joinGroup(user, group).isOk()\n```\n> If the field criteria don\'t return a unique value, the first entry in the list will be used.\n#### leaveGroup\n\nRemove a user from a group.\n\n```python\n createDCGroup()\n\n users = kc.build(\'users\', \'heroes\')\n user = {"key": "username", "value": "batman"}\n group = {"key": "uuid", "value": "123e4567-e89b-..."}\n\n users.leaveGroup(user, group).isOk()\n\n user = {"key": "uuid", "value": "12d3-a456-4"}\n group = {"key": "id", "value": "123e4567-e89b-..."}\n\n users.leaveGroup(user, group).isOk()\n\n```\n\n> The same rules for ``key/value`` discussed above also applies here.\n\n\n### Groups\n\nTo manage the relationship between realm level [roles](keycloak.org/docs/latest/server_admin/#assigning-permissions-and-access-using-roles-and-groups) and groups, we can use the **RealmsRolesMapping**.\n\nTo get an instance of this class you need to instantiate the ``group`` resource class:\n\n```Python\ngroups = kc.build(\'groups\', \'heroes\')\n```\n\nAnd use the method ``realmRoles`` passing a valid [group dictionary](https://access.redhat.com/webassets/avalon/d/red-hat-single-sign-on/version-7.0.0/restapi/#_grouprepresentation):\n\n```python\nrealmsRoles = groups.realmRoles({"key":"name", "value":\'DC\'})\n```\n\nThen we get a class with following methods:\n\n#### add\n\nAdd a list of existing roles to a group.\n\n```python\ndef makeRoles(self):\n roles = kc.build(\'roles\', self.realm)\n lvl1 = roles.create({"name": "level-1"}).isOk()\n lvl2 = roles.create({"name": "level-2"}).isOk()\n return lvl1 and lvl2\n\n\nif makeRoles():\n realmsRoles = groups.realmRoles({"key":"name", "value":\'DC\'})\n realmsRoles.add(["level-1", "level-2"])\n```\n\n#### remove\nRemove a list of associated roles from a group.\n\n```python\nrealmsRoles = groups.realmRoles({"key":"name", "value":\'DC\'})\nrealmsRoles.remove(["level-1", "level-2"])\n```\n\n\n## Roles \n\n\n#### composite\nIn Keycloak we can map roles to other roles, this method allow you to do just that. \n\n```python\nrole_watch = self.kc.build(\'roles\', \'my-realm\').find(\'watch\')\nadded = role_watch.add_composite(\'view\')\n```'` 2023-03-28T18:58:55,553 According to the spec (see the link below), however, setuptools CANNOT 2023-03-28T18:58:55,553 consider this value unless 'readme' is listed as `dynamic`. 2023-03-28T18:58:55,554 https://packaging.python.org/en/latest/specifications/declaring-project-metadata/ 2023-03-28T18:58:55,554 For the time being, `setuptools` will still consider the given value (as a 2023-03-28T18:58:55,555 **transitional** measure), but please note that future releases of setuptools will 2023-03-28T18:58:55,555 follow strictly the standard. 2023-03-28T18:58:55,555 To prevent this warning, you can list 'readme' under `dynamic` or alternatively 2023-03-28T18:58:55,556 remove the `[project]` table from your file and rely entirely on other means of 2023-03-28T18:58:55,556 configuration. 2023-03-28T18:58:55,557 !! 2023-03-28T18:58:55,558 warnings.warn(msg, _WouldIgnoreField) 2023-03-28T18:58:56,213 running dist_info 2023-03-28T18:58:56,229 creating /tmp/pip-modern-metadata-b6foc47u/kcapi.egg-info 2023-03-28T18:58:56,238 writing /tmp/pip-modern-metadata-b6foc47u/kcapi.egg-info/PKG-INFO 2023-03-28T18:58:56,245 writing dependency_links to /tmp/pip-modern-metadata-b6foc47u/kcapi.egg-info/dependency_links.txt 2023-03-28T18:58:56,249 writing requirements to /tmp/pip-modern-metadata-b6foc47u/kcapi.egg-info/requires.txt 2023-03-28T18:58:56,251 writing top-level names to /tmp/pip-modern-metadata-b6foc47u/kcapi.egg-info/top_level.txt 2023-03-28T18:58:56,254 writing manifest file '/tmp/pip-modern-metadata-b6foc47u/kcapi.egg-info/SOURCES.txt' 2023-03-28T18:58:56,300 reading manifest file '/tmp/pip-modern-metadata-b6foc47u/kcapi.egg-info/SOURCES.txt' 2023-03-28T18:58:56,305 adding license file 'LICENSE' 2023-03-28T18:58:56,312 writing manifest file '/tmp/pip-modern-metadata-b6foc47u/kcapi.egg-info/SOURCES.txt' 2023-03-28T18:58:56,314 creating '/tmp/pip-modern-metadata-b6foc47u/kcapi-1.1.2.dist-info' 2023-03-28T18:58:56,391 /tmp/pip-build-env-x3jrkter/overlay/lib/python3.7/site-packages/setuptools/config/_apply_pyprojecttoml.py:103: _WouldIgnoreField: 'license' defined outside of `pyproject.toml` would be ignored. 2023-03-28T18:58:56,391 !! 2023-03-28T18:58:56,392 ########################################################################## 2023-03-28T18:58:56,393 # configuration would be ignored/result in error due to `pyproject.toml` # 2023-03-28T18:58:56,393 ########################################################################## 2023-03-28T18:58:56,394 The following seems to be defined outside of `pyproject.toml`: 2023-03-28T18:58:56,395 `license = 'MIT'` 2023-03-28T18:58:56,396 According to the spec (see the link below), however, setuptools CANNOT 2023-03-28T18:58:56,397 consider this value unless 'license' is listed as `dynamic`. 2023-03-28T18:58:56,397 https://packaging.python.org/en/latest/specifications/declaring-project-metadata/ 2023-03-28T18:58:56,398 For the time being, `setuptools` will still consider the given value (as a 2023-03-28T18:58:56,399 **transitional** measure), but please note that future releases of setuptools will 2023-03-28T18:58:56,399 follow strictly the standard. 2023-03-28T18:58:56,400 To prevent this warning, you can list 'license' under `dynamic` or alternatively 2023-03-28T18:58:56,401 remove the `[project]` table from your file and rely entirely on other means of 2023-03-28T18:58:56,401 configuration. 2023-03-28T18:58:56,403 !! 2023-03-28T18:58:56,404 warnings.warn(msg, _WouldIgnoreField) 2023-03-28T18:58:56,404 /tmp/pip-build-env-x3jrkter/overlay/lib/python3.7/site-packages/setuptools/config/_apply_pyprojecttoml.py:103: _WouldIgnoreField: 'dependencies' defined outside of `pyproject.toml` would be ignored. 2023-03-28T18:58:56,404 !! 2023-03-28T18:58:56,406 ########################################################################## 2023-03-28T18:58:56,406 # configuration would be ignored/result in error due to `pyproject.toml` # 2023-03-28T18:58:56,407 ########################################################################## 2023-03-28T18:58:56,407 The following seems to be defined outside of `pyproject.toml`: 2023-03-28T18:58:56,408 `dependencies = ['requests']` 2023-03-28T18:58:56,409 According to the spec (see the link below), however, setuptools CANNOT 2023-03-28T18:58:56,409 consider this value unless 'dependencies' is listed as `dynamic`. 2023-03-28T18:58:56,410 https://packaging.python.org/en/latest/specifications/declaring-project-metadata/ 2023-03-28T18:58:56,411 For the time being, `setuptools` will still consider the given value (as a 2023-03-28T18:58:56,411 **transitional** measure), but please note that future releases of setuptools will 2023-03-28T18:58:56,412 follow strictly the standard. 2023-03-28T18:58:56,412 To prevent this warning, you can list 'dependencies' under `dynamic` or alternatively 2023-03-28T18:58:56,413 remove the `[project]` table from your file and rely entirely on other means of 2023-03-28T18:58:56,413 configuration. 2023-03-28T18:58:56,414 !! 2023-03-28T18:58:56,415 warnings.warn(msg, _WouldIgnoreField) 2023-03-28T18:58:56,568 Preparing metadata (pyproject.toml): finished with status 'done' 2023-03-28T18:58:56,585 Source in /tmp/pip-wheel-t__xeeom/kcapi_5269bb6aef9140a88a2f9e016f9d4fb6 has version 1.1.2, which satisfies requirement kcapi==1.1.2 from https://files.pythonhosted.org/packages/3a/5c/6e2c1bc7a1f8491defe6f325cf28756f5e13e327cc21d0d1079e226a149d/kcapi-1.1.2.tar.gz 2023-03-28T18:58:56,587 Removed kcapi==1.1.2 from https://files.pythonhosted.org/packages/3a/5c/6e2c1bc7a1f8491defe6f325cf28756f5e13e327cc21d0d1079e226a149d/kcapi-1.1.2.tar.gz from build tracker '/tmp/pip-build-tracker-qum1lirg' 2023-03-28T18:58:56,604 Created temporary directory: /tmp/pip-unpack-noktx_a4 2023-03-28T18:58:56,605 Building wheels for collected packages: kcapi 2023-03-28T18:58:56,616 Created temporary directory: /tmp/pip-wheel-j_ewwyms 2023-03-28T18:58:56,616 Destination directory: /tmp/pip-wheel-j_ewwyms 2023-03-28T18:58:56,621 Building wheel for kcapi (pyproject.toml): started 2023-03-28T18:58:56,623 Running command Building wheel for kcapi (pyproject.toml) 2023-03-28T18:58:57,801 /tmp/pip-build-env-x3jrkter/overlay/lib/python3.7/site-packages/setuptools/config/_apply_pyprojecttoml.py:103: _WouldIgnoreField: 'readme' defined outside of `pyproject.toml` would be ignored. 2023-03-28T18:58:57,802 !! 2023-03-28T18:58:57,803 ########################################################################## 2023-03-28T18:58:57,803 # configuration would be ignored/result in error due to `pyproject.toml` # 2023-03-28T18:58:57,804 ########################################################################## 2023-03-28T18:58:57,804 The following seems to be defined outside of `pyproject.toml`: 2023-03-28T18:58:57,805 `readme = '# Keycloak API\n\nPython module to automate Keycloak or Red Hat Single Sign-On (RHSSO) configuration.\n\n## How To Install\n\n```sh\npip install kcapi\n```\n\n\n## Testing\n\nTo run the test you would need a Keycloak instance, you can run one locally or in the [cloud]( https://developers.redhat.com/developer-sandbox/get-started) then you just have to follow this steps: \n\n```shell script\npython3.10 -m venv .venv\nsource .venv/bin/activate\npip install requests\n\n# Setup SSO server - go to https://developers.redhat.com/developer-sandbox/get-started,\n# launch sandbox environment, +Add, select some "Red Hat Single Sign-On..." template.\nexport KC_USER=admin\nexport KC_PASSWORD=admin_password\nexport KC_REALM=myrealm # do not use master realm, it cannot be removed\nexport KC_ENDPOINT=https://my-first-sso-me-me-dev.apps.sandbox.x8i5.p1.openshiftapps.com\n\npython -m unittest\n```\n\n\n## API\n\n### OpenID\n\nThis class takes care of OpenID login using [password owner credentials](https://datatracker.ietf.org/doc/html/rfc6749#section-1.3.3) flow.\n\n\n#### Constructor\n\n```python\nfrom rhsso import OpenID\n\noid_client = OpenID({\n "client_id": "admin-cli",\n "username": USER,\n "password": PASSWORD,\n "grant_type":"password",\n "realm" : "master"\n }, endpoint)\n```\n\n- **client_id**: Client Identifier in Keycloak.\n- **username**: Login username for the Realm.\n- **password**: Login password for the Realm.\n- **grant_type**: The grant type you want to use (usually ``password``).\n- **endpoint**: A Keycloak or RHSSO URL endpoint, something like: ``https://my_keycloak.com``. \n\n\n#### Methods\n\n##### getToken\n\nThis will initiate a session with the Keycloak server and will return a OpenID token back.\n\n```python\noid_client.getToken() #glTeDLlmmpLYoAAUMcFQqNOMjw5dA\n```\n\n##### createAdminClient\n\nThis static method should be used in order to access the master Realm in Keycloak.\n\n```python\n oidc = OpenID.createAdminClient(self.USER, self.PASSWORD)\n oidc.getToken() #glTeDLlmmpLYoAAUMcFQqNOMjw5dA\n```\n### Keycloak\n\nThis class builds all the Keycloak configuration REST resources by using REST conventions we can target the majority of Keycloak services.\n\n#### Constructor\n\n```Python\nkc = Keycloak(token, self.ENDPOINT)\n```\n\nThe constructor takes two parameters:\n\n- **token**: A token with enough priviledge to perform the desired operation.\n- **endpoint**: A Keycloak or RHSSO URL endpoint, something like: ``https://my_keycloak.com``. \n\n\n#### Methods\n\n#### build\nThis methods build a REST client (capabilities detailed below) targeting a specific Keycloak REST resource.\n\n```python\ngroups = kc.build(\'groups\', \'my_realm\')\n\n# Create a group called DC\nstate = groups.create({"name": "DC"}).isOk()\n\n```\n> In this example we build the \'groups\' API for ``my_realm`` Realm.\n\n##### Supported Resources\n\nHere is a quick list of supported resources:\n\n- **users**: [users API](https://access.redhat.com/webassets/avalon/d/red-hat-single-sign-on/version-7.0.0/restapi/#_create_a_new_user).\n- **clients**: [client API](https://access.redhat.com/webassets/avalon/d/red-hat-single-sign-on/version-7.0.0/restapi/#_create_a_new_client). \n- **groups**: [groups API](https://access.redhat.com/documentation/en-us/red_hat_single_sign-on/7.0/html/server_administration_guide/groups).\n- **roles**: [roles API](https://access.redhat.com/webassets/avalon/d/red-hat-single-sign-on/version-7.0.0/restapi/#_create_a_new_role_for_the_realm_or_client_2)\n- **identity-provider**: [identity provider API](https://access.redhat.com/webassets/avalon/d/red-hat-single-sign-on/version-7.0.0/restapi/#_get_identity_providers)\n\n\n> As long as you find a REST endpoint that follow the standard you can use this method to build a client around it, an example of this is the non well documented ``components`` endpoint.\n\n- **components**: This API allows you configure things like [user federation](https://access.redhat.com/documentation/en-us/red_hat_single_sign-on/7.0/html/server_administration_guide/user-storage-federation) or [Realm keys](https://access.redhat.com/documentation/en-us/red_hat_single_sign-on/7.2/html/server_administration_guide/admin_permissions#realm_keys).\n\n- **authentication**: Provide access to built-in and/or custom authentication flows.\n
\n\n#### admin\nSimilar to the ``build`` method but the client points to the ``master`` realm, allowing us operation such as realm creation.\n\n```python\n main_realm = kc.admin()\n\n # Creates a realm called my_realm\n main_realm.create({"enabled": "true", "id": my_realm, "realm": my_realm})\n```\n\n\n### REST API\n\nWhen you use the ``build`` or ``admin`` methods you will get back a **REST** class pointing to the Keycloak resource, keep in mind that this class don\'t check that the resource is valid, this is done to keep it flexible and to make it easy to adapt to new Keycloak REST API changes in the future. \n\n#### Usage\n\nIn order to create one you need to ``build`` method we have used before:\n\n```python\nbatman = {\n "enabled":\'true\',\n "attributes":{},\n "username":"batman",\n "firstName":"Bruce",\n "lastName":"Wayne",\n "emailVerified":""\n}\n\nusers = kc.build(\'users\', \'DC\')\n\n# Create a user called batman in DC\nstate = users.create(batman).isOk()\n```\n\n#### Methods\n\nFollowing the example above lets see the methods we have starting with the usual CRUD methods:\n\n#### create\n\nThis method ``POST`` a dictionary into any given resource:\n\n```python\nbatman = {\n "enabled":\'true\',\n "attributes":{},\n "username":"batman",\n "firstName":"Bruce",\n "lastName":"Wayne",\n "emailVerified":""\n}\n\nstate = users.create(batman).isOk()\n```\n\n- **dictionary**: Dictionary with the fields we want to POST to the server.\n\n\n\n\n#### update\n\nThis method performs a ``PUT`` on the resource.\n\n```python\nbatman_update = {\n "firstName":"Bruno",\n "emailVerified": True\n}\n\nid = \'bf81a9d9-811f-4807-bd69-3d74eecbe9f4\'\n\nstate = users.update(id, batman_update).isOk()\n```\n- **id**: Id of the resource in Keycloak.\n- **dictionary**: Dictionary representing the updated fields. \n\n#### remove\nThis method sends a ``DELETE`` to the pointed resource.\n\n```python\nbatman_update = {\n "firstName":"Bruno",\n "emailVerified": True\n}\n\nid = \'bf81a9d9-811f-4807-bd69-3d74eecbe9f4\'\n\nstate = users.remove(id).isOk()\n```\n- **id**: Id of the resource in Keycloak.\n- **dictionary**: Dictionary representing the updated fields. \n\n\n#### get\nSend a ``GET`` request to retrieve a specific Keycloak resource.\n\n```python\nid = \'bf81a9d9-811f-4807-bd69-3d74eecbe9f4\'\n\nuser = users.get(id).response()\n```\n\n#### all\n\nReturn all objects of a particular resource type.\n\n```Python\nusers = kc.build(\'users\', \'DC\')\n\n# Create a user called batman in DC\nuser_list = users.all() #\xa0[ {id:\'xxx-yyy\', username: \'batman\', ...} ] \n```\n#### findFirst\nFinds a resource by passing an arbitrary key/value pair.\n\n```Python\nusers = kc.build(\'users\', \'DC\')\n\nusers.findFirst({"key":"username", "value": \'batman\'})\n```\n\n#### exist\nCheck if a resource matching the provided ``id`` exists:\n```Python\nusers = kc.build(\'users\', \'DC\')\nid = \'bf81a9d9-811f-4807-bd69-3d74eecbe9f4\'\n\nusers.exists(id) #True\n```\n\n#### existByKV\nCheck if a resource matching the provided key/value pair, exists.\n\n\n```Python\nusers = kc.build(\'users\', \'DC\')\n\nusers.existByKV("username", \'batman\') #False\n```\n\n\n### ResponseHandler\n\nEach **CRUD** method returns a ``ResponseHandler`` class with the following methods.\n\n#### Methods\n\n\n#### response\nreturns the requests [response object](https://docs.python-requests.org/en/latest/api/#requests.Response).\n\n```Python\nusers.update(id, batman_update).response().status_code #HTTP 201\n```\n\n\n#### isOk\n\nReturn ``True`` if the request complete successfully otherwise it will raise an exception.\n\n```Python\nstate = users.update(id, batman_update).isOk() # Return True here.\n```\n\n#### verify\n\nDoes the same as ``isOk`` but it allow you to chain more methods.\n\n```python\nbatman_update = {\n "firstName":"Bruno",\n "emailVerified": True\n}\n\nid = \'bf81a9d9-811f-4807-bd69-3d74eecbe9f4\'\n\ncookies = users.update(id, batman_update).verify().response().cookies # Get cookies.\n```\n\n\n## Specialisations\n\n### Realms \n\n### KeycloakCaches \n\nThis class handles the Keycloak caches. \n\n#### Instantiation \n\n```python\n# Creates a REST API instance target the Realms API. \nrealms = kc.build(\'realms\', \'my_realm\') \n\n# Gets the cache Realms cache API. \ncaches = realms.caches(self.REALM)\n```\n\n#### clearUserCache \nThis method tells Keycloak to clear the user cache.\n\n```python\ncaches.clearUserCache()\n```\n\n\n#### clearRealmCache \nThis method tells Keycloak to clear the realm cache.\n\n```python\ncaches.clearRealmCache()\n```\n\n\n#### clearKeyCache \nThis method tells Keycloak to clear the external public key cache for clients and identity providers.\n\n```python\ncaches.clearKeyCache()\n```\n\n> For more information on how this caches works follow this [link](https://access.redhat.com/documentation/en-us/red_hat_single_sign-on/7.0/html/server_installation_and_configuration_guide/server_cache_configuration).\n\n\n### Users\n\n#### updateCredentials\n\nUpdate user credentials.\n\n```js\nuser_credentials = {\n \'temporary\': False,\n \'value\':\'12345\'\n}\n\nstate = users.updateCredentials(user_info, user_credentials).isOk() # Updated user password.\n```\nWhere:\n- **temporary**: Boolean where if ``True`` provide a temporary password just for the first login. \n- **value**: String with the password.\n\n\n#### joinGroup\n\nAdd a user into a existing [group](https://access.redhat.com/documentation/en-us/red_hat_single_sign-on/7.0/html/server_administration_guide/groups).\n\nFirst we need a group:\n```python\ndef createDCGroup():\n group = kc.build(\'groups\', \'heroes\')\n return group.create({"name": "DC"}).isOk()\n```\n\nThen we can join the group the following way:\n\n```python\n createDCGroup()\n\n users = kc.build(\'users\', \'heroes\')\n user = {"key": "username", "value": "batman"}\n group = {"key": "name", "value": "DC"}\n\n users.joinGroup(user, group).isOk()\n```\n\n> The API works by matching the first occurrence between the provided ``key/value`` for the two resources (User and Group), this can help in various situation for example if we want to target the user by ``uuid``.\n\n\nUsing ``uuid`` as user identifier.\n\n```python\n createDCGroup()\n\n users = kc.build(\'users\', \'heroes\')\n user = {"key": "uuid", "value": "23e4567-e89b-..."}\n group = {"key": "name", "value": "DC"}\n\n users.joinGroup(user, group).isOk()\n```\n\nOr we want to use the group ``id``:\n\n```python\n user = {"key": "uuid", "value": "23e4567-e89b-..."}\n group = {"key": "id", "value": "f8d91722-a1f0-45e..."}\n\n users.joinGroup(user, group).isOk()\n```\n> If the field criteria don\'t return a unique value, the first entry in the list will be used.\n#### leaveGroup\n\nRemove a user from a group.\n\n```python\n createDCGroup()\n\n users = kc.build(\'users\', \'heroes\')\n user = {"key": "username", "value": "batman"}\n group = {"key": "uuid", "value": "123e4567-e89b-..."}\n\n users.leaveGroup(user, group).isOk()\n\n user = {"key": "uuid", "value": "12d3-a456-4"}\n group = {"key": "id", "value": "123e4567-e89b-..."}\n\n users.leaveGroup(user, group).isOk()\n\n```\n\n> The same rules for ``key/value`` discussed above also applies here.\n\n\n### Groups\n\nTo manage the relationship between realm level [roles](keycloak.org/docs/latest/server_admin/#assigning-permissions-and-access-using-roles-and-groups) and groups, we can use the **RealmsRolesMapping**.\n\nTo get an instance of this class you need to instantiate the ``group`` resource class:\n\n```Python\ngroups = kc.build(\'groups\', \'heroes\')\n```\n\nAnd use the method ``realmRoles`` passing a valid [group dictionary](https://access.redhat.com/webassets/avalon/d/red-hat-single-sign-on/version-7.0.0/restapi/#_grouprepresentation):\n\n```python\nrealmsRoles = groups.realmRoles({"key":"name", "value":\'DC\'})\n```\n\nThen we get a class with following methods:\n\n#### add\n\nAdd a list of existing roles to a group.\n\n```python\ndef makeRoles(self):\n roles = kc.build(\'roles\', self.realm)\n lvl1 = roles.create({"name": "level-1"}).isOk()\n lvl2 = roles.create({"name": "level-2"}).isOk()\n return lvl1 and lvl2\n\n\nif makeRoles():\n realmsRoles = groups.realmRoles({"key":"name", "value":\'DC\'})\n realmsRoles.add(["level-1", "level-2"])\n```\n\n#### remove\nRemove a list of associated roles from a group.\n\n```python\nrealmsRoles = groups.realmRoles({"key":"name", "value":\'DC\'})\nrealmsRoles.remove(["level-1", "level-2"])\n```\n\n\n## Roles \n\n\n#### composite\nIn Keycloak we can map roles to other roles, this method allow you to do just that. \n\n```python\nrole_watch = self.kc.build(\'roles\', \'my-realm\').find(\'watch\')\nadded = role_watch.add_composite(\'view\')\n```'` 2023-03-28T18:58:57,806 According to the spec (see the link below), however, setuptools CANNOT 2023-03-28T18:58:57,807 consider this value unless 'readme' is listed as `dynamic`. 2023-03-28T18:58:57,807 https://packaging.python.org/en/latest/specifications/declaring-project-metadata/ 2023-03-28T18:58:57,808 For the time being, `setuptools` will still consider the given value (as a 2023-03-28T18:58:57,808 **transitional** measure), but please note that future releases of setuptools will 2023-03-28T18:58:57,808 follow strictly the standard. 2023-03-28T18:58:57,809 To prevent this warning, you can list 'readme' under `dynamic` or alternatively 2023-03-28T18:58:57,810 remove the `[project]` table from your file and rely entirely on other means of 2023-03-28T18:58:57,810 configuration. 2023-03-28T18:58:57,811 !! 2023-03-28T18:58:57,811 warnings.warn(msg, _WouldIgnoreField) 2023-03-28T18:58:58,404 running bdist_wheel 2023-03-28T18:58:58,441 running build 2023-03-28T18:58:58,441 running build_py 2023-03-28T18:58:58,452 creating build 2023-03-28T18:58:58,453 creating build/lib 2023-03-28T18:58:58,455 creating build/lib/kcapi 2023-03-28T18:58:58,457 copying kcapi/oid.py -> build/lib/kcapi 2023-03-28T18:58:58,461 copying kcapi/sso.py -> build/lib/kcapi 2023-03-28T18:58:58,464 copying kcapi/__init__.py -> build/lib/kcapi 2023-03-28T18:58:58,470 creating build/lib/kcapi/rest 2023-03-28T18:58:58,472 copying kcapi/rest/url.py -> build/lib/kcapi/rest 2023-03-28T18:58:58,476 copying kcapi/rest/resp.py -> build/lib/kcapi/rest 2023-03-28T18:58:58,479 copying kcapi/rest/realms.py -> build/lib/kcapi/rest 2023-03-28T18:58:58,482 copying kcapi/rest/users.py -> build/lib/kcapi/rest 2023-03-28T18:58:58,486 copying kcapi/rest/targets.py -> build/lib/kcapi/rest 2023-03-28T18:58:58,490 copying kcapi/rest/roles.py -> build/lib/kcapi/rest 2023-03-28T18:58:58,493 copying kcapi/rest/crud.py -> build/lib/kcapi/rest 2023-03-28T18:58:58,496 copying kcapi/rest/auth_flows.py -> build/lib/kcapi/rest 2023-03-28T18:58:58,500 copying kcapi/rest/idp.py -> build/lib/kcapi/rest 2023-03-28T18:58:58,503 copying kcapi/rest/client_scopes.py -> build/lib/kcapi/rest 2023-03-28T18:58:58,506 copying kcapi/rest/helper.py -> build/lib/kcapi/rest 2023-03-28T18:58:58,510 copying kcapi/rest/groups.py -> build/lib/kcapi/rest 2023-03-28T18:58:58,513 copying kcapi/rest/recovery.py -> build/lib/kcapi/rest 2023-03-28T18:58:58,516 copying kcapi/rest/clients.py -> build/lib/kcapi/rest 2023-03-28T18:58:58,520 copying kcapi/rest/__init__.py -> build/lib/kcapi/rest 2023-03-28T18:58:58,524 creating build/lib/kcapi/ie 2023-03-28T18:58:58,526 copying kcapi/ie/auth_flows.py -> build/lib/kcapi/ie 2023-03-28T18:58:58,530 copying kcapi/ie/flows_publisher.py -> build/lib/kcapi/ie 2023-03-28T18:58:58,533 copying kcapi/ie/__init__.py -> build/lib/kcapi/ie 2023-03-28T18:58:58,557 installing to build/bdist.linux-armv7l/wheel 2023-03-28T18:58:58,558 running install 2023-03-28T18:58:58,618 running install_lib 2023-03-28T18:58:58,628 creating build/bdist.linux-armv7l 2023-03-28T18:58:58,629 creating build/bdist.linux-armv7l/wheel 2023-03-28T18:58:58,633 creating build/bdist.linux-armv7l/wheel/kcapi 2023-03-28T18:58:58,635 copying build/lib/kcapi/oid.py -> build/bdist.linux-armv7l/wheel/kcapi 2023-03-28T18:58:58,640 creating build/bdist.linux-armv7l/wheel/kcapi/ie 2023-03-28T18:58:58,642 copying build/lib/kcapi/ie/auth_flows.py -> build/bdist.linux-armv7l/wheel/kcapi/ie 2023-03-28T18:58:58,646 copying build/lib/kcapi/ie/flows_publisher.py -> build/bdist.linux-armv7l/wheel/kcapi/ie 2023-03-28T18:58:58,650 copying build/lib/kcapi/ie/__init__.py -> build/bdist.linux-armv7l/wheel/kcapi/ie 2023-03-28T18:58:58,655 creating build/bdist.linux-armv7l/wheel/kcapi/rest 2023-03-28T18:58:58,656 copying build/lib/kcapi/rest/url.py -> build/bdist.linux-armv7l/wheel/kcapi/rest 2023-03-28T18:58:58,661 copying build/lib/kcapi/rest/resp.py -> build/bdist.linux-armv7l/wheel/kcapi/rest 2023-03-28T18:58:58,664 copying build/lib/kcapi/rest/realms.py -> build/bdist.linux-armv7l/wheel/kcapi/rest 2023-03-28T18:58:58,668 copying build/lib/kcapi/rest/users.py -> build/bdist.linux-armv7l/wheel/kcapi/rest 2023-03-28T18:58:58,671 copying build/lib/kcapi/rest/targets.py -> build/bdist.linux-armv7l/wheel/kcapi/rest 2023-03-28T18:58:58,675 copying build/lib/kcapi/rest/roles.py -> build/bdist.linux-armv7l/wheel/kcapi/rest 2023-03-28T18:58:58,679 copying build/lib/kcapi/rest/crud.py -> build/bdist.linux-armv7l/wheel/kcapi/rest 2023-03-28T18:58:58,682 copying build/lib/kcapi/rest/auth_flows.py -> build/bdist.linux-armv7l/wheel/kcapi/rest 2023-03-28T18:58:58,686 copying build/lib/kcapi/rest/idp.py -> build/bdist.linux-armv7l/wheel/kcapi/rest 2023-03-28T18:58:58,690 copying build/lib/kcapi/rest/client_scopes.py -> build/bdist.linux-armv7l/wheel/kcapi/rest 2023-03-28T18:58:58,693 copying build/lib/kcapi/rest/helper.py -> build/bdist.linux-armv7l/wheel/kcapi/rest 2023-03-28T18:58:58,697 copying build/lib/kcapi/rest/groups.py -> build/bdist.linux-armv7l/wheel/kcapi/rest 2023-03-28T18:58:58,701 copying build/lib/kcapi/rest/recovery.py -> build/bdist.linux-armv7l/wheel/kcapi/rest 2023-03-28T18:58:58,704 copying build/lib/kcapi/rest/clients.py -> build/bdist.linux-armv7l/wheel/kcapi/rest 2023-03-28T18:58:58,708 copying build/lib/kcapi/rest/__init__.py -> build/bdist.linux-armv7l/wheel/kcapi/rest 2023-03-28T18:58:58,711 copying build/lib/kcapi/sso.py -> build/bdist.linux-armv7l/wheel/kcapi 2023-03-28T18:58:58,715 copying build/lib/kcapi/__init__.py -> build/bdist.linux-armv7l/wheel/kcapi 2023-03-28T18:58:58,718 running install_egg_info 2023-03-28T18:58:58,735 running egg_info 2023-03-28T18:58:58,744 writing kcapi.egg-info/PKG-INFO 2023-03-28T18:58:58,749 writing dependency_links to kcapi.egg-info/dependency_links.txt 2023-03-28T18:58:58,752 writing requirements to kcapi.egg-info/requires.txt 2023-03-28T18:58:58,754 writing top-level names to kcapi.egg-info/top_level.txt 2023-03-28T18:58:58,775 reading manifest file 'kcapi.egg-info/SOURCES.txt' 2023-03-28T18:58:58,781 adding license file 'LICENSE' 2023-03-28T18:58:58,790 writing manifest file 'kcapi.egg-info/SOURCES.txt' 2023-03-28T18:58:58,793 Copying kcapi.egg-info to build/bdist.linux-armv7l/wheel/kcapi-1.1.2-py3.7.egg-info 2023-03-28T18:58:58,817 running install_scripts 2023-03-28T18:58:58,853 creating build/bdist.linux-armv7l/wheel/kcapi-1.1.2.dist-info/WHEEL 2023-03-28T18:58:58,858 creating '/tmp/pip-wheel-j_ewwyms/.tmp-vf2myq4j/kcapi-1.1.2-py3-none-any.whl' and adding 'build/bdist.linux-armv7l/wheel' to it 2023-03-28T18:58:58,862 adding 'kcapi/__init__.py' 2023-03-28T18:58:58,866 adding 'kcapi/oid.py' 2023-03-28T18:58:58,869 adding 'kcapi/sso.py' 2023-03-28T18:58:58,872 adding 'kcapi/ie/__init__.py' 2023-03-28T18:58:58,875 adding 'kcapi/ie/auth_flows.py' 2023-03-28T18:58:58,878 adding 'kcapi/ie/flows_publisher.py' 2023-03-28T18:58:58,882 adding 'kcapi/rest/__init__.py' 2023-03-28T18:58:58,885 adding 'kcapi/rest/auth_flows.py' 2023-03-28T18:58:58,887 adding 'kcapi/rest/client_scopes.py' 2023-03-28T18:58:58,890 adding 'kcapi/rest/clients.py' 2023-03-28T18:58:58,893 adding 'kcapi/rest/crud.py' 2023-03-28T18:58:58,895 adding 'kcapi/rest/groups.py' 2023-03-28T18:58:58,898 adding 'kcapi/rest/helper.py' 2023-03-28T18:58:58,900 adding 'kcapi/rest/idp.py' 2023-03-28T18:58:58,903 adding 'kcapi/rest/realms.py' 2023-03-28T18:58:58,905 adding 'kcapi/rest/recovery.py' 2023-03-28T18:58:58,907 adding 'kcapi/rest/resp.py' 2023-03-28T18:58:58,911 adding 'kcapi/rest/roles.py' 2023-03-28T18:58:58,913 adding 'kcapi/rest/targets.py' 2023-03-28T18:58:58,916 adding 'kcapi/rest/url.py' 2023-03-28T18:58:58,919 adding 'kcapi/rest/users.py' 2023-03-28T18:58:58,923 adding 'kcapi-1.1.2.dist-info/LICENSE' 2023-03-28T18:58:58,928 adding 'kcapi-1.1.2.dist-info/METADATA' 2023-03-28T18:58:58,930 adding 'kcapi-1.1.2.dist-info/WHEEL' 2023-03-28T18:58:58,932 adding 'kcapi-1.1.2.dist-info/top_level.txt' 2023-03-28T18:58:58,934 adding 'kcapi-1.1.2.dist-info/RECORD' 2023-03-28T18:58:58,938 removing build/bdist.linux-armv7l/wheel 2023-03-28T18:58:58,957 /tmp/pip-build-env-x3jrkter/overlay/lib/python3.7/site-packages/setuptools/config/_apply_pyprojecttoml.py:103: _WouldIgnoreField: 'license' defined outside of `pyproject.toml` would be ignored. 2023-03-28T18:58:58,958 !! 2023-03-28T18:58:58,959 ########################################################################## 2023-03-28T18:58:58,960 # configuration would be ignored/result in error due to `pyproject.toml` # 2023-03-28T18:58:58,960 ########################################################################## 2023-03-28T18:58:58,961 The following seems to be defined outside of `pyproject.toml`: 2023-03-28T18:58:58,962 `license = 'MIT'` 2023-03-28T18:58:58,963 According to the spec (see the link below), however, setuptools CANNOT 2023-03-28T18:58:58,963 consider this value unless 'license' is listed as `dynamic`. 2023-03-28T18:58:58,964 https://packaging.python.org/en/latest/specifications/declaring-project-metadata/ 2023-03-28T18:58:58,965 For the time being, `setuptools` will still consider the given value (as a 2023-03-28T18:58:58,966 **transitional** measure), but please note that future releases of setuptools will 2023-03-28T18:58:58,966 follow strictly the standard. 2023-03-28T18:58:58,967 To prevent this warning, you can list 'license' under `dynamic` or alternatively 2023-03-28T18:58:58,968 remove the `[project]` table from your file and rely entirely on other means of 2023-03-28T18:58:58,968 configuration. 2023-03-28T18:58:58,969 !! 2023-03-28T18:58:58,970 warnings.warn(msg, _WouldIgnoreField) 2023-03-28T18:58:58,971 /tmp/pip-build-env-x3jrkter/overlay/lib/python3.7/site-packages/setuptools/config/_apply_pyprojecttoml.py:103: _WouldIgnoreField: 'dependencies' defined outside of `pyproject.toml` would be ignored. 2023-03-28T18:58:58,971 !! 2023-03-28T18:58:58,973 ########################################################################## 2023-03-28T18:58:58,973 # configuration would be ignored/result in error due to `pyproject.toml` # 2023-03-28T18:58:58,973 ########################################################################## 2023-03-28T18:58:58,974 The following seems to be defined outside of `pyproject.toml`: 2023-03-28T18:58:58,975 `dependencies = ['requests']` 2023-03-28T18:58:58,976 According to the spec (see the link below), however, setuptools CANNOT 2023-03-28T18:58:58,976 consider this value unless 'dependencies' is listed as `dynamic`. 2023-03-28T18:58:58,977 https://packaging.python.org/en/latest/specifications/declaring-project-metadata/ 2023-03-28T18:58:58,978 For the time being, `setuptools` will still consider the given value (as a 2023-03-28T18:58:58,978 **transitional** measure), but please note that future releases of setuptools will 2023-03-28T18:58:58,979 follow strictly the standard. 2023-03-28T18:58:58,980 To prevent this warning, you can list 'dependencies' under `dynamic` or alternatively 2023-03-28T18:58:58,980 remove the `[project]` table from your file and rely entirely on other means of 2023-03-28T18:58:58,980 configuration. 2023-03-28T18:58:58,982 !! 2023-03-28T18:58:58,982 warnings.warn(msg, _WouldIgnoreField) 2023-03-28T18:58:59,136 Building wheel for kcapi (pyproject.toml): finished with status 'done' 2023-03-28T18:58:59,149 Created wheel for kcapi: filename=kcapi-1.1.2-py3-none-any.whl size=22278 sha256=7e508a917714ad2cc807faa83fb14241fa506e0210ff3b5a3a25829a013d7970 2023-03-28T18:58:59,151 Stored in directory: /tmp/pip-ephem-wheel-cache-1gszi275/wheels/46/fd/c9/0e8e3b1bf101b3cc1991dc7f2d874fd34f66e3e4c1065d1a3e 2023-03-28T18:58:59,182 Successfully built kcapi 2023-03-28T18:58:59,190 Removed build tracker: '/tmp/pip-build-tracker-qum1lirg'