Skip to content

Commit

Permalink
Initial unique project helper
Browse files Browse the repository at this point in the history
* unique project helper

* Rest api call helper

Co-authored-by: John Myers <john@gretel.ai>
Co-authored-by: Drew Newberry <drew@gretel.ai>
GitOrigin-RevId: 6a2771c913c515a0c06cef16d49f282d7c8043cc
  • Loading branch information
3 people committed Dec 8, 2021
1 parent a393d7f commit b475304
Show file tree
Hide file tree
Showing 10 changed files with 367 additions and 3 deletions.
77 changes: 77 additions & 0 deletions docs/rest/UsersApi.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# gretel_client.rest.UsersApi

All URIs are relative to *https://api-dev.gretel.cloud*

Method | HTTP request | Description
------------- | ------------- | -------------
[**users_me**](UsersApi.md#users_me) | **GET** /users/me |


# **users_me**
> {str: (bool, date, datetime, dict, float, int, list, str, none_type)} users_me()


### Example

* Api Key Authentication (ApiKey):
```python
import time
import gretel_client.rest
from gretel_client.rest.api import users_api
from pprint import pprint
# Defining the host is optional and defaults to https://api-dev.gretel.cloud
# See configuration.py for a list of all supported configuration parameters.
configuration = gretel_client.rest.Configuration(
host = "https://api-dev.gretel.cloud"
)

# The client must configure the authentication and authorization parameters
# in accordance with the API server security policy.
# Examples for each auth method are provided below, use the example that
# satisfies your auth use case.

# Configure API key authorization: ApiKey
configuration.api_key['ApiKey'] = 'YOUR_API_KEY'

# Uncomment below to setup prefix (e.g. Bearer) for API key, if needed
# configuration.api_key_prefix['ApiKey'] = 'Bearer'

# Enter a context with an instance of the API client
with gretel_client.rest.ApiClient(configuration) as api_client:
# Create an instance of the API class
api_instance = users_api.UsersApi(api_client)

# example, this endpoint has no required or optional parameters
try:
api_response = api_instance.users_me()
pprint(api_response)
except gretel_client.rest.ApiException as e:
print("Exception when calling UsersApi->users_me: %s\n" % e)
```


### Parameters
This endpoint does not need any parameter.

### Return type

**{str: (bool, date, datetime, dict, float, int, list, str, none_type)}**

### Authorization

[ApiKey](../README.md#ApiKey)

### HTTP request headers

- **Content-Type**: Not defined
- **Accept**: application/json


### HTTP response details
| Status code | Description | Response headers |
|-------------|-------------|------------------|
**200** | Get my user | - |

[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)

1 change: 0 additions & 1 deletion src/gretel_client/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
from gretel_client.rest.api.projects_api import ProjectsApi
from gretel_client.rest.api_client import ApiClient
from gretel_client.rest.configuration import Configuration
from gretel_client.rest.exceptions import NotFoundException, UnauthorizedException

GRETEL = "gretel"
"""Gretel application name"""
Expand Down
54 changes: 53 additions & 1 deletion src/gretel_client/helpers.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import json
import os
import sys

Expand All @@ -7,7 +8,7 @@
import click

from gretel_client.cli.common import get_description_set, poll_and_print, SessionContext
from gretel_client.config import get_logger
from gretel_client.config import get_logger, get_session_config
from gretel_client.projects.common import WAIT_UNTIL_DONE
from gretel_client.projects.docker import ContainerRun, ContainerRunError
from gretel_client.projects.jobs import GPU, Job
Expand Down Expand Up @@ -95,3 +96,54 @@ def submit_docker_local(
poll(job)
run.extract_output_dir(str(output_dir))
return run


def do_api_call(
method: str,
path: str,
query_params: Optional[dict] = None,
body: Optional[dict] = None,
headers: Optional[dict] = None,
) -> dict:
"""
Make a direct API call to Gretel Cloud.
Args:
method: "get", "post", etc
path: The full path to make the request to, any path params must be already included.
Example: "/users/me"
query_params: Optional URL based query parameters
body: An optional JSON payload to send
headers: Any custom headers that need to bet set.
NOTE:
This function will automatically inject the appropiate API hostname and
authentication from the Gretel configuration.
"""
if headers is None:
headers = {}

method = method.upper()

if not path.startswith("/"):
path = "/" + path

api = get_session_config()._get_api_client()

# Utilize the ApiClient method to inject the proper authentication
# into our headers, since Gretel only uses header-based auth we don't
# need to pass any other data into this
#
# NOTE: This function does a pointer-like update of ``headers``
api.update_params_for_auth(
headers, None, api.configuration.auth_settings(), None, None, None
)

url = api.configuration.host + path

response = api.request(
method, url, query_params=query_params, body=body, headers=headers
)

resp_dict = json.loads(response.data.decode())
return resp_dict.get("data")
1 change: 1 addition & 0 deletions src/gretel_client/projects/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# flake8: noqa
from gretel_client.projects.projects import (
create_or_get_unique_project,
create_project,
get_project,
Project,
Expand Down
45 changes: 45 additions & 0 deletions src/gretel_client/projects/projects.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from gretel_client.rest.api.projects_api import ProjectsApi
from gretel_client.rest.exceptions import UnauthorizedException
from gretel_client.rest.model.artifact import Artifact
from gretel_client.users.users import get_me

DATA = "data"
PROJECTS = "projects"
Expand Down Expand Up @@ -367,3 +368,47 @@ def tmp_project():
yield project
finally:
project.delete()


def create_or_get_unique_project(
*, name: str, desc: str = None, display_name: str = None
) -> Project:
"""
Helper function that provides a consistent experience for creating
and fetching a project with the same name. Given a name of a project,
this helper will fetch the current user's ID and use that as a suffix
in order to create a project name unique to that user. Once the project
is created, if it can be fetched, it will not be re-created over and
over again.
Args:
name: The name of the project, which will have the User's ID appended
to it automatically.
desc: Description of the project
display_name: If None, the display name will be set equal to the value
of ``name`` _before_ the user ID is appended.
NOTE:
The ``desc`` and ``display_name`` parameters will only be used when
the project is first created. If the project already exists, these
params will have no affect.
"""
current_user_dict = get_me()
unique_suffix = current_user_dict["_id"][9:19]
target_name = f"{name}-{unique_suffix}"

try:
project = get_project(name=target_name)
return project
except UnauthorizedException:
# Project name not found
pass
except Exception:
raise

# Try and create the project if we coud not find it
# originally
project = create_project(
name=target_name, display_name=display_name or name, desc=desc
)
return project
130 changes: 130 additions & 0 deletions src/gretel_client/rest/api/users_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
"""
Gretel Api
Gretel api definitions # noqa: E501
The version of the OpenAPI document: dev
Generated by: https://openapi-generator.tech
"""


import re # noqa: F401
import sys # noqa: F401

from gretel_client.rest.api_client import ApiClient
from gretel_client.rest.api_client import Endpoint as _Endpoint
from gretel_client.rest.model_utils import ( # noqa: F401
check_allowed_values,
check_validations,
date,
datetime,
file_type,
none_type,
validate_and_convert_types,
)


class UsersApi(object):
"""NOTE: This class is auto generated by OpenAPI Generator
Ref: https://openapi-generator.tech
Do not edit the class manually.
"""

def __init__(self, api_client=None):
if api_client is None:
api_client = ApiClient()
self.api_client = api_client

def __users_me(self, **kwargs):
"""users_me # noqa: E501
This method makes a synchronous HTTP request by default. To make an
asynchronous HTTP request, please pass async_req=True
>>> thread = api.users_me(async_req=True)
>>> result = thread.get()
Keyword Args:
_return_http_data_only (bool): response data without head status
code and headers. Default is True.
_preload_content (bool): if False, the urllib3.HTTPResponse object
will be returned without reading/decoding response data.
Default is True.
_request_timeout (float/tuple): timeout setting for this request. If one
number provided, it will be total request timeout. It can also
be a pair (tuple) of (connection, read) timeouts.
Default is None.
_check_input_type (bool): specifies if type checking
should be done one the data sent to the server.
Default is True.
_check_return_type (bool): specifies if type checking
should be done one the data received from the server.
Default is True.
_host_index (int/None): specifies the index of the server
that we want to use.
Default is read from the configuration.
async_req (bool): execute request asynchronously
Returns:
{str: (bool, date, datetime, dict, float, int, list, str, none_type)}
If the method is called asynchronously, returns the request
thread.
"""
kwargs["async_req"] = kwargs.get("async_req", False)
kwargs["_return_http_data_only"] = kwargs.get(
"_return_http_data_only", True
)
kwargs["_preload_content"] = kwargs.get("_preload_content", True)
kwargs["_request_timeout"] = kwargs.get("_request_timeout", None)
kwargs["_check_input_type"] = kwargs.get("_check_input_type", True)
kwargs["_check_return_type"] = kwargs.get("_check_return_type", True)
kwargs["_host_index"] = kwargs.get("_host_index")
return self.call_with_http_info(**kwargs)

self.users_me = _Endpoint(
settings={
"response_type": (
{
str: (
bool,
date,
datetime,
dict,
float,
int,
list,
str,
none_type,
)
},
),
"auth": ["ApiKey"],
"endpoint_path": "/users/me",
"operation_id": "users_me",
"http_method": "GET",
"servers": None,
},
params_map={
"all": [],
"required": [],
"nullable": [],
"enum": [],
"validation": [],
},
root_map={
"validations": {},
"allowed_values": {},
"openapi_types": {},
"attribute_map": {},
"location_map": {},
"collection_format_map": {},
},
headers_map={
"accept": ["application/json"],
"content_type": [],
},
api_client=api_client,
callable=__users_me,
)
1 change: 1 addition & 0 deletions src/gretel_client/rest/apis/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@
# Import APIs into API package:
from gretel_client.rest.api.opt_api import OptApi
from gretel_client.rest.api.projects_api import ProjectsApi
from gretel_client.rest.api.users_api import UsersApi
Empty file.
24 changes: 24 additions & 0 deletions src/gretel_client/users/users.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""
High level API for interacting with the Gretel Users API
"""
from gretel_client.config import get_session_config
from gretel_client.rest.api.users_api import UsersApi


def get_me(as_dict: bool = True) -> dict:
"""
Retrieve current user's profile from Gretel Cloud.
Returns:
A dictionary with the current user's profile information.
Params:
as_dict: If true, will return a raw dictionary of the user's data. This is currently
the only option available.
"""
api = get_session_config().get_api(UsersApi)
resp = api.users_me()
if as_dict:
return resp.get("data", {}).get("me")

raise NotImplementedError("Simple dict access to profile available only")
Loading

0 comments on commit b475304

Please sign in to comment.