Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

+doc - simple sphinx-generated apidoc

  • Loading branch information...
commit 99ba8d3c3cd2bd39868e8ef7e98ef2df4aff95da 1 parent 5d5c528
@mk-fg authored
View
2  .gitignore
@@ -1,6 +1,8 @@
/*.egg-info
/build
/dist
+/doc/.doctrees
+/doc/*.txt
/README.txt
*.pyc
*.pyo
View
11 doc/Makefile
@@ -0,0 +1,11 @@
+PROJECT_ROOT = ..
+
+.PHONY: text clean
+
+text:
+ cd $(PROJECT_ROOT); python setup.py build; cd
+ sphinx-build -b text . .
+ ./sphinx_text_to_md.py api.txt > api.md
+
+clean:
+ -rm -rf $(BUILDDIR)/*
View
228 doc/api.md
@@ -0,0 +1,228 @@
+* **exception skydrive.api\_v5.SkyDriveInteractionError**
+
+ Bases: "exceptions.Exception"
+
+* **exception skydrive.api\_v5.ProtocolError(msg, code=None)**
+
+ Bases: "skydrive.api\_v5.SkyDriveInteractionError"
+
+
+ * \_\_init\_\_(msg, code=None)
+
+* **exception skydrive.api\_v5.AuthenticationError**
+
+ Bases: "skydrive.api\_v5.SkyDriveInteractionError"
+
+* **class skydrive.api\_v5.SkyDriveAuth(**config)**
+
+ Bases: "object"
+
+ * client\_id = None
+
+ Client id/secret should be static on per-application basis.
+
+ Can be received from LiveConnect by any registered user at
+ https://manage.dev.live.com/
+
+ API ToS can be found here at http://msdn.microsoft.com/en-
+ US/library/live/ff765012
+
+ * client\_secret = None
+
+ Client id/secret should be static on per-application basis.
+
+ Can be received from LiveConnect by any registered user at
+ https://manage.dev.live.com/
+
+ API ToS can be found here at http://msdn.microsoft.com/en-
+ US/library/live/ff765012
+
+ * auth\_url\_user = 'https://login.live.com/oauth20_authorize.srf'
+
+ * auth\_url\_token = 'https://login.live.com/oauth20_token.srf'
+
+ * auth\_scope = ('wl.skydrive', 'wl.skydrive\_update', 'wl.offline\_access')
+
+ * auth\_redirect\_uri\_mobile = 'https://login.live.com/oauth20_desktop.srf'
+
+ * auth\_access\_expires = None
+
+ Set by auth_get_token, not used internally
+
+ * auth\_access\_data\_raw = None
+
+ Set by auth_get_token, not used internally
+
+ * auth\_code = None
+
+ At least one of auth_code, auth_refresh_token or
+ auth_access_token should be set before data requests.
+
+ * auth\_refresh\_token = None
+
+ At least one of auth_code, auth_refresh_token or
+ auth_access_token should be set before data requests.
+
+ * auth\_access\_token = None
+
+ At least one of auth_code, auth_refresh_token or
+ auth_access_token should be set before data requests.
+
+ * auth\_redirect\_uri = 'https://login.live.com/oauth20_desktop.srf'
+
+ This (default) redirect_uri is **special** - app must be marked
+ as "mobile" to use it.
+
+
+ * auth\_user\_get\_url(scope=None)
+
+ Build authorization URL for User Agent.
+
+
+ * auth\_user\_process\_url(url)
+
+ Process tokens and errors from redirect_uri.
+
+
+ * auth\_get\_token(check\_scope=True)
+
+ Refresh or acquire access_token.
+
+* **class skydrive.api\_v5.SkyDriveAPI(**config)**
+
+ Bases: "skydrive.api\_v5.SkyDriveAuth"
+
+ * api\_url\_base = 'https://apis.live.net/v5.0/'
+
+
+ * get\_quota()
+
+ Return tuple of (bytes_available, bytes_quota).
+
+
+ * info(obj\_id='me/skydrive')
+
+ Return metadata of a specified object.
+
+ See http://msdn.microsoft.com/en-us/library/live/hh243648.aspx
+ for the list and description of metadata keys for each object
+ type.
+
+
+ * listdir(folder\_id='me/skydrive', type\_filter=None, limit=None)
+
+ Return a list of objects in the specified folder_id.
+
+ limit is passed to the API, so might be used as optimization.
+
+ type_filter can be set to type (str) or sequence of object types
+ to return, post-api-call processing.
+
+
+ * resolve\_path(path, root\_id='me/skydrive', objects=False)
+
+ Return id (or metadata) of an object, specified by chain
+ (iterable or fs-style path string) of "name" attributes of it's
+ ancestors.
+
+ Requires a lot of calls to resolve each name in path, so use
+ with care.
+
+ root_id parameter allows to specify path relative to some
+ folder_id (default: me/skydrive).
+
+
+ * get(obj\_id, byte\_range=None)
+
+ Download and return an file (object) or a specified byte_range
+ from it.
+
+ See HTTP Range header (rfc2616) for possible byte_range formats,
+ some examples: "0-499" - byte offsets 0-499 (inclusive), "-500"
+ \- final 500 bytes.
+
+
+ * put(path, folder\_id='me/skydrive', overwrite=True)
+
+ Upload a file (object), possibly overwriting (default behavior)
+ a file with the same "name" attribute, if exists.
+
+ overwrite option can be set to False to allow two identically-
+ named files or "ChooseNewName" to let SkyDrive derive some
+ similar unique name. Behavior of this option mimics underlying
+ API.
+
+
+ * mkdir(name=None, folder\_id='me/skydrive', metadata={})
+
+ Create a folder with a specified "name" attribute.
+
+ folder_id allows to specify a parent folder.
+
+ metadata mapping may contain additional folder properties to
+ pass to an API.
+
+
+ * delete(obj\_id)
+
+ Delete specified object.
+
+
+ * info\_update(obj\_id, data)
+
+ Update metadata with of a specified object.
+
+ See http://msdn.microsoft.com/en-us/library/live/hh243648.aspx
+ for the list of RW keys for each object type.
+
+
+ * link(obj\_id, link\_type='shared\_read\_link')
+
+ Return a preauthenticated (useable by anyone) link to a
+ specified object.
+
+ Object will be considered "shared" by SkyDrive, even if link is
+ never actually used.
+
+ link_type can be either "embed" (returns html),
+ "shared_read_link" or "shared_edit_link".
+
+
+ * copy(obj\_id, folder\_id, move=False)
+
+ Copy specified file (object) to a folder.
+
+ Note that folders cannot be copied, this is API limitation.
+
+
+ * move(obj\_id, folder\_id)
+
+ Move specified file (object) to a folder.
+
+ Note that folders cannot be moved, this is API limitation.
+
+
+ * comments(obj\_id)
+
+ Get a list of comments (message + metadata) for an object.
+
+
+ * comment\_add(obj\_id, message)
+
+ Add comment message to a specified object.
+
+
+ * comment\_delete(comment\_id)
+
+ Delete specified comment.
+
+ comment_id can be acquired by listing comments for an object.
+
+* **class skydrive.api\_v5.PersistentSkyDriveAPI(**config)**
+
+ Bases: "skydrive.api\_v5.SkyDriveAPI", "skydrive.conf.ConfigMixin"
+
+
+ * auth\_get\_token(*argz, **kwz)
+
+ Refresh or acquire access_token.
View
5 doc/api.rst
@@ -0,0 +1,5 @@
+.. automodule:: skydrive.api_v5
+ :members:
+ :undoc-members:
+ :show-inheritance:
+ :exclude-members: request
View
24 doc/conf.py
@@ -0,0 +1,24 @@
+import sys, os
+from os.path import abspath, dirname, join
+
+
+doc_root = dirname(__file__)
+# autodoc_dump_rst = open(join(doc_root, 'autodoc.rst'), 'w')
+
+os.chdir(doc_root)
+sys.path.insert(0, abspath('..')) # for module itself
+sys.path.append(abspath('.')) # for extenstions
+
+
+needs_sphinx = '1.1'
+extensions = ['sphinx.ext.autodoc', 'sphinx_local_hooks']
+
+master_doc = 'api'
+pygments_style = 'sphinx'
+
+source_suffix = '.rst'
+# exclude_patterns = ['_build']
+# templates_path = ['_templates']
+
+autoclass_content = 'class'
+autodoc_member_order = 'bysource'
View
63 doc/sphinx_local_hooks.py
@@ -0,0 +1,63 @@
+#-*- coding: utf-8 -*-
+
+import itertools as it, operator as op, functools as ft
+from collections import Iterable
+import types
+
+
+from sphinx.ext.autodoc import Documenter
+
+_autodoc_add_line = Documenter.add_line
+
+@ft.wraps(_autodoc_add_line)
+def autodoc_add_line(self, line, *argz, **kwz):
+ tee = self.env.app.config.autodoc_dump_rst
+ if tee:
+ tee_line = self.indent + line
+ if isinstance(tee, file): tee.write(tee_line + '\n')
+ elif tee is True: print tee_line
+ else:
+ raise ValueError( 'Unrecognized'
+ ' value for "autodoc_dump_rst" option: {!r}'.format(tee) )
+ return _autodoc_add_line(self, line, *argz, **kwz)
+
+Documenter.add_line = autodoc_add_line
+
+
+def process_docstring(app, what, name, obj, options, lines):
+ if not lines: return
+
+ i, ld = 0, dict(enumerate(lines)) # to allow arbitrary peeks
+ i_max = max(ld)
+
+ def process_line(i):
+ line, i_next = ld[i], i + 1
+ while i_next not in ld and i_next <= i_max: i_next += 1
+ line_next = ld.get(i_next)
+
+ if line_next and line_next[0] in u' \t': # tabbed continuation of the sentence
+ ld[i] = u'{} {}'.format(line, line_next.strip())
+ del ld[i_next]
+ process_line(i)
+ elif line.endswith(u'.') or (line_next and line_next[0].isupper()): ld[i+0.5] = u''
+
+ for i in xrange(i_max + 1):
+ if i not in ld: continue # was removed
+ process_line(i)
+
+ # Overwrite the list items inplace, extending the list if necessary
+ for i, (k, line) in enumerate(sorted(ld.viewitems())):
+ try: lines[i] = line
+ except IndexError: lines.append(line)
+
+
+def skip_override(app, what, name, obj, skip, options):
+ if what == 'exception':
+ return False if name == '__init__'\
+ and isinstance(obj, types.UnboundMethodType) else True
+ return skip
+
+def setup(app):
+ app.connect('autodoc-process-docstring', process_docstring)
+ app.connect('autodoc-skip-member', skip_override)
+ app.add_config_value('autodoc_dump_rst', None, True)
View
78 doc/sphinx_text_to_md.py
@@ -0,0 +1,78 @@
+#!/usr/bin/env python
+#-*- coding: utf-8 -*-
+from __future__ import unicode_literals, print_function
+
+import itertools as it, operator as op, functools as ft
+import os, sys, re
+
+
+class FormatError(Exception): pass
+
+
+def main():
+ import argparse
+ parser = argparse.ArgumentParser(
+ description='Convert sphinx-produced autodoc.apidoc text to markdown.')
+ parser.add_argument('src', nargs='?', help='Source file (default: use stdin).')
+ optz = parser.parse_args()
+
+ src = open(optz.src) if optz.src else sys.stdin
+ dst = sys.stdout
+
+ py_name = r'[\w_\d]+'
+ out = ft.partial(print, file=dst)
+
+ st_attrdoc = 0
+
+ for line in src:
+ ls = line.strip()
+ if not ls: # blank line
+ out(line, end='')
+ continue
+
+ line_indent = re.search(r'^( +)', line)
+ if not line_indent: line_indent = 0
+ else:
+ line_indent = len(line_indent.group(1))
+ if line_indent % 3: raise FormatError('Weird indent size: {}'.format(line_indent))
+ line_indent = line_indent / 3
+
+ lp = line.split()
+ lse = ls.replace('_', r'\_').replace('*', r'\*')
+ for url in re.findall(r'\b\w+://\S+', lse):
+ lse = lse.replace(url, url.replace(r'\_', '_'))
+ lse = re.sub(r'\bu([\'"])', r'\1', lse)
+
+ st_attrdoc_reset = True
+ if not line_indent:
+ if len(lp) > 2 and lp[0] == lp[1]:
+ if lp[0] in ('exception', 'class'): # class, exception
+ out('* **{}**'.format(' '.join(lse.split()[1:])))
+
+ else:
+ raise FormatError('Unhandled: {!r}'.format(line))
+
+ elif line_indent == 1:
+ if re.search(r'^{}\('.format(py_name), ls): # function
+ out('\n'*1, end='')
+ out('{}* {}'.format(' '*4, lse))
+ st_attrdoc, st_attrdoc_reset = 8, False
+ elif re.search(r'^{}\s+=\s+'.format(py_name), ls): # attribute
+ out('{}* {}'.format(' '*4, lse))
+ st_attrdoc, st_attrdoc_reset = 8, False
+ elif lp[0] == 'Bases:': # class bases
+ out('{}{}'.format(' '*4, lse))
+ st_attrdoc, st_attrdoc_reset = 4, False
+
+ else:
+ raise FormatError('Unhandled: {!r}'.format(line))
+
+ else: # description line
+ if ls[0] in '-*': line = '\\' + line.lstrip()
+ out('{}{}'.format(' '*st_attrdoc, line.lstrip()), end='')
+ st_attrdoc_reset = False
+
+ if st_attrdoc and st_attrdoc_reset: st_attrdoc = 0
+
+
+if __name__ == '__main__': main()
View
2  setup.py
@@ -12,7 +12,7 @@
setup(
name = 'python-skydrive',
- version = '12.09.30',
+ version = '12.09.31',
author = 'Mike Kazantsev',
author_email = 'mk.fraggod@gmail.com',
license = 'WTFPL',
View
24 skydrive/api_v5.py
@@ -54,9 +54,9 @@ def request( url, method='get', data=None, files=None,
class SkyDriveAuth(object):
- # Client id/secret should be static on per-application basis.
- # Can be received from LiveConnect by any registered user at https://manage.dev.live.com/
- # API ToS can be found here at http://msdn.microsoft.com/en-US/library/live/ff765012
+ #: Client id/secret should be static on per-application basis.
+ #: Can be received from LiveConnect by any registered user at https://manage.dev.live.com/
+ #: API ToS can be found here at http://msdn.microsoft.com/en-US/library/live/ff765012
client_id = client_secret = None
auth_url_user = 'https://login.live.com/oauth20_authorize.srf'
@@ -64,17 +64,19 @@ class SkyDriveAuth(object):
auth_scope = 'wl.skydrive', 'wl.skydrive_update', 'wl.offline_access'
auth_redirect_uri_mobile = 'https://login.live.com/oauth20_desktop.srf'
- # Set by auth_get_token, not used internally
+ #: Set by auth_get_token, not used internally
auth_access_expires = auth_access_data_raw = None
- # At least one of these should be set before data requests.
+ #: At least one of auth_code, auth_refresh_token or
+ #: auth_access_token should be set before data requests.
auth_code = auth_refresh_token = auth_access_token = None
- # This (default) redirect_uri is **special** - app must be marked as "mobile" to use it.
+ #: This (default) redirect_uri is **special** - app must be marked as "mobile" to use it.
auth_redirect_uri = auth_redirect_uri_mobile
def __init__(self, **config):
+ 'Initialize API wrapper class with specified properties set.'
for k, v in config.viewitems():
try: getattr(self, k)
except AttributeError:
@@ -83,6 +85,7 @@ def __init__(self, **config):
def auth_user_get_url(self, scope=None):
+ 'Build authorization URL for User Agent.'
# Note: default redirect_uri is **special**, app must be marked as "mobile" to use it
if not self.client_id: raise AuthenticationError('No client_id specified')
return '{}?{}'.format( self.auth_url_user, urllib.urlencode(dict(
@@ -90,6 +93,7 @@ def auth_user_get_url(self, scope=None):
response_type='code', redirect_uri=self.auth_redirect_uri )) )
def auth_user_process_url(self, url):
+ 'Process tokens and errors from redirect_uri.'
url = urlparse.urlparse(url)
url_qs = dict(it.chain.from_iterable(
urlparse.parse_qsl(v) for v in [url.query, url.fragment] ))
@@ -100,9 +104,8 @@ def auth_user_process_url(self, url):
return self.auth_code
- def auth_get_token( self, check_scope=True,
- _check_keys=['client_id', 'client_secret', 'code', 'refresh_token', 'grant_type'] ):
-
+ def auth_get_token(self, check_scope=True):
+ 'Refresh or acquire access_token.'
post_data = dict( client_id=self.client_id,
client_secret=self.client_secret, redirect_uri=self.auth_redirect_uri )
if not self.auth_refresh_token:
@@ -115,7 +118,8 @@ def auth_get_token( self, check_scope=True,
post_data.update(
refresh_token=self.auth_refresh_token, grant_type='refresh_token' )
post_data_missing_keys = list( k for k in
- _check_keys if k in post_data and not post_data[k] )
+ ['client_id', 'client_secret', 'code', 'refresh_token', 'grant_type']
+ if k in post_data and not post_data[k] )
if post_data_missing_keys:
raise AuthenticationError( 'Insufficient authentication'
' data provided (missing keys: {})'.format(post_data_missing_keys) )
Please sign in to comment.
Something went wrong with that request. Please try again.