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.

@@ -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
- template_summary = template_data.get('summary', '').lower()
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
- step_summary = step.get('summary', '').lower()
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
- summary = template_data.get('summary', '').strip()
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
- guidance = template_data.get('guidance', '').strip()
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
- step_title = step.get('title', '').strip()
247
- step_summary = step.get('summary', '').strip()
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
- for step in steps:
376
- step_text = (step.get('title', '') + " " + step.get('summary', '')).lower()
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
- deadline = step.get('deadline')
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.7
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.7
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=9rCAw5B8k5919_PUCUAaJe-hJ8n1yCB27rSZWCbYGlg,51547
16
- tallyfy/template_management/automation.py,sha256=jJnVBdLKUkuS7NsxKmQQ-MGoS0vb9xiX-EOqVNoNcQQ,19809
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=ApyLE3j_XnmtmGsRjWvjPp2faQIcmToi9PvZ0hrVk4o,32085
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.7.dist-info/licenses/LICENSE,sha256=8HUsrXnc3l2sZxhPV9Z1gYinq76Q2Ym7ahYJy57QlLc,1063
25
- tallyfy-1.0.7.dist-info/METADATA,sha256=ubTQlHzZnNEbfGa2dDYSFQHmnF9JnYSYoRwjF_iMsCo,26359
26
- tallyfy-1.0.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
27
- tallyfy-1.0.7.dist-info/top_level.txt,sha256=yIycWbR61EZJD0MYRPwUQjOS2XZw5B5jCWx1IP73KcM,8
28
- tallyfy-1.0.7.dist-info/RECORD,,
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,,