From 56d08e2ffb3cd8cdf77c525c383ae08702d2d269 Mon Sep 17 00:00:00 2001 From: "Ing. Fabian Franz Steiner BSc." Date: Wed, 11 Dec 2024 20:35:04 +0100 Subject: [PATCH 1/3] Add string representation method to RequestStatus, CompletionReason, and PredefinedFilter enums --- src/xurrent/requests.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/xurrent/requests.py b/src/xurrent/requests.py index 86187c1..f6a393a 100644 --- a/src/xurrent/requests.py +++ b/src/xurrent/requests.py @@ -33,6 +33,9 @@ class RequestStatus(str, Enum): project_pending = "project_pending" # Project Pending completed = "completed" # Completed + def __str__(self): + return self.value + class CompletionReason(str, Enum): solved = "solved" # Solved - Root Cause Analysis Not Required workaround = "workaround" # Workaround - Root Cause Not Removed @@ -45,6 +48,9 @@ class CompletionReason(str, Enum): declined = "declined" # Declined - Declined by Service Provider unsolvable = "unsolvable" # Unsolvable - Unable to Solve + def __str__(self): + return self.value + class PredefinedFilter(str, Enum): completed = "completed" # /requests/completed @@ -56,6 +62,9 @@ class PredefinedFilter(str, Enum): problem_management_review = "problem_management_review" # /requests/problem_management_review sla_accountability = "sla_accountability" # /requests/sla_accountability + def __str__(self): + return self.value + class PredefinedNotesFilter(str, Enum): public = "public" # /requests/public internal = "internal" # /requests/internal From 8cbbba3aa3ed304adef3b5150e054eadad97d26b Mon Sep 17 00:00:00 2001 From: "Ing. Fabian Franz Steiner BSc." Date: Wed, 18 Dec 2024 13:24:33 +0100 Subject: [PATCH 2/3] Add logging functionality with LogLevel enum and set_log_level method --- ChangeLog.md | 11 +++++++ README.md | 5 ++-- pyproject.toml | 4 +-- src/xurrent/core.py | 55 ++++++++++++++++++++++++++++++++-- tests/integration/core_test.py | 9 ++++++ 5 files changed, 78 insertions(+), 6 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 485e335..0a5b597 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,5 +1,16 @@ # Change Log +## v0.0.2.10 + +### New Features + +- Core: add enum LogLevel +- Core: add method set_log_level to change the log level + +### Breaking Changes + +- Core: init: parameter for logger has been added, if not provided, a new logger will be created + ## v0.0.2.9 ### New Features diff --git a/README.md b/README.md index c5dca94..14be68e 100644 --- a/README.md +++ b/README.md @@ -22,10 +22,11 @@ This module is used to interact with the Xurrent API. It provides a set of class baseUrl = "https://api.4me.qa/v1" account = "account-name" - logger = setup_logger(verbose=True) - x_api_helper = XurrentApiHelper(baseUrl, apitoken, account) + # change log level (default: INFO) + x_api_helper.set_log_level("DEBUG") + # Plain API Call uri = "/requests?subject=Example Subject" connection_object.api_call(uri, 'GET') diff --git a/pyproject.toml b/pyproject.toml index 9eb65d5..f832ae7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "xurrent" -version = "0.0.2.9" +version = "0.0.2.10" authors = [ { name="Fabian Steiner", email="fabian@stei-ner.net" }, ] @@ -18,7 +18,7 @@ Homepage = "https://github.com/fasteiner/xurrent-python" Issues = "https://github.com/fasteiner/xurrent-python/issues" [tool.poetry] name = "xurrent" -version = "0.0.2.9" +version = "0.0.2.10" description = "A python module to interact with the Xurrent API." authors = ["Ing. Fabian Franz Steiner BSc. "] readme = "README.md" diff --git a/src/xurrent/core.py b/src/xurrent/core.py index 90e8c21..34aeefc 100644 --- a/src/xurrent/core.py +++ b/src/xurrent/core.py @@ -1,11 +1,19 @@ from __future__ import annotations # Needed for forward references from datetime import datetime +from enum import Enum import time import requests import logging import json import re +class LogLevel(Enum): + DEBUG = logging.DEBUG + INFO = logging.INFO + WARNING = logging.WARNING + ERROR = logging.ERROR + CRITICAL = logging.CRITICAL + class JsonSerializableDict(dict): def __init__(self, **kwargs): # Initialize with keyword arguments as dictionary items @@ -37,11 +45,23 @@ class XurrentApiHelper: api_user: Person # Forward declaration with a string api_user_teams: List[Team] # Forward declaration with a string - def __init__(self, base_url, api_key, api_account, resolve_user=True): + def __init__(self, base_url, api_key, api_account,resolve_user=True, logger: Logger=None): + """ + Initialize the Xurrent API helper. + + :param base_url: Base URL of the Xurrent API + :param api_key: API key to authenticate with + :param api_account: Account name to use + :param resolve_user: Resolve the API user and their teams (default: True) + :param logger: Logger to use (optional), otherwise a new logger is created + """ self.base_url = base_url self.api_key = api_key self.api_account = api_account - self.logger = logging.getLogger(__name__) + if logger: + self.logger = logger + else: + self.logger = self.create_logger(False) if resolve_user: # Import Person lazily from .people import Person @@ -77,6 +97,37 @@ def __append_per_page(self, uri, per_page=100): return f'{uri}?per_page={per_page}' return uri + def create_logger(self, verbose) -> Logger: + """ + Create a logger for the API helper. + :param verbose: Enable verbose logging (debug level) + :return: Logger instance + """ + logger = logging.getLogger() + log_stream = logging.StreamHandler() + + if verbose: + logger.setLevel(logging.DEBUG) + log_stream.setLevel(logging.DEBUG) + else: + logger.setLevel(logging.INFO) + log_stream.setLevel(logging.INFO) + + formatter = logging.Formatter('%(levelname)s - %(message)s') + log_stream.setFormatter(formatter) + logger.addHandler(log_stream) + return logger + + def set_log_level(self, level: LogLevel): + """ + Set the log level for the logger and all handlers. + + :param level: Log level to set + """ + self.logger.setLevel(level) + for handler in self.logger.handlers: + handler.setLevel(level) + def api_call(self, uri: str, method='GET', data=None, per_page=100): """ diff --git a/tests/integration/core_test.py b/tests/integration/core_test.py index 5192428..9031a2e 100644 --- a/tests/integration/core_test.py +++ b/tests/integration/core_test.py @@ -2,6 +2,7 @@ import os import sys from dotenv import load_dotenv +import logging # Add the `../src` directory to sys.path sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "../../src"))) @@ -46,5 +47,13 @@ def test_api_helper_setup(x_api_helper): assert isinstance(x_api_helper.api_user_teams, list) for team in x_api_helper.api_user_teams: assert isinstance(team, Team) + + assert x_api_helper.logger.level == logging.INFO + +def test_set_log_level(x_api_helper): + x_api_helper.set_log_level("DEBUG") + assert x_api_helper.logger.level == logging.DEBUG + x_api_helper.set_log_level(logging.WARNING) + assert x_api_helper.logger.level == logging.WARNING \ No newline at end of file From 7bbea6997447cebfc6202932e3b6dfff7d9ebbe1 Mon Sep 17 00:00:00 2001 From: "Ing. Fabian Franz Steiner BSc." Date: Wed, 18 Dec 2024 13:29:50 +0100 Subject: [PATCH 3/3] Update README to include examples for People and Teams modules --- README.md | 92 +++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 72 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 14be68e..9759f5d 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,35 @@ This module is used to interact with the Xurrent API. It provides a set of class ``` -### Requests +#### People + +```python + from xurrent.people import Person + + people = Person.get_by_id(x_api_helper, ) + + api_user = Person.get_me(x_api_helper) + + # get all people with a specific subject + people = Person.get_people(x_api_helper,queryfilter={ + "name": "Werner" + }) + + # enable + people.enable() + + #disable + people.disable() + #archive + people.archive() + #trash + people.trash() + #restore + people.restore() + +``` + +#### Requests ```python from xurrent.requests import Request @@ -61,7 +89,7 @@ This module is used to interact with the Xurrent API. It provides a set of class ``` -#### Request Notes +##### Request Notes ```python from xurrent.requests import Request @@ -81,24 +109,7 @@ This module is used to interact with the Xurrent API. It provides a set of class ``` -### Workflows - -```python - - from xurrent.workflows import Workflow - - workflow = Workflow.get_by_id(x_api_helper, ) - - #close - workflow.close() # completion reason: completed, note: closed - # close with completion reason - workflow.close(completion_reason="withdrawn") - #close with completion reason and note - workflow.close(completion_reason="withdrawn", note="This is a test note") - -``` - -### Tasks +#### Tasks ```python from xurrent.tasks import Task @@ -126,3 +137,44 @@ This module is used to interact with the Xurrent API. It provides a set of class ``` + +#### Teams + +```python + from xurrent.teams import Team + + team = Team.get_by_id(x_api_helper, ) + + # get all teams with a specific subject + teams = Team.get_team(x_api_helper,predifinedFilter="enabled") + + # enable + team.enable() + + #disable + team.disable() + #archive + team.archive() + #trash + team.trash() + #restore + team.restore() + +``` + +#### Workflows + +```python + + from xurrent.workflows import Workflow + + workflow = Workflow.get_by_id(x_api_helper, ) + + #close + workflow.close() # completion reason: completed, note: closed + # close with completion reason + workflow.close(completion_reason="withdrawn") + #close with completion reason and note + workflow.close(completion_reason="withdrawn", note="This is a test note") + +```