Skip to content
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
cfbd889
initial commit
jaegeral Jun 25, 2026
41d4918
Merge branch 'master' into 2026-06-25-api-client
jaegeral Jun 25, 2026
0c43bbf
typing
jaegeral Jun 25, 2026
4fd1064
Update api_client/python/timesketch_api_client/sketch.py
jaegeral Jun 25, 2026
b0ef14f
Update api_client/python/timesketch_api_client/sketch.py
jaegeral Jun 25, 2026
bdea6b1
Update api_client/python/timesketch_api_client/sketch.py
jaegeral Jun 25, 2026
5151d97
Update api_client/python/timesketch_api_client/client.py
jaegeral Jun 25, 2026
1aba34d
Update api_client/python/timesketch_api_client/sketch.py
jaegeral Jun 25, 2026
d220f04
black
jaegeral Jun 25, 2026
db4a1a3
Update api_client/python/timesketch_api_client/story.py
jaegeral Jun 25, 2026
add2d97
black
jaegeral Jun 25, 2026
e02852b
more readable
jaegeral Jun 25, 2026
f539970
more readable
jaegeral Jun 25, 2026
b469b30
fix errors
jaegeral Jun 25, 2026
cd79ec4
Update api_client/python/timesketch_api_client/aggregation.py
jaegeral Jun 25, 2026
ae25539
Update api_client/python/timesketch_api_client/aggregation.py
jaegeral Jun 25, 2026
c1b2b25
Update api_client/python/timesketch_api_client/aggregation.py
jaegeral Jun 25, 2026
1ff5a5e
Update api_client/python/timesketch_api_client/cli_input.py
jaegeral Jun 25, 2026
b194652
fix errors
jaegeral Jun 25, 2026
28bcfac
fix errors
jaegeral Jun 25, 2026
503480e
black
jaegeral Jun 25, 2026
447daa7
black
jaegeral Jun 25, 2026
611304b
black
jaegeral Jun 25, 2026
4f371bb
Update api_client/python/timesketch_api_client/client.py
jaegeral Jun 25, 2026
c6c6697
Update api_client/python/timesketch_api_client/sketch.py
jaegeral Jun 25, 2026
bf2c62c
Update api_client/python/timesketch_api_client/sketch.py
jaegeral Jun 25, 2026
64acdbc
Update api_client/python/timesketch_api_client/sketch.py
jaegeral Jun 25, 2026
5e08b79
Update api_client/python/timesketch_api_client/aggregation.py
jaegeral Jun 25, 2026
f30a4d7
Update api_client/python/timesketch_api_client/aggregation.py
jaegeral Jun 25, 2026
4cc0d70
update docstring to not mention types
jaegeral Jun 25, 2026
89485e3
Merge branch 'master' into 2026-06-25-api-client
jkppr Jun 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
180 changes: 117 additions & 63 deletions api_client/python/timesketch_api_client/aggregation.py

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"""Tests for the Timesketch API aggregation object."""

import unittest
import mock
from unittest import mock

import altair as alt

Expand Down
63 changes: 38 additions & 25 deletions api_client/python/timesketch_api_client/analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,36 @@
# limitations under the License.
"""Timesketch API analyzer result object."""

from __future__ import unicode_literals
from __future__ import annotations

import datetime
import json
import logging
from typing import Any, Dict, Generator, List, TYPE_CHECKING

from . import error
from . import resource

if TYPE_CHECKING:
from .client import TimesketchApi

logger = logging.getLogger("timesketch_api.analyzer")


class AnalyzerResult(resource.BaseResource):
"""Class to store and retrieve session information for an analyzer."""

def __init__(self, timeline_id, session_id, sketch_id, api):
"""Initialize the class."""
def __init__(
self, timeline_id: int, session_id: int, sketch_id: int, api: TimesketchApi
) -> None:
"""Initialize the class.

Args:
timeline_id (int): The ID of the timeline.
session_id (int): The ID of the analyzer session.
sketch_id (int): The ID of the sketch.
api (TimesketchApi): An instance of TimesketchApi.
"""
self._session_id = session_id
self._sketch_id = sketch_id
self._timeline_id = timeline_id
Expand All @@ -38,21 +51,21 @@ def __init__(self, timeline_id, session_id, sketch_id, api):
)
super().__init__(api, resource_uri)

def _get_status_data(self):
def _get_status_data(self) -> Generator[Dict[str, str], None, None]:
"""Yields a dict for each analyzer status."""
data = self._fetch_data()
for entry in data.get("analyzers", []):
yield {
"log": entry.get("log", "No recorded logs."),
"name": entry.get("name", "No Name"),
"results": entry.get("results", ""),
"status": entry.get("status", "Unknown"),
"date": entry.get(
"status_date", datetime.datetime.utcnow().isoformat()
"log": str(entry.get("log", "No recorded logs.")),
"name": str(entry.get("name", "No Name")),
"results": str(entry.get("results", "")),
"status": str(entry.get("status", "Unknown")),
"date": str(
entry.get("status_date", datetime.datetime.utcnow().isoformat())
),
}

def _fetch_data(self):
def _fetch_data(self) -> Dict[str, Any]:
"""Returns a dict with the analyzer results."""
response = self.api.session.get(self.resource_uri)
if not error.check_return_status(response, logger):
Expand All @@ -64,7 +77,7 @@ def _fetch_data(self):
if not objects:
return {}

result_dict = {}
result_dict: Dict[str, Any] = {}
for result in objects[0]:
result_id = result.get("analysissession_id")
if result_id != self._session_id:
Expand Down Expand Up @@ -100,14 +113,14 @@ def _fetch_data(self):
return result_dict

@property
def id(self):
def id(self) -> int:
"""Returns the session ID."""
return self._session_id

@property
def log(self):
def log(self) -> str:
"""Returns back logs from the analyzer session, if there are any."""
return_strings = []
return_strings: List[str] = []
for entry in self._get_status_data():
return_strings.append(
"[{0:s}] = {1:s}".format(
Expand All @@ -118,9 +131,9 @@ def log(self):
return "\n".join(return_strings)

@property
def results(self):
def results(self) -> str:
"""Returns the results from the analyzer session."""
return_strings = []
return_strings: List[str] = []
for entry in self._get_status_data():
results = entry.get("results")
if not results:
Expand All @@ -131,9 +144,9 @@ def results(self):
return "\n".join(return_strings)

@property
def results_dict(self):
def results_dict(self) -> Dict[str, List[str]]:
"""Returns the results from the analyzer session as a dict."""
result_dict = {}
result_dict: Dict[str, List[str]] = {}
for entry in self._get_status_data():
results = entry.get("results")
if not results:
Expand All @@ -144,9 +157,9 @@ def results_dict(self):
return result_dict

@property
def status(self):
def status(self) -> str:
"""Returns the current status of the analyzer run."""
return_strings = []
return_strings: List[str] = []
for entry in self._get_status_data():
return_strings.append(
"[{0:s}] = {1:s}".format(
Expand All @@ -157,9 +170,9 @@ def status(self):
return "\n".join(return_strings)

@property
def status_dict(self):
def status_dict(self) -> Dict[str, List[str]]:
"""Returns the current status of the analyzers run as a dict."""
return_dict = {}
return_dict: Dict[str, List[str]] = {}
for entry in self._get_status_data():
name = entry.get("name", "No Name")

Expand All @@ -168,9 +181,9 @@ def status_dict(self):
return return_dict

@property
def status_string(self):
def status_string(self) -> str:
"""Returns a longer version of a status string."""
return_strings = []
return_strings: List[str] = []
for entry in self._get_status_data():
return_strings.append(
"{0:s} - {1:s}: {2:s}".format(
Expand Down
18 changes: 7 additions & 11 deletions api_client/python/timesketch_api_client/cli_input.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,24 @@
# limitations under the License.
"""CLI assistance for importer tools."""

from typing import Any
from typing import Callable
from typing import Optional
from typing import Text
from __future__ import annotations

import getpass
from typing import Any, Callable, Optional


def ask_question(
question: Text,
input_type: Callable[[Text], Any],
question: str,
input_type: Callable[[str], Any],
default: Optional[Any] = None,
hide_input: Optional[bool] = False,
hide_input: bool = False,
) -> Any:
"""Presents the user with a prompt with a default return value and a type.

Args:
question (str): the text that the user will be prompted.
input_type (type): the type of the input data.
default (object): default value for the question, optional.
default: default value for the question, optional.
Comment thread
jaegeral marked this conversation as resolved.
hide_input (bool): whether the input should be hidden, eg. when asking
for a password.

Expand All @@ -56,9 +54,7 @@ def ask_question(
return input_type(answer)


def confirm_choice(
choice: Text, default: Optional[bool] = True, abort: Optional[bool] = True
) -> bool:
def confirm_choice(choice: str, default: bool = True, abort: bool = True) -> bool:
"""Returns a bool from a yes/no question presented to the end user.

Args:
Expand Down
Loading
Loading