python-alfresco-api 1.2.0__py3-none-any.whl → 1.2.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- python_alfresco_api/__init__.py +6 -1
- python_alfresco_api/_compat.py +55 -0
- {python_alfresco_api-1.2.0.dist-info → python_alfresco_api-1.2.1.dist-info}/METADATA +3 -1
- {python_alfresco_api-1.2.0.dist-info → python_alfresco_api-1.2.1.dist-info}/RECORD +6 -5
- {python_alfresco_api-1.2.0.dist-info → python_alfresco_api-1.2.1.dist-info}/WHEEL +0 -0
- {python_alfresco_api-1.2.0.dist-info → python_alfresco_api-1.2.1.dist-info}/licenses/LICENSE +0 -0
python_alfresco_api/__init__.py
CHANGED
|
@@ -36,7 +36,12 @@ from .clients.conversion_utils import (
|
|
|
36
36
|
# Import raw_clients to ensure they get packaged
|
|
37
37
|
from . import raw_clients
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
# Tolerate Alfresco responses that omit the (spec-required) UserInfo.displayName for JIT /
|
|
40
|
+
# OAuth2 service-account users (defaults displayName -> id). See _compat.py.
|
|
41
|
+
from ._compat import install_shims as _install_shims
|
|
42
|
+
_install_shims()
|
|
43
|
+
|
|
44
|
+
__version__ = "1.2.1"
|
|
40
45
|
__all__ = [
|
|
41
46
|
# Factory & utilities
|
|
42
47
|
"ClientFactory",
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""Runtime compatibility shims for Alfresco responses that deviate from the OpenAPI spec.
|
|
2
|
+
|
|
3
|
+
Alfresco marks ``UserInfo.displayName`` as *required*, but omits it for JIT / OAuth2 service-account
|
|
4
|
+
users (e.g. ``service-account-*`` produced by the client-credentials grant). That makes the generated
|
|
5
|
+
``UserInfo.from_dict`` raise ``KeyError('displayName')`` while parsing ``createdByUser`` /
|
|
6
|
+
``modifiedByUser`` / ``owner`` on node responses.
|
|
7
|
+
|
|
8
|
+
This shim defaults ``displayName`` to ``id`` when it is absent, so parsing never crashes. It lives
|
|
9
|
+
outside ``raw_clients/`` so it survives client re-generation.
|
|
10
|
+
|
|
11
|
+
Scope (verified across all 7 generated raw clients): the ``UserInfo`` model — which is what
|
|
12
|
+
createdBy/modifiedBy/owner deserialize to — exists **only** in the core and search clients; the other
|
|
13
|
+
five (auth, discovery, model, search_sql, workflow) have no required-``displayName`` models. Core's
|
|
14
|
+
group models (``Group`` / ``GroupMember`` / ``GroupBodyCreate`` / ``GroupBodyUpdate``) also mark
|
|
15
|
+
``displayName`` required, but groups always carry a display name and those models have *other* required
|
|
16
|
+
fields (e.g. ``Group.isRoot``), so they are not the JIT/service-account case and are left alone.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from importlib import import_module
|
|
20
|
+
|
|
21
|
+
# UserInfo covers every user reference (createdByUser / modifiedByUser / owner), in the two clients
|
|
22
|
+
# that define it.
|
|
23
|
+
_MODELS = (
|
|
24
|
+
("python_alfresco_api.raw_clients.alfresco_core_client.core_client.models.user_info", "UserInfo"),
|
|
25
|
+
("python_alfresco_api.raw_clients.alfresco_search_client.search_client.models.user_info", "UserInfo"),
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _patch_from_dict(cls) -> None:
|
|
30
|
+
if getattr(cls, "_display_name_shim_installed", False):
|
|
31
|
+
return
|
|
32
|
+
_orig_from_dict = cls.from_dict # bound classmethod
|
|
33
|
+
|
|
34
|
+
def _from_dict(src_dict, _orig=_orig_from_dict):
|
|
35
|
+
d = dict(src_dict)
|
|
36
|
+
if "displayName" not in d and "id" in d:
|
|
37
|
+
# Alfresco omitted the (spec-required) display name; fall back to the id.
|
|
38
|
+
d["displayName"] = d["id"]
|
|
39
|
+
return _orig(d)
|
|
40
|
+
|
|
41
|
+
cls.from_dict = staticmethod(_from_dict)
|
|
42
|
+
cls._display_name_shim_installed = True
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def install_shims() -> None:
|
|
46
|
+
"""Patch ``UserInfo.from_dict`` in the raw clients to tolerate a missing ``displayName``.
|
|
47
|
+
|
|
48
|
+
Idempotent — safe to call more than once.
|
|
49
|
+
"""
|
|
50
|
+
for mod_path, cls_name in _MODELS:
|
|
51
|
+
try:
|
|
52
|
+
_patch_from_dict(getattr(import_module(mod_path), cls_name))
|
|
53
|
+
except Exception:
|
|
54
|
+
# Model not present in this build/layout — skip quietly.
|
|
55
|
+
continue
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-alfresco-api
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.1
|
|
4
4
|
Summary: Python Client for all Alfresco Content Services REST APIs, with Pydantic v2 Models, and Event Support
|
|
5
5
|
Project-URL: Homepage, https://github.com/stevereiner/python-alfresco-api
|
|
6
6
|
Project-URL: Repository, https://github.com/stevereiner/python-alfresco-api
|
|
@@ -325,6 +325,8 @@ master_client = factory.create_master_client()
|
|
|
325
325
|
|
|
326
326
|
A provided access token that has already expired is detected from its JWT `exp` claim and auto-refreshed when a `refresh_token` + `token_endpoint` are supplied. `ALFRESCO_OAUTH2_*` environment variables are also read when `load_env=True`.
|
|
327
327
|
|
|
328
|
+
> **Service account vs. user token.** `client_credentials` authenticates as the client's *service account* (e.g. `service-account-<client-id>`) — a just-in-time Alfresco user with **no display name** and only **default permissions** (not an admin, and not the same as Alfresco's `guest`). For content operations prefer a **user token** (obtain one via a password grant, then pass `access_token`/`refresh_token`) so operations run as a real user with a display name and that user's ACLs. As of **1.2.1** the client also tolerates a missing `displayName` (defaults it to the user id), so the service-account path no longer raises `KeyError`.
|
|
329
|
+
|
|
328
330
|
### Sync and Async Usage
|
|
329
331
|
|
|
330
332
|
```python
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
python_alfresco_api/__init__.py,sha256=
|
|
1
|
+
python_alfresco_api/__init__.py,sha256=PGcKjRKCcSuamQ20gx5AkghQIzda1YzchOBgPB-lahQ,2001
|
|
2
|
+
python_alfresco_api/_compat.py,sha256=liuk6giBNWxS6Qnk4rvzCi-skJohJM9BcfEwLcYFv9w,2541
|
|
2
3
|
python_alfresco_api/auth_util.py,sha256=pp9Ig_YGIjfS7SwSrjnJGQ0AmhWNx5AHM4B5hZ6_uyY,35333
|
|
3
4
|
python_alfresco_api/client_factory.py,sha256=-fTIUdT_aPCCH_d9A2RJU7554_yNaUo-ZsZMkxR5588,11458
|
|
4
5
|
python_alfresco_api/clients/__init__.py,sha256=3_SHjsn1iCht_kEmXDFzPNOZlp-EvH3BajmuzTmUdkI,1877
|
|
@@ -768,7 +769,7 @@ python_alfresco_api/utils/node_utils_highlevel.py,sha256=Xfebn8rv958SkMcaaSRS-oa
|
|
|
768
769
|
python_alfresco_api/utils/search_utils.py,sha256=0TJGTWtVWb6I-0QNCYyrNfd714CwKl9dZcw6R7L-aR8,15634
|
|
769
770
|
python_alfresco_api/utils/version_utils.py,sha256=3NIhLyM3rkaH-fm4c-PH8MTIMJmwGKg9KiSBEc8FBJc,11462
|
|
770
771
|
python_alfresco_api/utils/version_utils_highlevel.py,sha256=xa2O6xZfNN9Lx6iHKGnvHGW7watnu8rPTPlcsZUpdis,19079
|
|
771
|
-
python_alfresco_api-1.2.
|
|
772
|
-
python_alfresco_api-1.2.
|
|
773
|
-
python_alfresco_api-1.2.
|
|
774
|
-
python_alfresco_api-1.2.
|
|
772
|
+
python_alfresco_api-1.2.1.dist-info/METADATA,sha256=45VOzf7hjpjF2ReK5CDaC9oAdP82bVaewhGXDxzGFc4,29505
|
|
773
|
+
python_alfresco_api-1.2.1.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
|
|
774
|
+
python_alfresco_api-1.2.1.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
775
|
+
python_alfresco_api-1.2.1.dist-info/RECORD,,
|
|
File without changes
|
{python_alfresco_api-1.2.0.dist-info → python_alfresco_api-1.2.1.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|