[MERGE] docstrings improvements and preparation for api-doc structure

bzr revid: odo@openerp.com-20110701231956-93zu7xtibpo06eqm
This commit is contained in:
P. Christeas 2011-07-02 01:19:56 +02:00 committed by Olivier Dony
commit 7c8665bb69
38 changed files with 310 additions and 116 deletions

1
openerp/.apidoc Normal file
View File

@ -0,0 +1 @@
excludes: pychart release openerp-server test run_tests addons/base_quality_interrogation

View File

@ -57,6 +57,9 @@ def close_socket(sock):
sock.close()
#.apidoc title: Common Services: netsvc
#.apidoc module-mods: member-order: bysource
class Service(object):
""" Base class for *Local* services
@ -242,19 +245,22 @@ def init_alternative_logger():
logger.setLevel(logging.ERROR)
class Agent(object):
"""Singleton that keeps track of cancellable tasks to run at a given
timestamp.
The tasks are caracterised by:
""" Singleton that keeps track of cancellable tasks to run at a given
timestamp.
The tasks are characterised by:
* a timestamp
* the database on which the task run
* the function to call
* the arguments and keyword arguments to pass to the function
Implementation details:
Tasks are stored as list, allowing the cancellation by setting
the timestamp to 0.
A heapq is used to store tasks, so we don't need to sort
tasks ourself.
- Tasks are stored as list, allowing the cancellation by setting
the timestamp to 0.
- A heapq is used to store tasks, so we don't need to sort
tasks ourself.
"""
__tasks = []
__tasks_by_db = {}

View File

@ -22,6 +22,7 @@
import osv
import fields
#.apidoc title: Object Services and Relational Mapping
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -23,6 +23,8 @@
from openerp.tools import flatten, reverse_enumerate
import fields
#.apidoc title: Domain Expressions
NOT_OPERATOR = '!'
OR_OPERATOR = '|'
AND_OPERATOR = '&'

View File

@ -19,18 +19,19 @@
#
##############################################################################
# . Fields:
# - simple
# - relations (one2many, many2one, many2many)
# - function
#
# Fields Attributes:
# _classic_read: is a classic sql fields
# _type : field type
# readonly
# required
# size
#
""" Fields:
- simple
- relations (one2many, many2one, many2many)
- function
Fields Attributes:
* _classic_read: is a classic sql fields
* _type : field type
* readonly
* required
* size
"""
import datetime as DT
import string
import sys
@ -51,6 +52,12 @@ def _symbol_set(symb):
class _column(object):
""" Base of all fields, a database column
An instance of this object is a *description* of a database column. It will
not hold any data, but only provide the methods to manipulate data of an
ORM record or even prepare/update the database to hold such a field of data.
"""
_classic_read = True
_classic_write = True
_prefetch = True
@ -855,6 +862,15 @@ class function(_column):
# ---------------------------------------------------------
class related(function):
"""Field that points to some data inside another field of the current record.
Example::
_columns = {
'foo_id': fields.many2one('my.foo', 'Foo'),
'bar': fields.related('frol', 'foo_id', type='char', string='Frol of Foo'),
}
"""
def _fnct_search(self, tobj, cr, uid, obj=None, name=None, domain=None, context=None):
self._field_get2(cr, uid, obj, context)

View File

@ -19,24 +19,28 @@
#
##############################################################################
#
# Object relationnal mapping to postgresql module
# . Hierarchical structure
# . Constraints consistency, validations
# . Object meta Data depends on its status
# . Optimised processing by complex query (multiple actions at once)
# . Default fields value
# . Permissions optimisation
# . Persistant object: DB postgresql
# . Datas conversions
# . Multi-level caching system
# . 2 different inheritancies
# . Fields:
# - classicals (varchar, integer, boolean, ...)
# - relations (one2many, many2one, many2many)
# - functions
#
#
#.apidoc title: Object Relational Mapping
#.apidoc module-mods: member-order: bysource
"""
Object relational mapping to database (postgresql) module
* Hierarchical structure
* Constraints consistency, validations
* Object meta Data depends on its status
* Optimised processing by complex query (multiple actions at once)
* Default fields value
* Permissions optimisation
* Persistant object: DB postgresql
* Datas conversions
* Multi-level caching system
* 2 different inheritancies
* Fields:
- classicals (varchar, integer, boolean, ...)
- relations (one2many, many2one, many2many)
- functions
"""
import calendar
import copy
import datetime
@ -125,8 +129,9 @@ class except_orm(Exception):
class BrowseRecordError(Exception):
pass
# Readonly python database object browser
class browse_null(object):
""" Readonly python database object browser
"""
def __init__(self):
self.id = False
@ -154,6 +159,11 @@ class browse_null(object):
# TODO: execute an object method on browse_record_list
#
class browse_record_list(list):
""" Collection of browse objects
Such an instance will be returned when doing a ``browse([ids..])``
and will be iterable, yielding browse() objects
"""
def __init__(self, lst, context=None):
if not context:
@ -163,13 +173,25 @@ class browse_record_list(list):
class browse_record(object):
""" An object that behaves like a row of an object's table.
It has attributes after the columns of the corresponding object.
Examples::
uobj = pool.get('res.users')
user_rec = uobj.browse(cr, uid, 104)
name = user_rec.name
"""
logger = netsvc.Logger()
def __init__(self, cr, uid, id, table, cache, context=None, list_class=None, fields_process=None):
'''
table : the object (inherited from orm)
context : dictionary with an optional context
'''
"""
@param cache a dictionary of model->field->data to be shared accross browse
objects, thus reducing the SQL read()s . It can speed up things a lot,
but also be disastrous if not discarded after write()/unlink() operations
@param table the object (inherited from orm)
@param context dictionary with an optional context
"""
if fields_process is None:
fields_process = {}
if context is None:
@ -363,10 +385,10 @@ class browse_record(object):
def get_pg_type(f):
'''
"""
returns a tuple
(type returned by postgres when the column was created, type expression to create the column)
'''
"""
type_dict = {
fields.boolean: 'bool',
@ -732,7 +754,7 @@ class orm_template(object):
:param cr: database cursor
:param user: current user id
:param select: id or list of ids
:param select: id or list of ids.
:param context: context arguments, like lang, time zone
:rtype: object or list of objects requested

View File

@ -19,9 +19,7 @@
#
##############################################################################
#
# OSV: Objects Services
#
#.apidoc title: Objects Services (OSV)
import orm
import openerp.netsvc as netsvc

View File

@ -19,6 +19,7 @@
#
##############################################################################
#.apidoc title: Query object
def _quote(to_quote):
if '"' not in to_quote:

View File

@ -31,5 +31,7 @@ import report_sxw
import printscreen
#.apidoc title: Reporting Support and Engines
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -22,6 +22,11 @@
import ps_list
import ps_form
#.apidoc title: Printscreen Support
""" A special report, that is automatically formatted to look like the
screen contents of Form/List Views.
"""
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -28,6 +28,8 @@ from lxml import etree
import time, os
#.apidoc title: Printscreen for Form Views
class report_printscreen_list(report_int):
def __init__(self, name):
report_int.__init__(self, name)

View File

@ -31,6 +31,8 @@ import time, os
from operator import itemgetter
from datetime import datetime
#.apidoc title: Printscreen for List Views
class report_printscreen_list(report_int):
def __init__(self, name):
report_int.__init__(self, name)

View File

@ -1,2 +1,5 @@
from pdf import PdfFileReader, PdfFileWriter
#.apidoc title: pyPdf Engine
__all__ = ["pdf"]

View File

@ -23,6 +23,8 @@ from simple import simple
from rml import rml, rml2html, rml2txt, odt2odt , html2html, makohtml2html
from render import render
#.apidoc title: Report Rendering
try:
import Image
except ImportError:

View File

@ -21,5 +21,7 @@
from html2html import parseString
#.apidoc title: HTML to HTML engine
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -19,4 +19,7 @@
#
##############################################################################
from makohtml2html import parseNode
from makohtml2html import parseNode
#.apidoc title: MAKO to HTML engine

View File

@ -21,4 +21,6 @@
from odt2odt import parseNode
#.apidoc title: ODT to ODT engine
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -21,5 +21,7 @@
from rml2html import parseString
#.apidoc title: RML to HTML engine
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -21,3 +21,5 @@
from trml2pdf import parseString, parseNode
#.apidoc title: RML to PDF engine

View File

@ -28,6 +28,8 @@ from reportlab import rl_config
from openerp.tools import config
#.apidoc title: TTF Font Table
"""This module allows the mapping of some system-available TTF fonts to
the reportlab engine.

View File

@ -21,5 +21,14 @@
from rml2txt import parseString, parseNode
#.apidoc title: RML to TXT engine
""" This engine is the minimalistic renderer of RML documents into text files,
using spaces and newlines to format.
It was needed in some special applications, where legal reports need to be
printed in special (dot-matrix) printers.
"""
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -23,6 +23,16 @@ import http_server
import netrpc_server
import web_services
#.apidoc title: RPC Services
""" Classes of this module implement the network protocols that the
OpenERP server uses to communicate with remote clients.
Some classes are mostly utilities, whose API need not be visible to
the average user/developer. Study them only if you are about to
implement an extension to the network protocols, or need to debug some
low-level behavior of the wire.
"""
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -26,10 +26,19 @@
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
###############################################################################
""" This file contains instance of the http server.
#.apidoc title: HTTP and XML-RPC Server
""" This module offers the family of HTTP-based servers. These are not a single
class/functionality, but a set of network stack layers, implementing
extendable HTTP protocols.
The OpenERP server defines a single instance of a HTTP server, listening at
the standard 8069, 8071 ports (well, it is 2 servers, and ports are
configurable, of course). This "single" server then uses a `MultiHTTPHandler`
to dispatch requests to the appropriate channel protocol, like the XML-RPC,
static HTTP, DAV or other.
"""
from websrv_lib import *
import openerp.netsvc as netsvc
import errno

View File

@ -19,6 +19,8 @@
#
##############################################################################
#.apidoc title: NET-RPC Server
""" This file contains instance of the net-rpc server

View File

@ -22,8 +22,11 @@
import openerp.pooler as pooler
import openerp.tools as tools
# When rejecting a password, hide the traceback
#.apidoc title: Authentication helpers
class ExceptionNoTb(Exception):
""" When rejecting a password, hide the traceback
"""
def __init__(self, msg):
super(ExceptionNoTb, self).__init__(msg)
self.traceback = ('','','')

View File

@ -38,6 +38,15 @@ import locale
import logging
from cStringIO import StringIO
#.apidoc title: Exported Service methods
#.apidoc module-mods: member-order: bysource
""" This python module defines the RPC methods available to remote clients.
Each 'Export Service' is a group of 'methods', which in turn are RPC
procedures to be called. Each method has its own arguments footprint.
"""
class db(netsvc.ExportService):
def __init__(self, name="db"):
netsvc.ExportService.__init__(self, name)

View File

@ -24,8 +24,12 @@
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
###############################################################################
#.apidoc title: HTTP Layer library (websrv_lib)
""" Framework for generic http servers
This library contains *no* OpenERP-specific functionality. It should be
usable in other projects, too.
"""
import socket

View File

@ -20,6 +20,19 @@
#
##############################################################################
#.apidoc title: PostgreSQL interface
"""
The PostgreSQL connector is a connectivity layer between the OpenERP code and
the database, *not* a database abstraction toolkit. Database abstraction is what
the ORM does, in fact.
See also: the `pooler` module
"""
#.apidoc add-functions: print_stats
#.apidoc add-classes: Cursor Connection ConnectionPool
__all__ = ['db_connect', 'close_db']
from threading import currentThread
@ -66,6 +79,13 @@ re_into = re.compile('.* into "?([a-zA-Z_0-9]+)"? .*$');
sql_counter = 0
class Cursor(object):
""" Cursor is an open transaction to Postgres, utilizing a TCP connection
A lightweight wrapper around psycopg2's `psycopg1cursor` objects
This is the object behind the `cr` variable used all over the OpenERP
code.
"""
IN_MAX = 1000 # decent limit on size of IN queries - guideline = Oracle limit
__logger = None
@ -233,22 +253,37 @@ class Cursor(object):
@check
def commit(self):
""" Perform an SQL `COMMIT`
"""
return self._cnx.commit()
@check
def rollback(self):
""" Perform an SQL `ROLLBACK`
"""
return self._cnx.rollback()
@check
def __getattr__(self, name):
return getattr(self._obj, name)
""" Set the mode of postgres operations for all cursors
"""
"""Obtain the mode of postgres operations for all cursors
"""
class PsycoConnection(psycopg2.extensions.connection):
pass
class ConnectionPool(object):
""" The pool of connections to database(s)
Keep a set of connections to pg databases open, and reuse them
to open cursors for all transactions.
The connections are *not* automatically closed. Only a close_db()
can trigger that.
"""
__logger = logging.getLogger('db.connection_pool')
def locked(fun):
@ -340,6 +375,8 @@ class ConnectionPool(object):
class Connection(object):
""" A lightweight instance of a connection to postgres
"""
__logger = logging.getLogger('db.connection')
def __init__(self, pool, dbname):

View File

@ -26,9 +26,11 @@ import marshal
import netsvc
#.apidoc title: Net-RPC classes
class Myexception(Exception):
"""
custome exception object store
custom exception object store
* faultcode
* faulestring
* args

View File

@ -32,5 +32,7 @@ from pdf_utils import *
from yaml_import import *
from sql import *
#.apidoc title: Tools
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -34,8 +34,9 @@ denom_fr = ( '',
'Décillion', 'Undecillion', 'Duodecillion', 'Tredecillion', 'Quattuordecillion',
'Sexdecillion', 'Septendecillion', 'Octodecillion', 'Icosillion', 'Vigintillion' )
# convert a value < 100 to French.
def _convert_nn_fr(val):
""" convert a value < 100 to French
"""
if val < 20:
return to_19_fr[val]
for (dcap, dval) in ((k, 20 + (10 * v)) for (v, k) in enumerate(tens_fr)):
@ -44,10 +45,13 @@ def _convert_nn_fr(val):
return dcap + '-' + to_19_fr[val % 10]
return dcap
# convert a value < 1000 to french, special cased because it is the level that kicks
# off the < 100 special case. The rest are more general. This also allows you to
# get strings in the form of 'forty-five hundred' if called directly.
def _convert_nnn_fr(val):
""" convert a value < 1000 to french
special cased because it is the level that kicks
off the < 100 special case. The rest are more general. This also allows you to
get strings in the form of 'forty-five hundred' if called directly.
"""
word = ''
(mod, rem) = (val % 100, val // 100)
if rem > 0:
@ -98,8 +102,9 @@ denom_nl = ( '',
'Decillion', 'Undecillion', 'Duodecillion', 'Tredecillion', 'Quattuordecillion',
'Sexdecillion', 'Septendecillion', 'Octodecillion', 'Novemdecillion', 'Vigintillion' )
# convert a value < 100 to Dutch.
def _convert_nn_nl(val):
""" convert a value < 100 to Dutch
"""
if val < 20:
return to_19_nl[val]
for (dcap, dval) in ((k, 20 + (10 * v)) for (v, k) in enumerate(tens_nl)):
@ -108,10 +113,13 @@ def _convert_nn_nl(val):
return dcap + '-' + to_19_nl[val % 10]
return dcap
# convert a value < 1000 to Dutch, special cased because it is the level that kicks
# off the < 100 special case. The rest are more general. This also allows you to
# get strings in the form of 'forty-five hundred' if called directly.
def _convert_nnn_nl(val):
""" convert a value < 1000 to Dutch
special cased because it is the level that kicks
off the < 100 special case. The rest are more general. This also allows you to
get strings in the form of 'forty-five hundred' if called directly.
"""
word = ''
(mod, rem) = (val % 100, val // 100)
if rem > 0:
@ -160,10 +168,11 @@ def add_amount_to_text_function(lang, func):
#TODO: we should use the country AND language (ex: septante VS soixante dix)
#TODO: we should use en by default, but the translation func is yet to be implemented
def amount_to_text(nbr, lang='fr', currency='euro'):
"""
Converts an integer to its textual representation, using the language set in the context if any.
Example:
1654: mille six cent cinquante-quatre.
""" Converts an integer to its textual representation, using the language set in the context if any.
Example::
1654: mille six cent cinquante-quatre.
"""
# if nbr > 1000000:
##TODO: use logger

View File

@ -34,8 +34,9 @@ denom = ( '',
'Decillion', 'Undecillion', 'Duodecillion', 'Tredecillion', 'Quattuordecillion',
'Sexdecillion', 'Septendecillion', 'Octodecillion', 'Novemdecillion', 'Vigintillion' )
# convert a value < 100 to English.
def _convert_nn(val):
"""convert a value < 100 to English.
"""
if val < 20:
return to_19[val]
for (dcap, dval) in ((k, 20 + (10 * v)) for (v, k) in enumerate(tens)):
@ -44,10 +45,12 @@ def _convert_nn(val):
return dcap + '-' + to_19[val % 10]
return dcap
# convert a value < 1000 to english, special cased because it is the level that kicks
# off the < 100 special case. The rest are more general. This also allows you to
# get strings in the form of 'forty-five hundred' if called directly.
def _convert_nnn(val):
"""
convert a value < 1000 to english, special cased because it is the level that kicks
off the < 100 special case. The rest are more general. This also allows you to
get strings in the form of 'forty-five hundred' if called directly.
"""
word = ''
(mod, rem) = (val % 100, val // 100)
if rem > 0:
@ -94,10 +97,11 @@ _translate_funcs = {'en' : amount_to_text}
#TODO: we should use the country AND language (ex: septante VS soixante dix)
#TODO: we should use en by default, but the translation func is yet to be implemented
def amount_to_text(nbr, lang='en', currency='euro'):
"""
Converts an integer to its textual representation, using the language set in the context if any.
Example:
1654: thousands six cent cinquante-quatre.
""" Converts an integer to its textual representation, using the language set in the context if any.
Example::
1654: thousands six cent cinquante-quatre.
"""
import openerp.loglevels as loglevels
# if nbr > 10000000:

View File

@ -45,6 +45,8 @@ class MyOption (optparse.Option, object):
self.my_default = attrs.pop('my_default', None)
super(MyOption, self).__init__(*opts, **attrs)
#.apidoc title: Server Configuration Loader
def check_ssl():
try:
from OpenSSL import SSL

View File

@ -30,6 +30,10 @@ except ImportError:
# http://svn.python.org/view/python/tags/r254/Lib/functools.py?view=markup
def partial(fun, *args, **kwargs):
""" Partial implementation
See: http://svn.python.org/view/python/tags/r254/Lib/functools.py
"""
def _partial(*args2, **kwargs2):
return fun(*(args+args2), **dict(kwargs, **kwargs2))
return _partial

View File

@ -25,11 +25,11 @@ import math
class graph(object):
def __init__(self, nodes, transitions, no_ancester=None):
"""Initailize graph's object
"""Initialize graph's object
@param nodes: list of ids of nodes in the graph
@param transitions: list of edges in the graph in the form (source_node, destination_node)
@param no_ancester: list of nodes with no incoming edges
@param nodes list of ids of nodes in the graph
@param transitions list of edges in the graph in the form (source_node, destination_node)
@param no_ancester list of nodes with no incoming edges
"""
self.nodes = nodes or []
@ -210,8 +210,8 @@ class graph(object):
def exchange(self, e, f):
"""Exchange edges to make feasible-tree optimized
@param edge: edge with negative cut-value
@param edge: new edge with minimum slack-value
@param edge edge with negative cut-value
@param edge new edge with minimum slack-value
"""
self.tree_edges.__delitem__(self.tree_edges.index(e))
self.tree_edges.append(f)
@ -221,7 +221,7 @@ class graph(object):
def enter_edge(self, edge):
"""Finds a new_edge with minimum slack value to replace an edge with negative cut-value
@param edge: edge with negative cut-value
@param edge edge with negative cut-value
"""
self.head_nodes = []
@ -345,8 +345,8 @@ class graph(object):
def median_value(self, node, adj_rank):
"""Returns median value of a vertex , defined as the median position of the adjacent vertices
@param node: node to process
@param adj_rank: rank 1 less than the node's rank
@param node node to process
@param adj_rank rank 1 less than the node's rank
"""
adj_nodes = self.adj_position(node, adj_rank)
l = len(adj_nodes)
@ -367,8 +367,8 @@ class graph(object):
def adj_position(self, node, adj_rank):
"""Returns list of the present positions of the nodes adjacent to node in the given adjacent rank.
@param node: node to process
@param adj_rank: rank 1 less than the node's rank
@param node node to process
@param adj_rank rank 1 less than the node's rank
"""
pre_level_nodes = self.levels.get(adj_rank, [])
@ -606,7 +606,7 @@ class graph(object):
def rank(self):
"""Finds the optimized rank of the nodes using Network-simplex algorithm
@param start: starting node of the component
@param start starting node of the component
"""
self.levels = {}
self.critical_edges = []
@ -668,7 +668,7 @@ class graph(object):
def process(self, starting_node):
"""Process the graph to find ranks and order of the nodes
@param starting_node: node from where to start the graph search
@param starting_node node from where to start the graph search
"""
self.start_nodes = starting_node or []

View File

@ -20,6 +20,8 @@
#
##############################################################################
#.apidoc title: Utilities: tools.misc
"""
Miscelleanous tools used by OpenERP.
"""
@ -124,16 +126,18 @@ def exec_command_pipe(name, *args):
def file_open(name, mode="r", subdir='addons', pathinfo=False):
"""Open a file from the OpenERP root, using a subdir folder.
Example::
>>> file_open('hr/report/timesheer.xsl')
>>> file_open('addons/hr/report/timesheet.xsl')
>>> file_open('../../base/report/rml_template.xsl', subdir='addons/hr/report', pathinfo=True)
@param name: name of the file
@param mode: file open mode
@param subdir: subdirectory
@param pathinfo: if True returns tupple (fileobject, filepath)
@param name name of the file
@param mode file open mode
@param subdir subdirectory
@param pathinfo if True returns tupple (fileobject, filepath)
@return: fileobject if pathinfo is False else (fileobject, filepath)
@return fileobject if pathinfo is False else (fileobject, filepath)
"""
import openerp.modules as addons
adps = addons.module.ad_paths
@ -217,7 +221,7 @@ def flatten(list):
"""Flatten a list of elements into a uniqu list
Author: Christophe Simonis (christophe@tinyerp.com)
Examples:
Examples::
>>> flatten(['a'])
['a']
>>> flatten('b')
@ -246,6 +250,8 @@ def flatten(list):
def reverse_enumerate(l):
"""Like enumerate but in the other sens
Usage::
>>> a = ['a', 'b', 'c']
>>> it = reverse_enumerate(a)
>>> it.next()
@ -285,16 +291,14 @@ priorities = {
}
def html2plaintext(html, body_id=None, encoding='utf-8'):
""" From an HTML text, convert the HTML to plain text.
If @param body_id is provided then this is the tag where the
body (not necessarily <body>) starts.
"""
## (c) Fry-IT, www.fry-it.com, 2007
## <peter@fry-it.com>
## download here: http://www.peterbe.com/plog/html2plaintext
""" from an HTML text, convert the HTML to plain text.
If @body_id is provided then this is the tag where the
body (not necessarily <body>) starts.
"""
html = ustr(html)
from lxml.etree import tostring
@ -351,14 +355,16 @@ def html2plaintext(html, body_id=None, encoding='utf-8'):
return html
def generate_tracking_message_id(openobject_id):
"""Returns a string that can be used in the Message-ID RFC822 header field so we
can track the replies related to a given object thanks to the "In-Reply-To" or
"References" fields that Mail User Agents will set.
"""Returns a string that can be used in the Message-ID RFC822 header field
Used to track the replies related to a given object thanks to the "In-Reply-To"
or "References" fields that Mail User Agents will set.
"""
return "<%s-openobject-%s@%s>" % (time.time(), openobject_id, socket.gethostname())
def _email_send(smtp_from, smtp_to_list, message, openobject_id=None, ssl=False, debug=False):
"""Low-level method to send directly a Message through the configured smtp server.
""" Low-level method to send directly a Message through the configured smtp server.
:param smtp_from: RFC-822 envelope FROM (not displayed to recipient)
:param smtp_to_list: RFC-822 envelope RCPT_TOs (not displayed to recipient)
:param message: an email.message.Message to send
@ -427,17 +433,16 @@ def email_send(email_from, email_to, subject, body, email_cc=None, email_bcc=Non
"""Send an email.
Arguments:
`email_from`: A string used to fill the `From` header, if falsy,
@param email_from A string used to fill the `From` header, if falsy,
config['email_from'] is used instead. Also used for
the `Reply-To` header if `reply_to` is not provided
`email_to`: a sequence of addresses to send the mail to.
@param email_to a sequence of addresses to send the mail to.
"""
if x_headers is None:
x_headers = {}
if not (email_from or config['email_from']):
raise ValueError("Sending an email requires either providing a sender "
@ -507,10 +512,9 @@ def sms_send(user, password, api_id, text, to):
# FIXME: Use the logger if there is an error
return True
#---------------------------------------------------------
# Class that stores an updateable string (used in wizards)
#---------------------------------------------------------
class UpdateableStr(local):
""" Class that stores an updateable string (used in wizards)
"""
def __init__(self, string=''):
self.string = string
@ -526,7 +530,8 @@ class UpdateableStr(local):
class UpdateableDict(local):
'''Stores an updateable dict to use in wizards'''
"""Stores an updateable dict to use in wizards
"""
def __init__(self, dict=None):
if dict is None:
@ -624,8 +629,13 @@ class UpdateableDict(local):
return self.dict.__ne__(y)
# Don't use ! Use res.currency.round()
class currency(float):
""" Deprecate
.. warning::
Don't use ! Use res.currency.round()
"""
def __init__(self, value, accuracy=2, rounding=None):
if rounding is None:
@ -1168,7 +1178,7 @@ def detect_ip_addr():
# times.
def get_win32_timezone():
"""Attempt to return the "standard name" of the current timezone on a win32 system.
@return: the standard name of the current win32 timezone, or False if it cannot be found.
@return the standard name of the current win32 timezone, or False if it cannot be found.
"""
res = False
if (sys.platform == "win32"):
@ -1186,7 +1196,7 @@ def get_win32_timezone():
def detect_server_timezone():
"""Attempt to detect the timezone to use on the server side.
Defaults to UTC if no working timezone can be found.
@return: the timezone identifier as expected by pytz.timezone.
@return the timezone identifier as expected by pytz.timezone.
"""
try:
import pytz
@ -1312,7 +1322,7 @@ def server_to_local_timestamp(src_tstamp_str, src_format, dst_format, dst_tz_nam
@param ignore_unparsable_time: if True, return False if src_tstamp_str cannot be parsed
using src_format or formatted using dst_format.
@return: local/client formatted timestamp, expressed in the local/client timezone if possible
@return local/client formatted timestamp, expressed in the local/client timezone if possible
and if tz_offset is true, or src_tstamp_str if timezone offset could not be determined.
"""
if not src_tstamp_str:

View File

@ -19,8 +19,8 @@
Return a generator which yields full paths in which the *file* name exists
in a directory that is part of the file name, or on *path*,
and has the given *mode*.
By default, *mode* matches an inclusive OR of os.F_OK and os.X_OK
- an existing executable file.
By default, *mode* matches an inclusive OR of os.F_OK and os.X_OK - an
existing executable file.
The *path* is, by default, the ``PATH`` variable on the platform,
or the string/iterable passed in as *path*.
In the event that a ``PATH`` variable is not found, :const:`os.defpath` is used.

View File

@ -21,6 +21,8 @@
import wkf_service
#.apidoc title: Workflow objects
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: