oerppy-hackers team mailing list archive
-
oerppy-hackers team
-
Mailing list archive
-
Message #00013
[Branch ~oerppy-hackers/oerppy/trunk] Rev 33: * Added a results decorator that intercepts what xmlrpclib gets back from the
------------------------------------------------------------
revno: 33
committer: duncan@xxxxxxxxxx
branch nick: trunk
timestamp: Thu 2011-06-02 13:03:01 -0600
message:
* Added a results decorator that intercepts what xmlrpclib gets back from the
OpenERP server (good for adding custom exceptions and possibly parsing raw
data into model objects).
* With this in place, most of the client methods were decorated with it.
* Added a validation check for login.
* Added several more custom exceptions and updated the base Error exception
class to use the docstring as the message if no message was passed.
* Added support for instantiating classes stored in the registry.
* Fixed a nasty, hidden little but with the proxy. Turns out that you can't do
normal existance checks against an xmlrpclib proxy instance, as that causes
it to make a "__nonzero__" call to the server. Whatever the hell that means.
Anyway, I had to change the check to do a comparison against a None type
check.
modified:
Makefile
oerppy/addons/canonical/query.py
oerppy/addons/canonical/scripting/export.py
oerppy/client.py
oerppy/exceptions.py
oerppy/reg.py
oerppy/service.py
oerppy/util.py
--
lp:oerppy
https://code.launchpad.net/~oerppy-hackers/oerppy/trunk
Your team oerppy Hackers is subscribed to branch lp:oerppy.
To unsubscribe from this branch go to https://code.launchpad.net/~oerppy-hackers/oerppy/trunk/+edit-subscription
=== modified file 'Makefile'
--- Makefile 2011-06-01 18:49:40 +0000
+++ Makefile 2011-06-02 19:03:01 +0000
@@ -10,5 +10,13 @@
commit: check
bzr commit --show-diff
+commit-msg: check
+ bzr commit --file=MSG
+
push: commit
bzr push lp:oerppy
+
+push-msg: commit-msg
+ bzr push lp:oerppy
+ mv MSG MSG.backup
+ touch MSG
=== modified file 'oerppy/addons/canonical/query.py'
--- oerppy/addons/canonical/query.py 2011-06-02 17:25:28 +0000
+++ oerppy/addons/canonical/query.py 2011-06-02 19:03:01 +0000
@@ -1,3 +1,5 @@
+from datetime import date, timedelta
+
from oerppy.addons.canonical import const
@@ -21,8 +23,8 @@
A dispatch method that runs the query for the given report name, and
optionally, domains.
"""
- if not domain:
- domain = []
+ if not domains:
+ domains = []
if not self.user_dept:
self.get_departments()
if report == const.TIMESHEET_HOURS:
@@ -89,8 +91,8 @@
Get the weekly timeentry records, highlighting the missing weeks.
"""
# Get user Ids of timesheet users and the weeks we're interested in
- today = datetime.date.today()
- last_week = today - datetime.timedelta(days=-7)
+ today = date.today()
+ last_week = today - timedelta(days=-7)
weeks = self.client.searchfields(
'project.timeentry.week',
[
=== modified file 'oerppy/addons/canonical/scripting/export.py'
--- oerppy/addons/canonical/scripting/export.py 2011-06-02 17:25:28 +0000
+++ oerppy/addons/canonical/scripting/export.py 2011-06-02 19:03:01 +0000
@@ -1,8 +1,10 @@
from datetime import datetime
-from oerppy import config, export, service
+from oerppy import config
from oerppy.scripting import ExportScript
+from oerppy.addons.canonical import const
+
class MonthlyExport(ExportScript):
"""
@@ -40,6 +42,7 @@
parser = super(WeeklyExport, self).get_option_parser()
parser.add_option(
"-s", "--report-style", dest="report_style", action="store",
+ default=const.TIMESHEETS_WEEKLY,
help=("the report style to present in export (e.g., 'hours' "
"or 'weekly'"))
return parser
=== modified file 'oerppy/client.py'
--- oerppy/client.py 2011-06-02 17:25:28 +0000
+++ oerppy/client.py 2011-06-02 19:03:01 +0000
@@ -1,5 +1,7 @@
import base64, datetime, time, xmlrpclib
+from oerppy import exceptions
+from oerppy.util import parse_results
# * client.Parser (parse the responses from the server and convert them to
# model objects; optional)
@@ -21,6 +23,8 @@
Login to OpenERP, set the user ID, and prepare the proxies' callables.
"""
uid = self.endpoints.common.login(self.dbname, self.credentials)
+ if uid == False:
+ raise exceptions.OpenERPPyLoginFailure()
self.credentials.set_uid(uid)
# cache the object proxy and prepare the execute callable
@@ -30,14 +34,18 @@
# do the same for the report proxy
self.endpoints.report.get_proxy()
self.endpoints.report.prepare(self.dbname, self.credentials)
+ return uid
+ @parse_results
def create(self, entity, record):
"""Create an entity"""
return self.endpoints.object.execute(entity, "create", record)
+ @parse_results
def search(self, entity, query):
return self.endpoints.object.execute(entity, "search", query)
+ @parse_results
def update(self, entity, record, ids):
"""Update an entity"""
return self.endpoints.object.execute(entity, "write", ids, record)
@@ -45,6 +53,7 @@
# preserve parity with publicly defined OpenERP API
write = update
+ @parse_results
def delete(self, entity, ids):
"""Delete an entity"""
return self.endpoints.object.execute(entity, "unlink", ids)
@@ -52,12 +61,14 @@
# preserve parity with publicly defined OpenERP API
unlink = delete
+ @parse_results
def read(self, entity, ids, fields):
"""
Read an entity when provided a list of Ids
"""
return self.endpoints.object.execute(entity, "read", ids, fields)
+ @parse_results
def searchfields(self, entity, query, fields):
"""
"""
@@ -70,6 +81,7 @@
else:
return None
+ @parse_results
def report(self, model, ids, report_name, form):
# Get the model's records and context
if not ids:
=== modified file 'oerppy/exceptions.py'
--- oerppy/exceptions.py 2011-06-02 17:25:28 +0000
+++ oerppy/exceptions.py 2011-06-02 19:03:01 +0000
@@ -1,5 +1,9 @@
class OpenERPPyError(Exception):
- pass
+
+ def __init__(self, *args, **kwargs):
+ super(OpenERPPyError, self).__init__(*args, **kwargs)
+ if not self.args:
+ self.args = (self.__doc__.strip(),)
class OpenERPPyConfigError(OpenERPPyError):
@@ -8,3 +12,13 @@
class OpenERPPyParameterError(OpenERPPyError):
pass
+
+
+class OpenERPPyLoginFailure(OpenERPPyError):
+ """
+ Incorrect username or password provided.
+ """
+
+
+class OpenERPPyRemoteError(OpenERPPyError):
+ pass
=== modified file 'oerppy/reg.py'
--- oerppy/reg.py 2011-06-02 15:16:11 +0000
+++ oerppy/reg.py 2011-06-02 19:03:01 +0000
@@ -35,6 +35,7 @@
def __init__(self, *args, **kwargs):
super(AddOnRegistry, self).__init__(*args, **kwargs)
self._order = []
+ self.are_instantiated = False
def add(self, name, instance):
super(AddOnRegistry, self).add(name, instance)
@@ -55,6 +56,19 @@
addons.append(self.get_value(name))
return addons
+ def instantiate(self, client):
+ """
+ This method updates the registry, replacing the addon classes with
+ actual instances.
+
+ Though intended for use by the service instance, anything that has
+ access to the client instance can use it.
+ """
+ class_pairs = zip(self._order, self.get_addons())
+ instance_pairs = [(name, klass(client)) for name, klass in class_pairs]
+ self.update(dict(instance_pairs))
+ self.are_instantiated = True
+
# Default registry is for addons; we can change this later, if a general
# registry is needed, and then make the addon registry a sub-reg of the general
=== modified file 'oerppy/service.py'
--- oerppy/service.py 2011-06-02 15:49:02 +0000
+++ oerppy/service.py 2011-06-02 19:03:01 +0000
@@ -78,8 +78,9 @@
Get an XML-RPC proxy for the endpoint.
"""
uri = self.get_uri()
- if purge or not self._proxy:
- self._proxy = xmlrpclib.ServerProxy(uri)
+ if purge or type(self._proxy) == type(None):
+ print uri
+ self._proxy = xmlrpclib.ServerProxy(uri, allow_none=1)
return self._proxy
@@ -94,7 +95,7 @@
def login(self, dbname, creds):
"""
- Returns the UID of the user upon successfull login.
+ Returns the UID of the user upon successful login.
"""
proxy = self.get_proxy()
return proxy.login(dbname, creds.user, creds.password)
@@ -161,6 +162,8 @@
self.credentials = Credentials(user, password)
self.client = client.Client(
self.endpoints, self.dbname, self.credentials)
+ # now that the client is defined, let's start up the addons
+ reg.registry.instantiate(self.client)
def __getattr__(self, name):
"""
@@ -194,7 +197,7 @@
try:
attrib = getattr(self.client, name)
except AttributeError:
- for addon in registry.get_addons():
+ for addon in reg.registry.get_addons():
try:
attrib = getattr(addon, name)
except AttributeError:
@@ -212,4 +215,6 @@
this method is for you. Simply get the addon that you want, and call
methods on the returned object like usual.
"""
- return registry.get_addon(name)
+ if not reg.registry.are_instantiated:
+ return
+ return reg.registry.get_addon(name)
=== modified file 'oerppy/util.py'
--- oerppy/util.py 2011-06-01 22:52:15 +0000
+++ oerppy/util.py 2011-06-02 19:03:01 +0000
@@ -1,6 +1,7 @@
import os
import datetime
from urlparse import urlparse, urlunparse
+import xmlrpclib
from oerppy import const, exceptions
@@ -86,7 +87,7 @@
return (str(scheme), str(host), port, str(path))
-def partial(func, *args, **keywords):
+def partial(func, *args, **kwargs):
"""
By using partial function application, we're able "pre-process" functions
whose first few arguments we know ahead of time.
@@ -98,15 +99,30 @@
arguments remaining the same every time.
"""
def newfunc(*fargs, **fkeywords):
- newkeywords = keywords.copy()
+ newkeywords = kwargs.copy()
newkeywords.update(fkeywords)
return func(*(args + fargs), **newkeywords)
newfunc.func = func
newfunc.args = args
- newfunc.keywords = keywords
+ newfunc.keywords = kwargs
return newfunc
+def parse_results(func):
+ """
+ This is a decorator for methods that perform remote calls against the
+ OpenERP XML-RPC server. It provides the ability to intercept results and
+ have them parsed.
+ """
+ def checker(*args, **kwargs):
+ try:
+ results = func(*args, **kwargs)
+ return results
+ except xmlrpclib.Fault, error:
+ raise exceptions.OpenERPPyRemoteError(error.faultCode)
+ return checker
+
+
def start_of_week(date, return_iso=False):
# check to see if the date is in ISO date format
if isinstance(date, basestring):