Skip to content

Commit

Permalink
Merge pull request #279 from specklesystems/kate/separate_metrics
Browse files Browse the repository at this point in the history
Kate/separate metrics
  • Loading branch information
JR-Morgan authored Jun 27, 2023
2 parents 1c9b186 + ed9f1ad commit 64926bd
Show file tree
Hide file tree
Showing 28 changed files with 2,507 additions and 1,412 deletions.
6 changes: 1 addition & 5 deletions src/specklepy/api/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from gql.transport.websockets import WebsocketsTransport

from specklepy.api import resources
from specklepy.api.credentials import Account, get_account_from_token
from specklepy.core.api.credentials import Account, get_account_from_token
from specklepy.api.resources import (
active_user,
branch,
Expand Down Expand Up @@ -60,7 +60,6 @@ class SpeckleClient:
USE_SSL = True

def __init__(self, host: str = DEFAULT_HOST, use_ssl: bool = USE_SSL) -> None:
metrics.track(metrics.CLIENT, custom_props={"name": "create"})
ws_protocol = "ws"
http_protocol = "http"

Expand Down Expand Up @@ -129,7 +128,6 @@ def authenticate_with_token(self, token: str) -> None:
token {str} -- an api token
"""
self.account = get_account_from_token(token, self.url)
metrics.track(metrics.CLIENT, self.account, {"name": "authenticate with token"})
self._set_up_client()

def authenticate_with_account(self, account: Account) -> None:
Expand All @@ -141,12 +139,10 @@ def authenticate_with_account(self, account: Account) -> None:
account {Account} -- the account object which can be found with
`get_default_account` or `get_local_accounts`
"""
metrics.track(metrics.CLIENT, account, {"name": "authenticate with account"})
self.account = account
self._set_up_client()

def _set_up_client(self) -> None:
metrics.track(metrics.CLIENT, self.account, {"name": "set up client"})
headers = {
"Authorization": f"Bearer {self.account.token}",
"Content-Type": "application/json",
Expand Down
118 changes: 10 additions & 108 deletions src/specklepy/api/credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,37 +9,11 @@
from specklepy.logging.exceptions import SpeckleException
from specklepy.transports.sqlite import SQLiteTransport


class UserInfo(BaseModel):
name: Optional[str] = None
email: Optional[str] = None
company: Optional[str] = None
id: Optional[str] = None


class Account(BaseModel):
isDefault: bool = False
token: Optional[str] = None
refreshToken: Optional[str] = None
serverInfo: ServerInfo = Field(default_factory=ServerInfo)
userInfo: UserInfo = Field(default_factory=UserInfo)
id: Optional[str] = None

def __repr__(self) -> str:
return (
f"Account(email: {self.userInfo.email}, server: {self.serverInfo.url},"
f" isDefault: {self.isDefault})"
)

def __str__(self) -> str:
return self.__repr__()

@classmethod
def from_token(cls, token: str, server_url: str = None):
acct = cls(token=token)
acct.serverInfo.url = server_url
return acct

# following imports seem to be unnecessary, but they need to stay
# to not break the scripts using these functions as non-core
from specklepy.core.api.credentials import (UserInfo, Account, StreamWrapper,
get_account_from_token,
get_local_accounts as core_get_local_accounts)

def get_local_accounts(base_path: Optional[str] = None) -> List[Account]:
"""Gets all the accounts present in this environment
Expand All @@ -51,53 +25,19 @@ def get_local_accounts(base_path: Optional[str] = None) -> List[Account]:
List[Account] -- list of all local accounts or an empty list if
no accounts were found
"""
accounts: List[Account] = []
try:
account_storage = SQLiteTransport(scope="Accounts", base_path=base_path)
res = account_storage.get_all_objects()
account_storage.close()
if res:
accounts.extend(Account.parse_raw(r[1]) for r in res)
except SpeckleException:
# cannot open SQLiteTransport, probably because of the lack
# of disk write permissions
pass

json_acct_files = []
json_path = str(speckle_path_provider.accounts_folder_path())
try:
os.makedirs(json_path, exist_ok=True)
json_acct_files.extend(
file for file in os.listdir(json_path) if file.endswith(".json")
)

except Exception:
# cannot find or get the json account paths
pass

if json_acct_files:
try:
accounts.extend(
Account.parse_file(os.path.join(json_path, json_file))
for json_file in json_acct_files
)
except Exception as ex:
raise SpeckleException(
"Invalid json accounts could not be read. Please fix or remove them.",
ex,
) from ex
accounts = core_get_local_accounts(base_path)

metrics.track(
metrics.ACCOUNTS,
metrics.SDK,
next(
(acc for acc in accounts if acc.isDefault),
accounts[0] if accounts else None,
),
{"name": "Get Local Accounts"}
)

return accounts


def get_default_account(base_path: Optional[str] = None) -> Optional[Account]:
"""
Gets this environment's default account if any. If there is no default,
Expand All @@ -108,7 +48,7 @@ def get_default_account(base_path: Optional[str] = None) -> Optional[Account]:
Returns:
Account -- the default account or None if no local accounts were found
"""
accounts = get_local_accounts(base_path=base_path)
accounts = core_get_local_accounts(base_path=base_path)
if not accounts:
return None

Expand All @@ -119,42 +59,4 @@ def get_default_account(base_path: Optional[str] = None) -> Optional[Account]:
metrics.initialise_tracker(default)

return default


def get_account_from_token(token: str, server_url: str = None) -> Account:
"""Gets the local account for the token if it exists
Arguments:
token {str} -- the api token
Returns:
Account -- the local account with this token or a shell account containing
just the token and url if no local account is found
"""
accounts = get_local_accounts()
if not accounts:
return Account.from_token(token, server_url)

acct = next((acc for acc in accounts if acc.token == token), None)
if acct:
return acct

if server_url:
url = server_url.lower()
acct = next(
(acc for acc in accounts if url in acc.serverInfo.url.lower()), None
)
if acct:
return acct

return Account.from_token(token, server_url)


class StreamWrapper:
def __init__(self, url: str = None) -> None:
raise SpeckleException(
message=(
"The StreamWrapper has moved as of v2.6.0! Please import from"
" specklepy.api.wrapper"
),
exception=DeprecationWarning(),
)

73 changes: 12 additions & 61 deletions src/specklepy/api/operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
from specklepy.transports.abstract_transport import AbstractTransport
from specklepy.transports.sqlite import SQLiteTransport

from specklepy.core.api.operations import (send as core_send,
receive as _untracked_receive,
serialize as core_serialize,
deserialize as core_deserialize)


def send(
base: Base,
Expand All @@ -24,47 +29,20 @@ def send(
Returns:
str -- the object id of the sent object
"""

if not transports and not use_default_cache:
raise SpeckleException(
message=(
"You need to provide at least one transport: cannot send with an empty"
" transport list and no default cache"
)
)

if isinstance(transports, AbstractTransport):
transports = [transports]
obj_hash = core_send(base, transports, use_default_cache)

if transports is None:
metrics.track(metrics.SEND)
transports = []
else:
metrics.track(metrics.SEND, getattr(transports[0], "account", None))

if use_default_cache:
transports.insert(0, SQLiteTransport())

serializer = BaseObjectSerializer(write_transports=transports)

obj_hash, _ = serializer.write_json(base=base)

return obj_hash


def receive(
obj_id: str,
remote_transport: Optional[AbstractTransport] = None,
local_transport: Optional[AbstractTransport] = None,
) -> Base:
metrics.track(metrics.RECEIVE, getattr(remote_transport, "account", None))
return _untracked_receive(obj_id, remote_transport, local_transport)


def _untracked_receive(
obj_id: str,
remote_transport: Optional[AbstractTransport] = None,
local_transport: Optional[AbstractTransport] = None,
) -> Base:
"""Receives an object from a transport.
Expand All @@ -77,29 +55,8 @@ def _untracked_receive(
Returns:
Base -- the base object
"""
if not local_transport:
local_transport = SQLiteTransport()

serializer = BaseObjectSerializer(read_transport=local_transport)

# try local transport first. if the parent is there, we assume all the children are there and continue with deserialization using the local transport
obj_string = local_transport.get_object(obj_id)
if obj_string:
return serializer.read_json(obj_string=obj_string)

if not remote_transport:
raise SpeckleException(
message=(
"Could not find the specified object using the local transport, and you"
" didn't provide a fallback remote from which to pull it."
)
)

obj_string = remote_transport.copy_object_and_children(
id=obj_id, target_transport=local_transport
)

return serializer.read_json(obj_string=obj_string)
metrics.track(metrics.RECEIVE, getattr(remote_transport, "account", None))
return _untracked_receive(obj_id, remote_transport, local_transport)


def serialize(base: Base, write_transports: List[AbstractTransport] = []) -> str:
Expand All @@ -116,11 +73,9 @@ def serialize(base: Base, write_transports: List[AbstractTransport] = []) -> str
Returns:
str -- the serialized object
"""
metrics.track(metrics.SERIALIZE)
serializer = BaseObjectSerializer(write_transports=write_transports)

return serializer.write_json(base)[1]
metrics.track(metrics.SDK, custom_props={"name": "Serialize"})

return core_serialize(base, write_transports)

def deserialize(
obj_string: str, read_transport: Optional[AbstractTransport] = None
Expand All @@ -141,13 +96,9 @@ def deserialize(
Returns:
Base -- the deserialized object
"""
metrics.track(metrics.DESERIALIZE)
if not read_transport:
read_transport = SQLiteTransport()

serializer = BaseObjectSerializer(read_transport=read_transport)
metrics.track(metrics.SDK, custom_props={"name": "Deserialize"})

return serializer.read_json(obj_string=obj_string)
return core_deserialize(obj_string, read_transport)


__all__ = ["receive", "send", "serialize", "deserialize"]
2 changes: 1 addition & 1 deletion src/specklepy/api/resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from gql.transport.exceptions import TransportQueryError
from graphql import DocumentNode

from specklepy.api.credentials import Account
from specklepy.core.api.credentials import Account
from specklepy.logging.exceptions import (
GraphQLException,
SpeckleException,
Expand Down
Loading

0 comments on commit 64926bd

Please sign in to comment.