Skip to content

Commit

Permalink
Merge pull request #1 from GreenBuildingRegistry/ft-packaging
Browse files Browse the repository at this point in the history
added tests and packaging files
  • Loading branch information
fablet authored Feb 18, 2018
2 parents 0e4aea0 + 2de8461 commit 10a40ec
Show file tree
Hide file tree
Showing 17 changed files with 1,180 additions and 66 deletions.
17 changes: 17 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[paths]
source =
yamlconf

[run]
source =
yamlconf
omit =
*tox*
setup.py
*test*

[report]
;sort = Cover
sort = Name
skip_covered = True
show_missing = True
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,4 @@ ENV/
# ignore backup files etc
*.bak
*.old
.pytest_cache/
16 changes: 16 additions & 0 deletions .isort.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[settings]
line_length=79
multi_line_output=3
include_trailing_comma=1
known_standard_library=typing
known_django=django
known_thirdparty=peewee
import_heading_stdlib=Imports from Standard Library
import_heading_thirdparty=Imports from Third Party Modules
import_heading_django=Imports from Django
import_heading_firstparty=Local Imports
sections=FUTURE,STDLIB,DJANGO,THIRDPARTY,FIRSTPARTY,LOCALFOLDER
not_skip = __init__.py

# for additional settings see:
# https://github.com/timothycrosley/isort/wiki/isort-Settings
6 changes: 6 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Changelog
=========

0.1.0 [2018-02-16]
------------------
* OpenSource release
47 changes: 0 additions & 47 deletions README.md

This file was deleted.

67 changes: 67 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
Py-SEED
=======

A python API client for the SEED Platform


Documentation
-------------
This provides two user authentication based Python clients and two OAuth2 authentication based Python clients for interacting with the SEED Platform Api::


SEEDOAuthReadOnlyClient
SEEDOAuthReadWriteClient
SEEDReadOnlyClient
SEEDReadWriteClient


(The OAuthMixin is constructed around the the JWTGrantClient found in jwt-oauth2lib. see https://github.com/GreenBuildingRegistry/jwt_oauth2)

SEED (Standard Energy Efficiency Data Platform™) is an open source "web-based application that helps organizations easily manage data on the energy performance of large groups of buildings" funded by the United States Department of Energy.

More information can be found here:
* https://energy.gov/eere/buildings/standard-energy-efficiency-data-platform
* http://seedinfo.lbl.gov/
* https://github.com/SEED-platform


Note the clients do not provide per api-call methods, but does provide the standard CRUD methods: get, list, put, post, patch, delete

The intended use of these clients is to be futher subclassed or wrapped in functions to provide the desired functionality. The CRUD methods are provided via mixins so its possible to create a client for example without the ability to delete by subclassing SEEDUserAuthBaseClient, or SEEDOAuthBaseClient, and adding only the mixins that provided the Create, Read and Update capabilities.

Basic usage for the provided clients is below.

Usage:


.. code-block:: python
from pyseed import SEEDReadWriteClient
seed_client = SEEDReadWriteClient(
your_org_id,
username=your_username,
password=your_password,
base_url=url_of_your_seed_host,
)
# list all properties
seed_client.list(endpoint='properties')
# get a single property
seed_client.get(property_pk, endpoint='properties')
Contributing
------------

License
-------
py-SEED is released under the terms of the MIT license. Full details in LICENSE file.

Changelog
---------
py-SEED was developed for use in the greenbuildingregistry project.
For a full changelog see `CHANGELOG.rst <https://github.com/GreenBuildingRegistry/py-seed/blob/master/CHANGELOG.rst>`_.

N.B. this client is undergoing development and should be considered experimental.
7 changes: 7 additions & 0 deletions pyseed/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Local Imports
from pyseed.seedclient import (
SEEDOAuthReadOnlyClient,
SEEDOAuthReadWriteClient,
SEEDReadOnlyClient,
SEEDReadWriteClient,
)
51 changes: 46 additions & 5 deletions pyseed/apibase.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@
# Imports from Standard Library
import re

# Imports from Third Party Modules
# Imports from External Modules
import requests


# Local Imports
# Public Functions and Classes
# Helper functions for use by BaseAPI subclasses
from pyseed.exceptions import APIClientError


def add_pk(url, pk, required=True, slash=False):
"""Add id/primary key to url"""
if required and not pk:
Expand All @@ -32,10 +36,6 @@ def add_pk(url, pk, required=True, slash=False):
return url


class APIClientError(Exception):
pass


class BaseAPI(object):
"""
Base class for API Calls
Expand Down Expand Up @@ -281,3 +281,44 @@ def _construct_payload(self, params):
if getattr(self, 'use_auth', None) and not getattr(self, 'auth', None):
self.auth = self._get_auth()
return super(UserAuthMixin, self)._construct_payload(params)


class OAuthMixin(object):
"""
Mixin to provide api client authentication via OAuth access tokens based
on the JWTGrantClient found in jwt-oauth2lib.
see https://github.com/GreenBuildingRegistry/jwt_oauth2
"""

_token_type = "Bearer"
oauth_client = None

def _get_access_token(self):
"""Generate OAuth access token"""
config = getattr(self, 'config')
private_key_file = config.get('private_key_location', default=None)
client_id = config.get('client_id', default=None)
username = getattr(self, 'username', None)
with open(private_key_file, 'r') as pk_file:
sig = pk_file.read()
oauth_client = self.oauth_client(
sig, username, client_id,
pvt_key_password=getattr(self, 'pvt_key_password', None)
)
return oauth_client.get_access_token()

def _construct_payload(self, params):
"""Construct parameters for an api call.
.
:param params: An dictionary of key-value pairs to include
in the request.
:return: A dictionary of k-v pairs to send to the server
in the request.
"""
params = super(OAuthMixin, self)._construct_payload(params)
token = getattr(self, 'token', None) or self._get_access_token()
params['headers'] = {
'Authorization': '{} {}'.format(self._token_type, token)
}
return params
69 changes: 69 additions & 0 deletions pyseed/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#!/usr/bin/env python
# encoding: utf-8
"""
copyright (c) 2016-2017 Earth Advantage.
All rights reserved
..codeauthor::Paul Munday <[email protected]>
"""


# Setup

# Constants

# Data Structure Definitions

# Private Functions

# Public Classes and Functions


class APIClientError(Exception):
"""Indicates errors when calling an API"""

def __init__(self, error, service=None, url=None, caller=None,
verb=None, status_code=None, **kwargs):
self.error = error
self.service = service
self.url = url
self.caller = caller
self.verb = verb
self.status_code = status_code
args = (
error, service, url, caller, verb.upper() if verb else None,
status_code
)
self.kwargs = kwargs
super(APIClientError, self).__init__(*args)

def __str__(self):
msg = "{}: {}".format(self.__class__.__name__, self.error)
if self.service:
msg = "{}, calling service {}".format(msg, self.service)
if self.caller:
msg = "{} as {}".format(msg, self.caller)
if self.url:
msg = "{} with url {}".format(msg, self.url)
if self.verb:
msg = "{}, http method: {}".format(msg, self.verb.upper())
if self.kwargs:
arguments = ", ".join([
"{}={}".format(str(key), str(val))
for key, val in self.kwargs.items()
])
msg = "{} supplied with {}".format(msg, arguments)
if self.status_code:
msg = "{} http status code: {}".format(msg, self.status_code)
return msg


class SEEDError(APIClientError):
"""Indicates Error interacting with SEED API"""

def __init__(self, error, url=None, caller=None, verb=None,
status_code=None, **kwargs):
super(SEEDError, self).__init__(
error, service='SEED', url=url, caller=caller, verb=verb,
status_code=status_code, **kwargs
)
Loading

0 comments on commit 10a40ec

Please sign in to comment.