[docs] for frappe client #2209

This commit is contained in:
Rushabh Mehta 2016-11-08 12:24:20 +05:30
parent a16e6a143f
commit 638816acd0
3 changed files with 140 additions and 4 deletions

View file

@ -8,14 +8,33 @@ import frappe.model
import frappe.utils
import json, os
'''
Handle RESTful requests that are mapped to the `/api/resource` route.
Requests via FrappeClient are also handled here.
'''
@frappe.whitelist()
def get_list(doctype, fields=None, filters=None, order_by=None,
limit_start=None, limit_page_length=20):
'''Returns a list of records by filters, fields, ordering and limit
:param doctype: DocType of the data to be queried
:param fields: fields to be returned. Default is `name`
:param filters: filter list by this dict
:param order_by: Order by this fieldname
:param limit_start: Start at this index
:param limit_page_length: Number of records to be returned (default 20)'''
return frappe.get_list(doctype, fields=fields, filters=filters, order_by=order_by,
limit_start=limit_start, limit_page_length=limit_page_length, ignore_permissions=False)
@frappe.whitelist()
def get(doctype, name=None, filters=None):
'''Returns a document by name or filters
:param doctype: DocType of the document to be returned
:param name: return document of this `name`
:param filters: If name is not set, filter by these values and return the first match'''
if filters and not name:
name = frappe.db.get_value(doctype, json.loads(filters))
if not name:
@ -29,6 +48,12 @@ def get(doctype, name=None, filters=None):
@frappe.whitelist()
def get_value(doctype, fieldname, filters=None, as_dict=True, debug=False):
'''Returns a value form a document
:param doctype: DocType to be queried
:param fieldname: Field to be returned (default `name`)
:param filters: dict or string for identifying the record'''
if not frappe.has_permission(doctype):
frappe.throw(_("Not permitted"), frappe.PermissionError)
@ -80,6 +105,9 @@ def set_value(doctype, name, fieldname, value=None):
@frappe.whitelist()
def insert(doc=None):
'''Insert a document
:param doc: JSON or dict object to be inserted'''
if isinstance(doc, basestring):
doc = json.loads(doc)
@ -95,6 +123,9 @@ def insert(doc=None):
@frappe.whitelist()
def insert_many(docs=None):
'''Insert multiple documents
:param docs: JSON or list of dict objects to be inserted in one request'''
if isinstance(docs, basestring):
docs = json.loads(docs)
@ -118,6 +149,9 @@ def insert_many(docs=None):
@frappe.whitelist()
def save(doc):
'''Update (save) an existing document
:param doc: JSON or dict object with the properties of the document to be updated'''
if isinstance(doc, basestring):
doc = json.loads(doc)
@ -126,11 +160,19 @@ def save(doc):
@frappe.whitelist()
def rename_doc(doctype, old_name, new_name, merge=False):
'''Rename document
:param doctype: DocType of the document to be renamed
:param old_name: Current `name` of the document to be renamed
:param new_name: New `name` to be set'''
new_name = frappe.rename_doc(doctype, old_name, new_name, merge=merge)
return new_name
@frappe.whitelist()
def submit(doc):
'''Submit a document
:param doc: JSON or dict object to be submitted remotely'''
if isinstance(doc, basestring):
doc = json.loads(doc)
@ -141,6 +183,10 @@ def submit(doc):
@frappe.whitelist()
def cancel(doctype, name):
'''Cancel a document
:param doctype: DocType of the document to be cancelled
:param name: name of the document to be cancelled'''
wrapper = frappe.get_doc(doctype, name)
wrapper.cancel()
@ -148,6 +194,10 @@ def cancel(doctype, name):
@frappe.whitelist()
def delete(doctype, name):
'''Delete a remote document
:param doctype: DocType of the document to be deleted
:param name: name of the document to be deleted'''
frappe.delete_doc(doctype, name)
@frappe.whitelist()
@ -158,6 +208,9 @@ def set_default(key, value, parent=None):
@frappe.whitelist()
def make_width_property_setter(doc):
'''Set width Property Setter
:param doc: Property Setter document with `width` property'''
if isinstance(doc, basestring):
doc = json.loads(doc)
if doc["doctype"]=="Property Setter" and doc["property"]=="width":
@ -165,6 +218,9 @@ def make_width_property_setter(doc):
@frappe.whitelist()
def bulk_update(docs):
'''Bulk update documents
:param docs: JSON list of documents to be updated remotely. Each document must have `docname` property'''
docs = json.loads(docs)
failed_docs = []
for doc in docs:
@ -184,17 +240,32 @@ def bulk_update(docs):
@frappe.whitelist()
def has_permission(doctype, docname, perm_type="read"):
'''Returns a JSON with data whether the document has the requested permission
:param doctype: DocType of the document to be checked
:param docname: `name` of the document to be checked
:param perm_type: one of `read`, `write`, `create`, `submit`, `cancel`, `report`. Default is `read`'''
# perm_type can be one of read, write, create, submit, cancel, report
return {"has_permission": frappe.has_permission(doctype, perm_type.lower(), docname)}
@frappe.whitelist()
def get_password(doctype, name, fieldname):
'''Return a password type property. Only applicable for System Managers
:param doctype: DocType of the document that holds the password
:param name: `name` of the document that holds the password
:param fieldname: `fieldname` of the password property
'''
frappe.only_for("System Manager")
return frappe.get_doc(doctype, name).get_password(fieldname)
@frappe.whitelist()
def get_js(items):
'''Load JS code files. Will also append translations
and extend `frappe._messages`
:param items: JSON list of paths of the js files to be loaded.'''
items = json.loads(items)
out = []
for src in items:

View file

@ -2,6 +2,13 @@ import requests
import json
import frappe
'''
FrappeClient is a library that helps you connect with other frappe systems
'''
class AuthError(Exception):
pass
@ -13,7 +20,7 @@ class FrappeClient(object):
self.verify = verify
self.session = requests.session()
self.url = url
self.login(username, password)
self._login(username, password)
def __enter__(self):
return self
@ -21,7 +28,8 @@ class FrappeClient(object):
def __exit__(self, *args, **kwargs):
self.logout()
def login(self, username, password):
def _login(self, username, password):
'''Login/start a sesion. Called internally on init'''
r = self.session.post(self.url, data={
'cmd': 'login',
'usr': username,
@ -34,6 +42,7 @@ class FrappeClient(object):
raise AuthError
def logout(self):
'''Logout session'''
self.session.get(self.url, params={
'cmd': 'logout',
}, verify=self.verify)
@ -54,41 +63,65 @@ class FrappeClient(object):
return self.post_process(res)
def insert(self, doc):
'''Insert a document to the remote server
:param doc: A dict or Document object to be inserted remotely'''
res = self.session.post(self.url + "/api/resource/" + doc.get("doctype"),
data={"data":frappe.as_json(doc)}, verify=self.verify)
return self.post_process(res)
def insert_many(self, docs):
'''Insert multiple documents to the remote server
:param docs: List of dict or Document objects to be inserted in one request'''
return self.post_request({
"cmd": "frappe.client.insert_many",
"docs": frappe.as_json(docs)
})
def update(self, doc):
'''Update a remote document
:param doc: dict or Document object to be updated remotely. `name` is mandatory for this'''
url = self.url + "/api/resource/" + doc.get("doctype") + "/" + doc.get("name")
res = self.session.put(url, data={"data":frappe.as_json(doc)}, verify=self.verify)
return self.post_process(res)
def bulk_update(self, docs):
'''Bulk update documents remotely
:param docs: List of dict or Document objects to be updated remotely (by `name`)'''
return self.post_request({
"cmd": "frappe.client.bulk_update",
"docs": frappe.as_json(docs)
})
def delete(self, doctype, name):
'''Delete remote document by name
:param doctype: `doctype` to be deleted
:param name: `name` of document to be deleted'''
return self.post_request({
"cmd": "frappe.model.delete_doc",
"doctype": doctype,
"name": name
})
def submit(self, doclist):
def submit(self, doc):
'''Submit remote document
:param doc: dict or Document object to be submitted remotely'''
return self.post_request({
"cmd": "frappe.client.submit",
"doclist": frappe.as_json(doclist)
"doc": frappe.as_json(doc)
})
def get_value(self, doctype, fieldname=None, filters=None):
'''Returns a value form a document
:param doctype: DocType to be queried
:param fieldname: Field to be returned (default `name`)
:param filters: dict or string for identifying the record'''
return self.get_request({
"cmd": "frappe.client.get_value",
"doctype": doctype,
@ -97,6 +130,12 @@ class FrappeClient(object):
})
def set_value(self, doctype, docname, fieldname, value):
'''Set a value in a remote document
:param doctype: DocType of the document to be updated
:param docname: name of the document to be updated
:param fieldname: fieldname of the document to be updated
:param value: value to be updated'''
return self.post_request({
"cmd": "frappe.client.set_value",
"doctype": doctype,
@ -106,6 +145,10 @@ class FrappeClient(object):
})
def cancel(self, doctype, name):
'''Cancel a remote document
:param doctype: DocType of the document to be cancelled
:param name: name of the document to be cancelled'''
return self.post_request({
"cmd": "frappe.client.cancel",
"doctype": doctype,
@ -113,6 +156,12 @@ class FrappeClient(object):
})
def get_doc(self, doctype, name="", filters=None, fields=None):
'''Returns a single remote document
:param doctype: DocType of the document to be returned
:param name: (optional) `name` of the document to be returned
:param filters: (optional) Filter by this dict if name is not set
:param fields: (optional) Fields to be returned, will return everythign if not set'''
params = {}
if filters:
params["filters"] = json.dumps(filters)
@ -125,6 +174,11 @@ class FrappeClient(object):
return self.post_process(res)
def rename_doc(self, doctype, old_name, new_name):
'''Rename remote document
:param doctype: DocType of the document to be renamed
:param old_name: Current `name` of the document to be renamed
:param new_name: New `name` to be set'''
params = {
"cmd": "frappe.client.rename_doc",
"doctype": doctype,

View file

@ -137,10 +137,21 @@ def parse(docs):
def strip_leading_tabs(docs):
"""Strip leading tabs from __doc__ text."""
lines = docs.splitlines()
# remove empty lines in the front
start = 0
for line in lines:
if line != '': break
start += 1
if start:
lines = lines[start:]
# remove default indentation
if len(lines) > 1:
start_line = 1
ref_line = lines[start_line]
while not ref_line:
# find reference line for indentations (the first line that is nonempty (false))
start_line += 1
if start_line > len(lines): break
ref_line = lines[start_line]