Added documentation

This commit is contained in:
Stijn Van Campenhout
2019-09-18 12:11:42 +02:00
parent 1108f87ec9
commit 2222856f4d
6 changed files with 167 additions and 42 deletions

View File

@@ -32,7 +32,10 @@ release = '0.1'
# ones. # ones.
extensions = ['sphinx.ext.napoleon'] extensions = [
'sphinx.ext.napoleon',
'sphinx_autodoc_typehints'
]
# Add any paths that contain templates here, relative to this directory. # Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates'] templates_path = ['_templates']
@@ -54,3 +57,16 @@ html_theme = 'alabaster'
# relative to this directory. They are copied after the builtin static files, # relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css". # so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static'] html_static_path = ['_static']
napoleon_google_docstring = True
napoleon_numpy_docstring = True
napoleon_include_init_with_doc = False
napoleon_include_private_with_doc = False
napoleon_include_special_with_doc = True
napoleon_use_admonition_for_examples = False
napoleon_use_admonition_for_notes = False
napoleon_use_admonition_for_references = False
napoleon_use_ivar = False
napoleon_use_param = True
napoleon_use_rtype = True

View File

@@ -8,7 +8,8 @@ Welcome to rmapi's documentation!
.. toctree:: .. toctree::
:maxdepth: 2 :maxdepth: 2
:caption: Contents:
rmapi
.. automodule:: rmapi .. automodule:: rmapi

View File

@@ -297,12 +297,9 @@ class Client(object):
This needs to be done in 3 steps: This needs to be done in 3 steps:
1. Create an upload request for a new CollectionType meta object. #. Create an upload request for a new CollectionType meta object.
#. Upload a zipfile with a *.content file containing an empty object.
2. Upload a zipfile with a *.content file containing #. Update the meta object with the new name.
an empty object.
3. Update the meta object with the new name.
Args: Args:
folder: A folder instance. folder: A folder instance.

View File

@@ -1,13 +1,17 @@
from .document import Document from .document import Document
from .folder import Folder from .folder import Folder
from typing import NoReturn, TypeVar from typing import NoReturn, TypeVar, List
from .exceptions import FolderNotFound
DocOrFolder = TypeVar('DocumentOrFolder', Document, Folder) DocOrFolder = TypeVar('DocumentOrFolder', Document, Folder)
class Collection(object): class Collection(object):
""" """A collection of meta items
A collection of meta items
This is basicly the content of the Remarkable Cloud.
Attributes:
items: A list containing the items.
""" """
items = [] items = []
@@ -16,18 +20,36 @@ class Collection(object):
self.items.append(i) self.items.append(i)
def add(self, docdict: dict) -> NoReturn: def add(self, docdict: dict) -> NoReturn:
"""Add an item to the collection.
It wraps it in the correct class based on the Type parameter of the
dict.
Args:
docdict: A dict representing a document or folder.
"""
if docdict.get("Type", None) == "DocumentType": if docdict.get("Type", None) == "DocumentType":
return self.addDocument(docdict) return self.add_document(docdict)
elif docdict.get("Type", None) == "CollectionType": elif docdict.get("Type", None) == "CollectionType":
return self.addFolder(docdict) return self.add_folder(docdict)
else: else:
raise TypeError("Unsupported type: {_type}" raise TypeError("Unsupported type: {_type}"
.format(_type=docdict.get("Type", None))) .format(_type=docdict.get("Type", None)))
def addDocument(self, docdict: dict) -> NoReturn: def add_document(self, docdict: dict) -> NoReturn:
"""Add a document to the collection
Args:
docdict: A dict respresenting a document.
"""
self.items.append(Document(**docdict)) self.items.append(Document(**docdict))
def addFolder(self, dirdict: dict) -> NoReturn: def add_folder(self, dirdict: dict) -> NoReturn:
"""Add a document to the collection
Args:
dirdict: A dict respresenting a folder.
"""
self.items.append(Folder(**dirdict)) self.items.append(Folder(**dirdict))
def parent(self, docorfolder: DocOrFolder) -> Folder: def parent(self, docorfolder: DocOrFolder) -> Folder:

View File

@@ -4,8 +4,7 @@ from yaml import dump as yml_dump
def load() -> dict: def load() -> dict:
""" """Load the .rmapi config file
Load the .rmapi config file
""" """
config_file_path = Path.joinpath(Path.home(), ".rmapi") config_file_path = Path.joinpath(Path.home(), ".rmapi")
@@ -18,8 +17,11 @@ def load() -> dict:
def dump(config: dict) -> True: def dump(config: dict) -> True:
""" """Dump config to the .rmapi config file
Dump config to the .rmapi config file
Args:
config: A dict containing data to dump to the .rmapi
config file.
""" """
config_file_path = Path.joinpath(Path.home(), ".rmapi") config_file_path = Path.joinpath(Path.home(), ".rmapi")

View File

@@ -3,13 +3,36 @@ from zipfile import ZipFile, ZIP_DEFLATED
import shutil import shutil
from uuid import uuid4 from uuid import uuid4
import json import json
from typing import NoReturn from typing import NoReturn, TypeVar
from requests import Response from requests import Response
BytesOrString = TypeVar("BytesOrString", BytesIO, str)
class Document(object): class Document(object):
""" Document represents a real object expected in most """ Document represents a real object expected in most
calls by the remarkable API""" calls by the remarkable API
This contains the metadata from a document.
Attributes:
ID: Id of the meta object.
Version: The version of this object.
Success: If the last API Call was a succes.
BlobURLGet: The url to get the data blob from. Can be empty.
BlobURLGetExpires: The expiration date of the Get url.
BlobURLPut: The url to upload the data blob to. Can be empty.
BlobURLPutExpires: The expiration date of the Put url.
ModifiedClient: When the last change was by the client.
Type: Currently there are only 2 known types: DocumentType &
CollectionType.
VissibleName: The human name of the object.
CurrentPage: The current selected page of the object.
Bookmarked: If the object is bookmarked.
Parent: If empty, this object is is the root folder. This can be an ID
of a CollectionType.
"""
ID = "" ID = ""
Version = 0 Version = 0
@@ -31,7 +54,15 @@ class Document(object):
for k in kkeys: for k in kkeys:
setattr(self, k, kwargs.get(k, getattr(self, k))) setattr(self, k, kwargs.get(k, getattr(self, k)))
def to_dict(self): def to_dict(self) -> dict:
"""Return a dict representation of this object.
Used for API Calls.
Returns
a dict of the current object.
"""
return { return {
"ID": self.ID, "ID": self.ID,
"Version": self.Version, "Version": self.Version,
@@ -50,20 +81,23 @@ class Document(object):
} }
def __str__(self): def __str__(self):
"""String representation of this object"""
return f"<rmapi.document.Document {self.ID}>" return f"<rmapi.document.Document {self.ID}>"
def __repr__(self): def __repr__(self):
"""String representation of this object"""
return self.__str__() return self.__str__()
class ZipDocument(object): class ZipDocument(object):
""" """
Here is the content of an archive retried on the tablet as example: Here is the content of an archive retried on the tablet as example:
384327f5-133e-49c8-82ff-30aa19f3cfa40.content
384327f5-133e-49c8-82ff-30aa19f3cfa40-metadata.json * 384327f5-133e-49c8-82ff-30aa19f3cfa40.content
384327f5-133e-49c8-82ff-30aa19f3cfa40.rm * 384327f5-133e-49c8-82ff-30aa19f3cfa40-metadata.json
384327f5-133e-49c8-82ff-30aa19f3cfa40.pagedata * 384326f5-133e-49c8-82ff-30aa19f3cfa40.rm
384327f5-133e-49c8-82ff-30aa19f3cfa40.thumbnails/0.jpg * 384327f5-133e-49c8-82ff-30aa19f3cfa40.pagedata
* 384327f5-133e-49c8-82ff-30aa19f3cfa40.thumbnails/0.jpg
As the .zip file from remarkable is simply a normal .zip file As the .zip file from remarkable is simply a normal .zip file
containing specific file formats, this package is a helper to containing specific file formats, this package is a helper to
@@ -76,6 +110,16 @@ class ZipDocument(object):
You can find some help about the format at the following URL: You can find some help about the format at the following URL:
https://remarkablewiki.com/tech/filesystem https://remarkablewiki.com/tech/filesystem
Attributes:
content: Sane defaults for the .content file in the zip.
metadata: parameters describing this blob.
pagedata: the content of the .pagedata file.
zipfile: The raw zipfile in memory.
pdf: the raw pdf file if there is one.
epub: the raw epub file if there is one.
rm: A list of :class:rmapi.document.RmPage in this zip.
""" """
content = { content = {
"ExtraMetadata": { "ExtraMetadata": {
@@ -114,6 +158,7 @@ class ZipDocument(object):
"M33": 1, "M33": 1,
} }
} }
metadata = { metadata = {
"deleted": False, "deleted": False,
"lastModified": "1568368808000", "lastModified": "1568368808000",
@@ -136,6 +181,13 @@ class ZipDocument(object):
ID = None ID = None
def __init__(self, ID=None, doc=None, file=None): def __init__(self, ID=None, doc=None, file=None):
"""Create a new instance of a ZipDocument
Args:
ID: Can be left empty to generate one
doc: a raw pdf, epub or rm (.lines) file.
file: a zipfile to convert from
"""
if not ID: if not ID:
ID = str(uuid4()) ID = str(uuid4())
self.ID = ID self.ID = ID
@@ -160,15 +212,22 @@ class ZipDocument(object):
if file: if file:
self.load(file) self.load(file)
def __str__(self): def __str__(self) -> str:
"""string representation of this class"""
return f"<rmapi.document.ZipDocument {self.ID}>" return f"<rmapi.document.ZipDocument {self.ID}>"
def __repr__(self): def __repr__(self) -> str:
"""string representation of this class"""
return self.__str__() return self.__str__()
def dump(self, file): def dump(self, file: str) -> NoReturn:
""" """Dump the contents of ZipDocument back to a zip file.
Dump the contents of ZipDocument back to a zip file
This builds a zipfile to upload back to the Remarkable Cloud.
Args:
file: Where to save the zipfile
""" """
with ZipFile(f"{file}.zip", "w", ZIP_DEFLATED) as zf: with ZipFile(f"{file}.zip", "w", ZIP_DEFLATED) as zf:
@@ -198,10 +257,16 @@ class ZipDocument(object):
zf.writestr(f"{self.ID}.thumbnails/{page.order}.jpg", zf.writestr(f"{self.ID}.thumbnails/{page.order}.jpg",
page.thumbnail.read()) page.thumbnail.read())
def load(self, file) -> NoReturn: def load(self, file: BytesOrString) -> NoReturn:
""" """Load a zipfile into this class.
Fill in the defaults from the given ZIP
Extracts the zipfile and reads in the contents.
Args:
file: A string of a file location or a BytesIO instance of a raw
zipfile
""" """
self.zipfile = BytesIO() self.zipfile = BytesIO()
self.zipfile.seek(0) self.zipfile.seek(0)
if isinstance(file, str): if isinstance(file, str):
@@ -265,7 +330,11 @@ class ZipDocument(object):
class RmPage(object): class RmPage(object):
"""A Remarkable Page""" """A Remarkable Page
Contains the metadata, the page itself & thumbnail.
"""
def __init__(self, page, metadata=None, order=0, thumbnail=None, ID=None): def __init__(self, page, metadata=None, order=0, thumbnail=None, ID=None):
self.page = page self.page = page
if metadata: if metadata:
@@ -281,24 +350,42 @@ class RmPage(object):
else: else:
self.ID = str(uuid4()) self.ID = str(uuid4())
def __str__(self): def __str__(self) -> str:
"""String representation of this object"""
return f"<rmapi.document.RmPage {self.order} for {self.ID}>" return f"<rmapi.document.RmPage {self.order} for {self.ID}>"
def __repr__(self): def __repr__(self) -> str:
"""String representation of this object"""
return self.__str__() return self.__str__()
def from_zip(ID: str, file: str) -> ZipDocument: def from_zip(ID: str, file: str) -> ZipDocument:
"""Return A ZipDocument from a zipfile.
Create a ZipDocument instance from a zipfile.
Args:
ID: The object ID this zipfile represents.
file: the filename of the zipfile.
Returns:
An instance of the supplied zipfile.
""" """
Return A ZipDocument from a zipfile.
"""
return ZipDocument(ID, file=file) return ZipDocument(ID, file=file)
def from_request_stream(ID: str, stream: Response) -> ZipDocument: def from_request_stream(ID: str, stream: Response) -> ZipDocument:
"""Return a ZipDocument from a request stream containing a zipfile.
This is used with the BlobGETUrl from a :class:`rmapi.document.Document`.
Args:
ID: The object ID this zipfile represents.
stream: a stream containing the zipfile.
Returns:
the object of the downloaded zipfile.
""" """
Return a ZipDocument from a request stream containing a zipfile.
"""
tmp = BytesIO() tmp = BytesIO()
for chunk in stream.iter_content(chunk_size=8192): for chunk in stream.iter_content(chunk_size=8192):
tmp.write(chunk) tmp.write(chunk)