2023-03-28T14:44:53,084 Created temporary directory: /tmp/pip-ephem-wheel-cache-doui9z2l 2023-03-28T14:44:53,090 Created temporary directory: /tmp/pip-build-tracker-d8r43s2m 2023-03-28T14:44:53,091 Initialized build tracking at /tmp/pip-build-tracker-d8r43s2m 2023-03-28T14:44:53,091 Created build tracker: /tmp/pip-build-tracker-d8r43s2m 2023-03-28T14:44:53,091 Entered build tracker: /tmp/pip-build-tracker-d8r43s2m 2023-03-28T14:44:53,093 Created temporary directory: /tmp/pip-wheel-xp521uvf 2023-03-28T14:44:53,108 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-28T14:44:53,114 Created temporary directory: /tmp/pip-ephem-wheel-cache-mo7pw819 2023-03-28T14:44:53,167 Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple 2023-03-28T14:44:53,174 2 location(s) to search for versions of kcapi: 2023-03-28T14:44:53,174 * https://pypi.org/simple/kcapi/ 2023-03-28T14:44:53,174 * https://www.piwheels.org/simple/kcapi/ 2023-03-28T14:44:53,175 Fetching project page and analyzing links: https://pypi.org/simple/kcapi/ 2023-03-28T14:44:53,177 Getting page https://pypi.org/simple/kcapi/ 2023-03-28T14:44:53,180 Found index url https://pypi.org/simple 2023-03-28T14:44:53,434 Fetched page https://pypi.org/simple/kcapi/ as application/vnd.pypi.simple.v1+json 2023-03-28T14:44:53,473 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-28T14:44:53,474 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-28T14:44:53,475 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-28T14:44:53,475 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-28T14:44:53,476 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-28T14:44:53,477 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-28T14:44:53,477 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-28T14:44:53,478 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-28T14:44:53,479 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-28T14:44:53,479 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-28T14:44:53,480 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-28T14:44:53,481 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-28T14:44:53,481 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-28T14:44:53,482 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-28T14:44:53,482 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-28T14:44:53,483 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-28T14:44:53,484 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-28T14:44:53,484 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-28T14:44:53,485 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-28T14:44:53,485 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-28T14:44:53,486 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-28T14:44:53,487 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-28T14:44:53,487 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-28T14:44:53,488 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-28T14:44:53,488 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-28T14:44:53,489 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-28T14:44:53,490 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-28T14:44:53,490 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-28T14:44:53,491 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-28T14:44:53,492 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-28T14:44:53,492 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-28T14:44:53,493 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-28T14:44:53,494 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-28T14:44:53,494 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-28T14:44:53,495 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-28T14:44:53,495 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-28T14:44:53,496 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-28T14:44:53,497 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-28T14:44:53,497 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-28T14:44:53,498 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-28T14:44:53,498 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-28T14:44:53,499 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-28T14:44:53,500 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-28T14:44:53,500 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-28T14:44:53,501 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-28T14:44:53,502 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-28T14:44:53,502 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-28T14:44:53,503 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-28T14:44:53,503 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-28T14:44:53,504 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-28T14:44:53,505 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-28T14:44:53,505 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-28T14:44:53,506 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-28T14:44:53,507 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-28T14:44:53,507 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-28T14:44:53,508 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-28T14:44:53,508 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-28T14:44:53,509 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-28T14:44:53,510 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-28T14:44:53,510 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-28T14:44:53,511 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-28T14:44:53,511 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-28T14:44:53,512 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-28T14:44:53,513 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-28T14:44:53,513 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-28T14:44:53,514 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-28T14:44:53,514 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-28T14:44:53,515 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-28T14:44:53,516 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-28T14:44:53,516 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-28T14:44:53,517 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-28T14:44:53,517 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-28T14:44:53,518 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-28T14:44:53,519 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-28T14:44:53,519 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-28T14:44:53,520 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-28T14:44:53,521 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-28T14:44:53,522 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-28T14:44:53,523 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-28T14:44:53,524 Fetching project page and analyzing links: https://www.piwheels.org/simple/kcapi/ 2023-03-28T14:44:53,525 Getting page https://www.piwheels.org/simple/kcapi/ 2023-03-28T14:44:53,527 Found index url https://www.piwheels.org/simple 2023-03-28T14:44:53,778 Fetched page https://www.piwheels.org/simple/kcapi/ as text/html 2023-03-28T14:44:53,808 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-28T14:44:53,809 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-28T14:44:53,809 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-28T14:44:53,810 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-28T14:44:53,810 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-28T14:44:53,811 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-28T14:44:53,811 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-28T14:44:53,812 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-28T14:44:53,812 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-28T14:44:53,813 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-28T14:44:53,813 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-28T14:44:53,814 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-28T14:44:53,814 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-28T14:44:53,815 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-28T14:44:53,815 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-28T14:44:53,816 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-28T14:44:53,817 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-28T14:44:53,817 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-28T14:44:53,818 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-28T14:44:53,818 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-28T14:44:53,819 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-28T14:44:53,819 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-28T14:44:53,820 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-28T14:44:53,820 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-28T14:44:53,821 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-28T14:44:53,821 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-28T14:44:53,822 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-28T14:44:53,822 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-28T14:44:53,823 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-28T14:44:53,823 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-28T14:44:53,824 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-28T14:44:53,824 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-28T14:44:53,825 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-28T14:44:53,825 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-28T14:44:53,826 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-28T14:44:53,826 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-28T14:44:53,827 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-28T14:44:53,827 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-28T14:44:53,828 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-28T14:44:53,828 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-28T14:44:53,829 Skipping link: not a file: https://www.piwheels.org/simple/kcapi/ 2023-03-28T14:44:53,830 Skipping link: not a file: https://pypi.org/simple/kcapi/ 2023-03-28T14:44:53,878 Given no hashes to check 1 links for project 'kcapi': discarding no candidates 2023-03-28T14:44:53,908 Collecting kcapi==1.1.1 2023-03-28T14:44:53,913 Created temporary directory: /tmp/pip-unpack-btb7rt68 2023-03-28T14:44:54,170 Downloading kcapi-1.1.1.tar.gz (30 kB) 2023-03-28T14:44:54,377 Added kcapi==1.1.1 from https://files.pythonhosted.org/packages/eb/9e/32217926fbc7593b45f3f1e72da114e93d4e0c09085fba916c1f5e15ff17/kcapi-1.1.1.tar.gz to build tracker '/tmp/pip-build-tracker-d8r43s2m' 2023-03-28T14:44:54,385 Created temporary directory: /tmp/pip-build-env-l3g9wwkp 2023-03-28T14:44:54,406 Installing build dependencies: started 2023-03-28T14:44:54,408 Running command pip subprocess to install build dependencies 2023-03-28T14:44:57,177 Using pip 23.0.1 from /usr/local/lib/python3.7/dist-packages/pip (python 3.7) 2023-03-28T14:44:58,408 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-28T14:44:58,464 Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple 2023-03-28T14:45:02,311 Collecting setuptools>=61.0 2023-03-28T14:45:02,546 Using cached https://www.piwheels.org/simple/setuptools/setuptools-67.6.1-py3-none-any.whl (1.1 MB) 2023-03-28T14:45:07,653 Installing collected packages: setuptools 2023-03-28T14:45:11,862 Successfully installed setuptools-67.6.1 2023-03-28T14:45:12,800 Installing build dependencies: finished with status 'done' 2023-03-28T14:45:12,812 Getting requirements to build wheel: started 2023-03-28T14:45:12,814 Running command Getting requirements to build wheel 2023-03-28T14:45:14,072 /tmp/pip-build-env-l3g9wwkp/overlay/lib/python3.7/site-packages/setuptools/config/_apply_pyprojecttoml.py:103: _WouldIgnoreField: 'readme' defined outside of `pyproject.toml` would be ignored. 2023-03-28T14:45:14,073 !! 2023-03-28T14:45:14,074 ########################################################################## 2023-03-28T14:45:14,075 # configuration would be ignored/result in error due to `pyproject.toml` # 2023-03-28T14:45:14,075 ########################################################################## 2023-03-28T14:45:14,076 The following seems to be defined outside of `pyproject.toml`: 2023-03-28T14:45:14,077 `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-28T14:45:14,078 According to the spec (see the link below), however, setuptools CANNOT 2023-03-28T14:45:14,078 consider this value unless 'readme' is listed as `dynamic`. 2023-03-28T14:45:14,079 https://packaging.python.org/en/latest/specifications/declaring-project-metadata/ 2023-03-28T14:45:14,079 For the time being, `setuptools` will still consider the given value (as a 2023-03-28T14:45:14,080 **transitional** measure), but please note that future releases of setuptools will 2023-03-28T14:45:14,080 follow strictly the standard. 2023-03-28T14:45:14,081 To prevent this warning, you can list 'readme' under `dynamic` or alternatively 2023-03-28T14:45:14,081 remove the `[project]` table from your file and rely entirely on other means of 2023-03-28T14:45:14,081 configuration. 2023-03-28T14:45:14,083 !! 2023-03-28T14:45:14,083 warnings.warn(msg, _WouldIgnoreField) 2023-03-28T14:45:14,611 running egg_info 2023-03-28T14:45:14,621 writing kcapi.egg-info/PKG-INFO 2023-03-28T14:45:14,626 writing dependency_links to kcapi.egg-info/dependency_links.txt 2023-03-28T14:45:14,631 writing requirements to kcapi.egg-info/requires.txt 2023-03-28T14:45:14,634 writing top-level names to kcapi.egg-info/top_level.txt 2023-03-28T14:45:14,674 reading manifest file 'kcapi.egg-info/SOURCES.txt' 2023-03-28T14:45:14,680 adding license file 'LICENSE' 2023-03-28T14:45:14,689 writing manifest file 'kcapi.egg-info/SOURCES.txt' 2023-03-28T14:45:14,693 /tmp/pip-build-env-l3g9wwkp/overlay/lib/python3.7/site-packages/setuptools/config/_apply_pyprojecttoml.py:103: _WouldIgnoreField: 'license' defined outside of `pyproject.toml` would be ignored. 2023-03-28T14:45:14,693 !! 2023-03-28T14:45:14,694 ########################################################################## 2023-03-28T14:45:14,695 # configuration would be ignored/result in error due to `pyproject.toml` # 2023-03-28T14:45:14,695 ########################################################################## 2023-03-28T14:45:14,696 The following seems to be defined outside of `pyproject.toml`: 2023-03-28T14:45:14,697 `license = 'MIT'` 2023-03-28T14:45:14,698 According to the spec (see the link below), however, setuptools CANNOT 2023-03-28T14:45:14,699 consider this value unless 'license' is listed as `dynamic`. 2023-03-28T14:45:14,700 https://packaging.python.org/en/latest/specifications/declaring-project-metadata/ 2023-03-28T14:45:14,701 For the time being, `setuptools` will still consider the given value (as a 2023-03-28T14:45:14,701 **transitional** measure), but please note that future releases of setuptools will 2023-03-28T14:45:14,701 follow strictly the standard. 2023-03-28T14:45:14,702 To prevent this warning, you can list 'license' under `dynamic` or alternatively 2023-03-28T14:45:14,703 remove the `[project]` table from your file and rely entirely on other means of 2023-03-28T14:45:14,703 configuration. 2023-03-28T14:45:14,705 !! 2023-03-28T14:45:14,705 warnings.warn(msg, _WouldIgnoreField) 2023-03-28T14:45:14,706 /tmp/pip-build-env-l3g9wwkp/overlay/lib/python3.7/site-packages/setuptools/config/_apply_pyprojecttoml.py:103: _WouldIgnoreField: 'dependencies' defined outside of `pyproject.toml` would be ignored. 2023-03-28T14:45:14,706 !! 2023-03-28T14:45:14,708 ########################################################################## 2023-03-28T14:45:14,708 # configuration would be ignored/result in error due to `pyproject.toml` # 2023-03-28T14:45:14,708 ########################################################################## 2023-03-28T14:45:14,709 The following seems to be defined outside of `pyproject.toml`: 2023-03-28T14:45:14,710 `dependencies = ['requests']` 2023-03-28T14:45:14,711 According to the spec (see the link below), however, setuptools CANNOT 2023-03-28T14:45:14,712 consider this value unless 'dependencies' is listed as `dynamic`. 2023-03-28T14:45:14,712 https://packaging.python.org/en/latest/specifications/declaring-project-metadata/ 2023-03-28T14:45:14,713 For the time being, `setuptools` will still consider the given value (as a 2023-03-28T14:45:14,713 **transitional** measure), but please note that future releases of setuptools will 2023-03-28T14:45:14,714 follow strictly the standard. 2023-03-28T14:45:14,715 To prevent this warning, you can list 'dependencies' under `dynamic` or alternatively 2023-03-28T14:45:14,715 remove the `[project]` table from your file and rely entirely on other means of 2023-03-28T14:45:14,716 configuration. 2023-03-28T14:45:14,717 !! 2023-03-28T14:45:14,718 warnings.warn(msg, _WouldIgnoreField) 2023-03-28T14:45:14,861 Getting requirements to build wheel: finished with status 'done' 2023-03-28T14:45:14,885 Installing backend dependencies: started 2023-03-28T14:45:14,887 Running command pip subprocess to install backend dependencies 2023-03-28T14:45:17,642 Using pip 23.0.1 from /usr/local/lib/python3.7/dist-packages/pip (python 3.7) 2023-03-28T14:45:18,873 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-28T14:45:18,929 Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple 2023-03-28T14:45:19,924 Collecting wheel 2023-03-28T14:45:19,962 Using cached https://www.piwheels.org/simple/wheel/wheel-0.40.0-py3-none-any.whl (64 kB) 2023-03-28T14:45:24,219 Installing collected packages: wheel 2023-03-28T14:45:24,666 Creating /tmp/pip-build-env-l3g9wwkp/normal/bin 2023-03-28T14:45:24,671 changing mode of /tmp/pip-build-env-l3g9wwkp/normal/bin/wheel to 755 2023-03-28T14:45:24,697 Successfully installed wheel-0.40.0 2023-03-28T14:45:25,570 Installing backend dependencies: finished with status 'done' 2023-03-28T14:45:25,576 Created temporary directory: /tmp/pip-modern-metadata-r0q9ck7n 2023-03-28T14:45:25,582 Preparing metadata (pyproject.toml): started 2023-03-28T14:45:25,584 Running command Preparing metadata (pyproject.toml) 2023-03-28T14:45:26,817 /tmp/pip-build-env-l3g9wwkp/overlay/lib/python3.7/site-packages/setuptools/config/_apply_pyprojecttoml.py:103: _WouldIgnoreField: 'readme' defined outside of `pyproject.toml` would be ignored. 2023-03-28T14:45:26,819 !! 2023-03-28T14:45:26,820 ########################################################################## 2023-03-28T14:45:26,820 # configuration would be ignored/result in error due to `pyproject.toml` # 2023-03-28T14:45:26,821 ########################################################################## 2023-03-28T14:45:26,821 The following seems to be defined outside of `pyproject.toml`: 2023-03-28T14:45:26,822 `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-28T14:45:26,823 According to the spec (see the link below), however, setuptools CANNOT 2023-03-28T14:45:26,823 consider this value unless 'readme' is listed as `dynamic`. 2023-03-28T14:45:26,824 https://packaging.python.org/en/latest/specifications/declaring-project-metadata/ 2023-03-28T14:45:26,825 For the time being, `setuptools` will still consider the given value (as a 2023-03-28T14:45:26,825 **transitional** measure), but please note that future releases of setuptools will 2023-03-28T14:45:26,825 follow strictly the standard. 2023-03-28T14:45:26,826 To prevent this warning, you can list 'readme' under `dynamic` or alternatively 2023-03-28T14:45:26,826 remove the `[project]` table from your file and rely entirely on other means of 2023-03-28T14:45:26,827 configuration. 2023-03-28T14:45:26,828 !! 2023-03-28T14:45:26,828 warnings.warn(msg, _WouldIgnoreField) 2023-03-28T14:45:27,469 running dist_info 2023-03-28T14:45:27,485 creating /tmp/pip-modern-metadata-r0q9ck7n/kcapi.egg-info 2023-03-28T14:45:27,494 writing /tmp/pip-modern-metadata-r0q9ck7n/kcapi.egg-info/PKG-INFO 2023-03-28T14:45:27,501 writing dependency_links to /tmp/pip-modern-metadata-r0q9ck7n/kcapi.egg-info/dependency_links.txt 2023-03-28T14:45:27,506 writing requirements to /tmp/pip-modern-metadata-r0q9ck7n/kcapi.egg-info/requires.txt 2023-03-28T14:45:27,508 writing top-level names to /tmp/pip-modern-metadata-r0q9ck7n/kcapi.egg-info/top_level.txt 2023-03-28T14:45:27,510 writing manifest file '/tmp/pip-modern-metadata-r0q9ck7n/kcapi.egg-info/SOURCES.txt' 2023-03-28T14:45:27,556 reading manifest file '/tmp/pip-modern-metadata-r0q9ck7n/kcapi.egg-info/SOURCES.txt' 2023-03-28T14:45:27,560 adding license file 'LICENSE' 2023-03-28T14:45:27,568 writing manifest file '/tmp/pip-modern-metadata-r0q9ck7n/kcapi.egg-info/SOURCES.txt' 2023-03-28T14:45:27,570 creating '/tmp/pip-modern-metadata-r0q9ck7n/kcapi-1.1.1.dist-info' 2023-03-28T14:45:27,645 /tmp/pip-build-env-l3g9wwkp/overlay/lib/python3.7/site-packages/setuptools/config/_apply_pyprojecttoml.py:103: _WouldIgnoreField: 'license' defined outside of `pyproject.toml` would be ignored. 2023-03-28T14:45:27,645 !! 2023-03-28T14:45:27,647 ########################################################################## 2023-03-28T14:45:27,647 # configuration would be ignored/result in error due to `pyproject.toml` # 2023-03-28T14:45:27,648 ########################################################################## 2023-03-28T14:45:27,649 The following seems to be defined outside of `pyproject.toml`: 2023-03-28T14:45:27,650 `license = 'MIT'` 2023-03-28T14:45:27,651 According to the spec (see the link below), however, setuptools CANNOT 2023-03-28T14:45:27,651 consider this value unless 'license' is listed as `dynamic`. 2023-03-28T14:45:27,652 https://packaging.python.org/en/latest/specifications/declaring-project-metadata/ 2023-03-28T14:45:27,653 For the time being, `setuptools` will still consider the given value (as a 2023-03-28T14:45:27,653 **transitional** measure), but please note that future releases of setuptools will 2023-03-28T14:45:27,654 follow strictly the standard. 2023-03-28T14:45:27,655 To prevent this warning, you can list 'license' under `dynamic` or alternatively 2023-03-28T14:45:27,655 remove the `[project]` table from your file and rely entirely on other means of 2023-03-28T14:45:27,655 configuration. 2023-03-28T14:45:27,657 !! 2023-03-28T14:45:27,658 warnings.warn(msg, _WouldIgnoreField) 2023-03-28T14:45:27,658 /tmp/pip-build-env-l3g9wwkp/overlay/lib/python3.7/site-packages/setuptools/config/_apply_pyprojecttoml.py:103: _WouldIgnoreField: 'dependencies' defined outside of `pyproject.toml` would be ignored. 2023-03-28T14:45:27,659 !! 2023-03-28T14:45:27,660 ########################################################################## 2023-03-28T14:45:27,661 # configuration would be ignored/result in error due to `pyproject.toml` # 2023-03-28T14:45:27,661 ########################################################################## 2023-03-28T14:45:27,662 The following seems to be defined outside of `pyproject.toml`: 2023-03-28T14:45:27,663 `dependencies = ['requests']` 2023-03-28T14:45:27,664 According to the spec (see the link below), however, setuptools CANNOT 2023-03-28T14:45:27,664 consider this value unless 'dependencies' is listed as `dynamic`. 2023-03-28T14:45:27,665 https://packaging.python.org/en/latest/specifications/declaring-project-metadata/ 2023-03-28T14:45:27,666 For the time being, `setuptools` will still consider the given value (as a 2023-03-28T14:45:27,666 **transitional** measure), but please note that future releases of setuptools will 2023-03-28T14:45:27,667 follow strictly the standard. 2023-03-28T14:45:27,667 To prevent this warning, you can list 'dependencies' under `dynamic` or alternatively 2023-03-28T14:45:27,668 remove the `[project]` table from your file and rely entirely on other means of 2023-03-28T14:45:27,668 configuration. 2023-03-28T14:45:27,670 !! 2023-03-28T14:45:27,671 warnings.warn(msg, _WouldIgnoreField) 2023-03-28T14:45:27,822 Preparing metadata (pyproject.toml): finished with status 'done' 2023-03-28T14:45:27,840 Source in /tmp/pip-wheel-xp521uvf/kcapi_7607e7f60e5b49ef8beaefdb6d29b747 has version 1.1.1, which satisfies requirement kcapi==1.1.1 from https://files.pythonhosted.org/packages/eb/9e/32217926fbc7593b45f3f1e72da114e93d4e0c09085fba916c1f5e15ff17/kcapi-1.1.1.tar.gz 2023-03-28T14:45:27,842 Removed kcapi==1.1.1 from https://files.pythonhosted.org/packages/eb/9e/32217926fbc7593b45f3f1e72da114e93d4e0c09085fba916c1f5e15ff17/kcapi-1.1.1.tar.gz from build tracker '/tmp/pip-build-tracker-d8r43s2m' 2023-03-28T14:45:27,858 Created temporary directory: /tmp/pip-unpack-qvgo02zf 2023-03-28T14:45:27,860 Building wheels for collected packages: kcapi 2023-03-28T14:45:27,871 Created temporary directory: /tmp/pip-wheel-9d5fb4li 2023-03-28T14:45:27,871 Destination directory: /tmp/pip-wheel-9d5fb4li 2023-03-28T14:45:27,876 Building wheel for kcapi (pyproject.toml): started 2023-03-28T14:45:27,878 Running command Building wheel for kcapi (pyproject.toml) 2023-03-28T14:45:29,066 /tmp/pip-build-env-l3g9wwkp/overlay/lib/python3.7/site-packages/setuptools/config/_apply_pyprojecttoml.py:103: _WouldIgnoreField: 'readme' defined outside of `pyproject.toml` would be ignored. 2023-03-28T14:45:29,068 !! 2023-03-28T14:45:29,069 ########################################################################## 2023-03-28T14:45:29,069 # configuration would be ignored/result in error due to `pyproject.toml` # 2023-03-28T14:45:29,070 ########################################################################## 2023-03-28T14:45:29,070 The following seems to be defined outside of `pyproject.toml`: 2023-03-28T14:45:29,071 `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-28T14:45:29,072 According to the spec (see the link below), however, setuptools CANNOT 2023-03-28T14:45:29,072 consider this value unless 'readme' is listed as `dynamic`. 2023-03-28T14:45:29,073 https://packaging.python.org/en/latest/specifications/declaring-project-metadata/ 2023-03-28T14:45:29,074 For the time being, `setuptools` will still consider the given value (as a 2023-03-28T14:45:29,074 **transitional** measure), but please note that future releases of setuptools will 2023-03-28T14:45:29,074 follow strictly the standard. 2023-03-28T14:45:29,075 To prevent this warning, you can list 'readme' under `dynamic` or alternatively 2023-03-28T14:45:29,075 remove the `[project]` table from your file and rely entirely on other means of 2023-03-28T14:45:29,076 configuration. 2023-03-28T14:45:29,077 !! 2023-03-28T14:45:29,077 warnings.warn(msg, _WouldIgnoreField) 2023-03-28T14:45:29,674 running bdist_wheel 2023-03-28T14:45:29,710 running build 2023-03-28T14:45:29,711 running build_py 2023-03-28T14:45:29,722 creating build 2023-03-28T14:45:29,723 creating build/lib 2023-03-28T14:45:29,724 creating build/lib/kcapi 2023-03-28T14:45:29,726 copying kcapi/oid.py -> build/lib/kcapi 2023-03-28T14:45:29,731 copying kcapi/sso.py -> build/lib/kcapi 2023-03-28T14:45:29,734 copying kcapi/__init__.py -> build/lib/kcapi 2023-03-28T14:45:29,740 creating build/lib/kcapi/rest 2023-03-28T14:45:29,742 copying kcapi/rest/url.py -> build/lib/kcapi/rest 2023-03-28T14:45:29,746 copying kcapi/rest/resp.py -> build/lib/kcapi/rest 2023-03-28T14:45:29,749 copying kcapi/rest/realms.py -> build/lib/kcapi/rest 2023-03-28T14:45:29,752 copying kcapi/rest/users.py -> build/lib/kcapi/rest 2023-03-28T14:45:29,756 copying kcapi/rest/targets.py -> build/lib/kcapi/rest 2023-03-28T14:45:29,759 copying kcapi/rest/roles.py -> build/lib/kcapi/rest 2023-03-28T14:45:29,763 copying kcapi/rest/crud.py -> build/lib/kcapi/rest 2023-03-28T14:45:29,766 copying kcapi/rest/auth_flows.py -> build/lib/kcapi/rest 2023-03-28T14:45:29,770 copying kcapi/rest/idp.py -> build/lib/kcapi/rest 2023-03-28T14:45:29,773 copying kcapi/rest/helper.py -> build/lib/kcapi/rest 2023-03-28T14:45:29,777 copying kcapi/rest/groups.py -> build/lib/kcapi/rest 2023-03-28T14:45:29,780 copying kcapi/rest/recovery.py -> build/lib/kcapi/rest 2023-03-28T14:45:29,784 copying kcapi/rest/clients.py -> build/lib/kcapi/rest 2023-03-28T14:45:29,787 copying kcapi/rest/__init__.py -> build/lib/kcapi/rest 2023-03-28T14:45:29,792 creating build/lib/kcapi/ie 2023-03-28T14:45:29,794 copying kcapi/ie/auth_flows.py -> build/lib/kcapi/ie 2023-03-28T14:45:29,798 copying kcapi/ie/flows_publisher.py -> build/lib/kcapi/ie 2023-03-28T14:45:29,802 copying kcapi/ie/__init__.py -> build/lib/kcapi/ie 2023-03-28T14:45:29,825 installing to build/bdist.linux-armv7l/wheel 2023-03-28T14:45:29,826 running install 2023-03-28T14:45:29,886 running install_lib 2023-03-28T14:45:29,896 creating build/bdist.linux-armv7l 2023-03-28T14:45:29,897 creating build/bdist.linux-armv7l/wheel 2023-03-28T14:45:29,901 creating build/bdist.linux-armv7l/wheel/kcapi 2023-03-28T14:45:29,904 copying build/lib/kcapi/oid.py -> build/bdist.linux-armv7l/wheel/kcapi 2023-03-28T14:45:29,910 creating build/bdist.linux-armv7l/wheel/kcapi/ie 2023-03-28T14:45:29,912 copying build/lib/kcapi/ie/auth_flows.py -> build/bdist.linux-armv7l/wheel/kcapi/ie 2023-03-28T14:45:29,916 copying build/lib/kcapi/ie/flows_publisher.py -> build/bdist.linux-armv7l/wheel/kcapi/ie 2023-03-28T14:45:29,921 copying build/lib/kcapi/ie/__init__.py -> build/bdist.linux-armv7l/wheel/kcapi/ie 2023-03-28T14:45:29,926 creating build/bdist.linux-armv7l/wheel/kcapi/rest 2023-03-28T14:45:29,928 copying build/lib/kcapi/rest/url.py -> build/bdist.linux-armv7l/wheel/kcapi/rest 2023-03-28T14:45:29,932 copying build/lib/kcapi/rest/resp.py -> build/bdist.linux-armv7l/wheel/kcapi/rest 2023-03-28T14:45:29,936 copying build/lib/kcapi/rest/realms.py -> build/bdist.linux-armv7l/wheel/kcapi/rest 2023-03-28T14:45:29,940 copying build/lib/kcapi/rest/users.py -> build/bdist.linux-armv7l/wheel/kcapi/rest 2023-03-28T14:45:29,943 copying build/lib/kcapi/rest/targets.py -> build/bdist.linux-armv7l/wheel/kcapi/rest 2023-03-28T14:45:29,947 copying build/lib/kcapi/rest/roles.py -> build/bdist.linux-armv7l/wheel/kcapi/rest 2023-03-28T14:45:29,951 copying build/lib/kcapi/rest/crud.py -> build/bdist.linux-armv7l/wheel/kcapi/rest 2023-03-28T14:45:29,955 copying build/lib/kcapi/rest/auth_flows.py -> build/bdist.linux-armv7l/wheel/kcapi/rest 2023-03-28T14:45:29,959 copying build/lib/kcapi/rest/idp.py -> build/bdist.linux-armv7l/wheel/kcapi/rest 2023-03-28T14:45:29,963 copying build/lib/kcapi/rest/helper.py -> build/bdist.linux-armv7l/wheel/kcapi/rest 2023-03-28T14:45:29,966 copying build/lib/kcapi/rest/groups.py -> build/bdist.linux-armv7l/wheel/kcapi/rest 2023-03-28T14:45:29,970 copying build/lib/kcapi/rest/recovery.py -> build/bdist.linux-armv7l/wheel/kcapi/rest 2023-03-28T14:45:29,974 copying build/lib/kcapi/rest/clients.py -> build/bdist.linux-armv7l/wheel/kcapi/rest 2023-03-28T14:45:29,978 copying build/lib/kcapi/rest/__init__.py -> build/bdist.linux-armv7l/wheel/kcapi/rest 2023-03-28T14:45:29,982 copying build/lib/kcapi/sso.py -> build/bdist.linux-armv7l/wheel/kcapi 2023-03-28T14:45:29,986 copying build/lib/kcapi/__init__.py -> build/bdist.linux-armv7l/wheel/kcapi 2023-03-28T14:45:29,989 running install_egg_info 2023-03-28T14:45:30,007 running egg_info 2023-03-28T14:45:30,016 writing kcapi.egg-info/PKG-INFO 2023-03-28T14:45:30,021 writing dependency_links to kcapi.egg-info/dependency_links.txt 2023-03-28T14:45:30,025 writing requirements to kcapi.egg-info/requires.txt 2023-03-28T14:45:30,027 writing top-level names to kcapi.egg-info/top_level.txt 2023-03-28T14:45:30,049 reading manifest file 'kcapi.egg-info/SOURCES.txt' 2023-03-28T14:45:30,055 adding license file 'LICENSE' 2023-03-28T14:45:30,064 writing manifest file 'kcapi.egg-info/SOURCES.txt' 2023-03-28T14:45:30,067 Copying kcapi.egg-info to build/bdist.linux-armv7l/wheel/kcapi-1.1.1-py3.7.egg-info 2023-03-28T14:45:30,093 running install_scripts 2023-03-28T14:45:30,129 creating build/bdist.linux-armv7l/wheel/kcapi-1.1.1.dist-info/WHEEL 2023-03-28T14:45:30,135 creating '/tmp/pip-wheel-9d5fb4li/.tmp-ynfvmhy5/kcapi-1.1.1-py3-none-any.whl' and adding 'build/bdist.linux-armv7l/wheel' to it 2023-03-28T14:45:30,140 adding 'kcapi/__init__.py' 2023-03-28T14:45:30,143 adding 'kcapi/oid.py' 2023-03-28T14:45:30,146 adding 'kcapi/sso.py' 2023-03-28T14:45:30,149 adding 'kcapi/ie/__init__.py' 2023-03-28T14:45:30,153 adding 'kcapi/ie/auth_flows.py' 2023-03-28T14:45:30,155 adding 'kcapi/ie/flows_publisher.py' 2023-03-28T14:45:30,159 adding 'kcapi/rest/__init__.py' 2023-03-28T14:45:30,162 adding 'kcapi/rest/auth_flows.py' 2023-03-28T14:45:30,165 adding 'kcapi/rest/clients.py' 2023-03-28T14:45:30,167 adding 'kcapi/rest/crud.py' 2023-03-28T14:45:30,171 adding 'kcapi/rest/groups.py' 2023-03-28T14:45:30,173 adding 'kcapi/rest/helper.py' 2023-03-28T14:45:30,175 adding 'kcapi/rest/idp.py' 2023-03-28T14:45:30,178 adding 'kcapi/rest/realms.py' 2023-03-28T14:45:30,181 adding 'kcapi/rest/recovery.py' 2023-03-28T14:45:30,183 adding 'kcapi/rest/resp.py' 2023-03-28T14:45:30,186 adding 'kcapi/rest/roles.py' 2023-03-28T14:45:30,189 adding 'kcapi/rest/targets.py' 2023-03-28T14:45:30,192 adding 'kcapi/rest/url.py' 2023-03-28T14:45:30,195 adding 'kcapi/rest/users.py' 2023-03-28T14:45:30,200 adding 'kcapi-1.1.1.dist-info/LICENSE' 2023-03-28T14:45:30,204 adding 'kcapi-1.1.1.dist-info/METADATA' 2023-03-28T14:45:30,206 adding 'kcapi-1.1.1.dist-info/WHEEL' 2023-03-28T14:45:30,208 adding 'kcapi-1.1.1.dist-info/top_level.txt' 2023-03-28T14:45:30,211 adding 'kcapi-1.1.1.dist-info/RECORD' 2023-03-28T14:45:30,214 removing build/bdist.linux-armv7l/wheel 2023-03-28T14:45:30,234 /tmp/pip-build-env-l3g9wwkp/overlay/lib/python3.7/site-packages/setuptools/config/_apply_pyprojecttoml.py:103: _WouldIgnoreField: 'license' defined outside of `pyproject.toml` would be ignored. 2023-03-28T14:45:30,235 !! 2023-03-28T14:45:30,236 ########################################################################## 2023-03-28T14:45:30,236 # configuration would be ignored/result in error due to `pyproject.toml` # 2023-03-28T14:45:30,237 ########################################################################## 2023-03-28T14:45:30,238 The following seems to be defined outside of `pyproject.toml`: 2023-03-28T14:45:30,239 `license = 'MIT'` 2023-03-28T14:45:30,240 According to the spec (see the link below), however, setuptools CANNOT 2023-03-28T14:45:30,240 consider this value unless 'license' is listed as `dynamic`. 2023-03-28T14:45:30,241 https://packaging.python.org/en/latest/specifications/declaring-project-metadata/ 2023-03-28T14:45:30,242 For the time being, `setuptools` will still consider the given value (as a 2023-03-28T14:45:30,243 **transitional** measure), but please note that future releases of setuptools will 2023-03-28T14:45:30,243 follow strictly the standard. 2023-03-28T14:45:30,244 To prevent this warning, you can list 'license' under `dynamic` or alternatively 2023-03-28T14:45:30,244 remove the `[project]` table from your file and rely entirely on other means of 2023-03-28T14:45:30,245 configuration. 2023-03-28T14:45:30,246 !! 2023-03-28T14:45:30,247 warnings.warn(msg, _WouldIgnoreField) 2023-03-28T14:45:30,248 /tmp/pip-build-env-l3g9wwkp/overlay/lib/python3.7/site-packages/setuptools/config/_apply_pyprojecttoml.py:103: _WouldIgnoreField: 'dependencies' defined outside of `pyproject.toml` would be ignored. 2023-03-28T14:45:30,248 !! 2023-03-28T14:45:30,249 ########################################################################## 2023-03-28T14:45:30,250 # configuration would be ignored/result in error due to `pyproject.toml` # 2023-03-28T14:45:30,250 ########################################################################## 2023-03-28T14:45:30,251 The following seems to be defined outside of `pyproject.toml`: 2023-03-28T14:45:30,252 `dependencies = ['requests']` 2023-03-28T14:45:30,253 According to the spec (see the link below), however, setuptools CANNOT 2023-03-28T14:45:30,253 consider this value unless 'dependencies' is listed as `dynamic`. 2023-03-28T14:45:30,254 https://packaging.python.org/en/latest/specifications/declaring-project-metadata/ 2023-03-28T14:45:30,255 For the time being, `setuptools` will still consider the given value (as a 2023-03-28T14:45:30,255 **transitional** measure), but please note that future releases of setuptools will 2023-03-28T14:45:30,256 follow strictly the standard. 2023-03-28T14:45:30,256 To prevent this warning, you can list 'dependencies' under `dynamic` or alternatively 2023-03-28T14:45:30,257 remove the `[project]` table from your file and rely entirely on other means of 2023-03-28T14:45:30,257 configuration. 2023-03-28T14:45:30,258 !! 2023-03-28T14:45:30,259 warnings.warn(msg, _WouldIgnoreField) 2023-03-28T14:45:30,412 Building wheel for kcapi (pyproject.toml): finished with status 'done' 2023-03-28T14:45:30,425 Created wheel for kcapi: filename=kcapi-1.1.1-py3-none-any.whl size=21499 sha256=c7b20c8e05ba72b52f5d01568ecdae532c5817a48cda4c2608718098e698a70f 2023-03-28T14:45:30,427 Stored in directory: /tmp/pip-ephem-wheel-cache-mo7pw819/wheels/38/1e/d6/508046de6e88ceafaeadcfbd0698b0da7e655beabba4a23758 2023-03-28T14:45:30,458 Successfully built kcapi 2023-03-28T14:45:30,467 Removed build tracker: '/tmp/pip-build-tracker-d8r43s2m'