import smtplib
import threading
+ from openerp import SUPERUSER_ID
from openerp.osv import osv, fields
from openerp.tools.translate import _
from openerp.tools import html2text
from openerp.loglevels import ustr
_logger = logging.getLogger(__name__)
+_test_logger = logging.getLogger('openerp.tests')
+
class MailDeliveryException(osv.except_osv):
"""Specific exception subclass for mail delivery errors"""
# Do not actually send emails in testing mode!
if getattr(threading.currentThread(), 'testing', False):
- _logger.log(logging.TEST, "skip sending email in test mode")
+ _test_logger.info("skip sending email in test mode")
return message['Message-Id']
# Get SMTP Server Details from Mail Server
mail_server = None
if mail_server_id:
- mail_server = self.browse(cr, uid, mail_server_id)
+ mail_server = self.browse(cr, SUPERUSER_ID, mail_server_id)
elif not smtp_server:
- mail_server_ids = self.search(cr, uid, [], order='sequence', limit=1)
+ mail_server_ids = self.search(cr, SUPERUSER_ID, [], order='sequence', limit=1)
if mail_server_ids:
- mail_server = self.browse(cr, uid, mail_server_ids[0])
+ mail_server = self.browse(cr, SUPERUSER_ID, mail_server_ids[0])
if mail_server:
smtp_server = mail_server.smtp_host
CURRENCY_DISPLAY_PATTERN = re.compile(r'(\w+)\s*(?:\((.*)\))?')
class res_currency(osv.osv):
+
def _current_rate(self, cr, uid, ids, name, arg, context=None):
+ return self._get_current_rate(cr, uid, ids, name, arg, context=context)
+
+ def _get_current_rate(self, cr, uid, ids, name, arg, context=None):
if context is None:
context = {}
res = {}
'position' : 'after',
'rounding': 0.01,
'accuracy': 4,
+ 'company_id': False,
}
_sql_constraints = [
# this constraint does not cover all cases due to SQL NULL handling for company_id,
import openerp
from openerp import SUPERUSER_ID
-from openerp import pooler, tools
+from openerp import tools
from openerp.osv import osv, fields
from openerp.tools.translate import _
from openerp.tools.yaml_import import is_comment
class format_address(object):
def fields_view_get_address(self, cr, uid, arch, context={}):
- user_obj = self.pool.get('res.users')
+ user_obj = self.pool['res.users']
fmt = user_obj.browse(cr, SUPERUSER_ID, uid, context).company_id.country_id
fmt = fmt and fmt.address_format
layouts = {
def _tz_get(self,cr,uid, context=None):
- return [(x, x) for x in pytz.all_timezones]
+ # put POSIX 'Etc/*' entries at the end to avoid confusing users - see bug 1086728
+ return [(tz,tz) for tz in sorted(pytz.all_timezones, key=lambda tz: tz if not tz.startswith('Etc/') else '_')]
class res_partner_category(osv.osv):
}
def _lang_get(self, cr, uid, context=None):
- lang_pool = self.pool.get('res.lang')
+ lang_pool = self.pool['res.lang']
ids = lang_pool.search(cr, uid, [], context=context)
res = lang_pool.read(cr, uid, ids, ['code', 'name'], context)
return [(r['code'], r['name']) for r in res]
# fields copy if 'use_parent_address' is checked
ADDRESS_FIELDS = ('street', 'street2', 'zip', 'city', 'state_id', 'country_id')
-POSTAL_ADDRESS_FIELDS = ADDRESS_FIELDS # deprecated, to remove after 7.0
class res_partner(osv.osv, format_address):
_description = 'Partner'
result[partner.id] = current_partner.id
return result
- # indirection to avoid passing a copy of the overridable method when declaring the function field
+ def _display_name_compute(self, cr, uid, ids, name, args, context=None):
+ return dict(self.name_get(cr, uid, ids, context=context))
+
+ # indirections to avoid passing a copy of the overridable method when declaring the function field
_commercial_partner_id = lambda self, *args, **kwargs: self._commercial_partner_compute(*args, **kwargs)
+ _display_name = lambda self, *args, **kwargs: self._display_name_compute(*args, **kwargs)
+
+ _commercial_partner_store_triggers = {
+ 'res.partner': (lambda self,cr,uid,ids,context=None: self.search(cr, uid, [('id','child_of',ids)]),
+ ['parent_id', 'is_company'], 10)
+ }
+ _display_name_store_triggers = {
+ 'res.partner': (lambda self,cr,uid,ids,context=None: self.search(cr, uid, [('id','child_of',ids)]),
+ ['parent_id', 'is_company', 'name'], 10)
+ }
- _order = "name"
+ _order = "display_name"
_columns = {
'name': fields.char('Name', size=128, required=True, select=True),
+ 'display_name': fields.function(_display_name, type='char', string='Name', store=_display_name_store_triggers),
'date': fields.date('Date', select=1),
'title': fields.many2one('res.partner.title', 'Title'),
'parent_id': fields.many2one('res.partner', 'Related Company'),
'contact_address': fields.function(_address_display, type='char', string='Complete Address'),
# technical field used for managing commercial fields
- 'commercial_partner_id': fields.function(_commercial_partner_id, type='many2one', relation='res.partner', string='Commercial Entity')
+ 'commercial_partner_id': fields.function(_commercial_partner_id, type='many2one', relation='res.partner', string='Commercial Entity', store=_commercial_partner_store_triggers)
}
def _default_category(self, cr, uid, context=None):
def fields_view_get(self, cr, user, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
if (not view_id) and (view_type=='form') and context and context.get('force_email', False):
- view_id = self.pool.get('ir.model.data').get_object_reference(cr, user, 'base', 'view_partner_simple_form')[1]
+ view_id = self.pool['ir.model.data'].get_object_reference(cr, user, 'base', 'view_partner_simple_form')[1]
res = super(res_partner,self).fields_view_get(cr, user, view_id, view_type, context, toolbar=toolbar, submenu=submenu)
if view_type == 'form':
res['arch'] = self.fields_view_get_address(cr, user, res['arch'], context=context)
'tz': lambda self, cr, uid, ctx: ctx.get('tz', False),
'customer': True,
'category_id': _default_category,
- 'company_id': lambda self, cr, uid, ctx: self.pool.get('res.company')._company_default_get(cr, uid, 'res.partner', context=ctx),
+ 'company_id': lambda self, cr, uid, ctx: self.pool['res.company']._company_default_get(cr, uid, 'res.partner', context=ctx),
'color': 0,
'is_company': False,
'type': 'contact', # type 'default' is wildcard and thus inappropriate
def onchange_state(self, cr, uid, ids, state_id, context=None):
if state_id:
- country_id = self.pool.get('res.country.state').browse(cr, uid, state_id, context).country_id.id
+ country_id = self.pool['res.country.state'].browse(cr, uid, state_id, context).country_id.id
return {'value':{'country_id':country_id}}
return {}
def _check_ean_key(self, cr, uid, ids, context=None):
- for partner_o in pooler.get_pool(cr.dbname).get('res.partner').read(cr, uid, ids, ['ean13',]):
+ for partner_o in self.pool['res.partner'].read(cr, uid, ids, ['ean13',]):
thisean=partner_o['ean13']
if thisean and thisean!='':
if len(thisean)!=13:
def email_send(self, cr, uid, ids, email_from, subject, body, on_error=''):
while len(ids):
- self.pool.get('ir.cron').create(cr, uid, {
+ self.pool['ir.cron'].create(cr, uid, {
'name': 'Send Partner Emails',
'user_id': uid,
'model': 'res.partner',
if res: return res
if not context.get('category_id', False):
return False
- return _('Partners: ')+self.pool.get('res.partner.category').browse(cr, uid, context['category_id'], context).name
+ return _('Partners: ')+self.pool['res.partner.category'].browse(cr, uid, context['category_id'], context).name
def main_partner(self, cr, uid):
''' Return the id of the main partner
'''
- model_data = self.pool.get('ir.model.data')
+ model_data = self.pool['ir.model.data']
return model_data.browse(cr, uid,
model_data.search(cr, uid, [('module','=','base'),
('name','=','main_partner')])[0],
- #!/usr/bin/env python
# -*- coding: utf-8 -*-
##############################################################################
#
""" Preload a registry, and start the cron."""
try:
update_module = True if openerp.tools.config['init'] or openerp.tools.config['update'] else False
- db, registry = openerp.pooler.get_db_and_pool(dbname,update_module=update_module)
+ openerp.modules.registry.RegistryManager.new(dbname, update_module=update_module)
except Exception:
_logger.exception('Failed to initialize database `%s`.', dbname)
+ return False
+ return True
def run_test_file(dbname, test_file):
""" Preload a registry, possibly run a test file, and start the cron."""
try:
config = openerp.tools.config
- db, registry = openerp.pooler.get_db_and_pool(dbname, update_module=config['init'] or config['update'])
- cr = db.cursor()
+ registry = openerp.modules.registry.RegistryManager.new(dbname, update_module=config['init'] or config['update'])
+ cr = registry.db.cursor()
_logger.info('loading test file %s', test_file)
openerp.tools.convert_yaml_import(cr, 'base', file(test_file), 'test', {}, 'test', True)
cr.rollback()
fileformat = os.path.splitext(config["translate_out"])[-1][1:].lower()
buf = file(config["translate_out"], "w")
- cr = openerp.pooler.get_db(dbname).cursor()
+ registry = openerp.modules.registry.RegistryManager.new(dbname)
+ cr = registry.db.cursor()
openerp.tools.trans_export(config["language"],
config["translate_modules"] or ["all"], buf, fileformat, cr)
cr.close()
context = {'overwrite': config["overwrite_existing_translations"]}
dbname = config['db_name']
- cr = openerp.pooler.get_db(dbname).cursor()
+ registry = openerp.modules.registry.RegistryManager.new(dbname)
+ cr = registry.db.cursor()
openerp.tools.trans_load( cr, config["translate_in"], config["language"],
context=context)
cr.commit()
code.append(" %s" % (line.strip()))
_logger.info("\n".join(code))
-def setup_signal_handlers():
- """ Register the signal handler defined above. """
- SIGNALS = map(lambda x: getattr(signal, "SIG%s" % x), "INT TERM".split())
+def setup_signal_handlers(signal_handler):
+ """ Register the given signal handler. """
+ SIGNALS = (signal.SIGINT, signal.SIGTERM)
if os.name == 'posix':
map(lambda sig: signal.signal(sig, signal_handler), SIGNALS)
signal.signal(signal.SIGQUIT, dumpstacks)
check_root_user()
openerp.tools.config.parse_config(args)
+ if openerp.tools.config.options["gevent"]:
+ openerp.evented = True
+ _logger.info('Using gevent mode')
+ import gevent.monkey
+ gevent.monkey.patch_all()
+ import gevent_psycopg2
+ gevent_psycopg2.monkey_patch()
+
check_postgres_user()
openerp.netsvc.init_logger()
report_configuration()
config = openerp.tools.config
- setup_signal_handlers()
+ setup_signal_handlers(signal_handler)
if config["test_file"]:
run_test_file(config['db_name'], config['test_file'])
else:
openerp.service.start_services()
+ rc = 0
if config['db_name']:
for dbname in config['db_name'].split(','):
- preload_registry(dbname)
+ if not preload_registry(dbname):
+ rc += 1
if config["stop_after_init"]:
- sys.exit(0)
+ sys.exit(rc)
_logger.info('OpenERP server is running, waiting for connections...')
quit_on_signals()
- #!/usr/bin/env python
# -*- coding: utf-8 -*-
##############################################################################
#
#
##############################################################################
-#.apidoc title: Common Services: netsvc
-#.apidoc module-mods: member-order: bysource
import logging
import logging.handlers
import os
-import platform
import release
-import socket
import sys
import threading
import time
import types
from pprint import pformat
+import psutil
-try:
- import psutil
-except ImportError:
- psutil = None
-
-# TODO modules that import netsvc only for things from loglevels must be changed to use loglevels.
-from loglevels import *
import tools
import openerp
_logger = logging.getLogger(__name__)
-
-def close_socket(sock):
- """ Closes a socket instance cleanly
-
- :param sock: the network socket to close
- :type sock: socket.socket
- """
- try:
- sock.shutdown(socket.SHUT_RDWR)
- except socket.error, e:
- # On OSX, socket shutdowns both sides if any side closes it
- # causing an error 57 'Socket is not connected' on shutdown
- # of the other side (or something), see
- # http://bugs.python.org/issue4397
- # note: stdlib fixed test, not behavior
- if e.errno != errno.ENOTCONN or platform.system() not in ['Darwin', 'Windows']:
- raise
- sock.close()
-
-def abort_response(dummy_1, description, dummy_2, details):
- # TODO Replace except_{osv,orm} with these directly.
- raise openerp.osv.osv.except_osv(description, details)
-
-class Service(object):
- """ Base class for Local services
- Functionality here is trusted, no authentication.
- Workflow engine and reports subclass this.
- """
- _services = {}
- def __init__(self, name):
- Service._services[name] = self
- self.__name = name
-
- @classmethod
- def exists(cls, name):
- return name in cls._services
-
- @classmethod
- def remove(cls, name):
- if cls.exists(name):
- cls._services.pop(name)
-
def LocalService(name):
- # Special case for addons support, will be removed in a few days when addons
- # are updated to directly use openerp.osv.osv.service.
- if name == 'object_proxy':
- return openerp.osv.osv.service
-
- return Service._services[name]
-
-class ExportService(object):
- """ Proxy for exported services.
-
- Note that this class has no direct proxy, capable of calling
- eservice.method(). Rather, the proxy should call
- dispatch(method, params)
"""
+ The openerp.netsvc.LocalService() function is deprecated. It still works
+ in two cases: workflows and reports. For workflows, instead of using
+ LocalService('workflow'), openerp.workflow should be used (better yet,
+ methods on openerp.osv.orm.Model should be used). For reports,
+ openerp.report.render_report() should be used (methods on the Model should
+ be provided too in the future).
+ """
+ assert openerp.conf.deprecation.allow_local_service
+ _logger.warning("LocalService() is deprecated since march 2013 (it was called with '%s')." % name)
- _services = {}
-
- def __init__(self, name):
- ExportService._services[name] = self
- self.__name = name
- _logger.debug("Registered an exported service: %s" % name)
-
- @classmethod
- def getService(cls,name):
- return cls._services[name]
+ if name == 'workflow':
+ return openerp.workflow
- # Dispatch a RPC call w.r.t. the method name. The dispatching
- # w.r.t. the service (this class) is done by OpenERPDispatcher.
- def dispatch(self, method, params):
- raise Exception("stub dispatch at %s" % self.__name)
+ if name.startswith('report.'):
+ report = openerp.report.interface.report_int._reports.get(name)
+ if report:
+ return report
+ else:
+ dbname = getattr(threading.currentThread(), 'dbname', None)
+ if dbname:
+ registry = openerp.modules.registry.RegistryManager.get(dbname)
+ with registry.cursor() as cr:
+ return registry['ir.actions.report.xml']._lookup_report(cr, name[len('report.'):])
BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, _NOTHING, DEFAULT = range(10)
#The background is set with 40 plus the number of the color, and the foreground with 30
LEVEL_COLOR_MAPPING = {
logging.DEBUG: (BLUE, DEFAULT),
logging.INFO: (GREEN, DEFAULT),
- logging.TEST: (WHITE, BLUE),
logging.WARNING: (YELLOW, DEFAULT),
logging.ERROR: (RED, DEFAULT),
logging.CRITICAL: (WHITE, RED),
handler.setFormatter(formatter)
# Configure handlers
- default_config = [
- 'openerp.netsvc.rpc.request:INFO',
- 'openerp.netsvc.rpc.response:INFO',
- 'openerp.addons.web.http:INFO',
- 'openerp.sql_db:INFO',
- ':INFO',
- ]
-
- if tools.config['log_level'] == 'info':
- pseudo_config = []
- elif tools.config['log_level'] == 'debug_rpc':
- pseudo_config = ['openerp:DEBUG','openerp.netsvc.rpc.request:DEBUG']
- elif tools.config['log_level'] == 'debug_rpc_answer':
- pseudo_config = ['openerp:DEBUG','openerp.netsvc.rpc.request:DEBUG', 'openerp.netsvc.rpc.response:DEBUG']
- elif tools.config['log_level'] == 'debug':
- pseudo_config = ['openerp:DEBUG']
- elif tools.config['log_level'] == 'test':
- pseudo_config = ['openerp:TEST']
- elif tools.config['log_level'] == 'warn':
- pseudo_config = ['openerp:WARNING']
- elif tools.config['log_level'] == 'error':
- pseudo_config = ['openerp:ERROR']
- elif tools.config['log_level'] == 'critical':
- pseudo_config = ['openerp:CRITICAL']
- elif tools.config['log_level'] == 'debug_sql':
- pseudo_config = ['openerp.sql_db:DEBUG']
- else:
- pseudo_config = []
+ pseudo_config = PSEUDOCONFIG_MAPPER.get(tools.config['log_level'], [])
logconfig = tools.config['log_handler']
- for logconfig_item in default_config + pseudo_config + logconfig:
+ logging_configurations = DEFAULT_LOG_CONFIGURATION + pseudo_config + logconfig
+ for logconfig_item in logging_configurations:
loggername, level = logconfig_item.split(':')
level = getattr(logging, level, logging.INFO)
logger = logging.getLogger(loggername)
if loggername != '':
logger.propagate = False
- for logconfig_item in default_config + pseudo_config + logconfig:
+ for logconfig_item in logging_configurations:
_logger.debug('logger level set: "%s"', logconfig_item)
+DEFAULT_LOG_CONFIGURATION = [
+ 'openerp.workflow.workitem:WARNING',
+ 'openerp.netsvc.rpc.request:INFO',
+ 'openerp.netsvc.rpc.response:INFO',
+ 'openerp.addons.web.http:INFO',
+ 'openerp.sql_db:INFO',
+ ':INFO',
+]
+PSEUDOCONFIG_MAPPER = {
+ 'debug_rpc_answer': ['openerp:DEBUG','openerp.netsvc.rpc.request:DEBUG', 'openerp.netsvc.rpc.response:DEBUG'],
+ 'debug_rpc': ['openerp:DEBUG','openerp.netsvc.rpc.request:DEBUG'],
+ 'debug': ['openerp:DEBUG'],
+ 'debug_sql': ['openerp.sql_db:DEBUG'],
+ 'info': [],
+ 'warn': ['openerp:WARNING'],
+ 'error': ['openerp:ERROR'],
+ 'critical': ['openerp:CRITICAL'],
+}
+
# A alternative logging scheme for automated runs of the
# server intended to test it.
def init_alternative_logger():
def dispatch_rpc(service_name, method, params):
""" Handle a RPC call.
- This is pure Python code, the actual marshalling (from/to XML-RPC or
- NET-RPC) is done in a upper layer.
+ This is pure Python code, the actual marshalling (from/to XML-RPC) is done
+ in a upper layer.
"""
try:
rpc_request = logging.getLogger(__name__ + '.rpc.request')
if rpc_request_flag or rpc_response_flag:
start_time = time.time()
start_rss, start_vms = 0, 0
- if psutil:
- start_rss, start_vms = psutil.Process(os.getpid()).get_memory_info()
+ start_rss, start_vms = psutil.Process(os.getpid()).get_memory_info()
if rpc_request and rpc_response_flag:
log(rpc_request,logging.DEBUG,'%s.%s'%(service_name,method), replace_request_password(params))
- result = ExportService.getService(service_name).dispatch(method, params)
+ threading.current_thread().uid = None
+ threading.current_thread().dbname = None
+ if service_name == 'common':
+ dispatch = openerp.service.common.dispatch
+ elif service_name == 'db':
+ dispatch = openerp.service.db.dispatch
+ elif service_name == 'object':
+ dispatch = openerp.service.model.dispatch
+ elif service_name == 'report':
+ dispatch = openerp.service.report.dispatch
+ else:
+ dispatch = openerp.service.wsgi_server.rpc_handlers.get(service_name)
+ result = dispatch(method, params)
if rpc_request_flag or rpc_response_flag:
end_time = time.time()
end_rss, end_vms = 0, 0
- if psutil:
- end_rss, end_vms = psutil.Process(os.getpid()).get_memory_info()
+ end_rss, end_vms = psutil.Process(os.getpid()).get_memory_info()
logline = '%s.%s time:%.3fs mem: %sk -> %sk (diff: %sk)' % (service_name, method, end_time - start_time, start_vms / 1024, end_vms / 1024, (end_vms - start_vms)/1024)
if rpc_response_flag:
log(rpc_response,logging.DEBUG, logline, result)
log(rpc_request,logging.DEBUG, logline, replace_request_password(params), depth=1)
return result
+ except openerp.osv.orm.except_orm:
+ raise
except openerp.exceptions.AccessError:
raise
except openerp.exceptions.AccessDenied:
raise
except openerp.exceptions.Warning:
raise
+ except openerp.exceptions.RedirectWarning:
+ raise
except openerp.exceptions.DeferredException, e:
_logger.exception(tools.exception_to_unicode(e))
post_mortem(e.traceback)
- #!/usr/bin/env python
# -*- coding: utf-8 -*-
##############################################################################
#
from openerp.osv.orm import MAGIC_COLUMNS
import openerp.tools as tools
-#.apidoc title: Domain Expressions
# Domain operators.
NOT_OPERATOR = '!'
field_path = left.split('.', 1)
field = working_model._columns.get(field_path[0])
if field and field._obj:
- relational_model = working_model.pool.get(field._obj)
+ relational_model = working_model.pool[field._obj]
else:
relational_model = None
# comments about inherits'd fields
# { 'field_name': ('parent_model', 'm2o_field_to_reach_parent',
# field_column_obj, origina_parent_model), ... }
- next_model = working_model.pool.get(working_model._inherit_fields[field_path[0]][0])
+ next_model = working_model.pool[working_model._inherit_fields[field_path[0]][0]]
leaf.add_join_context(next_model, working_model._inherits[next_model._name], 'id', working_model._inherits[next_model._name])
push(leaf)
- elif not field and left == 'id' and operator == 'child_of':
+ elif left == 'id' and operator == 'child_of':
ids2 = to_ids(right, working_model, context)
dom = child_of_domain(left, ids2, working_model)
for dom_leaf in reversed(dom):
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.
('Courier',"FreeMono", "FreeMono.ttf", 'normal'),
('Courier',"FreeMono Bold", "FreeMonoBold.ttf", 'bold'),
('Courier',"FreeMono Oblique", "FreeMonoOblique.ttf", 'italic'),
- ('Courier',"FreeMono BoldOblique", "FreeMonoBoldOblique.ttf", 'bolditalic'),]
+ ('Courier',"FreeMono BoldOblique", "FreeMonoBoldOblique.ttf", 'bolditalic'),
+ ('Sun-ExtA',"Sun-ExtA", "sun-exta.ttf", 'normal'),
+ ]
TTFSearchPath_Linux = [
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
- # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
##############################################################################
to_translate = tools.ustr(sps.pop(0))
result += tools.ustr(self.localcontext.get('translate', lambda x:x)(to_translate))
if sps:
- try:
- txt = None
- expr = sps.pop(0)
- txt = eval(expr, self.localcontext)
- if txt and isinstance(txt, basestring):
- txt = tools.ustr(txt)
- except Exception:
- pass
+ txt = None
+ expr = sps.pop(0)
+ txt = eval(expr, self.localcontext)
+ if txt and isinstance(txt, basestring):
+ txt = tools.ustr(txt)
if isinstance(txt, basestring):
result += txt
elif txt and (txt is not None) and (txt is not False):
- #!/usr/bin/env python
# -*- coding: utf-8 -*-
##############################################################################
#
_logger.debug('cron%d polling for jobs', number)
for db_name, registry in registries.items():
while True and registry.ready:
- # acquired = openerp.addons.base.ir.ir_cron.ir_cron._acquire_job(db_name)
- # TODO why isnt openerp.addons.base defined ?
- import sys
- base = sys.modules['addons.base']
- acquired = base.ir.ir_cron.ir_cron._acquire_job(db_name)
+ acquired = openerp.addons.base.ir.ir_cron.ir_cron._acquire_job(db_name)
if not acquired:
break
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
- # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
###############################################################################
-#.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
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
- # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
###############################################################################
-#.apidoc title: HTTP Layer library (websrv_lib)
""" Framework for generic http servers
- #!/usr/bin/env python
# -*- coding: utf-8 -*-
##############################################################################
#
'psutil', # windows binary code.google.com/p/psutil/downloads/list
'psycopg2 >= 2.2',
'pydot',
+ 'pyparsing < 2',
'python-dateutil < 2',
'python-ldap', # optional
'python-openid',