Skip to content
This repository has been archived by the owner on Dec 18, 2023. It is now read-only.

Commit

Permalink
Merge pull request #15 from credo-ai/develop
Browse files Browse the repository at this point in the history
Release 0.0.5
  • Loading branch information
esherman-credo authored Dec 13, 2022
2 parents f3fb341 + 684c9b3 commit 4a72c39
Show file tree
Hide file tree
Showing 14 changed files with 629 additions and 63 deletions.
19 changes: 19 additions & 0 deletions .readthedocs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# .readthedocs.yaml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details

# Required
version: 2

build:
os: ubuntu-20.04
tools:
python: "3.8"

sphinx:
configuration: docs/conf.py

python:
install:
- requirements: requirements.txt
- requirements: docs/requirements.txt
4 changes: 3 additions & 1 deletion connect/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
"""
Credo AI Connect package
"""
from connect.adapters import Adapter
from connect.governance import Governance
from connect.utils.version_check import validate_version

__version__ = "0.0.4"
__version__ = "0.0.5"

__all__ = ["governance", "evidence", "utils"]

Expand Down
108 changes: 95 additions & 13 deletions connect/adapters/adapters.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
from functools import partial
from typing import Optional

import pandas as pd

from connect.evidence import MetricContainer
from connect.evidence import EvidenceContainer, MetricContainer, TableContainer
from connect.governance import Governance
from connect.utils import ValidationError
from connect.utils import ValidationError, wrap_list


class Adapter:
Expand Down Expand Up @@ -38,9 +39,10 @@ def __init__(
def metrics_to_governance(
self,
metrics: dict,
source: str,
labels: dict = None,
metadata: dict = None,
overwrite_governance: bool = False,
overwrite_governance: bool = True,
):
"""
Packages metrics as evidence and sends them to governance
Expand All @@ -49,16 +51,93 @@ def metrics_to_governance(
---------
metrics : dict or pd.DataFrame
Dictionary of metrics. Form: {metric_type: value, ...}
source : str
Label for what generated the metrics
labels : dict
Additional labels to pass to underlying evidence
Additional key/value pairs to act as labels for the evidence
metadata : dict
Metadata to pass to underlying evidence
overwrite_governance : bool
When adding evidence to a Governance object, whether to overwrite existing
evidence or not, default False.
"""
self._evidence_to_governance(
self._metrics_to_evidence,
metrics,
source,
labels,
metadata,
overwrite_governance,
)

def table_to_governance(
self,
data: dict,
source: str,
labels: dict = None,
metadata: dict = None,
overwrite_governance: bool = True,
):
"""
Packages metrics as evidence and sends them to governance
Parameters
---------
data: pd.DataFrame
Dataframe to pass to evidence_fun. The DataFrame must have a "name" attribute
source : str
Label for what generated the table
labels : dict
Additional key/value pairs to act as labels for the evidence
metadata : dict
Metadata to pass to underlying evidence
overwrite_governance : bool
When adding evidence to a Governance object, whether to overwrite existing
evidence or not, default False.
evidence_fun : callable
Function to pass data, labels and metadata. The function should return a list of
evidence. Default: self._to_evidence
"""
evidence = self._metrics_to_evidence(metrics, labels, metadata)
self._evidence_to_governance(
TableContainer, data, source, labels, metadata, overwrite_governance
)

def _evidence_to_governance(
self,
evidence_fun,
data,
source,
labels,
metadata,
overwrite_governance=True,
):
"""
Packages data as evidence and sends to governance
Parameters
---------
evidence_fun : callable or Container
Function to pass data, labels and metadata. The function should return a list of
evidence. If a Container, use self._to_evidence with the specified container
data
data to pass to evidence_fun
source : str
Label for what generated the table
labels : dict
Additional key/value pairs to act as labels for the evidence
metadata : dict
Metadata to pass to underlying evidence
overwrite_governance : bool
When adding evidence to a Governance object, whether to overwrite existing
evidence or not, default False.
"""
try:
if issubclass(evidence_fun, EvidenceContainer):
evidence_fun = partial(self._to_evidence, container_class=evidence_fun)
except TypeError:
pass
labels = {**(labels or {}), "source": source}
evidence = evidence_fun(data=data, labels=labels, metadata=metadata)
if overwrite_governance:
self.governance.set_evidence(evidence)
else:
Expand All @@ -72,12 +151,12 @@ def _get_artifact_meta(self):
del model["tags"]
return model or {}

def _metrics_to_evidence(self, metrics, labels=None, metadata=None):
def _metrics_to_evidence(self, data, labels=None, metadata=None):
"""Converts a dictionary of metrics to evidence
Parameters
----------
metrics : dict or pd.DataFrame
data : dict or pd.DataFrame
Dictionary of metrics. Form: {metric_type: value, ...}
labels : dict
Additional labels to pass to underlying evidence
Expand All @@ -89,11 +168,14 @@ def _metrics_to_evidence(self, metrics, labels=None, metadata=None):
List
list of Evidence
"""
if isinstance(data, dict):
data = pd.DataFrame(data.items(), columns=["type", "value"])
elif not isinstance(data, pd.DataFrame):
raise ValidationError("Metrics must be a dictionary or a dataframe")
return self._to_evidence(MetricContainer, data, labels, metadata)

def _to_evidence(self, container_class, data, labels, metadata):
meta = self._get_artifact_meta()
meta.update(metadata or {})
if isinstance(metrics, dict):
metrics = pd.DataFrame(metrics.items(), columns=["type", "value"])
elif not isinstance(metrics, pd.DataFrame):
raise ValidationError("Metrics must be a dictionary or a dataframe")
container = MetricContainer(metrics, labels, meta)
return container.to_evidence()
container = container_class(data, labels, meta)
return wrap_list(container.to_evidence())
17 changes: 16 additions & 1 deletion connect/evidence/evidence.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,12 +140,27 @@ def __init__(

@property
def data(self):
columns = [
{"value": k, "type": self._transform_type(v)}
for k, v in self._data.dtypes.iteritems()
]
return {
"columns": self._data.columns.tolist(),
"columns": columns,
"value": self._data.values.tolist(),
}

@property
def base_label(self):
label = {"table_name": self.name}
return label

def _transform_type(self, pandas_type):
lookup = {
"int64": "number",
"float64": "number",
"object": "string",
"category": "string",
"datetime64": "datetime",
}
final_type = str(pandas_type)
return lookup.get(final_type, final_type)
4 changes: 2 additions & 2 deletions connect/evidence/lens_evidence/containers.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,10 @@ def to_evidence(self, **metadata):
]

def _validate(self, data):
necessary_index = ["parameters", "feature_names", "model_name"]
necessary_index = ["parameters", "model_name"]
if list(data.columns) != ["results"]:
raise ValidationError(
"Model profiler data must only have one column: 'results'"
)
if sum(data.index.isin(necessary_index)) != 3:
if sum(data.index.isin(necessary_index)) != 2:
raise ValidationError(f"Model profiler data must contain {necessary_index}")
8 changes: 5 additions & 3 deletions connect/evidence/lens_evidence/evidence.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,17 @@ def __init__(self, data: DataFrame, additional_labels: dict = None, **metadata):
@property
def data(self):
parameters = self._data.loc["parameters"]
features_names = self._data.loc["feature_names"]
remaining_info = self._data[
~self._data.index.isin(["parameters", "feature_names", "model_name"])
]
return {
output = {
"info": remaining_info.to_dict(),
"parameters": parameters,
"features_names": features_names,
}
if "feature_names" in self._data.index:
output["features_names"] = self._data.loc["feature_names"]

return output

@property
def base_label(self):
Expand Down
5 changes: 2 additions & 3 deletions connect/governance/credo_api_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@
from dotenv import dotenv_values
from json_api_doc import deserialize, serialize

from connect import __version__
from connect.utils import global_logger, json_dumps
from connect.utils import get_version, global_logger, json_dumps

CREDO_URL = "https://api.credo.ai"

Expand Down Expand Up @@ -133,7 +132,7 @@ def set_access_token(self, access_token):
"accept": "application/vnd.api+json",
"content-type": "application/vnd.api+json",
"X-Client-Name": "Credo AI Connect",
"X-Client-Version": __version__,
"X-Client-Version": get_version(),
}
self._session.headers.update(headers)

Expand Down
Loading

0 comments on commit 4a72c39

Please sign in to comment.