Skip to content

Commit

Permalink
Merge branch 'release/0.1.1'
Browse files Browse the repository at this point in the history
  • Loading branch information
Elliott Maguire committed Jul 14, 2019
2 parents 439b37e + 41332f5 commit bba8109
Show file tree
Hide file tree
Showing 11 changed files with 106 additions and 56 deletions.
6 changes: 3 additions & 3 deletions credentials.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"type": "service_account",
"project_id": "udsi-testing",
"private_key_id": "0ca1e3c466358eb61ad62c407b4da16d472c077a",
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDE8q3IiqKLvenC\ntDANoheLH3/1deRhlm7UwqOZZVMe+LyXLAb65EzjKacrqyLIZD+qQl3s5ldsEgxm\nLF+58rs3l4oeJhNSe5mPYrGyJRQNA5co6SqoqmWJTpyTL+TPpKPgmsQJk5gNcD0z\nWduX4K7yydB1l4l2JE6CB8GOhv8ZzsKHwjMUU3KzyMx4Z2v29tRHLEH4WI80FEtg\nkdMAm3wC8KHR+vEWmRdvRKJ8PGf0IslVGLSTe2YxROYz+B7gHZViNQqN6Hk0MwCv\n76xZmEoACmfeAXkWxNVOdctDRLT9h8dATRE58B0fsxiGA/mYqQbqhdE0CSOFZYT9\n6M0WXrtxAgMBAAECggEAOauQPL1vvHi3dyaZPZy9xSTLrN5BKlxJBu8ZxcS4UsTm\nQGQJhTUN2KTtSSm7LS/BvsLhSwnmBoTAcbjDrSkJLk2nCY3/sXL089okC3S1CtyG\nylmAftQqmErXKXhoSW8993qKNf2slB7OJPfGiBIoWHrFGnHttBUMkiHgSTJ5h54S\njZUA2Z9uJQ19n/rrHSZ5jRgkZoFlph3FoNrEq87eMTsmBX3Nphvr+6YOWmNEe2v0\nmyr+ZsV/AW2zTaLk6feBA/3q+l7ueeUFLsZrqBf3RbJ6yN+zS3YA7Cm3nnj1C1WO\n2WXZBkDSWkBKwmLu1icPtmpSRQORyr2ZYbCY4JQ+awKBgQDrYQVCp1EIH8vLyKr2\nQuHLznDqWSQl8GAwdz1dHVmD1/RuwZJZmGiuuh+OxR81D5DjQr/1ojGPHwf5378/\nV8cP7ikOVDwogKuli8X//bkbO/aKLCOgW3JoTEVYhdOeqmQGPysjRzp7W0UatDzJ\n5CAwpdETX8N3fAG9nHoFbbq0VwKBgQDWM75k5SUoF5JT2RbiHb1rnqeXssOGz+8Z\nA/boPkg+71gsySmNUoiBNJgS6meM993xUMogsavx6YWRwMXy7/azZxuj25MNK5F0\nDLW1y/PJuiLQSkTUIkutZ6TtwiLqO35GuXl14yg9k6Z3SKk3GCpJC6TdUf8bOkFh\nU4T7vEnxdwKBgQChmudFsCLOdSYzL/9RPPJSP9b+z10mPzeLjxKuj6wZ/XdxY63b\nneyhqmBoYabfg2Ry5C1vtIBaR2/ue1SPZPDjWx0NHYCAPnebHbA/5i/lJvJKQ6vi\nOWb/fP5PnPKCiXJLZ6tyeUEJ2MxFXWIvK1V+kRpPNvy5WIbJbFnKyF/b2QKBgQC4\nyv0XmCRdGTDRC3lVa6jN3prhIYTTmjHA2A27wHeda+kbAhTJ6gj/xrrnnrflArXD\niRpH6F/ZnMfxvWhItMKVdX9/9l8/vnWGs6xUAXb5co60OU514Hx/ReoggBqVDuxa\n4YoqrOU7clTrlZD+ied5CwWZNjMqbzCWYXJZps/38wKBgEAI4V3uZ1Rgdo7Cw78/\nMiTVUcijENJDvPmuPpJ54i68lrAWi+eZpsiICXzjQnwC/vR6eM8qCeYaW9WEhcNk\nP2KAQQE6uXmpdwGlCKz9UOGL7wdE8Si8Vq6kG3KYO3G3+nHC7AWcW20CzxbSaX+X\nv5+IsSPVglydWaKjhuw0yNVv\n-----END PRIVATE KEY-----\n",
"private_key_id": "f62a1b274ca1b49d3c64f18d46219d46e90f268b",
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCbxWigvEwTKOje\nbRcxIEbQioQd7pwu/iSK6BIcAH+m9o+u/oefZMksKEpBJCaT3Tv5XqqpH/stJHGn\nsR0phhz8ooHdeEfJlBjEGOU1P0Bf80w9aN7kVZo+0ISWAtGv32Nn93aIW6w4NjdX\n1l78PZ7l3AEn4yKIsDdhfO27HSCcYTevHkEHSXA75/IJukDfHnZ4Zw4gaOrR8Ehe\nkYyHCrW8HmHte4y8EHxGS/Mu1a3HfhhqFdLLRMrULjs5sgr3Wvs/rsLYzfJaOhOt\nkmmc96urLmdf9JZWYVXcpDpdXbzX/P30bnw/emf0WRwttlViKhwn/hNGQo0pyOxy\nJeham34FAgMBAAECggEAETFhQnh2BxlZVo+A4022MzdOrMUU3QT1AJXrxcZyUHnf\nUwfJ7Vhg8exCgd0dGu3svDHsMT2T6iAfIUyltNsWIPZI0ip/9epQL3i198IS92Qx\nsod8LoSaQTufnrUR8tD7tlJ0dUl1AUFOq3XARyQAAUvensntmlukyTBSRvhIjKns\nEOuyyojv4pgpO5GQLDonSOCQ0hlMBugl8/ZMRMVoMiTiQYWwoNixY9uEW/XeIxry\nodbywvC9hG/RaNvDAgdss1GFNV/wCytE1SiW6isUfzwX0QgqFFuCfY3t8DBoK5W0\n9p3pvakJw4/gR4xHiXXMX/+kWUlGzDHyd2bydWOXUwKBgQDZArfZ4GuLo9UPgc6i\nThJB+atszit9OH0xL/WDcs4V2bOIh+qS83aRLstoCNLXR1z/C3x7ERKCzDpwIOSX\n4HaLtkW9/43aXOMUQApt5nbzAgcppe9LVgORJ7ZPWPNEDylaqTUQqs7h2sNZr+BX\nlBJcKK2jWsM8OdwMqDddn3kBGwKBgQC3wgO1O8rbAIK56Wls66wVPmpQBcYV6UkE\nCBzwSQineVbJPn8mrPegAhyTBhSZxUw7cNcUGWpgnxhN8s3qFLxh/bt2CEwhJu5G\nrBrjY+aSCcRpBeG4n7px30J8HZ6kmUQFGlGGxqrfLN46apBALBRAi1HpS6ZiffnE\nuFh4xqKPXwKBgQCrjAGII2cAsRc5NfUBytOWAebokSZBy8jzfCUJr1SIY1sP/9mI\nJxvAcwxqhicd9RTnrM3Pf1Rxvz4m62mpQdCUaxdAtecOCkWb+XAFJp07Rowg+UJr\n/Ge/dHQiz38mexHG0GHZdh0q30Nz/5tJwAyve5yfuJ0DW/2+p690vB7spwKBgA+W\nNmhODRPshCou4VFq4CrhI3VsN/Qt2JKt+X5sQ36pLTJeybxHGa4J39CcyGyOrruw\nA55h1YMim5YpDUxYu+337snBRGvfeICoIpO9Kpaim3VpGU9mxRLZpDMQ9B70HS/t\nnpK3EVFi5erAlUHMO1+KMcV/NDrQgrosBN0hxDIzAoGAS1l1xecDMi+FmVgD0Tg7\nhcJ75Fu5OYDkIlGj+MRDvOrzU0p2bq9sCXEFjugg5ZslOlOcJDvbXrJiS2s4J6IQ\n0q8sp5mPY//z8m37o58NBN7MZTqFNf7pr0xmmiB2H8YojvGNy+VoA0PUMug22A3z\n7GbPwb/LBuNklH3OJaaNyA8=\n-----END PRIVATE KEY-----\n",
"client_email": "[email protected]",
"client_id": "101330637651138441167",
"client_id": "109823384243757955786",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
Expand Down
Binary file added dist/udsi-0.1.1-py3-none-any.whl
Binary file not shown.
Binary file added dist/udsi-0.1.1.tar.gz
Binary file not shown.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "udsi"
version = "0.1.0"
version = "0.1.1"
description = "Unlimited Drive Storage Improved"
authors = ["elliott-maguire <[email protected]>"]

Expand Down
37 changes: 22 additions & 15 deletions tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import os
import json
import asyncio

from udsi.client import Client
from udsi.utils import build
Expand All @@ -19,36 +20,42 @@
class TestClient:
""" Test class for the `client` module. """
@async_test
async def test_upload_file(self):
async def test_init(self):
client = make_client()
file, r = await make_file(client)

assert type(r) is dict
assert 'temp' in json.dumps(r)
assert 'udsi-root-folder' in json.dumps(client.root)

await cleanup(client, r.get('spreadsheetId'))
@async_test
async def test_upload(self):
client = make_client()
file, sheet = await make_file(client)

assert type(sheet) is dict
assert 'temp' in json.dumps(sheet)

await cleanup(client, sheet.get('spreadsheetId'))

@async_test
async def test_get_file(self):
async def test_get(self):
client = make_client()
file, r = await make_file(client)
file, sheet = await make_file(client)

id = r.get('spreadsheetId')
r, d = await client.get(id)
id = sheet.get('spreadsheetId')
sheet, data = await client.get(id)

assert type(r) is dict
assert 'temp' in json.dumps(r)
assert type(sheet) is dict
assert 'temp' in json.dumps(sheet)

await cleanup(client, r.get('id'))
await cleanup(client, sheet.get('spreadsheetId'))

@async_test
async def test_list_files(self):
async def test_list(self):
client = make_client()
file, r = await make_file(client)
file, sheet = await make_file(client)

files = await client.list()

assert type(files) is list
assert 'temp' in json.dumps(files)

await cleanup(client, r.get('spreadsheetId'))
await cleanup(client, sheet.get('spreadsheetId'))
8 changes: 4 additions & 4 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ def test_build(self):
async def test_rebuild(self):
client = make_client()
file, r = await make_file(client)
r, d = await client.get(r.get('spreadsheetId'))
sheet, data = await client.get(r.get('spreadsheetId'))

built = rebuild(r, d)
built = rebuild(sheet, data)

assert type(built) is UDSIFile
assert built.name == 'udsi-temp'
assert built.name == 'temp'

await cleanup(client, r.get('id'))
await cleanup(client, r.get('spreadsheetId'))
4 changes: 2 additions & 2 deletions tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ async def make_file(client):
new.close()

file = build('temp')
r = await client.upload(file)
sheet = await client.upload(file)

return file, r
return file, sheet


async def cleanup(client, id):
Expand Down
3 changes: 3 additions & 0 deletions udsi/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from .client import Client
from .utils import build, rebuild
from .models import UDSIFile
85 changes: 61 additions & 24 deletions udsi/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
"""

import time
import json
import uuid
import string
import asyncio
from textwrap import wrap

from .models import UDSIFile
Expand All @@ -22,15 +22,50 @@ class Client(object):
""" Implement Google API handling.
:param creds: a google-auth Credentials object.
:param session: (optional) a session capable of making persistent
HTTP requests. Defaults to `requests.Session()`.
"""
def __init__(self, creds: Credentials):
self.drive = build('drive', 'v3', credentials=creds)
self.sheets = build('sheets', 'v4', credentials=creds)

async def upload(self, file: UDSIFile, **kwargs):
""" Upload a UDSI file.
self.root = self._setup_root()

def _setup_root(self):
""" Gets or creates the root UDSI folder. """
q = 'name = "udsi-root-folder"'
r = self.drive.files() \
.list(
q=q,
fields=('files(id, name)')) \
.execute()

files = r.get('files', [])
root = files[0] \
if files \
else self.create_folder('root')

return root

def create_folder(self, name: str, parents: list = None) -> dict:
""" Create a folder for a UDSI filedump.
:param name: the name of the folder.
:param parents: (optional) a list of parent directories under which
the given file should be stored.
"""
body = {
'name': f'udsi-{name}-folder',
'mimeType': 'application/vnd.google-apps.folder',
'parents': parents}
r = self.drive.files() \
.create(
body=body,
fields='id, name') \
.execute()

return r

async def upload(self, file: UDSIFile, **kwargs) -> dict:
""" Uploads a UDSI file.
A spreadsheet and folder are created, data is chunked,
and pushed row-by-row to that sheet.
Expand Down Expand Up @@ -58,11 +93,11 @@ def split(seq: list, n: int):
seq = seq[n:]

blocks = wrap(file.data, 50000)
arrays = list(split(blocks, 10))
arrays = list(split(blocks, 26))

for i, array in enumerate(arrays):
row = i + 1
range = f'Sheet1!A{row}:J{row}'
range = f'Sheet1!A{row}:Z{row}'
body = {'values': [array]}

try:
Expand All @@ -84,29 +119,31 @@ def split(seq: list, n: int):

return sheet

async def get(self, id: str):
""" Get a UDSI file.
async def get(self, id: str) -> (dict, dict):
""" Gets a UDSI file.
:param id: a valid file ID.
:return r: a dict of file data.
:return d: a dict of sheet data.
:return sheet: a dict of sheet metadata.
:return data: a dict of sheet contents.
"""
r = self.drive.files() \
.get(
fileId=id,
fields='*') \
sheet = self.sheets.spreadsheets() \
.get(spreadsheetId=id) \
.execute()
d = self.sheets.spreadsheets().values() \
.get(
spreadsheetId=id,
range='A1:Z1000') \

nrows = sheet \
['sheets'][0] \
['properties']['gridProperties'] \
['rowCount']

data = self.sheets.spreadsheets().values() \
.get(spreadsheetId=id, range=f'A1:Z{nrows}') \
.execute()

return r, d
return sheet, data

async def list(self, folder: str = None):
""" List all UDSI files in a UDSI directory.
async def list(self, folder: str = None) -> list:
""" Lists all UDSI files in a UDSI directory.
:param folder: (optional) the ID of the folder from which
files should be fetched.
Expand All @@ -130,7 +167,7 @@ async def list(self, folder: str = None):
return files

async def delete(self, id: str):
""" Delete a UDSI file.
""" Deletes a UDSI file.
:param id: a valid file ID.
"""
Expand Down
2 changes: 1 addition & 1 deletion udsi/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class UDSIFile:
data: str

@property
def asdict(self):
def asdict(self) -> dict:
return dataclasses.asdict(self)

def export(self):
Expand Down
15 changes: 9 additions & 6 deletions udsi/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from .models import UDSIFile


def build(name: str, **kwargs):
def build(name: str, **kwargs) -> UDSIFile:
""" Builds a UDSIFile object from a file.
:param name: the name/path of an accessible file.
Expand All @@ -29,25 +29,28 @@ def build(name: str, **kwargs):
return file


def rebuild(r: dict, d: dict):
def rebuild(sheet: dict, data: dict) -> UDSIFile:
""" Rebuilds a UDSIFile object from an API response.
Data sent to `rebuild` must be dictionary responses
from the `get_file` method.
:param r: a dict of file data.
:param d: a dict of sheet data.
:param sheet: a dict of sheet metadata.
:param data: a dict of sheet contents.
:return file: a new UDSIFile object.
"""
arrays = d.get('values')
properties = sheet.get('properties')

arrays = data.get('values')
data = ''
for array in arrays:
block = ''.join(array)
data = ''.join([data, block])

file = UDSIFile(
id=r.get('spreadsheetId'), name=r.get('name'),
id=sheet.get('spreadsheetId'),
name=properties.get('title')[5:],
data=data)

return file

0 comments on commit bba8109

Please sign in to comment.