2023-02-20T11:51:24,143 Created temporary directory: /tmp/pip-ephem-wheel-cache-7wh3ds5w
2023-02-20T11:51:24,148 Created temporary directory: /tmp/pip-build-tracker-s8kz9h7v
2023-02-20T11:51:24,149 Initialized build tracking at /tmp/pip-build-tracker-s8kz9h7v
2023-02-20T11:51:24,149 Created build tracker: /tmp/pip-build-tracker-s8kz9h7v
2023-02-20T11:51:24,149 Entered build tracker: /tmp/pip-build-tracker-s8kz9h7v
2023-02-20T11:51:24,151 Created temporary directory: /tmp/pip-wheel-9i1zrf8e
2023-02-20T11:51:24,159 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-02-20T11:51:24,164 Created temporary directory: /tmp/pip-ephem-wheel-cache-jsdufbcu
2023-02-20T11:51:24,214 Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
2023-02-20T11:51:24,222 2 location(s) to search for versions of kcapi:
2023-02-20T11:51:24,222 * https://pypi.org/simple/kcapi/
2023-02-20T11:51:24,222 * https://www.piwheels.org/simple/kcapi/
2023-02-20T11:51:24,223 Fetching project page and analyzing links: https://pypi.org/simple/kcapi/
2023-02-20T11:51:24,224 Getting page https://pypi.org/simple/kcapi/
2023-02-20T11:51:24,227 Found index url https://pypi.org/simple
2023-02-20T11:51:24,469 Fetched page https://pypi.org/simple/kcapi/ as application/vnd.pypi.simple.v1+json
2023-02-20T11:51:24,507 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-02-20T11:51:24,507 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-02-20T11:51:24,508 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-02-20T11:51:24,509 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-02-20T11:51:24,510 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-02-20T11:51:24,510 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-02-20T11:51:24,511 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-02-20T11:51:24,512 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-02-20T11:51:24,512 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-02-20T11:51:24,513 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-02-20T11:51:24,513 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-02-20T11:51:24,514 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-02-20T11:51:24,515 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-02-20T11:51:24,515 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-02-20T11:51:24,516 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-02-20T11:51:24,517 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-02-20T11:51:24,517 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-02-20T11:51:24,518 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-02-20T11:51:24,518 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-02-20T11:51:24,519 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-02-20T11:51:24,519 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-02-20T11:51:24,520 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-02-20T11:51:24,521 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-02-20T11:51:24,521 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-02-20T11:51:24,522 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-02-20T11:51:24,522 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-02-20T11:51:24,523 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-02-20T11:51:24,524 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-02-20T11:51:24,524 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-02-20T11:51:24,525 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-02-20T11:51:24,525 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-02-20T11:51:24,526 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-02-20T11:51:24,527 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-02-20T11:51:24,527 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-02-20T11:51:24,528 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-02-20T11:51:24,529 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-02-20T11:51:24,529 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-02-20T11:51:24,530 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-02-20T11:51:24,530 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-02-20T11:51:24,531 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-02-20T11:51:24,532 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-02-20T11:51:24,533 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-02-20T11:51:24,533 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-02-20T11:51:24,534 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-02-20T11:51:24,534 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-02-20T11:51:24,535 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-02-20T11:51:24,536 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-02-20T11:51:24,536 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-02-20T11:51:24,537 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-02-20T11:51:24,537 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-02-20T11:51:24,538 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-02-20T11:51:24,539 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-02-20T11:51:24,539 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-02-20T11:51:24,540 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-02-20T11:51:24,540 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-02-20T11:51:24,541 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-02-20T11:51:24,542 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-02-20T11:51:24,542 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-02-20T11:51:24,543 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-02-20T11:51:24,543 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-02-20T11:51:24,544 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-02-20T11:51:24,545 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-02-20T11:51:24,545 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-02-20T11:51:24,546 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-02-20T11:51:24,546 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-02-20T11:51:24,547 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-02-20T11:51:24,547 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-02-20T11:51:24,548 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-02-20T11:51:24,549 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-02-20T11:51:24,549 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-02-20T11:51:24,550 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-02-20T11:51:24,550 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-02-20T11:51:24,551 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-02-20T11:51:24,552 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-02-20T11:51:24,552 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-02-20T11:51:24,553 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-02-20T11:51:24,554 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-02-20T11:51:24,555 Fetching project page and analyzing links: https://www.piwheels.org/simple/kcapi/
2023-02-20T11:51:24,556 Getting page https://www.piwheels.org/simple/kcapi/
2023-02-20T11:51:24,558 Found index url https://www.piwheels.org/simple
2023-02-20T11:51:24,787 Fetched page https://www.piwheels.org/simple/kcapi/ as text/html
2023-02-20T11:51:24,815 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-02-20T11:51:24,816 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-02-20T11:51:24,817 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-02-20T11:51:24,817 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-02-20T11:51:24,818 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-02-20T11:51:24,818 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-02-20T11:51:24,819 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-02-20T11:51:24,819 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-02-20T11:51:24,820 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-02-20T11:51:24,820 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-02-20T11:51:24,821 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-02-20T11:51:24,821 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-02-20T11:51:24,822 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-02-20T11:51:24,822 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-02-20T11:51:24,823 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-02-20T11:51:24,824 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-02-20T11:51:24,824 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-02-20T11:51:24,825 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-02-20T11:51:24,825 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-02-20T11:51:24,826 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-02-20T11:51:24,826 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-02-20T11:51:24,827 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-02-20T11:51:24,827 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-02-20T11:51:24,828 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-02-20T11:51:24,828 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-02-20T11:51:24,829 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-02-20T11:51:24,829 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-02-20T11:51:24,830 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-02-20T11:51:24,830 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-02-20T11:51:24,831 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-02-20T11:51:24,831 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-02-20T11:51:24,832 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-02-20T11:51:24,832 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-02-20T11:51:24,833 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-02-20T11:51:24,833 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-02-20T11:51:24,834 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-02-20T11:51:24,834 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-02-20T11:51:24,835 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-02-20T11:51:24,835 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-02-20T11:51:24,836 Skipping link: not a file: https://www.piwheels.org/simple/kcapi/
2023-02-20T11:51:24,837 Skipping link: not a file: https://pypi.org/simple/kcapi/
2023-02-20T11:51:24,884 Given no hashes to check 1 links for project 'kcapi': discarding no candidates
2023-02-20T11:51:24,915 Collecting kcapi==1.1.0
2023-02-20T11:51:24,919 Created temporary directory: /tmp/pip-unpack-vhnuxsez
2023-02-20T11:51:25,153 Downloading kcapi-1.1.0.tar.gz (29 kB)
2023-02-20T11:51:25,360 Added kcapi==1.1.0 from https://files.pythonhosted.org/packages/a0/7b/835a85b6268ae6f56b5a8fe1f6c88e6a27ef7fd4d150d43c0a3d49c42a60/kcapi-1.1.0.tar.gz to build tracker '/tmp/pip-build-tracker-s8kz9h7v'
2023-02-20T11:51:25,369 Created temporary directory: /tmp/pip-build-env-9bvwx8_y
2023-02-20T11:51:25,381 Installing build dependencies: started
2023-02-20T11:51:25,383 Running command pip subprocess to install build dependencies
2023-02-20T11:51:28,131 Using pip 23.0 from /home/piwheels/.local/lib/python3.7/site-packages/pip (python 3.7)
2023-02-20T11:51:28,944 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-02-20T11:51:28,998 Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
2023-02-20T11:51:32,816 Collecting setuptools>=61.0
2023-02-20T11:51:32,871 Using cached setuptools-67.3.2-py3-none-any.whl (1.1 MB)
2023-02-20T11:51:38,446 Installing collected packages: setuptools
2023-02-20T11:51:42,710 Successfully installed setuptools-67.3.2
2023-02-20T11:51:43,149 Installing build dependencies: finished with status 'done'
2023-02-20T11:51:43,161 Getting requirements to build wheel: started
2023-02-20T11:51:43,163 Running command Getting requirements to build wheel
2023-02-20T11:51:44,430 /tmp/pip-build-env-9bvwx8_y/overlay/lib/python3.7/site-packages/setuptools/config/_apply_pyprojecttoml.py:103: _WouldIgnoreField: 'readme' defined outside of `pyproject.toml` would be ignored.
2023-02-20T11:51:44,431 !!
2023-02-20T11:51:44,432 ##########################################################################
2023-02-20T11:51:44,433 # configuration would be ignored/result in error due to `pyproject.toml` #
2023-02-20T11:51:44,433 ##########################################################################
2023-02-20T11:51:44,434 The following seems to be defined outside of `pyproject.toml`:
2023-02-20T11:51:44,435 `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 provides 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 is a shortcut static method in order to get an admin token from 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({"key":"username", "value": \'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###\xa0Users\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'`
2023-02-20T11:51:44,436 According to the spec (see the link below), however, setuptools CANNOT
2023-02-20T11:51:44,436 consider this value unless 'readme' is listed as `dynamic`.
2023-02-20T11:51:44,437 https://packaging.python.org/en/latest/specifications/declaring-project-metadata/
2023-02-20T11:51:44,437 For the time being, `setuptools` will still consider the given value (as a
2023-02-20T11:51:44,438 **transitional** measure), but please note that future releases of setuptools will
2023-02-20T11:51:44,438 follow strictly the standard.
2023-02-20T11:51:44,439 To prevent this warning, you can list 'readme' under `dynamic` or alternatively
2023-02-20T11:51:44,439 remove the `[project]` table from your file and rely entirely on other means of
2023-02-20T11:51:44,439 configuration.
2023-02-20T11:51:44,440 !!
2023-02-20T11:51:44,441 warnings.warn(msg, _WouldIgnoreField)
2023-02-20T11:51:44,992 running egg_info
2023-02-20T11:51:45,002 writing kcapi.egg-info/PKG-INFO
2023-02-20T11:51:45,007 writing dependency_links to kcapi.egg-info/dependency_links.txt
2023-02-20T11:51:45,012 writing requirements to kcapi.egg-info/requires.txt
2023-02-20T11:51:45,014 writing top-level names to kcapi.egg-info/top_level.txt
2023-02-20T11:51:45,055 reading manifest file 'kcapi.egg-info/SOURCES.txt'
2023-02-20T11:51:45,061 adding license file 'LICENSE'
2023-02-20T11:51:45,070 writing manifest file 'kcapi.egg-info/SOURCES.txt'
2023-02-20T11:51:45,073 /tmp/pip-build-env-9bvwx8_y/overlay/lib/python3.7/site-packages/setuptools/config/_apply_pyprojecttoml.py:103: _WouldIgnoreField: 'license' defined outside of `pyproject.toml` would be ignored.
2023-02-20T11:51:45,074 !!
2023-02-20T11:51:45,075 ##########################################################################
2023-02-20T11:51:45,076 # configuration would be ignored/result in error due to `pyproject.toml` #
2023-02-20T11:51:45,076 ##########################################################################
2023-02-20T11:51:45,077 The following seems to be defined outside of `pyproject.toml`:
2023-02-20T11:51:45,078 `license = 'MIT'`
2023-02-20T11:51:45,079 According to the spec (see the link below), however, setuptools CANNOT
2023-02-20T11:51:45,079 consider this value unless 'license' is listed as `dynamic`.
2023-02-20T11:51:45,080 https://packaging.python.org/en/latest/specifications/declaring-project-metadata/
2023-02-20T11:51:45,081 For the time being, `setuptools` will still consider the given value (as a
2023-02-20T11:51:45,082 **transitional** measure), but please note that future releases of setuptools will
2023-02-20T11:51:45,082 follow strictly the standard.
2023-02-20T11:51:45,083 To prevent this warning, you can list 'license' under `dynamic` or alternatively
2023-02-20T11:51:45,084 remove the `[project]` table from your file and rely entirely on other means of
2023-02-20T11:51:45,084 configuration.
2023-02-20T11:51:45,085 !!
2023-02-20T11:51:45,086 warnings.warn(msg, _WouldIgnoreField)
2023-02-20T11:51:45,087 /tmp/pip-build-env-9bvwx8_y/overlay/lib/python3.7/site-packages/setuptools/config/_apply_pyprojecttoml.py:103: _WouldIgnoreField: 'dependencies' defined outside of `pyproject.toml` would be ignored.
2023-02-20T11:51:45,087 !!
2023-02-20T11:51:45,088 ##########################################################################
2023-02-20T11:51:45,089 # configuration would be ignored/result in error due to `pyproject.toml` #
2023-02-20T11:51:45,089 ##########################################################################
2023-02-20T11:51:45,090 The following seems to be defined outside of `pyproject.toml`:
2023-02-20T11:51:45,091 `dependencies = ['requests']`
2023-02-20T11:51:45,092 According to the spec (see the link below), however, setuptools CANNOT
2023-02-20T11:51:45,092 consider this value unless 'dependencies' is listed as `dynamic`.
2023-02-20T11:51:45,093 https://packaging.python.org/en/latest/specifications/declaring-project-metadata/
2023-02-20T11:51:45,094 For the time being, `setuptools` will still consider the given value (as a
2023-02-20T11:51:45,094 **transitional** measure), but please note that future releases of setuptools will
2023-02-20T11:51:45,094 follow strictly the standard.
2023-02-20T11:51:45,095 To prevent this warning, you can list 'dependencies' under `dynamic` or alternatively
2023-02-20T11:51:45,096 remove the `[project]` table from your file and rely entirely on other means of
2023-02-20T11:51:45,096 configuration.
2023-02-20T11:51:45,097 !!
2023-02-20T11:51:45,098 warnings.warn(msg, _WouldIgnoreField)
2023-02-20T11:51:45,239 Getting requirements to build wheel: finished with status 'done'
2023-02-20T11:51:45,264 Installing backend dependencies: started
2023-02-20T11:51:45,266 Running command pip subprocess to install backend dependencies
2023-02-20T11:51:47,968 Using pip 23.0 from /home/piwheels/.local/lib/python3.7/site-packages/pip (python 3.7)
2023-02-20T11:51:48,766 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-02-20T11:51:48,820 Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
2023-02-20T11:51:49,693 Collecting wheel
2023-02-20T11:51:49,728 Using cached https://www.piwheels.org/simple/wheel/wheel-0.38.4-py3-none-any.whl (36 kB)
2023-02-20T11:51:54,510 Installing collected packages: wheel
2023-02-20T11:51:54,790 Creating /tmp/pip-build-env-9bvwx8_y/normal/bin
2023-02-20T11:51:54,795 changing mode of /tmp/pip-build-env-9bvwx8_y/normal/bin/wheel to 755
2023-02-20T11:51:54,827 Successfully installed wheel-0.38.4
2023-02-20T11:51:55,216 Installing backend dependencies: finished with status 'done'
2023-02-20T11:51:55,222 Created temporary directory: /tmp/pip-modern-metadata-_guef3tr
2023-02-20T11:51:55,228 Preparing metadata (pyproject.toml): started
2023-02-20T11:51:55,230 Running command Preparing metadata (pyproject.toml)
2023-02-20T11:51:56,439 /tmp/pip-build-env-9bvwx8_y/overlay/lib/python3.7/site-packages/setuptools/config/_apply_pyprojecttoml.py:103: _WouldIgnoreField: 'readme' defined outside of `pyproject.toml` would be ignored.
2023-02-20T11:51:56,441 !!
2023-02-20T11:51:56,442 ##########################################################################
2023-02-20T11:51:56,442 # configuration would be ignored/result in error due to `pyproject.toml` #
2023-02-20T11:51:56,442 ##########################################################################
2023-02-20T11:51:56,443 The following seems to be defined outside of `pyproject.toml`:
2023-02-20T11:51:56,444 `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 provides 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 is a shortcut static method in order to get an admin token from 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({"key":"username", "value": \'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###\xa0Users\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'`
2023-02-20T11:51:56,445 According to the spec (see the link below), however, setuptools CANNOT
2023-02-20T11:51:56,446 consider this value unless 'readme' is listed as `dynamic`.
2023-02-20T11:51:56,446 https://packaging.python.org/en/latest/specifications/declaring-project-metadata/
2023-02-20T11:51:56,447 For the time being, `setuptools` will still consider the given value (as a
2023-02-20T11:51:56,447 **transitional** measure), but please note that future releases of setuptools will
2023-02-20T11:51:56,447 follow strictly the standard.
2023-02-20T11:51:56,448 To prevent this warning, you can list 'readme' under `dynamic` or alternatively
2023-02-20T11:51:56,448 remove the `[project]` table from your file and rely entirely on other means of
2023-02-20T11:51:56,449 configuration.
2023-02-20T11:51:56,450 !!
2023-02-20T11:51:56,450 warnings.warn(msg, _WouldIgnoreField)
2023-02-20T11:51:57,054 running dist_info
2023-02-20T11:51:57,066 creating /tmp/pip-modern-metadata-_guef3tr/kcapi.egg-info
2023-02-20T11:51:57,075 writing /tmp/pip-modern-metadata-_guef3tr/kcapi.egg-info/PKG-INFO
2023-02-20T11:51:57,081 writing dependency_links to /tmp/pip-modern-metadata-_guef3tr/kcapi.egg-info/dependency_links.txt
2023-02-20T11:51:57,086 writing requirements to /tmp/pip-modern-metadata-_guef3tr/kcapi.egg-info/requires.txt
2023-02-20T11:51:57,088 writing top-level names to /tmp/pip-modern-metadata-_guef3tr/kcapi.egg-info/top_level.txt
2023-02-20T11:51:57,091 writing manifest file '/tmp/pip-modern-metadata-_guef3tr/kcapi.egg-info/SOURCES.txt'
2023-02-20T11:51:57,137 reading manifest file '/tmp/pip-modern-metadata-_guef3tr/kcapi.egg-info/SOURCES.txt'
2023-02-20T11:51:57,142 adding license file 'LICENSE'
2023-02-20T11:51:57,149 writing manifest file '/tmp/pip-modern-metadata-_guef3tr/kcapi.egg-info/SOURCES.txt'
2023-02-20T11:51:57,151 creating '/tmp/pip-modern-metadata-_guef3tr/kcapi-1.1.0.dist-info'
2023-02-20T11:51:57,232 /tmp/pip-build-env-9bvwx8_y/overlay/lib/python3.7/site-packages/setuptools/config/_apply_pyprojecttoml.py:103: _WouldIgnoreField: 'license' defined outside of `pyproject.toml` would be ignored.
2023-02-20T11:51:57,233 !!
2023-02-20T11:51:57,234 ##########################################################################
2023-02-20T11:51:57,234 # configuration would be ignored/result in error due to `pyproject.toml` #
2023-02-20T11:51:57,235 ##########################################################################
2023-02-20T11:51:57,236 The following seems to be defined outside of `pyproject.toml`:
2023-02-20T11:51:57,237 `license = 'MIT'`
2023-02-20T11:51:57,237 According to the spec (see the link below), however, setuptools CANNOT
2023-02-20T11:51:57,238 consider this value unless 'license' is listed as `dynamic`.
2023-02-20T11:51:57,239 https://packaging.python.org/en/latest/specifications/declaring-project-metadata/
2023-02-20T11:51:57,240 For the time being, `setuptools` will still consider the given value (as a
2023-02-20T11:51:57,240 **transitional** measure), but please note that future releases of setuptools will
2023-02-20T11:51:57,241 follow strictly the standard.
2023-02-20T11:51:57,241 To prevent this warning, you can list 'license' under `dynamic` or alternatively
2023-02-20T11:51:57,242 remove the `[project]` table from your file and rely entirely on other means of
2023-02-20T11:51:57,242 configuration.
2023-02-20T11:51:57,244 !!
2023-02-20T11:51:57,245 warnings.warn(msg, _WouldIgnoreField)
2023-02-20T11:51:57,245 /tmp/pip-build-env-9bvwx8_y/overlay/lib/python3.7/site-packages/setuptools/config/_apply_pyprojecttoml.py:103: _WouldIgnoreField: 'dependencies' defined outside of `pyproject.toml` would be ignored.
2023-02-20T11:51:57,246 !!
2023-02-20T11:51:57,247 ##########################################################################
2023-02-20T11:51:57,247 # configuration would be ignored/result in error due to `pyproject.toml` #
2023-02-20T11:51:57,248 ##########################################################################
2023-02-20T11:51:57,248 The following seems to be defined outside of `pyproject.toml`:
2023-02-20T11:51:57,249 `dependencies = ['requests']`
2023-02-20T11:51:57,250 According to the spec (see the link below), however, setuptools CANNOT
2023-02-20T11:51:57,250 consider this value unless 'dependencies' is listed as `dynamic`.
2023-02-20T11:51:57,251 https://packaging.python.org/en/latest/specifications/declaring-project-metadata/
2023-02-20T11:51:57,252 For the time being, `setuptools` will still consider the given value (as a
2023-02-20T11:51:57,252 **transitional** measure), but please note that future releases of setuptools will
2023-02-20T11:51:57,253 follow strictly the standard.
2023-02-20T11:51:57,253 To prevent this warning, you can list 'dependencies' under `dynamic` or alternatively
2023-02-20T11:51:57,254 remove the `[project]` table from your file and rely entirely on other means of
2023-02-20T11:51:57,254 configuration.
2023-02-20T11:51:57,255 !!
2023-02-20T11:51:57,256 warnings.warn(msg, _WouldIgnoreField)
2023-02-20T11:51:57,404 Preparing metadata (pyproject.toml): finished with status 'done'
2023-02-20T11:51:57,422 Source in /tmp/pip-wheel-9i1zrf8e/kcapi_802ddbe35131464986f1da6137a0f148 has version 1.1.0, which satisfies requirement kcapi==1.1.0 from https://files.pythonhosted.org/packages/a0/7b/835a85b6268ae6f56b5a8fe1f6c88e6a27ef7fd4d150d43c0a3d49c42a60/kcapi-1.1.0.tar.gz
2023-02-20T11:51:57,424 Removed kcapi==1.1.0 from https://files.pythonhosted.org/packages/a0/7b/835a85b6268ae6f56b5a8fe1f6c88e6a27ef7fd4d150d43c0a3d49c42a60/kcapi-1.1.0.tar.gz from build tracker '/tmp/pip-build-tracker-s8kz9h7v'
2023-02-20T11:51:57,442 Created temporary directory: /tmp/pip-unpack-vpy0nkdh
2023-02-20T11:51:57,443 Building wheels for collected packages: kcapi
2023-02-20T11:51:57,453 Created temporary directory: /tmp/pip-wheel-9ytdm_6m
2023-02-20T11:51:57,453 Destination directory: /tmp/pip-wheel-9ytdm_6m
2023-02-20T11:51:57,458 Building wheel for kcapi (pyproject.toml): started
2023-02-20T11:51:57,461 Running command Building wheel for kcapi (pyproject.toml)
2023-02-20T11:51:58,626 /tmp/pip-build-env-9bvwx8_y/overlay/lib/python3.7/site-packages/setuptools/config/_apply_pyprojecttoml.py:103: _WouldIgnoreField: 'readme' defined outside of `pyproject.toml` would be ignored.
2023-02-20T11:51:58,627 !!
2023-02-20T11:51:58,628 ##########################################################################
2023-02-20T11:51:58,628 # configuration would be ignored/result in error due to `pyproject.toml` #
2023-02-20T11:51:58,629 ##########################################################################
2023-02-20T11:51:58,629 The following seems to be defined outside of `pyproject.toml`:
2023-02-20T11:51:58,630 `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 provides 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 is a shortcut static method in order to get an admin token from 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({"key":"username", "value": \'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###\xa0Users\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'`
2023-02-20T11:51:58,631 According to the spec (see the link below), however, setuptools CANNOT
2023-02-20T11:51:58,632 consider this value unless 'readme' is listed as `dynamic`.
2023-02-20T11:51:58,632 https://packaging.python.org/en/latest/specifications/declaring-project-metadata/
2023-02-20T11:51:58,633 For the time being, `setuptools` will still consider the given value (as a
2023-02-20T11:51:58,633 **transitional** measure), but please note that future releases of setuptools will
2023-02-20T11:51:58,634 follow strictly the standard.
2023-02-20T11:51:58,634 To prevent this warning, you can list 'readme' under `dynamic` or alternatively
2023-02-20T11:51:58,635 remove the `[project]` table from your file and rely entirely on other means of
2023-02-20T11:51:58,635 configuration.
2023-02-20T11:51:58,636 !!
2023-02-20T11:51:58,636 warnings.warn(msg, _WouldIgnoreField)
2023-02-20T11:51:59,192 running bdist_wheel
2023-02-20T11:51:59,223 running build
2023-02-20T11:51:59,224 running build_py
2023-02-20T11:51:59,235 creating build
2023-02-20T11:51:59,236 creating build/lib
2023-02-20T11:51:59,237 creating build/lib/kcapi
2023-02-20T11:51:59,239 copying kcapi/__init__.py -> build/lib/kcapi
2023-02-20T11:51:59,243 copying kcapi/oid.py -> build/lib/kcapi
2023-02-20T11:51:59,247 copying kcapi/sso.py -> build/lib/kcapi
2023-02-20T11:51:59,253 creating build/lib/kcapi/rest
2023-02-20T11:51:59,255 copying kcapi/rest/__init__.py -> build/lib/kcapi/rest
2023-02-20T11:51:59,258 copying kcapi/rest/crud.py -> build/lib/kcapi/rest
2023-02-20T11:51:59,262 copying kcapi/rest/targets.py -> build/lib/kcapi/rest
2023-02-20T11:51:59,265 copying kcapi/rest/resp.py -> build/lib/kcapi/rest
2023-02-20T11:51:59,268 copying kcapi/rest/auth_flows.py -> build/lib/kcapi/rest
2023-02-20T11:51:59,272 copying kcapi/rest/idp.py -> build/lib/kcapi/rest
2023-02-20T11:51:59,275 copying kcapi/rest/helper.py -> build/lib/kcapi/rest
2023-02-20T11:51:59,279 copying kcapi/rest/users.py -> build/lib/kcapi/rest
2023-02-20T11:51:59,282 copying kcapi/rest/recovery.py -> build/lib/kcapi/rest
2023-02-20T11:51:59,285 copying kcapi/rest/url.py -> build/lib/kcapi/rest
2023-02-20T11:51:59,289 copying kcapi/rest/groups.py -> build/lib/kcapi/rest
2023-02-20T11:51:59,292 copying kcapi/rest/realms.py -> build/lib/kcapi/rest
2023-02-20T11:51:59,296 copying kcapi/rest/roles.py -> build/lib/kcapi/rest
2023-02-20T11:51:59,299 copying kcapi/rest/clients.py -> build/lib/kcapi/rest
2023-02-20T11:51:59,304 creating build/lib/kcapi/ie
2023-02-20T11:51:59,305 copying kcapi/ie/__init__.py -> build/lib/kcapi/ie
2023-02-20T11:51:59,309 copying kcapi/ie/flows_publisher.py -> build/lib/kcapi/ie
2023-02-20T11:51:59,329 copying kcapi/ie/auth_flows.py -> build/lib/kcapi/ie
2023-02-20T11:51:59,354 installing to build/bdist.linux-armv7l/wheel
2023-02-20T11:51:59,354 running install
2023-02-20T11:51:59,416 running install_lib
2023-02-20T11:51:59,426 creating build/bdist.linux-armv7l
2023-02-20T11:51:59,427 creating build/bdist.linux-armv7l/wheel
2023-02-20T11:51:59,431 creating build/bdist.linux-armv7l/wheel/kcapi
2023-02-20T11:51:59,433 copying build/lib/kcapi/__init__.py -> build/bdist.linux-armv7l/wheel/kcapi
2023-02-20T11:51:59,438 creating build/bdist.linux-armv7l/wheel/kcapi/ie
2023-02-20T11:51:59,439 copying build/lib/kcapi/ie/__init__.py -> build/bdist.linux-armv7l/wheel/kcapi/ie
2023-02-20T11:51:59,443 copying build/lib/kcapi/ie/flows_publisher.py -> build/bdist.linux-armv7l/wheel/kcapi/ie
2023-02-20T11:51:59,447 copying build/lib/kcapi/ie/auth_flows.py -> build/bdist.linux-armv7l/wheel/kcapi/ie
2023-02-20T11:51:59,452 creating build/bdist.linux-armv7l/wheel/kcapi/rest
2023-02-20T11:51:59,454 copying build/lib/kcapi/rest/__init__.py -> build/bdist.linux-armv7l/wheel/kcapi/rest
2023-02-20T11:51:59,458 copying build/lib/kcapi/rest/crud.py -> build/bdist.linux-armv7l/wheel/kcapi/rest
2023-02-20T11:51:59,461 copying build/lib/kcapi/rest/targets.py -> build/bdist.linux-armv7l/wheel/kcapi/rest
2023-02-20T11:51:59,465 copying build/lib/kcapi/rest/resp.py -> build/bdist.linux-armv7l/wheel/kcapi/rest
2023-02-20T11:51:59,468 copying build/lib/kcapi/rest/auth_flows.py -> build/bdist.linux-armv7l/wheel/kcapi/rest
2023-02-20T11:51:59,472 copying build/lib/kcapi/rest/idp.py -> build/bdist.linux-armv7l/wheel/kcapi/rest
2023-02-20T11:51:59,476 copying build/lib/kcapi/rest/helper.py -> build/bdist.linux-armv7l/wheel/kcapi/rest
2023-02-20T11:51:59,479 copying build/lib/kcapi/rest/users.py -> build/bdist.linux-armv7l/wheel/kcapi/rest
2023-02-20T11:51:59,483 copying build/lib/kcapi/rest/recovery.py -> build/bdist.linux-armv7l/wheel/kcapi/rest
2023-02-20T11:51:59,487 copying build/lib/kcapi/rest/url.py -> build/bdist.linux-armv7l/wheel/kcapi/rest
2023-02-20T11:51:59,490 copying build/lib/kcapi/rest/groups.py -> build/bdist.linux-armv7l/wheel/kcapi/rest
2023-02-20T11:51:59,494 copying build/lib/kcapi/rest/realms.py -> build/bdist.linux-armv7l/wheel/kcapi/rest
2023-02-20T11:51:59,498 copying build/lib/kcapi/rest/roles.py -> build/bdist.linux-armv7l/wheel/kcapi/rest
2023-02-20T11:51:59,501 copying build/lib/kcapi/rest/clients.py -> build/bdist.linux-armv7l/wheel/kcapi/rest
2023-02-20T11:51:59,505 copying build/lib/kcapi/oid.py -> build/bdist.linux-armv7l/wheel/kcapi
2023-02-20T11:51:59,509 copying build/lib/kcapi/sso.py -> build/bdist.linux-armv7l/wheel/kcapi
2023-02-20T11:51:59,513 running install_egg_info
2023-02-20T11:51:59,529 running egg_info
2023-02-20T11:51:59,542 writing kcapi.egg-info/PKG-INFO
2023-02-20T11:51:59,546 writing dependency_links to kcapi.egg-info/dependency_links.txt
2023-02-20T11:51:59,549 writing requirements to kcapi.egg-info/requires.txt
2023-02-20T11:51:59,552 writing top-level names to kcapi.egg-info/top_level.txt
2023-02-20T11:51:59,573 reading manifest file 'kcapi.egg-info/SOURCES.txt'
2023-02-20T11:51:59,578 adding license file 'LICENSE'
2023-02-20T11:51:59,587 writing manifest file 'kcapi.egg-info/SOURCES.txt'
2023-02-20T11:51:59,590 Copying kcapi.egg-info to build/bdist.linux-armv7l/wheel/kcapi-1.1.0-py3.7.egg-info
2023-02-20T11:51:59,614 running install_scripts
2023-02-20T11:51:59,649 creating build/bdist.linux-armv7l/wheel/kcapi-1.1.0.dist-info/WHEEL
2023-02-20T11:51:59,654 creating '/tmp/pip-wheel-9ytdm_6m/.tmp-ibrcv8xa/kcapi-1.1.0-py3-none-any.whl' and adding 'build/bdist.linux-armv7l/wheel' to it
2023-02-20T11:51:59,659 adding 'kcapi/__init__.py'
2023-02-20T11:51:59,662 adding 'kcapi/oid.py'
2023-02-20T11:51:59,666 adding 'kcapi/sso.py'
2023-02-20T11:51:59,669 adding 'kcapi/ie/__init__.py'
2023-02-20T11:51:59,672 adding 'kcapi/ie/auth_flows.py'
2023-02-20T11:51:59,675 adding 'kcapi/ie/flows_publisher.py'
2023-02-20T11:51:59,679 adding 'kcapi/rest/__init__.py'
2023-02-20T11:51:59,681 adding 'kcapi/rest/auth_flows.py'
2023-02-20T11:51:59,684 adding 'kcapi/rest/clients.py'
2023-02-20T11:51:59,687 adding 'kcapi/rest/crud.py'
2023-02-20T11:51:59,689 adding 'kcapi/rest/groups.py'
2023-02-20T11:51:59,692 adding 'kcapi/rest/helper.py'
2023-02-20T11:51:59,694 adding 'kcapi/rest/idp.py'
2023-02-20T11:51:59,697 adding 'kcapi/rest/realms.py'
2023-02-20T11:51:59,699 adding 'kcapi/rest/recovery.py'
2023-02-20T11:51:59,701 adding 'kcapi/rest/resp.py'
2023-02-20T11:51:59,704 adding 'kcapi/rest/roles.py'
2023-02-20T11:51:59,706 adding 'kcapi/rest/targets.py'
2023-02-20T11:51:59,709 adding 'kcapi/rest/url.py'
2023-02-20T11:51:59,712 adding 'kcapi/rest/users.py'
2023-02-20T11:51:59,716 adding 'kcapi-1.1.0.dist-info/LICENSE'
2023-02-20T11:51:59,721 adding 'kcapi-1.1.0.dist-info/METADATA'
2023-02-20T11:51:59,724 adding 'kcapi-1.1.0.dist-info/WHEEL'
2023-02-20T11:51:59,726 adding 'kcapi-1.1.0.dist-info/top_level.txt'
2023-02-20T11:51:59,729 adding 'kcapi-1.1.0.dist-info/RECORD'
2023-02-20T11:51:59,732 removing build/bdist.linux-armv7l/wheel
2023-02-20T11:51:59,751 /tmp/pip-build-env-9bvwx8_y/overlay/lib/python3.7/site-packages/setuptools/config/_apply_pyprojecttoml.py:103: _WouldIgnoreField: 'license' defined outside of `pyproject.toml` would be ignored.
2023-02-20T11:51:59,752 !!
2023-02-20T11:51:59,753 ##########################################################################
2023-02-20T11:51:59,754 # configuration would be ignored/result in error due to `pyproject.toml` #
2023-02-20T11:51:59,754 ##########################################################################
2023-02-20T11:51:59,755 The following seems to be defined outside of `pyproject.toml`:
2023-02-20T11:51:59,756 `license = 'MIT'`
2023-02-20T11:51:59,757 According to the spec (see the link below), however, setuptools CANNOT
2023-02-20T11:51:59,757 consider this value unless 'license' is listed as `dynamic`.
2023-02-20T11:51:59,758 https://packaging.python.org/en/latest/specifications/declaring-project-metadata/
2023-02-20T11:51:59,759 For the time being, `setuptools` will still consider the given value (as a
2023-02-20T11:51:59,760 **transitional** measure), but please note that future releases of setuptools will
2023-02-20T11:51:59,760 follow strictly the standard.
2023-02-20T11:51:59,761 To prevent this warning, you can list 'license' under `dynamic` or alternatively
2023-02-20T11:51:59,761 remove the `[project]` table from your file and rely entirely on other means of
2023-02-20T11:51:59,762 configuration.
2023-02-20T11:51:59,763 !!
2023-02-20T11:51:59,764 warnings.warn(msg, _WouldIgnoreField)
2023-02-20T11:51:59,764 /tmp/pip-build-env-9bvwx8_y/overlay/lib/python3.7/site-packages/setuptools/config/_apply_pyprojecttoml.py:103: _WouldIgnoreField: 'dependencies' defined outside of `pyproject.toml` would be ignored.
2023-02-20T11:51:59,765 !!
2023-02-20T11:51:59,766 ##########################################################################
2023-02-20T11:51:59,766 # configuration would be ignored/result in error due to `pyproject.toml` #
2023-02-20T11:51:59,767 ##########################################################################
2023-02-20T11:51:59,768 The following seems to be defined outside of `pyproject.toml`:
2023-02-20T11:51:59,768 `dependencies = ['requests']`
2023-02-20T11:51:59,769 According to the spec (see the link below), however, setuptools CANNOT
2023-02-20T11:51:59,770 consider this value unless 'dependencies' is listed as `dynamic`.
2023-02-20T11:51:59,770 https://packaging.python.org/en/latest/specifications/declaring-project-metadata/
2023-02-20T11:51:59,771 For the time being, `setuptools` will still consider the given value (as a
2023-02-20T11:51:59,772 **transitional** measure), but please note that future releases of setuptools will
2023-02-20T11:51:59,772 follow strictly the standard.
2023-02-20T11:51:59,773 To prevent this warning, you can list 'dependencies' under `dynamic` or alternatively
2023-02-20T11:51:59,773 remove the `[project]` table from your file and rely entirely on other means of
2023-02-20T11:51:59,774 configuration.
2023-02-20T11:51:59,775 !!
2023-02-20T11:51:59,776 warnings.warn(msg, _WouldIgnoreField)
2023-02-20T11:51:59,923 Building wheel for kcapi (pyproject.toml): finished with status 'done'
2023-02-20T11:51:59,936 Created wheel for kcapi: filename=kcapi-1.1.0-py3-none-any.whl size=20981 sha256=ccde2d8b4b76f64029d43b382dcd01133cff2dd5850d869b6f3c6d02e348fd92
2023-02-20T11:51:59,938 Stored in directory: /tmp/pip-ephem-wheel-cache-jsdufbcu/wheels/0c/39/28/331861f38fd75f86af5eba080a1f3912034d9a869e65baf191
2023-02-20T11:51:59,968 Successfully built kcapi
2023-02-20T11:51:59,977 Removed build tracker: '/tmp/pip-build-tracker-s8kz9h7v'