tallyfy 1.0.7__py3-none-any.whl → 1.0.9__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.
Potentially problematic release.
This version of tallyfy might be problematic. Click here for more details.
- tallyfy/organization_management/__init__.py +26 -0
- tallyfy/organization_management/base.py +76 -0
- tallyfy/organization_management/retrieval.py +39 -0
- tallyfy/template_management/analysis.py +9 -3
- tallyfy/template_management/automation.py +1 -1
- tallyfy/template_management/health_assessment.py +40 -10
- {tallyfy-1.0.7.dist-info → tallyfy-1.0.9.dist-info}/METADATA +2 -2
- {tallyfy-1.0.7.dist-info → tallyfy-1.0.9.dist-info}/RECORD +11 -8
- {tallyfy-1.0.7.dist-info → tallyfy-1.0.9.dist-info}/WHEEL +0 -0
- {tallyfy-1.0.7.dist-info → tallyfy-1.0.9.dist-info}/licenses/LICENSE +0 -0
- {tallyfy-1.0.7.dist-info → tallyfy-1.0.9.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Organization management module for Tallyfy SDK
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from .base import OrganizationManagerBase
|
|
6
|
+
from .retrieval import OrganizationRetrieval
|
|
7
|
+
|
|
8
|
+
class OrganizationManager(OrganizationRetrieval):
|
|
9
|
+
"""
|
|
10
|
+
Complete organization management interface combining all functionality.
|
|
11
|
+
|
|
12
|
+
This class provides access to:
|
|
13
|
+
- Organization retrieval operations
|
|
14
|
+
|
|
15
|
+
Example:
|
|
16
|
+
>>> from tallyfy import TallyfySDK
|
|
17
|
+
>>> sdk = TallyfySDK(api_key="your_api_key")
|
|
18
|
+
>>> orgs = sdk.organizations.get_current_user_organizations()
|
|
19
|
+
>>> print(f"User belongs to {len(orgs.data)} organizations")
|
|
20
|
+
"""
|
|
21
|
+
pass
|
|
22
|
+
|
|
23
|
+
# Maintain backward compatibility
|
|
24
|
+
OrganizationManagement = OrganizationManager
|
|
25
|
+
|
|
26
|
+
__all__ = ['OrganizationManager', 'OrganizationManagement', 'OrganizationRetrieval', 'OrganizationManagerBase']
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Base class for organization management operations
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
from typing import Dict, Any, List, Optional
|
|
7
|
+
from ..models import TallyfyError
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class OrganizationManagerBase:
|
|
11
|
+
"""Base class providing common functionality for organization management operations"""
|
|
12
|
+
|
|
13
|
+
def __init__(self, sdk):
|
|
14
|
+
"""
|
|
15
|
+
Initialize the organization manager base.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
sdk: The main Tallyfy SDK instance
|
|
19
|
+
"""
|
|
20
|
+
self.sdk = sdk
|
|
21
|
+
self.logger = logging.getLogger(f"{__name__}.{self.__class__.__name__}")
|
|
22
|
+
|
|
23
|
+
def _extract_data(self, response_data: Dict[str, Any], default_empty: bool = True) -> Any:
|
|
24
|
+
"""
|
|
25
|
+
Extract data from API response.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
response_data: Raw API response
|
|
29
|
+
default_empty: Return empty list if no data found
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
Extracted data
|
|
33
|
+
"""
|
|
34
|
+
if not response_data:
|
|
35
|
+
return [] if default_empty else None
|
|
36
|
+
|
|
37
|
+
# Handle direct data responses
|
|
38
|
+
if 'data' in response_data:
|
|
39
|
+
return response_data['data']
|
|
40
|
+
|
|
41
|
+
# Handle responses where the main content is directly available
|
|
42
|
+
# This is common for single item responses
|
|
43
|
+
return response_data if not default_empty else []
|
|
44
|
+
|
|
45
|
+
def _handle_api_error(self, error: Exception, operation: str, **context) -> None:
|
|
46
|
+
"""
|
|
47
|
+
Handle and log API errors consistently.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
error: The exception that occurred
|
|
51
|
+
operation: Description of the operation that failed
|
|
52
|
+
**context: Additional context for debugging
|
|
53
|
+
"""
|
|
54
|
+
context_str = ", ".join([f"{k}={v}" for k, v in context.items()])
|
|
55
|
+
error_message = f"Failed to {operation}"
|
|
56
|
+
if context_str:
|
|
57
|
+
error_message += f" ({context_str})"
|
|
58
|
+
|
|
59
|
+
self.logger.error(f"{error_message}: {str(error)}")
|
|
60
|
+
|
|
61
|
+
if isinstance(error, TallyfyError):
|
|
62
|
+
raise error
|
|
63
|
+
else:
|
|
64
|
+
raise TallyfyError(f"{error_message}: {str(error)}")
|
|
65
|
+
|
|
66
|
+
def _build_query_params(self, **kwargs) -> Dict[str, Any]:
|
|
67
|
+
"""
|
|
68
|
+
Build query parameters for API requests.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
**kwargs: Parameters to include in the query string
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
Dictionary of query parameters with None values filtered out
|
|
75
|
+
"""
|
|
76
|
+
return {key: value for key, value in kwargs.items() if value is not None}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Organization retrieval operations
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import List, Optional
|
|
6
|
+
from .base import OrganizationManagerBase
|
|
7
|
+
from ..models import Organization, OrganizationsList, TallyfyError
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class OrganizationRetrieval(OrganizationManagerBase):
|
|
11
|
+
"""Handles organization retrieval operations"""
|
|
12
|
+
|
|
13
|
+
def get_current_user_organizations(self, page: int = 1, per_page: int = 10) -> OrganizationsList:
|
|
14
|
+
"""
|
|
15
|
+
Get all organizations the current member is a part of.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
page: Page number (default: 1)
|
|
19
|
+
per_page: Number of results per page (default: 10, max: 100)
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
OrganizationsList object containing organizations and pagination metadata
|
|
23
|
+
|
|
24
|
+
Raises:
|
|
25
|
+
TallyfyError: If the request fails
|
|
26
|
+
"""
|
|
27
|
+
try:
|
|
28
|
+
endpoint = "me/organizations"
|
|
29
|
+
params = self._build_query_params(page=page, per_page=min(per_page, 100))
|
|
30
|
+
|
|
31
|
+
response_data = self.sdk._make_request('GET', endpoint, params=params)
|
|
32
|
+
|
|
33
|
+
# Return the structured response with pagination
|
|
34
|
+
return OrganizationsList.from_dict(response_data)
|
|
35
|
+
|
|
36
|
+
except TallyfyError:
|
|
37
|
+
raise
|
|
38
|
+
except Exception as e:
|
|
39
|
+
self._handle_api_error(e, "get my organizations", page=page, per_page=per_page)
|
|
@@ -514,15 +514,21 @@ class TemplateAnalysis(TemplateManagerBase):
|
|
|
514
514
|
raise TallyfyError("Unable to retrieve template data for kickoff field analysis")
|
|
515
515
|
|
|
516
516
|
template_title = template_data.get('title', '').lower()
|
|
517
|
-
|
|
517
|
+
try:
|
|
518
|
+
template_summary = template_data.get('summary', '').lower()
|
|
519
|
+
except:
|
|
520
|
+
template_summary = ''
|
|
518
521
|
steps = template_data.get('steps', [])
|
|
519
522
|
existing_prerun = template_data.get('prerun', [])
|
|
520
523
|
|
|
521
524
|
# Collect all step content for analysis
|
|
522
525
|
all_step_content = ""
|
|
523
|
-
for step in steps:
|
|
526
|
+
for step in steps['data']:
|
|
524
527
|
step_title = step.get('title', '').lower()
|
|
525
|
-
|
|
528
|
+
try:
|
|
529
|
+
step_summary = step.get('summary', '').lower()
|
|
530
|
+
except:
|
|
531
|
+
step_summary = ''
|
|
526
532
|
all_step_content += f" {step_title} {step_summary}"
|
|
527
533
|
|
|
528
534
|
combined_content = f"{template_title} {template_summary} {all_step_content}"
|
|
@@ -360,7 +360,7 @@ class TemplateAutomation(TemplateManagerBase):
|
|
|
360
360
|
steps = template_data.get('steps', [])
|
|
361
361
|
|
|
362
362
|
# Create step lookup
|
|
363
|
-
step_lookup = {step.get('id'): step.get('title', 'Unknown') for step in steps}
|
|
363
|
+
step_lookup = {step.get('id'): step.get('title', 'Unknown') for step in steps['data']}
|
|
364
364
|
|
|
365
365
|
analysis = {
|
|
366
366
|
'redundant_rules': [],
|
|
@@ -165,9 +165,12 @@ class TemplateHealthAssessment(TemplateManagerBase):
|
|
|
165
165
|
score += 3
|
|
166
166
|
else:
|
|
167
167
|
score += 5
|
|
168
|
-
|
|
168
|
+
|
|
169
169
|
# Check summary/description quality (5 points)
|
|
170
|
-
|
|
170
|
+
try:
|
|
171
|
+
summary = template_data.get('summary', '').strip()
|
|
172
|
+
except:
|
|
173
|
+
summary = None
|
|
171
174
|
if not summary:
|
|
172
175
|
issues.append({
|
|
173
176
|
'category': 'metadata',
|
|
@@ -189,7 +192,11 @@ class TemplateHealthAssessment(TemplateManagerBase):
|
|
|
189
192
|
score += 5
|
|
190
193
|
|
|
191
194
|
# Check guidance quality (5 points)
|
|
192
|
-
|
|
195
|
+
try:
|
|
196
|
+
guidance = template_data.get('guidance', '').strip()
|
|
197
|
+
except:
|
|
198
|
+
guidance = None
|
|
199
|
+
|
|
193
200
|
if not guidance:
|
|
194
201
|
issues.append({
|
|
195
202
|
'category': 'metadata',
|
|
@@ -243,8 +250,15 @@ class TemplateHealthAssessment(TemplateManagerBase):
|
|
|
243
250
|
very_short_titles = 0
|
|
244
251
|
|
|
245
252
|
for step in steps:
|
|
246
|
-
|
|
247
|
-
|
|
253
|
+
try:
|
|
254
|
+
step_title = step.get('title', '').strip()
|
|
255
|
+
except:
|
|
256
|
+
step_title = None
|
|
257
|
+
|
|
258
|
+
try:
|
|
259
|
+
step_summary = step.get('summary', '').strip()
|
|
260
|
+
except:
|
|
261
|
+
step_summary = None
|
|
248
262
|
|
|
249
263
|
# Check title clarity
|
|
250
264
|
if not step_title:
|
|
@@ -371,9 +385,22 @@ class TemplateHealthAssessment(TemplateManagerBase):
|
|
|
371
385
|
# Check if steps might need forms
|
|
372
386
|
form_keywords = ['input', 'enter', 'provide', 'fill', 'complete', 'details', 'information']
|
|
373
387
|
steps_needing_forms = 0
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
388
|
+
for step in steps['data']:
|
|
389
|
+
try:
|
|
390
|
+
step_title = step.get('title', '').lower()
|
|
391
|
+
if not step_title:
|
|
392
|
+
step_title = ""
|
|
393
|
+
except:
|
|
394
|
+
step_title = ""
|
|
395
|
+
|
|
396
|
+
try:
|
|
397
|
+
step_summary = step.get('summary', '').lower()
|
|
398
|
+
if not step_summary:
|
|
399
|
+
step_summary = ""
|
|
400
|
+
except:
|
|
401
|
+
step_summary = ""
|
|
402
|
+
|
|
403
|
+
step_text = (step_title + " " + step_summary).lower()
|
|
377
404
|
if any(keyword in step_text for keyword in form_keywords):
|
|
378
405
|
steps_needing_forms += 1
|
|
379
406
|
|
|
@@ -496,7 +523,10 @@ class TemplateHealthAssessment(TemplateManagerBase):
|
|
|
496
523
|
unreasonable_deadlines = 0
|
|
497
524
|
|
|
498
525
|
for step in steps:
|
|
499
|
-
|
|
526
|
+
try:
|
|
527
|
+
deadline = step.get('deadline')
|
|
528
|
+
except:
|
|
529
|
+
deadline = None
|
|
500
530
|
if deadline:
|
|
501
531
|
steps_with_deadlines += 1
|
|
502
532
|
|
|
@@ -597,7 +627,7 @@ class TemplateHealthAssessment(TemplateManagerBase):
|
|
|
597
627
|
score += 2
|
|
598
628
|
else:
|
|
599
629
|
score += 3
|
|
600
|
-
|
|
630
|
+
steps = steps['data']
|
|
601
631
|
# Check step positioning and logic (5 points)
|
|
602
632
|
positions = [step.get('position', 0) for step in steps]
|
|
603
633
|
unique_positions = len(set(positions))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tallyfy
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.9
|
|
4
4
|
Summary: A comprehensive Python SDK for interacting with the Tallyfy API
|
|
5
5
|
Home-page: https://github.com/tallyfy/tallyfy-sdk
|
|
6
6
|
Author: Tallyfy
|
|
@@ -738,5 +738,5 @@ For bugs, feature requests, or questions:
|
|
|
738
738
|
2. Contact us at: support@tallyfy.com
|
|
739
739
|
---
|
|
740
740
|
|
|
741
|
-
**Version:** 1.0.
|
|
741
|
+
**Version:** 1.0.9
|
|
742
742
|
**Last Updated:** 2025
|
|
@@ -6,23 +6,26 @@ tallyfy/form_fields_management/base.py,sha256=6YH5wGTlG1EDEuEFxROz4CPadNHOVX1UZY
|
|
|
6
6
|
tallyfy/form_fields_management/crud_operations.py,sha256=3XCJunGwMo8z4we8fva8zRryKajBcQMt9Jgg_Y_QM5Q,8877
|
|
7
7
|
tallyfy/form_fields_management/options_management.py,sha256=cZWGBkR3770NEDQYDj9I1ug5lhGQ4tH482sZW6qkapk,8640
|
|
8
8
|
tallyfy/form_fields_management/suggestions.py,sha256=4XaYG7SHAXjjxnVLDGtd0FGOxPrBzPnp4fTjd-Iuj34,16866
|
|
9
|
+
tallyfy/organization_management/__init__.py,sha256=JvDHaULXypNW19UT0Dd3khcPAEh3CM7S9eo0TbutBoU,820
|
|
10
|
+
tallyfy/organization_management/base.py,sha256=CMhLYarx7085A1pDUhGIHSMuYq1lAJEDzst8IT0F9k4,2477
|
|
11
|
+
tallyfy/organization_management/retrieval.py,sha256=q3tZp1r7Sq0qBKru-dzxpmjGN46NDi6ZPp26-gdwgyM,1314
|
|
9
12
|
tallyfy/task_management/__init__.py,sha256=5pknQarjvQZtv3Sa2GXxlMqSZ9skCIE6DsJwaGBQWU4,2963
|
|
10
13
|
tallyfy/task_management/base.py,sha256=lHYvdFQh0YlFYawDnApZVU37UWnPkePFcYqFK1QLS1c,4027
|
|
11
14
|
tallyfy/task_management/creation.py,sha256=reaiAFWH7GIlNLTzGwqgJX5iXbHUROXh5oFgEXv-bX4,9012
|
|
12
15
|
tallyfy/task_management/retrieval.py,sha256=fWsED0K_DnDunQl-Y2B7uIjtqz47LdP4oLhrXAUNKYA,7926
|
|
13
16
|
tallyfy/task_management/search.py,sha256=2bFMIsnjq-sE8inj0EP_bK_Ituuq-59bcq9cYedDEmw,7404
|
|
14
17
|
tallyfy/template_management/__init__.py,sha256=9ID-EHNIyucko5TBWagVSp3FKi9ADjNfRMWyT7rPSAo,3674
|
|
15
|
-
tallyfy/template_management/analysis.py,sha256=
|
|
16
|
-
tallyfy/template_management/automation.py,sha256=
|
|
18
|
+
tallyfy/template_management/analysis.py,sha256=jYkTL7trZmNkQveTuvUChq1nA8VAIdm1omTDOHoPSrU,51721
|
|
19
|
+
tallyfy/template_management/automation.py,sha256=Qkz-JXl_IUzfGrtt7cME-XMTDF_a71UshcssUylXW-s,19817
|
|
17
20
|
tallyfy/template_management/base.py,sha256=wP18jd5T06QwCV2rw4FhSDQCEKlAMwbSg5ffd8vSDVw,2031
|
|
18
21
|
tallyfy/template_management/basic_operations.py,sha256=RzZSvGJ8Q0fcF_c6Vk_PrFhp0rGJ_UUMd3YfxgY5AwE,18888
|
|
19
|
-
tallyfy/template_management/health_assessment.py,sha256=
|
|
22
|
+
tallyfy/template_management/health_assessment.py,sha256=1Kan_mfQ2cGPyoiASQwcfN_Wre5CMLOjj4sptxJfBa4,32877
|
|
20
23
|
tallyfy/user_management/__init__.py,sha256=LTyxJ7i4JrsUMf8QMdtrLdwbgtv8_mmMi8eUmo5Yre8,2658
|
|
21
24
|
tallyfy/user_management/base.py,sha256=jD5jOAu3y0K7fumSH65t9zFRDLriOV-YYPZSuJzYuTE,4681
|
|
22
25
|
tallyfy/user_management/invitation.py,sha256=Ss1Gtii-sS02GuY-XUPYi7dHwAKWMkaG_tRFVOfS_2Q,11395
|
|
23
26
|
tallyfy/user_management/retrieval.py,sha256=M5xFlY2IPIR2b5TUbF0YF2Cm12Mdnu5ZU1iahBFI1vA,11696
|
|
24
|
-
tallyfy-1.0.
|
|
25
|
-
tallyfy-1.0.
|
|
26
|
-
tallyfy-1.0.
|
|
27
|
-
tallyfy-1.0.
|
|
28
|
-
tallyfy-1.0.
|
|
27
|
+
tallyfy-1.0.9.dist-info/licenses/LICENSE,sha256=8HUsrXnc3l2sZxhPV9Z1gYinq76Q2Ym7ahYJy57QlLc,1063
|
|
28
|
+
tallyfy-1.0.9.dist-info/METADATA,sha256=qMiQ4yKGlRuNPYpGeqn0sUSjP4MfvNJ99g_N4zIPYSA,26359
|
|
29
|
+
tallyfy-1.0.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
30
|
+
tallyfy-1.0.9.dist-info/top_level.txt,sha256=yIycWbR61EZJD0MYRPwUQjOS2XZw5B5jCWx1IP73KcM,8
|
|
31
|
+
tallyfy-1.0.9.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|