Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: adds metrics view events #170

Merged
merged 6 commits into from
Apr 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
34 changes: 26 additions & 8 deletions src/posit/connect/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@
from requests import Response, Session
from typing import Optional

from . import hooks, me, urls
from . import config, hooks, me, metrics, urls

from .auth import Auth
from .config import Config
from .oauth import OAuthIntegration
from .content import Content
from .usage import Usage
from .metrics.usage import Usage
from .users import User, Users
from .visits import Visits
from .metrics.visits import Visits


class Client:
Expand Down Expand Up @@ -98,12 +98,30 @@ def content(self) -> Content:
return Content(config=self.config, session=self.session)

@property
def usage(self) -> Usage:
return Usage(self.config, self.session)
def metrics(self) -> metrics.Metrics:
"""The Metrics API interface.
@property
def visits(self) -> Visits:
return Visits(self.config, self.session)
The Metrics API is designed for capturing, retrieving, and managing
quantitative measurements of Connect interactions. It is commonly used
for monitoring and analyzing system performance, user behavior, and
business processes. This API facilitates real-time data collection and
accessibility, enabling organizations to make informed decisions based
on key performance indicators (KPIs).
tdstein marked this conversation as resolved.
Show resolved Hide resolved
Returns
-------
metrics.Metrics
Examples
--------
>>> from posit import connect
>>> client = connect.Client()
>>> content_guid = "2243770d-ace0-4782-87f9-fe2aeca14fc8"
>>> view_events = client.metrics.views.find(content_guid=content_guid)
>>> len(view_events)
24
"""
return metrics.Metrics(self.config, self.session)

def __del__(self):
"""Close the session when the Client instance is deleted."""
Expand Down
9 changes: 9 additions & 0 deletions src/posit/connect/metrics/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from .. import resources

from . import views


class Metrics(resources.Resources):
@property
def views(self) -> views.Views:
return views.Views(self.config, self.session)
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

from typing import List, overload

from . import urls
from .. import urls

from .cursors import CursorPaginator
from .resources import Resource, Resources
from ..cursors import CursorPaginator
from ..resources import Resource, Resources


class UsageEvent(Resource):
Expand Down
256 changes: 256 additions & 0 deletions src/posit/connect/metrics/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
from __future__ import annotations

import itertools

from typing import List, overload

from requests.sessions import Session as Session

from . import usage, visits

from .. import resources


class ViewEvent(resources.Resource):
@staticmethod
def from_event(event: visits.VisitEvent | usage.UsageEvent) -> ViewEvent:
if type(event) == visits.VisitEvent:
return ViewEvent.from_visit_event(event)

if type(event) == usage.UsageEvent:
return ViewEvent.from_usage_event(event)

raise TypeError

@staticmethod
def from_visit_event(event: visits.VisitEvent) -> ViewEvent:
return ViewEvent(
event.config,
event.session,
content_guid=event.content_guid,
user_guid=event.user_guid,
variant_key=event.variant_key,
rendering_id=event.rendering_id,
bundle_id=event.bundle_id,
started=event.time,
ended=event.time,
data_version=event.data_version,
path=event.path,
)

@staticmethod
def from_usage_event(event: usage.UsageEvent) -> ViewEvent:
return ViewEvent(
event.config,
event.session,
content_guid=event.content_guid,
user_guid=event.user_guid,
started=event.started,
ended=event.ended,
data_version=event.data_version,
)

def __init__(self, config: resources.Config, session: Session, **kwargs):
super().__init__(config, session, **kwargs)

@property
def content_guid(self) -> str:
"""The associated unique content identifier.
Returns
-------
str
"""
return self["content_guid"]

@property
def user_guid(self) -> str:
"""The associated unique user identifier.
Returns
-------
str
"""
return self["user_guid"]

@property
def variant_key(self) -> str | None:
"""The variant key associated with the visit.
Returns
-------
str | None
The variant key, or None if the associated content type is static.
"""
return self.get("variant_key")

@property
def rendering_id(self) -> int | None:
"""The render id associated with the visit.
Returns
-------
int | None
The render id, or None if the associated content type is static.
"""
return self.get("rendering_id")

@property
def bundle_id(self) -> int | None:
"""The bundle id associated with the visit.
Returns
-------
int
"""
return self.get("bundle_id")

@property
def started(self) -> str:
"""The visit timestamp.
Returns
-------
str
"""
return self["started"]

@property
def ended(self) -> str:
"""The visit timestamp.
Returns
-------
str
"""
return self["ended"]

@property
def data_version(self) -> int:
"""The data version.
Returns
-------
int
"""
return self["data_version"]

@property
def path(self) -> str | None:
"""The path requested by the user.
Returns
-------
str
"""
return self.get("path")


class Views(resources.Resources):
@overload
def find(
self,
content_guid: str = ...,
min_data_version: int = ...,
start: str = ...,
end: str = ...,
) -> List[ViewEvent]:
"""Find view events.
Parameters
----------
content_guid : str, optional
Filter by an associated unique content identifer, by default ...
min_data_version : int, optional
Filter by a minimum data version, by default ...
start : str, optional
Filter by the start time, by default ...
end : str, optional
Filter by the end time, by default ...
Returns
-------
List[ViewEvent]
"""
...

@overload
def find(self, *args, **kwargs) -> List[ViewEvent]:
"""Find view events.
Returns
-------
List[ViewEvent]
"""
...

def find(self, *args, **kwargs) -> List[ViewEvent]:
"""Find view events.
Returns
-------
List[ViewEvent]
"""
events = []
finders = (visits.Visits, usage.Usage)
for finder in finders:
instance = finder(self.config, self.session)
events.extend(
[
ViewEvent.from_event(event)
for event in instance.find(*args, **kwargs) # type: ignore[attr-defined]
]
)
return events

@overload
def find_one(
self,
content_guid: str = ...,
min_data_version: int = ...,
start: str = ...,
end: str = ...,
) -> ViewEvent | None:
"""Find a view event.
Parameters
----------
content_guid : str, optional
Filter by an associated unique content identifer, by default ...
min_data_version : int, optional
Filter by a minimum data version, by default ...
start : str, optional
Filter by the start time, by default ...
end : str, optional
Filter by the end time, by default ...
Returns
-------
Visit | None
"""
...

@overload
def find_one(self, *args, **kwargs) -> ViewEvent | None:
"""Find a view event.
Returns
-------
Visit | None
"""
...

def find_one(self, *args, **kwargs) -> ViewEvent | None:
"""Find a view event.
Returns
-------
ViewEvent | None
"""
finders = (visits.Visits, usage.Usage)
for finder in finders:
instance = finder(self.config, self.session)
event = instance.find_one(*args, **kwargs) # type: ignore[attr-defined]
if event:
return ViewEvent.from_event(event)
return None
Loading
Loading