Skip to content

Commit c69f705

Browse files
committed
Fixed 16 subclients handling of timeout, implemented remaining 15 subclients
1. Note fixed timeout handling in 7 top level clients yesterday fixed the 31 subclients 2. Implemented the methods of 15 subclients that had placeholder sections 3. To fix other 16 subclients timeout handling and improve the code, the subclients use the raw client from the parent client instead recreating their own raw clients 4. Subclients now have raw_client() and httpx_client() properties that return parent client properties and replace any _get_raw_client() and get_httpx_client() methods 5. parent clients give subclient contstructors themselves instead of client factory 6. fixed in authentication_client.py to import correct raw client model packages 7. test_client_factory_configuration.py now also tests previous 16 subclients handling of timeout setup in addition to previous testing of the 7 parent clients 8. test_todays_15_subclients.py test the timeout handling the 15 subclients with the implementation methods added today 9. removed some use of emojis in logging from some files to avoid errors in windows consoles. 10. pyproject.toml version change from 1.1.2 to 1.1.4 (increase for both timeout fixing plus 15 subclient finishing) 11. publish_to_pypi removed specific version info, don't stop if test publish doesn't work since the website never works, give 403
1 parent fb1120b commit c69f705

File tree

65 files changed

+4614
-1101
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+4614
-1101
lines changed

CHANGELOG.md

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,32 @@ All notable changes to python-alfresco-api will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7-
## [Unreleased]
7+
## [1.1.4] - 2025-10-01
8+
9+
### Added
10+
- Implemented the methods of 15 subclients that had placeholder sections
11+
- `test_todays_15_subclients.py` test the timeout handling the 15 subclients with the implementation methods added today
12+
13+
### Changed
14+
- Same timeout fix by using the parent raw client
15+
- Removed some use of emojis in logging from some files to avoid errors in windows consoles
16+
- `pyproject.toml` version change from 1.1.2 to 1.1.4 (1.1.3 not in pypi)
17+
- `publish_to_pypi` removed specific version info, don't stop if test publish doesn't work since the website never works, gives 403
18+
19+
## [1.1.3] - 2025-09-30
20+
21+
### Fixed
22+
- Fixed timeout handling in 7 top level clients yesterday, this fixed 16 subclient timeout handling
23+
- To fix 16 subclients timeout handling and improve the code, the subclients use the raw client from the parent client instead recreating their own raw clients
24+
- Fixed in `authentication_client.py` to import correct raw client model packages
25+
26+
### Changed
27+
- Subclients now have `raw_client()` and `httpx_client()` properties that return parent client properties and replace any `_get_raw_client()` and `get_httpx_client()` methods
28+
- Parent clients give subclient constructors themselves instead of client factory
29+
30+
### Added
31+
- `test_client_factory_configuration.py` now also tests previous 16 subclients handling of timeout setup in addition to previous testing of the 7 parent clients
32+
833

934
## [1.1.2] - 2025-09-29
1035

publish_to_pypi.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def run_command(cmd, check=True):
2929

3030
def main():
3131
"""Main publishing workflow."""
32-
print("🚀 PYTHON-ALFRESCO-API v1.1 PyPI PUBLISHING")
32+
print("🚀 PYTHON-ALFRESCO-API PyPI PUBLISHING")
3333
print("=" * 50)
3434

3535
# 1. Verify we're in the right directory
@@ -88,9 +88,15 @@ def main():
8888
test_response = input("🧪 Upload to Test PyPI first? (yes/no): ").lower().strip()
8989
if test_response == "yes":
9090
print("📤 Uploading to Test PyPI...")
91-
run_command("python -m twine upload --repository testpypi dist/*")
92-
print("✅ Test PyPI upload complete!")
93-
print("🔗 Check: https://test.pypi.org/project/python-alfresco-api/")
91+
test_result = run_command("python -m twine upload --repository testpypi dist/*", check=False)
92+
93+
if test_result.returncode == 0:
94+
print("✅ Test PyPI upload complete!")
95+
print("🔗 Check: https://test.pypi.org/project/python-alfresco-api/")
96+
else:
97+
print("⚠️ Test PyPI upload failed (this is common)")
98+
print(" Common reasons: 403 errors, authentication issues, server problems")
99+
print(" Test PyPI is often unreliable - this won't prevent production upload")
94100

95101
confirm = input("\n📤 Proceed to production PyPI? (yes/no): ").lower().strip()
96102
if confirm != "yes":
@@ -103,7 +109,7 @@ def main():
103109

104110
print("\n🎉 PYPI PUBLISHING COMPLETE!")
105111
print("=" * 30)
106-
print("✅ python-alfresco-api v1.1.1 published to PyPI")
112+
print("✅ python-alfresco-api published to PyPI")
107113
print("🔗 Package URL: https://pypi.org/project/python-alfresco-api/")
108114
print("🛠️ Install with: pip install python-alfresco-api")
109115

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ include = [
3838

3939
[project]
4040
name = "python-alfresco-api"
41-
version = "1.1.2"
41+
version = "1.1.4"
4242
description = "Python Client for all Alfresco Content Services REST APIs, with Pydantic v2 Models, and Event Support"
4343
authors = [
4444
{name = "Steve Reiner", email = "example@example.com"}

python_alfresco_api/clients/__init__.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@
99
- Level 3: Operation-specific models for ONE operation
1010
1111
Key Benefits:
12-
- 🚀 Better performance with lazy loading
13-
- 📦 Organized locality (models exactly where used)
14-
- 🔧 Structured imports and clear organization
15-
- 📋 Pydantic v2 models for better type checking in general and for AI/LLM integration
16-
- Dual sync/async APIs (sync for simpler use, async for web apps)
12+
- [PERFORMANCE] Better performance with lazy loading
13+
- [ORGANIZATION] Organized locality (models exactly where used)
14+
- [STRUCTURE] Structured imports and clear organization
15+
- [MODELS] Pydantic v2 models for better type checking in general and for AI/LLM integration
16+
- [ASYNC] Dual sync/async APIs (sync for simpler use, async for web apps)
1717
"""
1818

1919
# Modern clients with three-tier architecture and lazy loading

python_alfresco_api/clients/auth/auth_client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ def authentication(self):
137137
if self._authentication is None:
138138
# Lazy load the authentication client
139139
from .authentication import AuthenticationClient
140-
self._authentication = AuthenticationClient(self._client_factory)
140+
self._authentication = AuthenticationClient(self)
141141
return self._authentication
142142

143143
# =================================================================

python_alfresco_api/clients/auth/authentication/authentication_client.py

Lines changed: 207 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@
2222
from httpx import Response
2323

2424
# Import model types for proper parameter signatures
25-
from ....raw_clients.alfresco_auth_client.auth_client.models.ticketbody import TicketBody
26-
from ....raw_clients.alfresco_auth_client.auth_client.models.ticketentry import TicketEntry
27-
from ....raw_clients.alfresco_auth_client.auth_client.models.validticketentry import ValidTicketEntry
25+
from ....raw_clients.alfresco_auth_client.auth_client.models.ticket_body import TicketBody
26+
from ....raw_clients.alfresco_auth_client.auth_client.models.ticket_entry import TicketEntry
27+
from ....raw_clients.alfresco_auth_client.auth_client.models.valid_ticket_entry import ValidTicketEntry
2828

2929
# Import from Level 3 (operation-specific models)
3030
from .models import AuthenticationResponse, AuthenticationListResponse, CreateAuthenticationRequest
@@ -53,9 +53,9 @@ class AuthenticationClient:
5353
- Detailed sync/async for full HTTP response access
5454
"""
5555

56-
def __init__(self, client_factory):
56+
def __init__(self, parent_client):
5757
"""Initialize with client factory for raw client access."""
58-
self._client_factory = client_factory
58+
self.parent_client = parent_client
5959
self._raw_client = None
6060

6161
# Store raw operation references
@@ -64,31 +64,213 @@ def __init__(self, client_factory):
6464
self._delete_ticket = _delete_ticket
6565
self._validate_ticket = _validate_ticket
6666

67-
def _get_raw_client(self):
68-
"""Get or create the raw client."""
69-
if self._raw_client is None:
70-
# Import the raw auth client directly
71-
from ....raw_clients.alfresco_auth_client.auth_client.client import AuthenticatedClient
72-
73-
# Create the raw client with same auth setup
74-
self._raw_client = AuthenticatedClient(
75-
base_url=f"{self._client_factory.base_url}/alfresco/api/-default-/public/authentication/versions/1",
76-
token=self._client_factory.auth.get_auth_token(),
77-
prefix=self._client_factory.auth.get_auth_prefix(),
78-
verify_ssl=self._client_factory.verify_ssl
79-
)
80-
return self._raw_client
67+
@property
68+
def raw_client(self):
69+
"""Delegate to parent client's raw client."""
70+
return self.parent_client.raw_client
8171

82-
def get_httpx_client(self):
72+
@property
73+
def httpx_client(self):
74+
"""Delegate to parent client's httpx client."""
75+
return self.parent_client.httpx_client
76+
77+
# =================================================================
78+
# AUTHENTICATION OPERATIONS - 4-PATTERN IMPLEMENTATION
79+
# =================================================================
80+
81+
def create_ticket(
82+
self,
83+
username: str,
84+
password: str
85+
) -> Optional[Any]:
86+
"""
87+
Create authentication ticket (sync).
88+
89+
Creates a new authentication ticket for the given credentials.
90+
"""
91+
if not RAW_OPERATIONS_AVAILABLE:
92+
raise ImportError("Raw authentication operations not available")
93+
94+
from ....raw_clients.alfresco_auth_client.auth_client.models.ticket_body import TicketBody
95+
96+
ticket_body = TicketBody(user_id=username, password=password)
97+
98+
return self._create_ticket.sync(
99+
client=self.raw_client,
100+
body=ticket_body
101+
)
102+
103+
async def create_ticket_async(
104+
self,
105+
username: str,
106+
password: str
107+
) -> Optional[Any]:
108+
"""
109+
Create authentication ticket (async).
110+
111+
Creates a new authentication ticket for the given credentials.
112+
"""
113+
if not RAW_OPERATIONS_AVAILABLE:
114+
raise ImportError("Raw authentication operations not available")
115+
116+
from ....raw_clients.alfresco_auth_client.auth_client.models.ticket_body import TicketBody
117+
118+
ticket_body = TicketBody(user_id=username, password=password)
119+
120+
return await self._create_ticket.asyncio(
121+
client=self.raw_client,
122+
body=ticket_body
123+
)
124+
125+
def create_ticket_detailed(
126+
self,
127+
username: str,
128+
password: str
129+
) -> Response:
130+
"""
131+
Create authentication ticket (detailed sync).
132+
133+
Creates a new authentication ticket with full HTTP response.
134+
"""
135+
if not RAW_OPERATIONS_AVAILABLE:
136+
raise ImportError("Raw authentication operations not available")
137+
138+
from ....raw_clients.alfresco_auth_client.auth_client.models.ticket_body import TicketBody
139+
140+
ticket_body = TicketBody(user_id=username, password=password)
141+
142+
return self._create_ticket.sync_detailed(
143+
client=self.raw_client,
144+
body=ticket_body
145+
)
146+
147+
async def create_ticket_detailed_async(
148+
self,
149+
username: str,
150+
password: str
151+
) -> Response:
152+
"""
153+
Create authentication ticket (detailed async).
154+
155+
Creates a new authentication ticket with full HTTP response.
156+
"""
157+
if not RAW_OPERATIONS_AVAILABLE:
158+
raise ImportError("Raw authentication operations not available")
159+
160+
from ....raw_clients.alfresco_auth_client.auth_client.models.ticket_body import TicketBody
161+
162+
ticket_body = TicketBody(user_id=username, password=password)
163+
164+
return await self._create_ticket.asyncio_detailed(
165+
client=self.raw_client,
166+
body=ticket_body
167+
)
168+
169+
def validate_ticket(self) -> Optional[Any]:
170+
"""
171+
Validate current authentication ticket (sync).
172+
173+
Validates the current authentication ticket.
174+
"""
175+
if not RAW_OPERATIONS_AVAILABLE:
176+
raise ImportError("Raw authentication operations not available")
177+
178+
return self._validate_ticket.sync(
179+
client=self.raw_client
180+
)
181+
182+
async def validate_ticket_async(self) -> Optional[Any]:
183+
"""
184+
Validate current authentication ticket (async).
185+
186+
Validates the current authentication ticket.
187+
"""
188+
if not RAW_OPERATIONS_AVAILABLE:
189+
raise ImportError("Raw authentication operations not available")
190+
191+
return await self._validate_ticket.asyncio(
192+
client=self.raw_client
193+
)
194+
195+
def validate_ticket_detailed(self) -> Response:
196+
"""
197+
Validate current authentication ticket (detailed sync).
198+
199+
Validates the current authentication ticket with full HTTP response.
200+
"""
201+
if not RAW_OPERATIONS_AVAILABLE:
202+
raise ImportError("Raw authentication operations not available")
203+
204+
return self._validate_ticket.sync_detailed(
205+
client=self.raw_client
206+
)
207+
208+
async def validate_ticket_detailed_async(self) -> Response:
209+
"""
210+
Validate current authentication ticket (detailed async).
211+
212+
Validates the current authentication ticket with full HTTP response.
213+
"""
214+
if not RAW_OPERATIONS_AVAILABLE:
215+
raise ImportError("Raw authentication operations not available")
216+
217+
return await self._validate_ticket.asyncio_detailed(
218+
client=self.raw_client
219+
)
220+
221+
def delete_ticket(self) -> Optional[Any]:
83222
"""
84-
Get direct access to raw httpx client for advanced operations.
223+
Delete current authentication ticket (sync).
85224
86-
Perfect for MCP servers that need raw HTTP access.
225+
Deletes/invalidates the current authentication ticket.
87226
"""
88-
return self._get_raw_client().get_httpx_client()
227+
if not RAW_OPERATIONS_AVAILABLE:
228+
raise ImportError("Raw authentication operations not available")
229+
230+
return self._delete_ticket.sync(
231+
client=self.raw_client
232+
)
233+
234+
async def delete_ticket_async(self) -> Optional[Any]:
235+
"""
236+
Delete current authentication ticket (async).
237+
238+
Deletes/invalidates the current authentication ticket.
239+
"""
240+
if not RAW_OPERATIONS_AVAILABLE:
241+
raise ImportError("Raw authentication operations not available")
242+
243+
return await self._delete_ticket.asyncio(
244+
client=self.raw_client
245+
)
246+
247+
def delete_ticket_detailed(self) -> Response:
248+
"""
249+
Delete current authentication ticket (detailed sync).
250+
251+
Deletes/invalidates the current authentication ticket with full HTTP response.
252+
"""
253+
if not RAW_OPERATIONS_AVAILABLE:
254+
raise ImportError("Raw authentication operations not available")
255+
256+
return self._delete_ticket.sync_detailed(
257+
client=self.raw_client
258+
)
259+
260+
async def delete_ticket_detailed_async(self) -> Response:
261+
"""
262+
Delete current authentication ticket (detailed async).
263+
264+
Deletes/invalidates the current authentication ticket with full HTTP response.
265+
"""
266+
if not RAW_OPERATIONS_AVAILABLE:
267+
raise ImportError("Raw authentication operations not available")
268+
269+
return await self._delete_ticket.asyncio_detailed(
270+
client=self.raw_client
271+
)
89272

90-
# Placeholder for authentication operations - will be populated from the original file
91273
def __repr__(self) -> str:
92274
"""String representation for debugging."""
93-
base_url = getattr(self._client_factory, 'base_url', 'unknown')
275+
base_url = getattr(self.parent_client._client_factory, 'base_url', 'unknown')
94276
return f"AlfrescoAuthenticationClient(base_url='{base_url}')"

python_alfresco_api/clients/conversion_utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ def enhanced_search_example():
184184

185185
if __name__ == "__main__":
186186
"""Test the conversion utilities."""
187-
print("🔧 Testing Conversion Utilities")
187+
print("[TESTING] Testing Conversion Utilities")
188188

189189
# Test 1: Enhanced create node
190190
print("\n1. Enhanced create node conversion:")
@@ -194,4 +194,4 @@ def enhanced_search_example():
194194
print("\n2. Enhanced search example:")
195195
enhanced_search_example()
196196

197-
print("\n Conversion utilities proof-of-concept complete!")
197+
print("\n[SUCCESS] Conversion utilities proof-of-concept complete!")

0 commit comments

Comments
 (0)