--- a/__init__.py Tue Apr 28 13:28:37 2009 +0200
+++ b/__init__.py Tue Apr 28 19:12:52 2009 +0200
@@ -74,7 +74,7 @@
encoding = 'utf-8'
self.encoding = encoding
# cache result of execution for (rql expr / eids),
- # should be emptied on commit/rollback of the server session / web
+ # should be emptied on commit/rollback of the server session / web
# connection
self.local_perm_cache = {}
@@ -82,7 +82,7 @@
if self.user:
return self.user.property_value(key)
return self.vreg.property_value(key)
-
+
def etype_rset(self, etype, size=1):
"""return a fake result set for a particular entity type"""
from cubicweb.rset import ResultSet
@@ -114,7 +114,7 @@
return None
# url generation methods ##################################################
-
+
def build_url(self, method, base_url=None, **kwargs):
"""return an absolute URL using params dictionary key/values as URL
parameters. Values are automatically URL quoted, and the
@@ -130,7 +130,7 @@
if not kwargs:
return u'%s%s' % (base_url, path)
return u'%s%s?%s' % (base_url, path, self.build_url_params(**kwargs))
-
+
def build_url_params(self, **kwargs):
"""return encoded params to incorporate them in an URL"""
@@ -154,7 +154,7 @@
def url_unquote(self, quoted):
"""returns a unicode unquoted string
-
+
decoding is based on `self.encoding` which is the encoding
used in `url_quote`
"""
@@ -164,10 +164,10 @@
return unicode(urlunquote(quoted), self.encoding)
except UnicodeDecodeError: # might occurs on manually typed URLs
return unicode(urlunquote(quoted), 'iso-8859-1')
-
+
# session's user related methods #####################################
-
+
@cached
def user_data(self):
"""returns a dictionnary with this user's information"""
@@ -197,21 +197,21 @@
return False
# abstract methods to override according to the web front-end #############
-
+
def base_url(self):
"""return the root url of the application"""
raise NotImplementedError
-
+
def decorate_rset(self, rset):
"""add vreg/req (at least) attributes to the given result set """
raise NotImplementedError
-
+
def describe(self, eid):
"""return a tuple (type, sourceuri, extid) for the entity with id <eid>"""
raise NotImplementedError
-
+
-# XXX 2.45 is allowing nicer entity type names, use this map for bw compat
+# XXX 2.45 is allowing nicer entity type names, use this map for bw compat
ETYPE_NAME_MAP = {# 3.2 migration
'ECache': 'CWCache',
'EUser': 'CWUser',
@@ -268,7 +268,7 @@
'ezone': 'zone',
'i18ncontent': 'i18ncontent',
'svnfile': 'vcsfile',
-
+
'eclassschemes': 'keyword',
'eclassfolders': 'folder',
'eclasstags': 'tag',
@@ -300,4 +300,4 @@
return obj.target
except AttributeError:
return neg_role(obj.role)
-
+
--- a/cwconfig.py Tue Apr 28 13:28:37 2009 +0200
+++ b/cwconfig.py Tue Apr 28 19:12:52 2009 +0200
@@ -4,6 +4,11 @@
:organization: Logilab
:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
+
+.. envvar:: CW_CUBES_PATH
+
+ Augments the default search path for cubes
+
"""
__docformat__ = "restructuredtext en"
--- a/cwvreg.py Tue Apr 28 13:28:37 2009 +0200
+++ b/cwvreg.py Tue Apr 28 19:12:52 2009 +0200
@@ -117,25 +117,24 @@
clear_cache(self, 'etype_class')
# we may want to keep interface dependent objects (e.g.for i18n
# catalog generation)
- if not self.config.cleanup_interface_sobjects:
- return
- # remove vobjects that don't support any available interface
- implemented_interfaces = set()
- for etype in self.schema.entities():
- cls = self.etype_class(etype)
- for iface in cls.__implements__:
- implemented_interfaces.update(iface.__mro__)
- implemented_interfaces.update(cls.__mro__)
- for obj, ifaces in self._needs_iface.items():
- ifaces = frozenset(isinstance(iface, basestring)
- and iface in self.schema
- and self.etype_class(iface)
- or iface
- for iface in ifaces)
- if not ('Any' in ifaces or ifaces & implemented_interfaces):
- self.debug('kicking vobject %s (no implemented interface '
- 'among %s)', obj, ifaces)
- self.unregister(obj)
+ if self.config.cleanup_interface_sobjects:
+ # remove vobjects that don't support any available interface
+ implemented_interfaces = set()
+ for etype in self.schema.entities():
+ cls = self.etype_class(etype)
+ for iface in cls.__implements__:
+ implemented_interfaces.update(iface.__mro__)
+ implemented_interfaces.update(cls.__mro__)
+ for obj, ifaces in self._needs_iface.items():
+ ifaces = frozenset(isinstance(iface, basestring)
+ and iface in self.schema
+ and self.etype_class(iface)
+ or iface
+ for iface in ifaces)
+ if not ('Any' in ifaces or ifaces & implemented_interfaces):
+ self.debug('kicking vobject %s (no implemented '
+ 'interface among %s)', obj, ifaces)
+ self.unregister(obj)
# clear needs_iface so we don't try to remove some not-anymore-in
# objects on automatic reloading
self._needs_iface.clear()
--- a/devtools/apptest.py Tue Apr 28 13:28:37 2009 +0200
+++ b/devtools/apptest.py Tue Apr 28 19:12:52 2009 +0200
@@ -32,11 +32,11 @@
@property
def message(self):
return message_from_string(self.msg)
-
+
def __repr__(self):
return '<Email to %s with subject %s>' % (','.join(self.recipients),
self.message.get('Subject'))
-
+
class MockSMTP:
def __init__(self, server, port):
pass
@@ -100,7 +100,7 @@
env = None
configcls = ApptestConfiguration
requestcls = FakeRequest
-
+
# user / session management ###############################################
def user(self, req=None):
@@ -118,13 +118,13 @@
def restore_connection(self):
self.env.restore_connection()
-
+
# db api ##################################################################
@nocoverage
def cursor(self, req=None):
return self.env.cnx.cursor(req or self.request())
-
+
@nocoverage
def execute(self, *args, **kwargs):
return self.env.execute(*args, **kwargs)
@@ -132,19 +132,19 @@
@nocoverage
def commit(self):
self.env.cnx.commit()
-
+
@nocoverage
def rollback(self):
try:
self.env.cnx.rollback()
except ProgrammingError:
pass
-
+
# other utilities #########################################################
def set_debug(self, debugmode):
from cubicweb.server import set_debug
set_debug(debugmode)
-
+
@property
def config(self):
return self.vreg.config
@@ -152,7 +152,7 @@
def session(self):
"""return current server side session (using default manager account)"""
return self.env.repo._sessions[self.env.cnx.sessionid]
-
+
def request(self, *args, **kwargs):
"""return a web interface request"""
return self.env.create_request(*args, **kwargs)
@@ -160,16 +160,16 @@
@nocoverage
def rset_and_req(self, *args, **kwargs):
return self.env.get_rset_and_req(*args, **kwargs)
-
+
def entity(self, rql, args=None, eidkey=None, req=None):
return self.execute(rql, args, eidkey, req=req).get_entity(0, 0)
-
+
def etype_instance(self, etype, req=None):
req = req or self.request()
e = self.env.vreg.etype_class(etype)(req, None, None)
e.eid = None
return e
-
+
def add_entity(self, etype, **kwargs):
rql = ['INSERT %s X' % etype]
@@ -185,15 +185,15 @@
sub_rql = []
for key, value in kwargs.iteritems():
# entities
- if hasattr(value, 'eid'):
+ if hasattr(value, 'eid'):
new_value = "%s__" % key.upper()
-
+
entities[new_value] = value.eid
rql_args[new_value] = value.eid
-
+
sub_rql.append("X %s %s" % (key, new_value))
# final attributes
- else:
+ else:
sub_rql.append('X %s %%(%s)s' % (key, key))
rql_args[key] = value
rql.append(', '.join(sub_rql))
@@ -215,8 +215,8 @@
self.vreg.config.global_set_option(optname, value)
def pviews(self, req, rset):
- return sorted((a.id, a.__class__) for a in self.vreg.possible_views(req, rset))
-
+ return sorted((a.id, a.__class__) for a in self.vreg.possible_views(req, rset))
+
def pactions(self, req, rset, skipcategories=('addrelated', 'siteactions', 'useractions')):
return [(a.id, a.__class__) for a in self.vreg.possible_vobjects('actions', req, rset)
if a.category not in skipcategories]
@@ -224,7 +224,7 @@
def pactions_by_cats(self, req, rset, categories=('addrelated',)):
return [(a.id, a.__class__) for a in self.vreg.possible_vobjects('actions', req, rset)
if a.category in categories]
-
+
paddrelactions = deprecated_function(pactions_by_cats)
def pactionsdict(self, req, rset, skipcategories=('addrelated', 'siteactions', 'useractions')):
@@ -234,7 +234,7 @@
res.setdefault(a.category, []).append(a.__class__)
return res
-
+
def remote_call(self, fname, *args):
"""remote call simulation"""
dump = simplejson.dumps
@@ -244,7 +244,7 @@
return ctrl.publish(), req
# default test setup and teardown #########################################
-
+
def setup_database(self):
pass
@@ -264,7 +264,7 @@
self.setup_database()
self.commit()
MAILBOX[:] = [] # reset mailbox
-
+
@nocoverage
def tearDown(self):
self.rollback()
@@ -355,7 +355,7 @@
"""
__metaclass__ = autorepo
repo_config = None # set a particular config instance if necessary
-
+
# user / session management ###############################################
def create_user(self, user, groups=('users',), password=None, commit=True):
@@ -369,9 +369,9 @@
{'x': eid})
if commit:
self.commit()
- self.session.reset_pool()
+ self.session.reset_pool()
return eid
-
+
def login(self, login, password=None):
cnx = repo_connect(self.repo, unicode(login), password or login,
ConnectionProperties('inmemory'))
@@ -380,7 +380,7 @@
def current_session(self):
return self.repo._sessions[self.cnxs[-1].sessionid]
-
+
def restore_connection(self):
assert len(self.cnxs) == 1, self.cnxs
cnx = self.cnxs.pop()
@@ -388,7 +388,7 @@
cnx.close()
except Exception, ex:
print "exception occured while closing connection", ex
-
+
# db api ##################################################################
def execute(self, rql, args=None, eid_key=None):
@@ -400,27 +400,27 @@
# application entities for convenience
self.session.set_pool()
return rset
-
+
def commit(self):
self.__commit(self.cnxid)
- self.session.set_pool()
-
+ self.session.set_pool()
+
def rollback(self):
self.__rollback(self.cnxid)
- self.session.set_pool()
-
+ self.session.set_pool()
+
def close(self):
self.__close(self.cnxid)
# other utilities #########################################################
-
+
def set_debug(self, debugmode):
from cubicweb.server import set_debug
set_debug(debugmode)
-
+
def set_option(self, optname, value):
self.vreg.config.global_set_option(optname, value)
-
+
def add_entity(self, etype, **kwargs):
restrictions = ', '.join('X %s %%(%s)s' % (key, key) for key in kwargs)
rql = 'INSERT %s X' % etype
@@ -434,7 +434,7 @@
user = unicode(config.sources()['system']['db-user'])
passwd = config.sources()['system']['db-password']
return user, passwd
-
+
def close_connections(self):
for cnx in self.cnxs:
try:
@@ -446,10 +446,10 @@
pactions = EnvBasedTC.pactions.im_func
pactionsdict = EnvBasedTC.pactionsdict.im_func
-
+
# default test setup and teardown #########################################
copy_schema = False
-
+
def _prepare(self):
MAILBOX[:] = [] # reset mailbox
if hasattr(self, 'cnxid'):
@@ -494,15 +494,15 @@
@property
def schema(self):
return self.repo.schema
-
+
def setUp(self):
self._prepare()
self.session.set_pool()
self.maxeid = self.session.system_sql('SELECT MAX(eid) FROM entities').fetchone()[0]
-
+
def tearDown(self):
self.close_connections()
self.rollback()
self.session.unsafe_execute('DELETE Any X WHERE X eid > %(x)s', {'x': self.maxeid})
self.commit()
-
+
--- a/devtools/devctl.py Tue Apr 28 13:28:37 2009 +0200
+++ b/devtools/devctl.py Tue Apr 28 19:12:52 2009 +0200
@@ -93,8 +93,8 @@
config = DevCubeConfiguration(cube)
schema = config.load_schema()
else:
+ config = libconfig
schema = config.load_schema()
- config = libconfig
libconfig = None
vreg = CubicWebRegistry(config)
# set_schema triggers objects registrations
@@ -130,7 +130,7 @@
w('# subject and object forms for each relation type\n')
w('# (no object form for final relation types)\n')
w('\n')
- if libschema is not None:
+ if libconfig is not None:
relations = [r for r in schema.relations() if not r in libschema]
else:
relations = schema.relations()
@@ -155,9 +155,13 @@
if rschema.is_final():
continue
for teschema in rschema.targets(eschema, role):
- if defined_in_library(libschema, eschema, rschema,
- teschema, role):
- continue
+ if libconfig is not None:
+ if role == 'subject':
+ subjtype, objtype = etype, tetype
+ else:
+ subjtype, objtype = tetype, etype
+ if libschema.rschema(rtype).has_rdef(subjtype, objtype):
+ continue
if actionbox.relation_mode(rschema, eschema, teschema, role) == 'create':
if role == 'subject':
label = 'add %s %s %s %s' % (eschema, rschema,
@@ -179,7 +183,6 @@
libvreg.set_schema(libschema) # trigger objects registration
# prefill done set
list(_iter_vreg_objids(libvreg, done))
- print 'done', done
for objid in _iter_vreg_objids(vreg, done):
add_msg(w, '%s_description' % objid)
add_msg(w, objid)
@@ -197,7 +200,7 @@
break
-def defined_in_library(libschema, etype, rtype, tetype, role):
+def defined_in_library(etype, rtype, tetype, role):
"""return true if the given relation definition exists in cubicweb's library
"""
if libschema is None:
@@ -271,8 +274,12 @@
cmd = 'xgettext --no-location --omit-header -k_ -o %s %s'
if lang is not None:
cmd += ' -L %s' % lang
- potfiles.append(join(tempdir, '%s.pot' % id))
- execute(cmd % (potfiles[-1], ' '.join(files)))
+ potfile = join(tempdir, '%s.pot' % id)
+ execute(cmd % (potfile, ' '.join(files)))
+ if exists(potfile):
+ potfiles.append(potfile)
+ else:
+ print 'WARNING: %s file not generated' % potfile
print '******** merging .pot files'
cubicwebpot = join(tempdir, 'cubicweb.pot')
execute('msgcat %s > %s' % (' '.join(potfiles), cubicwebpot))
--- a/devtools/fake.py Tue Apr 28 13:28:37 2009 +0200
+++ b/devtools/fake.py Tue Apr 28 19:12:52 2009 +0200
@@ -24,13 +24,13 @@
self.apphome = apphome
self._cubes = cubes
self['auth-mode'] = 'cookie'
- self['uid'] = None
+ self['uid'] = None
self['base-url'] = BASE_URL
self['rql-cache-size'] = 100
-
+
def cubes(self, expand=False):
return self._cubes
-
+
def sources(self):
return {}
@@ -41,7 +41,7 @@
self.properties = {'ui.encoding': 'UTF8',
'ui.language': 'en',
}
-
+
def property_value(self, key):
return self.properties[key]
@@ -51,10 +51,10 @@
'views' : [Mock(id='primary'), Mock(id='secondary'),
Mock(id='oneline'), Mock(id='list')],
}
-
+
def registry_objects(self, name, oid=None):
return self._registries[name]
-
+
def etype_class(self, etype):
class Entity(dict):
e_schema = self.schema[etype]
@@ -112,15 +112,15 @@
def set_header(self, header, value):
"""set an output HTTP header"""
pass
-
+
def add_header(self, header, value):
"""set an output HTTP header"""
pass
-
+
def remove_header(self, header):
"""remove an output HTTP header"""
pass
-
+
def get_header(self, header, default=None):
"""return the value associated with the given input header,
raise KeyError if the header is not set
@@ -169,7 +169,7 @@
self.is_internal_session = False
self.is_super_session = self.user.eid == -1
self._query_data = {}
-
+
def execute(self, *args):
pass
def commit(self, *args):
@@ -186,7 +186,7 @@
def set_entity_cache(self, entity):
pass
-
+
class FakeRepo(object):
querier = None
def __init__(self, schema, vreg=None, config=None):
@@ -199,8 +199,9 @@
def internal_session(self):
return FakeSession(self)
-
- def extid2eid(self, source, extid, etype, session, insert=True):
+
+ def extid2eid(self, source, extid, etype, session, insert=True,
+ recreate=False):
try:
return self.extids[extid]
except KeyError:
@@ -213,7 +214,7 @@
self.eids[eid] = extid
source.after_entity_insertion(session, extid, entity)
return eid
-
+
def eid2extid(self, source, eid, session=None):
return self.eids[eid]
@@ -228,7 +229,7 @@
def __init__(self, uri):
self.uri = uri
-
+
class FakePool(object):
def source(self, uri):
return FakeSource(uri)
--- a/devtools/htmlparser.py Tue Apr 28 13:28:37 2009 +0200
+++ b/devtools/htmlparser.py Tue Apr 28 19:12:52 2009 +0200
@@ -5,11 +5,13 @@
from lxml import etree
from cubicweb.view import STRICT_DOCTYPE, TRANSITIONAL_DOCTYPE
+STRICT_DOCTYPE = str(STRICT_DOCTYPE)
+TRANSITIONAL_DOCTYPE = str(TRANSITIONAL_DOCTYPE)
ERR_COUNT = 0
class Validator(object):
-
+
def parse_string(self, data, sysid=None):
try:
data = self.preprocess_data(data)
@@ -32,10 +34,10 @@
def preprocess_data(self, data):
"""used to fix potential blockquote mess generated by docutils"""
- if str(STRICT_DOCTYPE) not in data:
+ if STRICT_DOCTYPE not in data:
return data
# parse using transitional DTD
- data = data.replace(str(STRICT_DOCTYPE), str(TRANSITIONAL_DOCTYPE))
+ data = data.replace(STRICT_DOCTYPE, TRANSITIONAL_DOCTYPE)
tree = etree.fromstring(data, self.parser)
namespace = tree.nsmap.get(None)
# this is the list of authorized child tags for <blockquote> nodes
@@ -51,9 +53,10 @@
parent = blockquote.getparent()
parent.remove(blockquote)
data = etree.tostring(tree)
- return '<?xml version="1.0" encoding="UTF-8"?>%s\n%s' % (str(STRICT_DOCTYPE), data)
+ return '<?xml version="1.0" encoding="UTF-8"?>%s\n%s' % (
+ STRICT_DOCTYPE, data)
-
+
class SaxOnlyValidator(Validator):
def __init__(self):
@@ -66,7 +69,7 @@
Validator.__init__(self)
self.parser = etree.HTMLParser()
-
+
class PageInfo(object):
"""holds various informations on the view's output"""
@@ -84,7 +87,7 @@
self.h4_tags = self.find_tag('h4')
self.input_tags = self.find_tag('input')
self.title_tags = [self.h1_tags, self.h2_tags, self.h3_tags, self.h4_tags]
-
+
def find_tag(self, tag):
"""return a list which contains text of all "tag" elements """
if self.default_ns is None:
@@ -94,14 +97,14 @@
if tag in ('a', 'input'):
return [(elt.text, elt.attrib) for elt in self.etree.iterfind(iterstr)]
return [u''.join(elt.xpath('.//text()')) for elt in self.etree.iterfind(iterstr)]
-
+
def appears(self, text):
"""returns True if <text> appears in the page"""
return text in self.raw_text
def __contains__(self, text):
return text in self.source
-
+
def has_title(self, text, level=None):
"""returns True if <h?>text</h?>
@@ -131,7 +134,7 @@
if sre.match(title):
return True
return False
-
+
def has_link(self, text, url=None):
"""returns True if <a href=url>text</a> was found in the page"""
for link_text, attrs in self.a_tags:
@@ -145,7 +148,7 @@
except KeyError:
continue
return False
-
+
def has_link_regexp(self, pattern, url=None):
"""returns True if <a href=url>pattern</a> was found in the page"""
sre = re.compile(pattern)
--- a/embedded/mx/DateTime/ARPA.py Tue Apr 28 13:28:37 2009 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,227 +0,0 @@
-""" This module provides a set of constructors and routines to convert
- between DateTime[Delta] instances and ARPA representations of date
- and time. The format is specified by RFC822 + RFC1123.
-
- Note: Timezones are only interpreted by ParseDateTimeGMT(). All
- other constructors silently ignore the time zone information.
-
- Copyright (c) 1998-2000, Marc-Andre Lemburg; mailto:mal@lemburg.com
- Copyright (c) 2000-2007, eGenix.com Software GmbH; mailto:info@egenix.com
- See the documentation for further information on copyrights,
- or contact the author. All Rights Reserved.
-
-"""
-import DateTime,Timezone
-import re,string
-
-# Grammar: RFC822 + RFC1123 + depreciated RFC850
-_litday = '(?P<litday>Mon|Tue|Wed|Thu|Fri|Sat|Sun)[a-z]*'
-_litmonth = '(?P<litmonth>Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)'\
- '[a-z]*'
-_date = ('(?:(?P<day>\d?\d)(?: +' + _litmonth +
- ' +|-(?P<month>\d?\d)-)(?P<year>(?:\d\d)?\d\d))')
-_zone = Timezone.zone
-_time = ('(?:(?P<hour>\d\d):(?P<minute>\d\d)'
- '(?::(?P<second>\d\d))?(?: +'+_zone+')?)')
-# Timezone information is made optional because some mail apps
-# forget to add it (most of these seem to be spamming engines, btw).
-# It defaults to UTC.
-
-_arpadate = '(?:'+ _litday + ',? )? *' + _date
-_arpadatetime = '(?:'+ _litday + ',? )? *' + _date + ' +' + _time
-
-# We are not strict about the extra characters: some applications
-# add extra information to the date header field. Additional spaces
-# between the fields and extra characters in the literal day
-# and month fields are also silently ignored.
-
-arpadateRE = re.compile(_arpadate)
-arpadatetimeRE = re.compile(_arpadatetime)
-
-# Translation tables
-litdaytable = {'mon':0, 'tue':1, 'wed':2, 'thu':3, 'fri':4, 'sat':5, 'sun':6 }
-litmonthtable = {'jan':1, 'feb':2, 'mar':3, 'apr':4, 'may':5, 'jun':6,
- 'jul':7, 'aug':8, 'sep':9, 'oct':10, 'nov':11, 'dec':12 }
-_days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
-_months = [None, 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
- 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ]
-
-def ParseDate(arpastring,parse_arpadate=arpadateRE.match,
-
- strip=string.strip,atoi=string.atoi,atof=string.atof,
- lower=string.lower):
-
- """ParseDate(arpastring)
-
- Returns a DateTime instance reflecting the given ARPA
- date. Only the date part is parsed, any time part will be
- ignored. The instance's time is set to 0:00:00.
-
- """
- s = strip(arpastring)
- date = parse_arpadate(s)
- if not date:
- raise ValueError,'wrong format'
- litday,day,litmonth,month,year = date.groups()
- if len(year) == 2:
- year = DateTime.add_century(atoi(year))
- else:
- year = atoi(year)
- if litmonth:
- litmonth = lower(litmonth)
- try:
- month = litmonthtable[litmonth]
- except KeyError:
- raise ValueError,'wrong month format'
- else:
- month = atoi(month)
- day = atoi(day)
- # litday and timezone are ignored
- return DateTime.DateTime(year,month,day)
-
-def ParseDateTime(arpastring,parse_arpadatetime=arpadatetimeRE.match,
-
- strip=string.strip,atoi=string.atoi,atof=string.atof,
- lower=string.lower):
-
- """ParseDateTime(arpastring)
-
- Returns a DateTime instance reflecting the given ARPA date assuming
- it is local time (timezones are silently ignored).
- """
- s = strip(arpastring)
- date = parse_arpadatetime(s)
- if not date:
- raise ValueError,'wrong format or unknown time zone'
- litday,day,litmonth,month,year,hour,minute,second,zone = date.groups()
- if len(year) == 2:
- year = DateTime.add_century(atoi(year))
- else:
- year = atoi(year)
- if litmonth:
- litmonth = lower(litmonth)
- try:
- month = litmonthtable[litmonth]
- except KeyError:
- raise ValueError,'wrong month format'
- else:
- month = atoi(month)
- day = atoi(day)
- hour = atoi(hour)
- minute = atoi(minute)
- if second is None:
- second = 0.0
- else:
- second = atof(second)
- # litday and timezone are ignored
- return DateTime.DateTime(year,month,day,hour,minute,second)
-
-def ParseDateTimeGMT(arpastring,parse_arpadatetime=arpadatetimeRE.match,
-
- strip=string.strip,atoi=string.atoi,atof=string.atof,
- lower=string.lower):
-
- """ParseDateTimeGMT(arpastring)
-
- Returns a DateTime instance reflecting the given ARPA date converting
- it to UTC (timezones are honored).
- """
- s = strip(arpastring)
- date = parse_arpadatetime(s)
- if not date:
- raise ValueError,'wrong format or unknown time zone'
- litday,day,litmonth,month,year,hour,minute,second,zone = date.groups()
- if len(year) == 2:
- year = DateTime.add_century(atoi(year))
- else:
- year = atoi(year)
- if litmonth:
- litmonth = lower(litmonth)
- try:
- month = litmonthtable[litmonth]
- except KeyError:
- raise ValueError,'wrong month format'
- else:
- month = atoi(month)
- day = atoi(day)
- hour = atoi(hour)
- minute = atoi(minute)
- if second is None:
- second = 0.0
- else:
- second = atof(second)
- offset = Timezone.utc_offset(zone)
- # litday is ignored
- return DateTime.DateTime(year,month,day,hour,minute,second) - offset
-
-# Alias
-ParseDateTimeUTC = ParseDateTimeGMT
-
-def str(datetime,tz=None):
-
- """str(datetime,tz=DateTime.tz_offset(datetime))
-
- Returns the datetime instance as ARPA date string. tz can be given
- as DateTimeDelta instance providing the time zone difference from
- datetime's zone to UTC. It defaults to
- DateTime.tz_offset(datetime) which assumes local time. """
-
- if tz is None:
- tz = datetime.gmtoffset()
- return '%s, %02i %s %04i %02i:%02i:%02i %+03i%02i' % (
- _days[datetime.day_of_week], datetime.day,
- _months[datetime.month], datetime.year,
- datetime.hour, datetime.minute, datetime.second,
- tz.hour,tz.minute)
-
-def strGMT(datetime):
-
- """ strGMT(datetime)
-
- Returns the datetime instance as ARPA date string assuming it
- is given in GMT. """
-
- return '%s, %02i %s %04i %02i:%02i:%02i GMT' % (
- _days[datetime.day_of_week], datetime.day,
- _months[datetime.month], datetime.year,
- datetime.hour, datetime.minute, datetime.second)
-
-def strUTC(datetime):
-
- """ strUTC(datetime)
-
- Returns the datetime instance as ARPA date string assuming it
- is given in UTC. """
-
- return '%s, %02i %s %04i %02i:%02i:%02i UTC' % (
- _days[datetime.day_of_week], datetime.day,
- _months[datetime.month], datetime.year,
- datetime.hour, datetime.minute, datetime.second)
-
-def _test():
- import sys, os, rfc822
- file = os.path.join(os.environ['HOME'], 'nsmail/Inbox')
- f = open(file, 'r')
- while 1:
- m = rfc822.Message(f)
- if not m:
- break
- print 'From:', m.getaddr('from')
- print 'To:', m.getaddrlist('to')
- print 'Subject:', m.getheader('subject')
- raw = m.getheader('date')
- try:
- date = ParseDateTimeUTC(raw)
- print 'Date:',strUTC(date)
- except ValueError,why:
- print 'PROBLEMS:',repr(raw),'-->',why
- raw_input('...hit return to continue')
- print
- # Netscape mail file
- while 1:
- line = f.readline()
- if line[:6] == 'From -':
- break
-
-if __name__ == '__main__':
- _test()
--- a/embedded/mx/DateTime/DateTime.py Tue Apr 28 13:28:37 2009 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1054 +0,0 @@
-""" Python part of the low-level DateTime[Delta] type implementation.
-
- Copyright (c) 1998-2001, Marc-Andre Lemburg; mailto:mal@lemburg.com
- Copyright (c) 2000-2007, eGenix.com Software GmbH; mailto:info@egenix.com
- See the documentation for further information on copyrights,
- or contact the author. All Rights Reserved.
-"""
-# Import the python implementation module
-from mxDateTime_python import *
-from mxDateTime_python import __version__
-
-# Singletons
-oneSecond = DateTimeDelta(0,0,0,1)
-oneMinute = DateTimeDelta(0,0,1)
-oneHour = DateTimeDelta(0,1)
-oneDay = DateTimeDelta(1)
-oneWeek = DateTimeDelta(7)
-Epoch = DateTimeFromAbsDateTime(1,0)
-
-# Shortcuts for pickle; for backward compatibility only (they are now
-# defined in __init__.py to further reduce the pickles length)
-def _DT(absdate,abstime):
- return DateTimeFromAbsDateTime(absdate,abstime)
-def _DTD(seconds):
- return DateTimeDeltaFromSeconds(seconds)
-
-# Module init
-class modinit:
-
- global _time,_string,_math,_types
- import time,string,math,types
- _time = time
- _string = string
- _math = math
- _types = types
-
-del modinit
-
-### Helpers
-
-def _isstring(arg,
-
- isinstance=isinstance, types=_types):
-
- if isinstance(arg, types.StringType):
- return 1
- try:
- if isinstance(arg, types.UnicodeType):
- return 1
- except AttributeError:
- pass
- return 0
-
-### Compatibility APIs
-
-# Aliases and functions to make 'from mx.DateTime import *' work much
-# like 'from time import *'
-
-def localtime(ticks=None,
- # Locals:
- time=_time.time,float=float,localtime=_time.localtime,
- round=round,int=int,DateTime=DateTime,floor=_math.floor):
-
- """localtime(ticks=None)
-
- Construct a DateTime instance using local time from ticks. If
- ticks are not given, it defaults to the current time. The
- result is similar to time.localtime(). Fractions of a second
- are rounded to the nearest micro-second.
-
- """
- if ticks is None:
- ticks = time()
- else:
- ticks = float(ticks)
- ticks = round(ticks, 6)
- fticks = floor(ticks)
- Y,M,D,h,m,s = localtime(fticks)[:6]
- s = s + (ticks - fticks)
- return DateTime(Y,M,D,h,m,s)
-
-def gmtime(ticks=None,
- # Locals:
- time=_time.time,float=float,gmtime=_time.gmtime,
- round=round,int=int,DateTime=DateTime,floor=_math.floor):
-
- """gmtime(ticks=None)
-
- Construct a DateTime instance using UTC time from ticks. If
- ticks are not given, it defaults to the current time. The
- result is similar to time.gmtime(). Fractions of a second are
- rounded to the nearest micro-second.
-
- """
- if ticks is None:
- ticks = time()
- else:
- ticks = float(ticks)
- ticks = round(ticks, 6)
- fticks = floor(ticks)
- Y,M,D,h,m,s = gmtime(ticks)[:6]
- s = s + (ticks - fticks)
- return DateTime(Y,M,D,h,m,s)
-
-def mktime((year,month,day,hour,minute,second,dow,doy,dst),
- # Locals:
- DateTime=DateTime):
-
- """mktime((year,month,day,hour,minute,second,dow,doy,dst))
-
- Same as the DateTime() constructor accept that the interface
- used is compatible to the similar time.mktime() API.
-
- Note that the tuple elements dow, doy and dst are not used in
- any way.
-
- """
- return DateTime(year,month,day,hour,minute,second)
-
-def ctime(datetime):
-
- """ctime(datetime)
-
- Returns a string representation of the given DateTime instance
- using the current locale's default settings.
-
- """
- return datetime.strftime('%c')
-
-def today(hour=0,minute=0,second=0.0,
- # Locals:
- localtime=_time.localtime,time=_time.time,DateTime=DateTime):
-
- """today(hour=0,minute=0,second=0.0)
-
- Returns a DateTime instance for today (in local time) at the
- given time (defaults to midnight).
-
- """
- Y,M,D = localtime(time())[:3]
- return DateTime(Y,M,D,hour,minute,second)
-
-def TimeDelta(hours=0.0,minutes=0.0,seconds=0.0,
- # Locals:
- DateTimeDelta=DateTimeDelta):
-
- """TimeDelta(hours=0.0,minutes=0.0,seconds=0.0)
-
- Returns a DateTimeDelta-object reflecting the given time
- delta. Seconds can be given as float to indicate fractions.
-
- """
- return DateTimeDelta(0,hours,minutes,seconds)
-
-def gm2local(datetime):
-
- """ gm2local(datetime)
-
- Convert a DateTime instance holding UTC time to a DateTime
- instance using local time.
-
- """
- return localtime(datetime.gmticks())
-
-def local2gm(datetime):
-
- """ local2gm(datetime)
-
- Convert a DateTime instance holding local time to a DateTime
- instance using UTC time.
-
- """
- return gmtime(datetime.ticks())
-
-# Alias
-gmt = utc
-
-# Default value for DateTimeFromTJD's tjd_myriad parameter
-current_myriad = localtime().tjd_myriad
-
-def DateTimeFromTJD(tjd,tjd_myriad=current_myriad):
-
- """ DateTimeFromTJD(tjd[,myriad])
-
- Return a DateTime instance for the given Truncated Julian Day.
- myriad defaults to the TJD myriad current at package import
- time.
-
- Note that this version of Truncated Julian Day number does
- real truncation of important information. It's use is
- discouraged and unsupported.
-
- """
- return DateTimeFromAbsDays(tjd + tjd_myriad * 10000.0 - 1721425.0)
-
-def DateTimeFromJDN(jdn):
-
- """ DateTimeFromJDN(jdn)
-
- Return a DateTime instance for the given Julian Day Number.
-
- References:
- -----------
- Gregorian 2000-01-01 12:00:00 corresponds to JDN 2451545.0.
- Gregorian 1858-11-17 00:00:00.00 corresponds to JDN 2400000.5; MJD 0.0.
- Julian -4712-01-01 12:00:00.00 corresponds to JDN 0.0.
- Gregorian -4713-11-24 12:00:00.00 corresponds to JDN 0.0.
-
- """
- return DateTimeFromAbsDays(jdn - 1721425.5)
-
-def DateTimeFromMJD(mjd):
-
- """ DateTimeFromMJD(mjd)
-
- Return a DateTime instance for the given Modified Julian Day
- (MJD). The MJD is calculated the same way as the JDN except
- that 1858-11-17 00:00:00.00 is taken as origin of the scale.
-
- """
- return DateTimeFromAbsDays(mjd + 678575.0)
-
-def DateTimeFrom(*args, **kws):
-
- """ DateTimeFrom(*args, **kws)
-
- Generic DateTime instance constructor. Can handle parsing
- strings, numbers and keywords.
-
- XXX Add support for Unicode.
-
- """
- if len(args) == 1:
- # Single argument
- arg = args[0]
- argtype = type(arg)
- if _isstring(arg):
- import Parser
- return apply(Parser.DateTimeFromString, args, kws)
- elif argtype is DateTimeType:
- return arg
- elif argtype is DateTimeDeltaType:
- raise TypeError,'cannot convert DateTimeDelta to DateTime'
- else:
- try:
- value = float(arg)
- except (TypeError, ValueError):
- value = int(arg)
- assert not kws
- return DateTimeFromTicks(value)
-
- elif len(args) > 1:
- # More than one argument
- if len(args) == 2 and _isstring(args[0]) and _isstring(args[1]):
- # interpret as date and time string
- import Parser
- return apply(Parser.DateTimeFromString,
- (args[0] + ' ' + args[1],),
- kws)
-
- # Assume the arguments are the same as for DateTime()
- return apply(DateTime, args, kws)
-
- elif len(kws) > 0:
- # Keyword arguments; add defaults... today at 0:00:00
- hour = kws.get('hour',0)
- minute = kws.get('minute',0)
- second = kws.get('second',0)
- today = now()
- day = kws.get('day',today.day)
- month = kws.get('month',today.month)
- year = kws.get('year',today.year)
- return DateTime(year,month,day,hour,minute,second)
-
- else:
- raise TypeError,'cannot convert arguments to DateTime'
-
-def DateTimeDeltaFrom(*args, **kws):
-
- """ DateTimeDeltaFrom(*args, **kws)
-
- Generic DateTimeDelta instance constructor. Can handle parsing
- strings, numbers and keywords.
-
- XXX Add support for Unicode.
-
- """
- if len(args) == 1:
- # Single argument
- arg = args[0]
- if _isstring(arg):
- import Parser
- return apply(Parser.DateTimeDeltaFromString, args, kws)
- elif type(arg) is DateTimeDeltaType:
- return arg
- elif type(arg) is DateTimeType:
- raise TypeError,'cannot convert DateTime to DateTimeDelta'
- else:
- try:
- value = float(arg)
- except TypeError:
- value = int(arg)
- assert not kws
- return DateTimeDeltaFromSeconds(value)
-
- elif len(args) > 1:
- # Assume the arguments are the same as for DateTimeDelta()
- return apply(DateTimeDelta, args, kws)
-
- elif len(kws) > 0:
- # Keyword arguments; default: 00:00:00:00.00
- hours = kws.get('hours',0)
- minutes = kws.get('minutes',0)
- seconds = kws.get('seconds',0.0)
- days = kws.get('days',0)
- return DateTimeDelta(days,hours,minutes,seconds)
-
- else:
- raise TypeError,'cannot convert arguments to DateTimeDelta'
-
-def TimeDeltaFrom(*args, **kws):
-
- """ TimeDeltaFrom(*args, **kws)
-
- Generic TimeDelta instance constructor. Can handle parsing
- strings, numbers and keywords.
-
- XXX Add support for Unicode.
-
- """
- if len(args) > 1:
- # Assume the arguments are the same as for TimeDelta(): without
- # days part !
- return apply(DateTimeDelta, (0,)+args, kws)
- else:
- # Otherwise treat the arguments just like for DateTimeDelta
- # instances.
- return apply(DateTimeDeltaFrom, args, kws)
-
-def DateFromTicks(ticks,
- # Locals:
- DateTime=DateTime,localtime=_time.localtime):
-
- """ DateFromTicks(ticks)
-
- Constructs a DateTime instance pointing to the local time date
- at 00:00:00.00 (midnight) indicated by the given ticks value.
- The time part is ignored.
-
- """
- return apply(DateTime, localtime(ticks)[:3])
-
-def TimestampFromTicks(ticks,
- # Locals:
- DateTime=DateTime,localtime=_time.localtime):
-
- """ TimestampFromTicks(ticks)
-
- Constructs a DateTime instance pointing to the local date and
- time indicated by the given ticks value.
-
- """
- return apply(DateTime, localtime(ticks)[:6])
-
-def TimeFromTicks(ticks,
- # Locals:
- DateTimeDelta=DateTimeDelta,localtime=_time.localtime):
-
- """ TimeFromTicks(ticks)
-
- Constructs a DateTimeDelta instance pointing to the local time
- indicated by the given ticks value. The date part is ignored.
-
- """
- return apply(DateTimeDelta, (0,) + localtime(ticks)[3:6])
-
-# Aliases
-utctime = gmtime
-utc2local = gm2local
-local2utc = local2gm
-DateTimeFromTicks = localtime
-Date = DateTime
-Time = TimeDelta
-Timestamp = DateTime
-DateFrom = DateTimeFrom # XXX should only parse the date part !
-TimeFrom = TimeDeltaFrom
-TimestampFrom = DateTimeFrom
-GregorianDateTime = DateTime
-GregorianDate = Date
-JulianDate = JulianDateTime
-
-
-### For backward compatibility (these are depreciated):
-
-def gmticks(datetime):
-
- """gmticks(datetime)
-
- [DEPRECIATED: use the .gmticks() method]
-
- Returns a ticks value based on the values stored in
- datetime under the assumption that they are given in UTC,
- rather than local time.
-
- """
- return datetime.gmticks()
-
-# Alias
-utcticks = gmticks
-
-def tz_offset(datetime,
- # Locals:
- oneSecond=oneSecond):
-
- """tz_offset(datetime)
-
- [DEPRECIATED: use the .gmtoffset() method]
-
- Returns a DateTimeDelta instance representing the UTC
- offset for datetime assuming that the stored values refer
- to local time. If you subtract this value from datetime,
- you'll get UTC time.
-
- """
- return datetime.gmtoffset()
-
-### Constants (only English; see Locale.py for other languages)
-
-# Weekdays
-Monday = 0
-Tuesday = 1
-Wednesday = 2
-Thursday = 3
-Friday = 4
-Saturday = 5
-Sunday = 6
-# as mapping
-Weekday = {'Saturday': 5, 6: 'Sunday', 'Sunday': 6, 'Thursday': 3,
- 'Wednesday': 2, 'Friday': 4, 'Tuesday': 1, 'Monday': 0,
- 5: 'Saturday', 4: 'Friday', 3: 'Thursday', 2: 'Wednesday',
- 1: 'Tuesday', 0: 'Monday'}
-
-# Months
-January = 1
-February = 2
-March = 3
-April = 4
-May = 5
-June = 6
-July = 7
-August = 8
-September = 9
-October = 10
-November = 11
-December = 12
-# as mapping
-Month = {2: 'February', 3: 'March', None: 0, 'July': 7, 11: 'November',
- 'December': 12, 'June': 6, 'January': 1, 'September': 9, 'August':
- 8, 'March': 3, 'November': 11, 'April': 4, 12: 'December', 'May':
- 5, 10: 'October', 9: 'September', 8: 'August', 7: 'July', 6:
- 'June', 5: 'May', 4: 'April', 'October': 10, 'February': 2, 1:
- 'January', 0: None}
-
-# Limits (see also the range checks in mxDateTime.c)
-MaxDateTime = DateTime(5867440,12,31)
-MinDateTime = DateTime(-5851455,1,1)
-MaxDateTimeDelta = DateTimeDeltaFromSeconds(2147483647 * 86400.0)
-MinDateTimeDelta = -MaxDateTimeDelta
-
-###
-
-class RelativeDateTime:
-
- """RelativeDateTime(years=0,months=0,days=0,
- hours=0,minutes=0,seconds=0,
- year=0,month=0,day=0,
- hour=None,minute=None,second=None,
- weekday=None,weeks=None)
-
- Returns a RelativeDateTime instance for the specified relative
- time. The constructor handles keywords, so you'll only have to
- give those parameters which should be changed when you add the
- relative to an absolute DateTime instance.
-
- Adding RelativeDateTime instances is supported with the
- following rules: deltas will be added together, right side
- absolute values override left side ones.
-
- Adding RelativeDateTime instances to DateTime instances will
- return DateTime instances with the appropriate calculations
- applied, e.g. to get a DateTime instance for the first of next
- month, you'd call now() + RelativeDateTime(months=+1,day=1).
-
- """
- years = 0
- months = 0
- days = 0
- year = None
- month = 0
- day = 0
- hours = 0
- minutes = 0
- seconds = 0
- hour = None
- minute = None
- second = None
- weekday = None
-
- # cached hash value
- _hash = None
-
- # For Zope security:
- __roles__ = None
- __allow_access_to_unprotected_subobjects__ = 1
-
- def __init__(self,
- years=0,months=0,days=0,
- hours=0,minutes=0,seconds=0,
- year=None,month=None,day=None,
- hour=None,minute=None,second=None,
- weekday=None,weeks=0):
-
- self.years = years
- self.months = months
- self.days = days + weeks*7
- self.year = year
- self.month = month
- self.day = day
- self.hours = hours
- self.minutes = minutes
- self.seconds = seconds
- self.hour = hour
- self.minute = minute
- self.second = second
- if weekday is not None:
- # Make sure we've got a 2-tuple
- assert len(weekday) == 2
- self.weekday = weekday
-
- def __add__(self,other,
- # Locals:
- isinstance=isinstance):
-
- if isinstance(other,RelativeDateTime):
- # RelativeDateTime (self) + RelativeDateTime (other)
-
- r = RelativeDateTime()
- # date deltas
- r.years = self.years + other.years
- r.months = self.months + other.months
- r.days = self.days + other.days
- # absolute entries of other override those in self, if given
- r.year = other.year or self.year
- r.month = other.month or self.month
- r.day = other.day or self.day
- r.weekday = other.weekday or self.weekday
- # time deltas
- r.hours = self.hours + other.hours
- r.minutes = self.minutes + other.minutes
- r.seconds = self.seconds + other.seconds
- # absolute entries of other override those in self, if given
- r.hour = other.hour or self.hour
- r.minute = other.minute or self.minute
- r.second = other.second or self.second
- return r
-
- else:
- raise TypeError,"can't add the two types"
-
- def __radd__(self,other,
- # Locals:
- isinstance=isinstance,DateTimeType=DateTimeType,
- DateTime=DateTime,DateTimeDelta=DateTimeDelta):
-
- if isinstance(other,DateTimeType):
- # DateTime (other) + RelativeDateTime (self)
-
- # date
- if self.year is None:
- year = other.year + self.years
- else:
- year = self.year + self.years
- if self.month is None:
- month = other.month + self.months
- else:
- month = self.month + self.months
- if self.day is None:
- day = other.day
- else:
- day = self.day
- if day < 0:
- # fix negative day values
- month = month + 1
- day = day + 1
- day = day + self.days
- # time
- if self.hour is None:
- hour = other.hour + self.hours
- else:
- hour = self.hour + self.hours
- if self.minute is None:
- minute = other.minute + self.minutes
- else:
- minute = self.minute + self.minutes
- if self.second is None:
- second = other.second + self.seconds
- else:
- second = self.second + self.seconds
-
- # Refit into proper ranges:
- if month < 1 or month > 12:
- month = month - 1
- yeardelta, monthdelta = divmod(month, 12)
- year = year + yeardelta
- month = monthdelta + 1
-
- # Make sure we have integers
- year = int(year)
- month = int(month)
- day = int(day)
-
- if self.weekday is None:
- return DateTime(year, month, 1) + \
- DateTimeDelta(day-1,hour,minute,second)
-
- # Adjust to the correct weekday
- day_of_week,index = self.weekday
- d = DateTime(year, month, 1) + \
- DateTimeDelta(day-1,hour,minute,second)
- if index == 0:
- # 0 index: next weekday if no match
- return d + (day_of_week - d.day_of_week)
- elif index > 0:
- # positive index (1 == first weekday of month)
- first = d - (d.day - 1)
- diff = day_of_week - first.day_of_week
- if diff >= 0:
- return first + (diff + (index-1) * 7)
- else:
- return first + (diff + index * 7)
- else:
- # negative index (-1 == last weekday of month)
- last = d + (d.days_in_month - d.day)
- diff = day_of_week - last.day_of_week
- if diff <= 0:
- return last + (diff + (index+1) * 7)
- else:
- return last + (diff + index * 7)
-
- else:
- raise TypeError,"can't add the two types"
-
- def __sub__(self,other):
-
- if isinstance(other,RelativeDateTime):
- # RelativeDateTime (self) - RelativeDateTime (other)
-
- r = RelativeDateTime()
- # date deltas
- r.years = self.years - other.years
- r.months = self.months - other.months
- r.days = self.days - other.days
- # absolute entries of other override those in self, if given
- r.year = other.year or self.year
- r.month = other.month or self.month
- r.day = other.day or self.day
- r.weekday = other.weekday or self.weekday
- # time deltas
- r.hours = self.hours - other.hours
- r.minutes = self.minutes - other.minutes
- r.seconds = self.seconds - other.seconds
- # absolute entries of other override those in self, if given
- r.hour = other.hour or self.hour
- r.minute = other.minute or self.minute
- r.second = other.second or self.second
-
- return r
-
- else:
- raise TypeError,"can't subtract the two types"
-
- def __rsub__(self,other,
- # Locals:
- isinstance=isinstance,DateTimeType=DateTimeType):
-
- if isinstance(other,DateTimeType):
- # DateTime (other) - RelativeDateTime (self)
- return other + self.__neg__()
-
- else:
- raise TypeError,"can't subtract the two types"
-
- def __neg__(self):
-
- # - RelativeDateTime(self)
-
- r = RelativeDateTime()
- # negate date deltas
- r.years = - self.years
- r.months = - self.months
- r.days = - self.days
- # absolute entries don't change
- r.year = self.year
- r.month = self.month
- r.day = self.day
- r.weekday = self.weekday
- # negate time deltas
- r.hours = - self.hours
- r.minutes = - self.minutes
- r.seconds = - self.seconds
- # absolute entries don't change
- r.hour = self.hour
- r.minute = self.minute
- r.second = self.second
-
- return r
-
- def __nonzero__(self):
-
- # RelativeDateTime instances are considered false in case
- # they do not define any alterations
- if (self.year is None and
- self.years == 0 and
- self.month is None and
- self.months == 0 and
- self.day is None and
- self.weekday is None and
- self.days == 0 and
- self.hour is None and
- self.hours == 0 and
- self.minute is None and
- self.minutes == 0 and
- self.second is None and
- self.seconds == 0):
- return 0
- else:
- return 1
-
- def __mul__(self,other):
-
- # RelativeDateTime (self) * Number (other)
- factor = float(other)
-
- r = RelativeDateTime()
- # date deltas
- r.years = factor * self.years
- r.months = factor * self.months
- r.days = factor * self.days
- # time deltas
- r.hours = factor * self.hours
- r.minutes = factor * self.minutes
- r.seconds = factor * self.seconds
- return r
-
- __rmul__ = __mul__
-
- def __div__(self,other):
-
- # RelativeDateTime (self) / Number (other)
- return self.__mul__(1/float(other))
-
- def __eq__(self, other):
-
- if isinstance(self, RelativeDateTime) and \
- isinstance(other, RelativeDateTime):
- # RelativeDateTime (self) == RelativeDateTime (other)
- if (self.years == other.years and
- self.months == other.months and
- self.days == other.days and
- self.year == other.year and
- self.day == other.day and
- self.hours == other.hours and
- self.minutes == other.minutes and
- self.seconds == other.seconds and
- self.hour == other.hour and
- self.minute == other.minute and
- self.second == other.second and
- self.weekday == other.weekday):
- return 1
- else:
- return 0
- else:
- raise TypeError,"can't compare the two types"
-
- def __hash__(self):
-
- if self._hash is not None:
- return self._hash
- x = 1234
- for value in (self.years, self.months, self.days,
- self.year, self.day,
- self.hours, self.minutes, self.seconds,
- self.hour, self.minute, self.second,
- self.weekday):
- if value is None:
- x = 135051820 ^ x
- else:
- x = hash(value) ^ x
- self._hash = x
- return x
-
- def __str__(self,
-
- join=_string.join):
-
- l = []
- append = l.append
-
- # Format date part
- if self.year is not None:
- append('%04i-' % self.year)
- elif self.years:
- append('(%0+5i)-' % self.years)
- else:
- append('YYYY-')
- if self.month is not None:
- append('%02i-' % self.month)
- elif self.months:
- append('(%0+3i)-' % self.months)
- else:
- append('MM-')
- if self.day is not None:
- append('%02i' % self.day)
- elif self.days:
- append('(%0+3i)' % self.days)
- else:
- append('DD')
- if self.weekday:
- append(' %s:%i' % (Weekday[self.weekday[0]][:3],self.weekday[1]))
- append(' ')
-
- # Normalize relative time values to avoid fractions
- hours = self.hours
- minutes = self.minutes
- seconds = self.seconds
- hours_fraction = hours - int(hours)
- minutes = minutes + hours_fraction * 60.0
- minutes_fraction = minutes - int(minutes)
- seconds = seconds + minutes_fraction * 6.0
- seconds_fraction = seconds - int(seconds)
-
- if 0:
- # Normalize to standard time ranges
- if seconds > 60.0:
- extra_minutes, seconds = divmod(seconds, 60.0)
- minutes = minutes + extra_minutes
- elif seconds < -60.0:
- extra_minutes, seconds = divmod(seconds, -60.0)
- minutes = minutes - extra_minutes
- if minutes >= 60.0:
- extra_hours, minutes = divmod(minutes, 60.0)
- hours = hours + extra_hours
- elif minutes <= -60.0:
- extra_hours, minutes = divmod(minutes, -60.0)
- hours = hours - extra_hours
-
- # Format time part
- if self.hour is not None:
- append('%02i:' % self.hour)
- elif hours:
- append('(%0+3i):' % hours)
- else:
- append('HH:')
- if self.minute is not None:
- append('%02i:' % self.minute)
- elif minutes:
- append('(%0+3i):' % minutes)
- else:
- append('MM:')
- if self.second is not None:
- append('%02i' % self.second)
- elif seconds:
- append('(%0+3i)' % seconds)
- else:
- append('SS')
-
- return join(l,'')
-
- def __repr__(self):
-
- return "<%s instance for '%s' at 0x%x>" % (
- self.__class__.__name__,
- self.__str__(),
- id(self))
-
-# Alias
-RelativeDate = RelativeDateTime
-
-def RelativeDateTimeFrom(*args, **kws):
-
- """ RelativeDateTimeFrom(*args, **kws)
-
- Generic RelativeDateTime instance constructor. Can handle
- parsing strings and keywords.
-
- """
- if len(args) == 1:
- # Single argument
- arg = args[0]
- if _isstring(arg):
- import Parser
- return apply(Parser.RelativeDateTimeFromString, args, kws)
- elif isinstance(arg, RelativeDateTime):
- return arg
- else:
- raise TypeError,\
- 'cannot convert argument to RelativeDateTime'
-
- else:
- return apply(RelativeDateTime,args,kws)
-
-def RelativeDateTimeDiff(date1,date2,
-
- floor=_math.floor,int=int,divmod=divmod,
- RelativeDateTime=RelativeDateTime):
-
- """ RelativeDateTimeDiff(date1,date2)
-
- Returns a RelativeDateTime instance representing the difference
- between date1 and date2 in relative terms.
-
- The following should hold:
-
- date2 + RelativeDateDiff(date1,date2) == date1
-
- for all dates date1 and date2.
-
- Note that due to the algorithm used by this function, not the
- whole range of DateTime instances is supported; there could
- also be a loss of precision.
-
- XXX There are still some problems left (thanks to Carel
- Fellinger for pointing these out):
-
- 29 1 1901 -> 1 3 1901 = 1 month
- 29 1 1901 -> 1 3 1900 = -10 month and -28 days, but
- 29 1 1901 -> 28 2 1900 = -11 month and -1 day
-
- and even worse:
-
- >>> print RelativeDateDiff(Date(1900,3,1),Date(1901,2,1))
- YYYY-(-11)-DD HH:MM:SS
-
- with:
-
- >>> print Date(1901,1,29) + RelativeDateTime(months=-11)
- 1900-03-01 00:00:00.00
- >>> print Date(1901,2,1) + RelativeDateTime(months=-11)
- 1900-03-01 00:00:00.00
-
- """
- diff = date1 - date2
- if diff.days == 0:
- return RelativeDateTime()
- date1months = date1.year * 12 + (date1.month - 1)
- date2months = date2.year * 12 + (date2.month - 1)
- #print 'months',date1months,date2months
-
- # Calculate the months difference
- diffmonths = date1months - date2months
- #print 'diffmonths',diffmonths
- if diff.days > 0:
- years,months = divmod(diffmonths,12)
- else:
- years,months = divmod(diffmonths,-12)
- years = -years
- date3 = date2 + RelativeDateTime(years=years,months=months)
- diff3 = date1 - date3
- days = date1.absdays - date3.absdays
- #print 'date3',date3,'diff3',diff3,'days',days
-
- # Correction to ensure that all relative parts have the same sign
- while days * diff.days < 0:
- if diff.days > 0:
- diffmonths = diffmonths - 1
- years,months = divmod(diffmonths,12)
- else:
- diffmonths = diffmonths + 1
- years,months = divmod(diffmonths,-12)
- years = -years
- #print 'diffmonths',diffmonths
- date3 = date2 + RelativeDateTime(years=years,months=months)
- diff3 = date1 - date3
- days = date1.absdays - date3.absdays
- #print 'date3',date3,'diff3',diff3,'days',days
-
- # Drop the fraction part of days
- if days > 0:
- days = int(floor(days))
- else:
- days = int(-floor(-days))
-
- return RelativeDateTime(years=years,
- months=months,
- days=days,
- hours=diff3.hour,
- minutes=diff3.minute,
- seconds=diff3.second)
-
-# Aliases
-RelativeDateDiff = RelativeDateTimeDiff
-Age = RelativeDateTimeDiff
-
-###
-
-_current_year = now().year
-_current_century, _current_year_in_century = divmod(_current_year, 100)
-_current_century = _current_century * 100
-
-def add_century(year,
-
- current_year=_current_year,
- current_century=_current_century):
-
- """ Sliding window approach to the Y2K problem: adds a suitable
- century to the given year and returns it as integer.
-
- The window used depends on the current year (at import time).
- If adding the current century to the given year gives a year
- within the range current_year-70...current_year+30 [both
- inclusive], then the current century is added. Otherwise the
- century (current + 1 or - 1) producing the least difference is
- chosen.
-
- """
- if year > 99:
- # Take it as-is
- return year
- year = year + current_century
- diff = year - current_year
- if diff >= -70 and diff <= 30:
- return year
- elif diff < -70:
- return year + 100
- else:
- return year - 100
-
-# Reference formulas for JDN taken from the Calendar FAQ:
-
-def gregorian_jdn(year,month,day):
-
- # XXX These require proper integer division.
- a = (14-month)/12
- y = year+4800-a
- m = month + 12*a - 3
- return day + (306*m+5)/10 + y*365 + y/4 - y/100 + y/400 - 32045
-
-def julian_jdn(year,month,day):
-
- # XXX These require proper integer division.
- a = (14-month)/12
- y = year+4800-a
- m = month + 12*a - 3
- return day + (306*m+5)/10 + y*365 + y/4 - 32083
--- a/embedded/mx/DateTime/ISO.py Tue Apr 28 13:28:37 2009 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,366 +0,0 @@
-""" This module provides a set of constructors and routines to convert
- between DateTime[Delta] instances and ISO representations of date
- and time.
-
- Note: Timezones are only interpreted by ParseDateTimeGMT(). All
- other constructors silently ignore the time zone information.
-
- Copyright (c) 1998-2000, Marc-Andre Lemburg; mailto:mal@lemburg.com
- Copyright (c) 2000-2007, eGenix.com Software GmbH; mailto:info@egenix.com
- See the documentation for further information on copyrights,
- or contact the author.
-
-"""
-import DateTime,Timezone
-import re,string
-
-# Grammar: ISO 8601 (not all, but what we need from it)
-_year = '(?P<year>\d?\d\d\d)'
-_month = '(?P<month>\d?\d)'
-_day = '(?P<day>\d?\d)'
-_hour = '(?P<hour>\d?\d)'
-_minute = '(?P<minute>\d?\d)'
-_second = '(?P<second>\d?\d(?:\.\d+)?)'
-_sign = '(?P<sign>[-+])'
-_week = 'W(?P<week>\d?\d)'
-_zone = Timezone.isozone
-
-_weekdate = _year + '-?(?:' + _week + '-?' + _day + '?)?'
-_date = _year + '-?' + '(?:' + _month + '-?' + _day + '?)?'
-_time = _hour + ':?' + _minute + ':?' + _second + '?(?:' + _zone + ')?'
-
-isodatetimeRE = re.compile(_date + '(?:[ T]' + _time + ')?$')
-isodateRE = re.compile(_date + '$')
-isotimeRE = re.compile(_time + '$')
-isodeltaRE = re.compile(_sign + '?' + _time + '$')
-isoweekRE = re.compile(_weekdate + '$')
-isoweektimeRE = re.compile(_weekdate + '(?:[ T]' + _time + ')?$')
-
-def WeekTime(year,isoweek=1,isoday=1,hour=0,minute=0,second=0.0):
-
- """Week(year,isoweek=1,isoday=1,hour=0,minute=0,second=0.0)
-
- Returns a DateTime instance pointing to the given ISO week and
- day. isoday defaults to 1, which corresponds to Monday in the
- ISO numbering. The time part is set as given.
-
- """
- d = DateTime.DateTime(year,1,1,hour,minute,second)
- if d.iso_week[0] == year:
- # 1.1. belongs to year (backup to Monday)
- return d + (-d.day_of_week + 7 * (isoweek-1) + isoday-1)
- else:
- # 1.1. belongs to year-1 (advance to next Monday)
- return d + (7-d.day_of_week + 7 * (isoweek-1) + isoday-1)
-
-# Alias
-Week = WeekTime
-
-# Aliases for the other constructors (they all happen to already use
-# ISO format)
-Date = DateTime.Date
-Time = DateTime.Time
-TimeDelta = DateTime.TimeDelta
-
-def ParseDateTime(isostring,parse_isodatetime=isodatetimeRE.match,
-
- strip=string.strip,atoi=string.atoi,atof=string.atof):
-
- """ParseDateTime(isostring)
-
- Returns a DateTime instance reflecting the given ISO date. A
- time part is optional and must be delimited from the date by a
- space or 'T'.
-
- Time zone information is parsed, but not evaluated.
-
- """
- s = strip(isostring)
- date = parse_isodatetime(s)
- if not date:
- raise ValueError,'wrong format, use YYYY-MM-DD HH:MM:SS'
- year,month,day,hour,minute,second,zone = date.groups()
- year = atoi(year)
- if month is None:
- month = 1
- else:
- month = atoi(month)
- if day is None:
- day = 1
- else:
- day = atoi(day)
- if hour is None:
- hour = 0
- else:
- hour = atoi(hour)
- if minute is None:
- minute = 0
- else:
- minute = atoi(minute)
- if second is None:
- second = 0.0
- else:
- second = atof(second)
- return DateTime.DateTime(year,month,day,hour,minute,second)
-
-def ParseDateTimeGMT(isostring,parse_isodatetime=isodatetimeRE.match,
-
- strip=string.strip,atoi=string.atoi,atof=string.atof):
-
- """ParseDateTimeGMT(isostring)
-
- Returns a DateTime instance in UTC reflecting the given ISO
- date. A time part is optional and must be delimited from the
- date by a space or 'T'. Timezones are honored.
-
- """
- s = strip(isostring)
- date = parse_isodatetime(s)
- if not date:
- raise ValueError,'wrong format, use YYYY-MM-DD HH:MM:SS'
- year,month,day,hour,minute,second,zone = date.groups()
- year = atoi(year)
- if month is None:
- month = 1
- else:
- month = atoi(month)
- if day is None:
- day = 1
- else:
- day = atoi(day)
- if hour is None:
- hour = 0
- else:
- hour = atoi(hour)
- if minute is None:
- minute = 0
- else:
- minute = atoi(minute)
- if second is None:
- second = 0.0
- else:
- second = atof(second)
- offset = Timezone.utc_offset(zone)
- return DateTime.DateTime(year,month,day,hour,minute,second) - offset
-
-# Alias
-ParseDateTimeUTC = ParseDateTimeGMT
-
-def ParseDate(isostring,parse_isodate=isodateRE.match,
-
- strip=string.strip,atoi=string.atoi,atof=string.atof):
-
- """ParseDate(isostring)
-
- Returns a DateTime instance reflecting the given ISO date. A
- time part may not be included.
-
- """
- s = strip(isostring)
- date = parse_isodate(s)
- if not date:
- raise ValueError,'wrong format, use YYYY-MM-DD'
- year,month,day = date.groups()
- year = atoi(year)
- if month is None:
- month = 1
- else:
- month = atoi(month)
- if day is None:
- day = 1
- else:
- day = atoi(day)
- return DateTime.DateTime(year,month,day)
-
-def ParseWeek(isostring,parse_isoweek=isoweekRE.match,
-
- strip=string.strip,atoi=string.atoi,atof=string.atof):
-
- """ParseWeek(isostring)
-
- Returns a DateTime instance reflecting the given ISO date. A
- time part may not be included.
-
- """
- s = strip(isostring)
- date = parse_isoweek(s)
- if not date:
- raise ValueError,'wrong format, use yyyy-Www-d, e.g. 1998-W01-1'
- year,week,day = date.groups()
- year = atoi(year)
- if week is None:
- week = 1
- else:
- week = atoi(week)
- if day is None:
- day = 1
- else:
- day = atoi(day)
- return Week(year,week,day)
-
-def ParseWeekTime(isostring,parse_isoweektime=isoweektimeRE.match,
-
- strip=string.strip,atoi=string.atoi,atof=string.atof):
-
- """ParseWeekTime(isostring)
-
- Returns a DateTime instance reflecting the given ISO date. A
- time part is optional and must be delimited from the date by a
- space or 'T'.
-
- """
- s = strip(isostring)
- date = parse_isoweektime(s)
- if not date:
- raise ValueError,'wrong format, use e.g. "1998-W01-1 12:00:30"'
- year,week,day,hour,minute,second,zone = date.groups()
- year = atoi(year)
- if week is None:
- week = 1
- else:
- week = atoi(week)
- if day is None:
- day = 1
- else:
- day = atoi(day)
- if hour is None:
- hour = 0
- else:
- hour = atoi(hour)
- if minute is None:
- minute = 0
- else:
- minute = atoi(minute)
- if second is None:
- second = 0.0
- else:
- second = atof(second)
- return WeekTime(year,week,day,hour,minute,second)
-
-def ParseTime(isostring,parse_isotime=isotimeRE.match,
-
- strip=string.strip,atoi=string.atoi,atof=string.atof):
-
- """ParseTime(isostring)
-
- Returns a DateTimeDelta instance reflecting the given ISO time.
- Hours and minutes must be given, seconds are
- optional. Fractions of a second may also be used,
- e.g. 12:23:12.34.
-
- """
- s = strip(isostring)
- time = parse_isotime(s)
- if not time:
- raise ValueError,'wrong format, use HH:MM:SS'
- hour,minute,second,zone = time.groups()
- hour = atoi(hour)
- minute = atoi(minute)
- if second is not None:
- second = atof(second)
- else:
- second = 0.0
- return DateTime.TimeDelta(hour,minute,second)
-
-def ParseTimeDelta(isostring,parse_isodelta=isodeltaRE.match,
-
- strip=string.strip,atoi=string.atoi,atof=string.atof):
-
- """ParseTimeDelta(isostring)
-
- Returns a DateTimeDelta instance reflecting the given ISO time
- as delta. Hours and minutes must be given, seconds are
- optional. Fractions of a second may also be used,
- e.g. 12:23:12.34. In addition to the ISO standard a sign may be
- prepended to the time, e.g. -12:34.
-
- """
- s = strip(isostring)
- time = parse_isodelta(s)
- if not time:
- raise ValueError,'wrong format, use [-]HH:MM:SS'
- sign,hour,minute,second,zone = time.groups()
- hour = atoi(hour)
- minute = atoi(minute)
- if second is not None:
- second = atof(second)
- else:
- second = 0.0
- if sign and sign == '-':
- return -DateTime.TimeDelta(hour,minute,second)
- else:
- return DateTime.TimeDelta(hour,minute,second)
-
-def ParseAny(isostring):
-
- """ParseAny(isostring)
-
- Parses the given string and tries to convert it to a
- DateTime[Delta] instance.
-
- """
- try:
- return ParseDateTime(isostring)
- except ValueError:
- pass
- try:
- return ParseWeekTime(isostring)
- except ValueError:
- pass
- try:
- return ParseTimeDelta(isostring)
- except ValueError:
- raise ValueError,'unsupported format: "%s"' % isostring
-
-def str(datetime,tz=None):
-
- """str(datetime,tz=DateTime.tz_offset(datetime))
-
- Returns the datetime instance as ISO date string. tz can be
- given as DateTimeDelta instance providing the time zone
- difference from datetime's zone to UTC. It defaults to
- DateTime.tz_offset(datetime) which assumes local time.
-
- """
- if tz is None:
- tz = datetime.gmtoffset()
- return '%04i-%02i-%02i %02i:%02i:%02i%+03i%02i' % (
- datetime.year, datetime.month, datetime.day,
- datetime.hour, datetime.minute, datetime.second,
- tz.hour,tz.minute)
-
-def strGMT(datetime):
-
- """strGMT(datetime)
-
- Returns the datetime instance as ISO date string assuming it is
- given in GMT.
-
- """
- return '%04i-%02i-%02i %02i:%02i:%02i+0000' % (
- datetime.year, datetime.month, datetime.day,
- datetime.hour, datetime.minute, datetime.second)
-
-def strUTC(datetime):
-
- """strUTC(datetime)
-
- Returns the datetime instance as ISO date string assuming it is
- given in UTC.
-
- """
- return '%04i-%02i-%02i %02i:%02i:%02i+0000' % (
- datetime.year, datetime.month, datetime.day,
- datetime.hour, datetime.minute, datetime.second)
-
-# Testing
-if __name__ == '__main__':
- e = DateTime.Date(1900,1,1)
- for i in range(100000):
- d = e + i
- year,week,day = d.iso_week
- c = WeekTime(year,week,day)
- if d != c:
- print ' Check %s (given; %i) != %s (parsed)' % (d,d.day_of_week,c)
- elif i % 1000 == 0:
- print d,'ok'
--- a/embedded/mx/DateTime/Parser.py Tue Apr 28 13:28:37 2009 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1225 +0,0 @@
-# -*- coding: latin-1 -*-
-
-""" Date/Time string parsing module.
-
- Note about the Y2K problems:
-
- The parser can only handle years with at least 2 digits. 2
- digit year values get expanded by adding the century using
- DateTime.add_century(), while 3 digit year get converted
- literally. To have 2 digit years also be interpreted literally,
- add leading zeros, e.g. year 99 must be written as 099 or 0099.
-
- Copyright (c) 1998-2000, Marc-Andre Lemburg; mailto:mal@lemburg.com
- Copyright (c) 2000-2007, eGenix.com Software GmbH; mailto:info@egenix.com
- See the documentation for further information on copyrights,
- or contact the author. All Rights Reserved.
-
-"""
-import types,re,string
-import DateTime,ISO,ARPA,Timezone
-
-# Enable to produce debugging output
-_debug = 0
-
-# REs for matching date and time parts in a string; These REs
-# parse a superset of ARPA, ISO, American and European style dates.
-# Timezones are supported via the Timezone submodule.
-
-_year = '(?P<year>-?\d+\d(?!:))'
-_fullyear = '(?P<year>-?\d+\d\d(?!:))'
-_year_epoch = '(?:' + _year + '(?P<epoch> *[ABCDE\.]+)?)'
-_fullyear_epoch = '(?:' + _fullyear + '(?P<epoch> *[ABCDE\.]+)?)'
-_relyear = '(?:\((?P<relyear>[-+]?\d+)\))'
-
-_month = '(?P<month>\d?\d(?!:))'
-_fullmonth = '(?P<month>\d\d(?!:))'
-_litmonth = ('(?P<litmonth>'
- 'jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec|'
- 'mär|mae|mrz|mai|okt|dez|'
- 'fev|avr|juin|juil|aou|aoû|déc|'
- 'ene|abr|ago|dic|'
- 'out'
- ')[a-z,\.;]*')
-litmonthtable = {
- # English
- 'jan':1, 'feb':2, 'mar':3, 'apr':4, 'may':5, 'jun':6,
- 'jul':7, 'aug':8, 'sep':9, 'oct':10, 'nov':11, 'dec':12,
- # German
- 'mär':3, 'mae':3, 'mrz':3, 'mai':5, 'okt':10, 'dez':12,
- # French
- 'fev':2, 'avr':4, 'juin':6, 'juil':7, 'aou':8, 'aoû':8,
- 'déc':12,
- # Spanish
- 'ene':1, 'abr':4, 'ago':8, 'dic':12,
- # Portuguese
- 'out':10,
- }
-_relmonth = '(?:\((?P<relmonth>[-+]?\d+)\))'
-
-_day = '(?P<day>\d?\d(?!:))'
-_usday = '(?P<day>\d?\d(?!:))(?:st|nd|rd|th|[,\.;])?'
-_fullday = '(?P<day>\d\d(?!:))'
-_litday = ('(?P<litday>'
- 'mon|tue|wed|thu|fri|sat|sun|'
- 'die|mit|don|fre|sam|son|'
- 'lun|mar|mer|jeu|ven|sam|dim|'
- 'mie|jue|vie|sab|dom|'
- 'pri|seg|ter|cua|qui'
- ')[a-z]*')
-litdaytable = {
- # English
- 'mon':0, 'tue':1, 'wed':2, 'thu':3, 'fri':4, 'sat':5, 'sun':6,
- # German
- 'die':1, 'mit':2, 'don':3, 'fre':4, 'sam':5, 'son':6,
- # French
- 'lun':0, 'mar':1, 'mer':2, 'jeu':3, 'ven':4, 'sam':5, 'dim':6,
- # Spanish
- 'mie':2, 'jue':3, 'vie':4, 'sab':5, 'dom':6,
- # Portuguese
- 'pri':0, 'seg':1, 'ter':2, 'cua':3, 'qui':4,
- }
-_relday = '(?:\((?P<relday>[-+]?\d+)\))'
-
-_hour = '(?P<hour>[012]?\d)'
-_minute = '(?P<minute>[0-6]\d)'
-_second = '(?P<second>[0-6]\d(?:[.,]\d+)?)'
-
-_days = '(?P<days>\d*\d(?:[.,]\d+)?)'
-_hours = '(?P<hours>\d*\d(?:[.,]\d+)?)'
-_minutes = '(?P<minutes>\d*\d(?:[.,]\d+)?)'
-_seconds = '(?P<seconds>\d*\d(?:[.,]\d+)?)'
-
-_reldays = '(?:\((?P<reldays>[-+]?\d+(?:[.,]\d+)?)\))'
-_relhours = '(?:\((?P<relhours>[-+]?\d+(?:[.,]\d+)?)\))'
-_relminutes = '(?:\((?P<relminutes>[-+]?\d+(?:[.,]\d+)?)\))'
-_relseconds = '(?:\((?P<relseconds>[-+]?\d+(?:[.,]\d+)?)\))'
-
-_sign = '(?:(?P<sign>[-+]) *)'
-_week = 'W(?P<week>\d?\d)'
-_zone = Timezone.zone
-_ampm = '(?P<ampm>[ap][m.]+)'
-
-_time = (_hour + ':' + _minute + '(?::' + _second + '|[^:]|$) *'
- + _ampm + '? *' + _zone + '?')
-_isotime = _hour + ':?' + _minute + ':?' + _second + '? *' + _zone + '?'
-
-_weekdate = _year + '-?(?:' + _week + '-?' + _day + '?)?'
-_eurodate = _day + '\.' + _month + '\.' + _year_epoch + '?'
-_usdate = _month + '/' + _day + '(?:/' + _year_epoch + '|[^/]|$)'
-_altusdate = _month + '-' + _day + '-' + _fullyear_epoch
-_isodate = _year + '-' + _month + '-?' + _day + '?(?!:)'
-_altisodate = _year + _fullmonth + _fullday + '(?!:)'
-_usisodate = _fullyear + '/' + _fullmonth + '/' + _fullday
-_litdate = ('(?:'+ _litday + ',? )? *' +
- _usday + ' *' +
- '[- ] *(?:' + _litmonth + '|'+ _month +') *[- ] *' +
- _year_epoch + '?')
-_altlitdate = ('(?:'+ _litday + ',? )? *' +
- _litmonth + '[ ,.a-z]+' +
- _usday +
- '(?:[ a-z]+' + _year_epoch + ')?')
-_eurlitdate = ('(?:'+ _litday + ',?[ a-z]+)? *' +
- '(?:'+ _usday + '[ a-z]+)? *' +
- _litmonth +
- '(?:[ ,.a-z]+' + _year_epoch + ')?')
-
-_relany = '[*%?a-zA-Z]+'
-
-_relisodate = ('(?:(?:' + _relany + '|' + _year + '|' + _relyear + ')-' +
- '(?:' + _relany + '|' + _month + '|' + _relmonth + ')-' +
- '(?:' + _relany + '|' + _day + '|' + _relday + '))')
-
-_asctime = ('(?:'+ _litday + ',? )? *' +
- _usday + ' *' +
- '[- ] *(?:' + _litmonth + '|'+ _month +') *[- ]' +
- '(?:[0-9: ]+)' +
- _year_epoch + '?')
-
-_relisotime = ('(?:(?:' + _relany + '|' + _hour + '|' + _relhours + '):' +
- '(?:' + _relany + '|' + _minute + '|' + _relminutes + ')' +
- '(?::(?:' + _relany + '|' + _second + '|' + _relseconds + '))?)')
-
-_isodelta1 = (_sign + '?' +
- _days + ':' + _hours + ':' + _minutes + ':' + _seconds)
-_isodelta2 = (_sign + '?' +
- _hours + ':' + _minutes + ':' + _seconds)
-_isodelta3 = (_sign + '?' +
- _hours + ':' + _minutes)
-_litdelta = (_sign + '?' +
- '(?:' + _days + ' *d[a-z]*[,; ]*)?' +
- '(?:' + _hours + ' *h[a-z]*[,; ]*)?' +
- '(?:' + _minutes + ' *m[a-z]*[,; ]*)?' +
- '(?:' + _seconds + ' *s[a-z]*[,; ]*)?')
-_litdelta2 = (_sign + '?' +
- '(?:' + _days + ' *d[a-z]*[,; ]*)?' +
- _hours + ':' + _minutes + '(?::' + _seconds + ')?')
-
-_timeRE = re.compile(_time, re.I)
-_isotimeRE = re.compile(_isotime, re.I)
-_isodateRE = re.compile(_isodate, re.I)
-_altisodateRE = re.compile(_altisodate, re.I)
-_usisodateRE = re.compile(_usisodate, re.I)
-_eurodateRE = re.compile(_eurodate, re.I)
-_usdateRE = re.compile(_usdate, re.I)
-_altusdateRE = re.compile(_altusdate, re.I)
-_litdateRE = re.compile(_litdate, re.I)
-_altlitdateRE = re.compile(_altlitdate, re.I)
-_eurlitdateRE = re.compile(_eurlitdate, re.I)
-_relisodateRE = re.compile(_relisodate, re.I)
-_asctimeRE = re.compile(_asctime, re.I)
-_isodelta1RE = re.compile(_isodelta1)
-_isodelta2RE = re.compile(_isodelta2)
-_isodelta3RE = re.compile(_isodelta3)
-_litdeltaRE = re.compile(_litdelta)
-_litdelta2RE = re.compile(_litdelta2)
-_relisotimeRE = re.compile(_relisotime, re.I)
-
-# Available date parsers
-_date_formats = ('euro',
- 'usiso', 'us', 'altus',
- 'iso', 'altiso',
- 'lit', 'altlit', 'eurlit',
- 'unknown')
-
-# Available time parsers
-_time_formats = ('standard',
- 'iso',
- 'unknown')
-
-def _parse_date(text, formats=_date_formats, defaultdate=None,
-
- int=int,float=float,lower=string.lower,
- add_century=DateTime.add_century,
- now=DateTime.now,us_formats=('us', 'altus'),
- iso_formats=('iso', 'altiso', 'usiso')):
-
- """ Parses the date part given in text and returns a tuple
- (text,day,month,year,style) with the following
- meanings:
-
- * text gives the original text without the date part
-
- * day,month,year give the parsed date
-
- * style gives information about which parser was successful:
- 'euro' - the European date parser
- 'us' - the US date parser
- 'altus' - the alternative US date parser (with '-' instead of '/')
- 'iso' - the ISO date parser
- 'altiso' - the alternative ISO date parser (without '-')
- 'usiso' - US style ISO date parser (yyyy/mm/dd)
- 'lit' - the US literal date parser
- 'altlit' - the alternative US literal date parser
- 'eurlit' - the Eurpean literal date parser
- 'unknown' - no date part was found, defaultdate was used
-
- formats may be set to a tuple of style strings specifying
- which of the above parsers to use and in which order to try
- them. Default is to try all of them in the above order.
-
- defaultdate provides the defaults to use in case no date part
- is found. Most other parsers default to the current year
- January 1 if some of these date parts are missing.
-
- If 'unknown' is not given in formats and the date cannot be
- parsed, a ValueError is raised.
-
- """
- match = None
- style = ''
-
- # Apply parsers in the order given in formats
- for format in formats:
-
- if format == 'euro':
- # European style date
- match = _eurodateRE.search(text)
- if match is not None:
- day,month,year,epoch = match.groups()
- if year:
- if len(year) == 2:
- # Y2K problem:
- year = add_century(int(year))
- else:
- year = int(year)
- else:
- if defaultdate is None:
- defaultdate = now()
- year = defaultdate.year
- if epoch and 'B' in epoch:
- year = -year + 1
- month = int(month)
- day = int(day)
- # Could have mistaken euro format for us style date
- # which uses month, day order
- if month > 12 or month == 0:
- match = None
- continue
- break
-
- elif format in iso_formats:
- # ISO style date
- if format == 'iso':
- match = _isodateRE.search(text)
- elif format == 'altiso':
- match = _altisodateRE.search(text)
- # Avoid mistaking ISO time parts ('Thhmmss') for dates
- if match is not None:
- left, right = match.span()
- if left > 0 and \
- text[left - 1:left] == 'T':
- match = None
- continue
- else:
- match = _usisodateRE.search(text)
- if match is not None:
- year,month,day = match.groups()
- if len(year) == 2:
- # Y2K problem:
- year = add_century(int(year))
- else:
- year = int(year)
- # Default to January 1st
- if not month:
- month = 1
- else:
- month = int(month)
- if not day:
- day = 1
- else:
- day = int(day)
- break
-
- elif format in us_formats:
- # US style date
- if format == 'us':
- match = _usdateRE.search(text)
- else:
- match = _altusdateRE.search(text)
- if match is not None:
- month,day,year,epoch = match.groups()
- if year:
- if len(year) == 2:
- # Y2K problem:
- year = add_century(int(year))
- else:
- year = int(year)
- else:
- if defaultdate is None:
- defaultdate = now()
- year = defaultdate.year
- if epoch and 'B' in epoch:
- year = -year + 1
- # Default to 1 if no day is given
- if day:
- day = int(day)
- else:
- day = 1
- month = int(month)
- # Could have mistaken us format for euro style date
- # which uses day, month order
- if month > 12 or month == 0:
- match = None
- continue
- break
-
- elif format == 'lit':
- # US style literal date
- match = _litdateRE.search(text)
- if match is not None:
- litday,day,litmonth,month,year,epoch = match.groups()
- break
-
- elif format == 'altlit':
- # Alternative US style literal date
- match = _altlitdateRE.search(text)
- if match is not None:
- litday,litmonth,day,year,epoch = match.groups()
- month = '<missing>'
- break
-
- elif format == 'eurlit':
- # European style literal date
- match = _eurlitdateRE.search(text)
- if match is not None:
- litday,day,litmonth,year,epoch = match.groups()
- month = '<missing>'
- break
-
- elif format == 'unknown':
- # No date part: use defaultdate
- if defaultdate is None:
- defaultdate = now()
- year = defaultdate.year
- month = defaultdate.month
- day = defaultdate.day
- style = format
- break
-
- # Check success
- if match is not None:
- # Remove date from text
- left, right = match.span()
- if 0 and _debug:
- print 'parsed date:',repr(text[left:right]),\
- 'giving:',year,month,day
- text = text[:left] + text[right:]
- style = format
-
- elif not style:
- # Not recognized: raise an error
- raise ValueError, 'unknown date format: "%s"' % text
-
- # Literal date post-processing
- if style in ('lit', 'altlit', 'eurlit'):
- if 0 and _debug: print match.groups()
- # Default to current year, January 1st
- if not year:
- if defaultdate is None:
- defaultdate = now()
- year = defaultdate.year
- else:
- if len(year) == 2:
- # Y2K problem:
- year = add_century(int(year))
- else:
- year = int(year)
- if epoch and 'B' in epoch:
- year = -year + 1
- if litmonth:
- litmonth = lower(litmonth)
- try:
- month = litmonthtable[litmonth]
- except KeyError:
- raise ValueError,\
- 'wrong month name: "%s"' % litmonth
- elif month:
- month = int(month)
- else:
- month = 1
- if day:
- day = int(day)
- else:
- day = 1
-
- #print '_parse_date:',text,day,month,year,style
- return text,day,month,year,style
-
-def _parse_time(text, formats=_time_formats,
-
- int=int,float=float,replace=string.replace):
-
- """ Parses a time part given in text and returns a tuple
- (text,hour,minute,second,offset,style) with the following
- meanings:
-
- * text gives the original text without the time part
- * hour,minute,second give the parsed time
- * offset gives the time zone UTC offset
- * style gives information about which parser was successful:
- 'standard' - the standard parser
- 'iso' - the ISO time format parser
- 'unknown' - no time part was found
-
- formats may be set to a tuple specifying the parsers to use:
- 'standard' - standard time format with ':' delimiter
- 'iso' - ISO time format (superset of 'standard')
- 'unknown' - default to 0:00:00, 0 zone offset
-
- If 'unknown' is not given in formats and the time cannot be
- parsed, a ValueError is raised.
-
- """
- match = None
- style = ''
-
- # Apply parsers in the order given in formats
- for format in formats:
-
- # Standard format
- if format == 'standard':
- match = _timeRE.search(text)
- if match is not None:
- hour,minute,second,ampm,zone = match.groups()
- style = 'standard'
- break
-
- # ISO format
- if format == 'iso':
- match = _isotimeRE.search(text)
- if match is not None:
- hour,minute,second,zone = match.groups()
- ampm = None
- style = 'iso'
- break
-
- # Default handling
- elif format == 'unknown':
- hour,minute,second,offset = 0,0,0.0,0
- style = 'unknown'
- break
-
- if not style:
- # If no default handling should be applied, raise an error
- raise ValueError, 'unknown time format: "%s"' % text
-
- # Post-processing
- if match is not None:
- if zone:
- # Convert to UTC offset
- offset = Timezone.utc_offset(zone)
- else:
- offset = 0
- hour = int(hour)
- if ampm:
- if ampm[0] in ('p', 'P'):
- # 12pm = midday
- if hour < 12:
- hour = hour + 12
- else:
- # 12am = midnight
- if hour >= 12:
- hour = hour - 12
- if minute:
- minute = int(minute)
- else:
- minute = 0
- if not second:
- second = 0.0
- else:
- if ',' in second:
- second = replace(second, ',', '.')
- second = float(second)
-
- # Remove time from text
- left,right = match.span()
- if 0 and _debug:
- print 'parsed time:',repr(text[left:right]),\
- 'giving:',hour,minute,second,offset
- text = text[:left] + text[right:]
-
- #print '_parse_time:',text,hour,minute,second,offset,style
- return text,hour,minute,second,offset,style
-
-###
-
-def DateTimeFromString(text, formats=_date_formats, defaultdate=None,
- time_formats=_time_formats,
-
- DateTime=DateTime):
-
- """ DateTimeFromString(text, [formats, defaultdate])
-
- Returns a DateTime instance reflecting the date and time given
- in text. In case a timezone is given, the returned instance
- will point to the corresponding UTC time value. Otherwise, the
- value is set as given in the string.
-
- formats may be set to a tuple of strings specifying which of
- the following parsers to use and in which order to try
- them. Default is to try all of them in the order given below:
-
- 'euro' - the European date parser
- 'us' - the US date parser
- 'altus' - the alternative US date parser (with '-' instead of '/')
- 'iso' - the ISO date parser
- 'altiso' - the alternative ISO date parser (without '-')
- 'usiso' - US style ISO date parser (yyyy/mm/dd)
- 'lit' - the US literal date parser
- 'altlit' - the alternative US literal date parser
- 'eurlit' - the Eurpean literal date parser
- 'unknown' - if no date part is found, use defaultdate
-
- defaultdate provides the defaults to use in case no date part
- is found. Most of the parsers default to the current year
- January 1 if some of these date parts are missing.
-
- If 'unknown' is not given in formats and the date cannot
- be parsed, a ValueError is raised.
-
- time_formats may be set to a tuple of strings specifying which
- of the following parsers to use and in which order to try
- them. Default is to try all of them in the order given below:
-
- 'standard' - standard time format HH:MM:SS (with ':' delimiter)
- 'iso' - ISO time format (superset of 'standard')
- 'unknown' - default to 00:00:00 in case the time format
- cannot be parsed
-
- Defaults to 00:00:00.00 for time parts that are not included
- in the textual representation.
-
- If 'unknown' is not given in time_formats and the time cannot
- be parsed, a ValueError is raised.
-
- """
- origtext = text
- formats = tuple(formats)
-
- if formats is _date_formats or \
- 'iso' in formats or \
- 'altiso' in formats:
-
- # First try standard order (parse time, then date)
- if formats[0] not in ('iso', 'altiso'):
- text,hour,minute,second,offset,timestyle = _parse_time(
- origtext,
- time_formats)
- text,day,month,year,datestyle = _parse_date(
- text,
- formats + ('unknown',),
- defaultdate)
- if 0 and _debug:
- print 'tried time/date on %s, date=%s, time=%s' % (origtext,
- datestyle,
- timestyle)
- else:
- timestyle = 'iso'
-
- # If this fails, try the ISO order (date, then time)
- if timestyle in ('iso', 'unknown'):
- text,day,month,year,datestyle = _parse_date(
- origtext,
- formats,
- defaultdate)
- text,hour,minute,second,offset,timestyle = _parse_time(
- text,
- time_formats)
- if 0 and _debug:
- print 'tried ISO on %s, date=%s, time=%s' % (origtext,
- datestyle,
- timestyle)
- else:
- # Standard order: time part, then date part
- text,hour,minute,second,offset,timestyle = _parse_time(
- origtext,
- time_formats)
- text,day,month,year,datestyle = _parse_date(
- text,
- formats,
- defaultdate)
-
- if (datestyle == 'unknown' and 'unknown' not in formats) or \
- (timestyle == 'unknown' and 'unknown' not in time_formats):
- raise ValueError,\
- 'Failed to parse "%s": found "%s" date, "%s" time' % \
- (origtext, datestyle, timestyle)
-
- try:
- return DateTime.DateTime(year,month,day,hour,minute,second) - offset
- except DateTime.RangeError, why:
- raise DateTime.RangeError,\
- 'Failed to parse "%s": %s' % (origtext, why)
-
-def DateFromString(text, formats=_date_formats, defaultdate=None,
-
- DateTime=DateTime):
-
- """ DateFromString(text, [formats, defaultdate])
-
- Returns a DateTime instance reflecting the date given in
- text. A possibly included time part is ignored.
-
- formats and defaultdate work just like for
- DateTimeFromString().
-
- """
- _text,day,month,year,datestyle = _parse_date(text, formats, defaultdate)
-
- if datestyle == 'unknown' and \
- 'unknown' not in formats:
- raise ValueError,\
- 'Failed to parse "%s": found "%s" date' % \
- (origtext, datestyle)
-
- try:
- return DateTime.DateTime(year,month,day)
- except DateTime.RangeError, why:
- raise DateTime.RangeError,\
- 'Failed to parse "%s": %s' % (text, why)
-
-def validateDateTimeString(text, formats=_date_formats):
-
- """ validateDateTimeString(text, [formats, defaultdate])
-
- Validates the given text and returns 1/0 depending on whether
- text includes parseable date and time values or not.
-
- formats works just like for DateTimeFromString() and defines
- the order of date/time parsers to apply. It defaults to the
- same list of parsers as for DateTimeFromString().
-
- XXX Undocumented !
-
- """
- formats = list(formats)
- if 'unknown' in formats:
- formats.remove('unknown')
- try:
- DateTimeFromString(text, formats)
- except (DateTime.RangeError, ValueError), why:
- return 0
- return 1
-
-def validateDateString(text, formats=_date_formats):
-
- """ validateDateString(text, [formats, defaultdate])
-
- Validates the given text and returns 1/0 depending on whether
- text includes a parseable date value or not.
-
- formats works just like for DateTimeFromString() and defines
- the order of date/time parsers to apply. It defaults to the
- same list of parsers as for DateTimeFromString().
-
- XXX Undocumented !
-
- """
- formats = list(formats)
- if 'unknown' in formats:
- formats.remove('unknown')
- try:
- DateFromString(text, formats)
- except (DateTime.RangeError, ValueError), why:
- return 0
- return 1
-
-def TimeFromString(text, formats=_time_formats,
-
- DateTime=DateTime):
-
- """ TimeFromString(text, [formats])
-
- Returns a DateTimeDelta instance reflecting the time given in
- text. A possibly included date part is ignored.
-
- formats may be set to a tuple of strings specifying which of
- the following parsers to use and in which order to try
- them. Default is to try all of them in the order given below:
-
- 'standard' - standard time format with ':' delimiter
- 'iso' - ISO time format (superset of 'standard')
- 'unknown' - default to 00:00:00 in case the time format
- cannot be parsed
-
- Defaults to 00:00:00.00 for parts that are not included in the
- textual representation.
-
- """
- _text,hour,minute,second,offset,timestyle = _parse_time(
- text,
- formats)
-
- if timestyle == 'unknown' and \
- 'unknown' not in formats:
- raise ValueError,\
- 'Failed to parse "%s": found "%s" time' % \
- (text, timestyle)
-
- try:
- dtd = DateTime.DateTimeDelta(0.0, hour, minute, second)
- except DateTime.RangeError, why:
- raise DateTime.RangeError,\
- 'Failed to parse "%s": %s' % (text, why)
- else:
- # XXX What to do with offset ?
- return dtd
-
-#
-# XXX Still missing: validateTimeString(), validateDateTimeDeltaString()
-# and validateTimeDeltaString()
-#
-
-def DateTimeDeltaFromString(text,
-
- float=float,DateTime=DateTime):
-
- """ DateTimeDeltaFromString(text)
-
- Returns a DateTimeDelta instance reflecting the delta given in
- text. Defaults to 0:00:00:00.00 for parts that are not
- included in the textual representation or cannot be parsed.
-
- """
- match = _isodelta1RE.search(text)
- if match is not None:
- sign, days, hours, minutes, seconds = match.groups()
- else:
- match = _litdelta2RE.search(text)
- if match is not None:
- sign, days, hours, minutes, seconds = match.groups()
- else:
- match = _isodelta2RE.search(text)
- if match is not None:
- sign, hours, minutes, seconds = match.groups()
- days = None
- else:
- match = _isodelta3RE.search(text)
- if match is not None:
- sign, hours, minutes = match.groups()
- days = None
- seconds = None
- else:
- match = _litdeltaRE.search(text)
- if match is not None:
- sign, days, hours, minutes, seconds = match.groups()
-
- else:
- # Not matched:
- return DateTime.DateTimeDelta(0.0)
-
- # Conversions
- if days:
- days = float(days)
- else:
- days = 0.0
- if hours:
- hours = float(hours)
- else:
- hours = 0.0
- if minutes:
- minutes = float(minutes)
- else:
- minutes = 0.0
- if seconds:
- seconds = float(seconds)
- else:
- seconds = 0.0
- if sign != '-':
- sign = 1
- else:
- sign = -1
-
- try:
- dtd = DateTime.DateTimeDelta(days,hours,minutes,seconds)
- except DateTime.RangeError, why:
- raise DateTime.RangeError,\
- 'Failed to parse "%s": %s' % (text, why)
- else:
- if sign < 0:
- return -dtd
- else:
- return dtd
-
-# Aliases
-TimeDeltaFromString = DateTimeDeltaFromString
-
-###
-
-def _parse_reldate(text,
-
- int=int,float=float):
-
- match = _relisodateRE.search(text)
- if match is not None:
- groups = match.groups()
- if 0 and _debug: print groups
- year,years,month,months,day,days = groups
- if year:
- year = int(year)
- if years:
- years = float(years)
- else:
- years = 0
- if month:
- month = int(month)
- if months:
- months = float(months)
- else:
- months = 0
- if day:
- day = int(day)
- if days:
- days = float(days)
- else:
- days = 0
- return year,years,month,months,day,days
- else:
- return None,0,None,0,None,0
-
-def _parse_reltime(text,
-
- int=int,float=float):
-
- match = _relisotimeRE.search(text)
- if match is not None:
- groups = match.groups()
- if 0 and _debug: print groups
- hour,hours,minute,minutes,second,seconds = groups
- if hour:
- hour = int(hour)
- if hours:
- hours = float(hours)
- else:
- hours = 0
- if minute:
- minute = int(minute)
- if minutes:
- minutes = float(minutes)
- else:
- minutes = 0
- if second:
- second = int(second)
- if seconds:
- seconds = float(seconds)
- else:
- seconds = 0
- return hour,hours,minute,minutes,second,seconds
- else:
- return None,0,None,0,None,0
-
-def RelativeDateTimeFromString(text,
-
- RelativeDateTime=DateTime.RelativeDateTime):
-
- """ RelativeDateTimeFromString(text)
-
- Returns a RelativeDateTime instance reflecting the relative
- date and time given in text.
-
- Defaults to wildcards for parts or values which are not
- included in the textual representation or cannot be parsed.
-
- The format used in text must adhere to the following syntax:
-
- [YYYY-MM-DD] [HH:MM[:SS]]
-
- with the usual meanings. Values which should not be altered
- may be replaced with '*', '%', '?' or any combination of
- letters, e.g. 'YYYY'. Relative settings must be enclosed in
- parenthesis if given and should include a sign, e.g. '(+0001)'
- for the year part. All other settings are interpreted as
- absolute values.
-
- Date and time parts are both optional as a whole. Seconds in
- the time part are optional too. Everything else (including the
- hyphens and colons) is mandatory.
-
- """
- year,years,month,months,day,days = _parse_reldate(text)
- hour,hours,minute,minutes,second,seconds = _parse_reltime(text)
- return RelativeDateTime(year=year,years=years,
- month=month,months=months,
- day=day,days=days,
- hour=hour,hours=hours,
- minute=minute,minutes=minutes,
- second=second,seconds=seconds)
-
-def RelativeDateFromString(text,
-
- RelativeDateTime=DateTime.RelativeDateTime):
-
- """ RelativeDateFromString(text)
-
- Same as RelativeDateTimeFromString(text) except that only the
- date part of text is taken into account.
-
- """
- year,years,month,months,day,days = _parse_reldate(text)
- return RelativeDateTime(year=year,years=years,
- month=month,months=months,
- day=day,days=days)
-
-def RelativeTimeFromString(text,
-
- RelativeDateTime=DateTime.RelativeDateTime):
-
- """ RelativeTimeFromString(text)
-
- Same as RelativeDateTimeFromString(text) except that only the
- time part of text is taken into account.
-
- """
- hour,hours,minute,minutes,second,seconds = _parse_reltime(text)
- return RelativeDateTime(hour=hour,hours=hours,
- minute=minute,minutes=minutes,
- second=second,seconds=seconds)
-
-### Tests
-
-def _test():
-
- import sys
-
- t = DateTime.now()
-
- print 'Testing DateTime Parser...'
-
- l = [
-
- # Literal formats
- ('Sun Nov 6 08:49:37 1994', '1994-11-06 08:49:37.00'),
- ('sun nov 6 08:49:37 1994', '1994-11-06 08:49:37.00'),
- ('sUN NOV 6 08:49:37 1994', '1994-11-06 08:49:37.00'),
- ('Sunday, 06-Nov-94 08:49:37 GMT', '1994-11-06 08:49:37.00'),
- ('Sun, 06 Nov 1994 08:49:37 GMT', '1994-11-06 08:49:37.00'),
- ('06-Nov-94 08:49:37', '1994-11-06 08:49:37.00'),
- ('06-Nov-94', '1994-11-06 00:00:00.00'),
- ('06-NOV-94', '1994-11-06 00:00:00.00'),
- ('November 19 08:49:37', '%s-11-19 08:49:37.00' % t.year),
- ('Nov. 9', '%s-11-09 00:00:00.00' % t.year),
- ('Sonntag, der 6. November 1994, 08:49:37 GMT', '1994-11-06 08:49:37.00'),
- ('6. November 2001, 08:49:37', '2001-11-06 08:49:37.00'),
- ('sep 6', '%s-09-06 00:00:00.00' % t.year),
- ('sep 6 2000', '2000-09-06 00:00:00.00'),
- ('September 29', '%s-09-29 00:00:00.00' % t.year),
- ('Sep. 29', '%s-09-29 00:00:00.00' % t.year),
- ('6 sep', '%s-09-06 00:00:00.00' % t.year),
- ('29 September', '%s-09-29 00:00:00.00' % t.year),
- ('29 Sep.', '%s-09-29 00:00:00.00' % t.year),
- ('sep 6 2001', '2001-09-06 00:00:00.00'),
- ('Sep 6, 2001', '2001-09-06 00:00:00.00'),
- ('September 6, 2001', '2001-09-06 00:00:00.00'),
- ('sep 6 01', '2001-09-06 00:00:00.00'),
- ('Sep 6, 01', '2001-09-06 00:00:00.00'),
- ('September 6, 01', '2001-09-06 00:00:00.00'),
- ('30 Apr 2006 20:19:00', '2006-04-30 20:19:00.00'),
-
- # ISO formats
- ('1994-11-06 08:49:37', '1994-11-06 08:49:37.00'),
- ('010203', '2001-02-03 00:00:00.00'),
- ('2001-02-03 00:00:00.00', '2001-02-03 00:00:00.00'),
- ('2001-02 00:00:00.00', '2001-02-01 00:00:00.00'),
- ('2001-02-03', '2001-02-03 00:00:00.00'),
- ('2001-02', '2001-02-01 00:00:00.00'),
- ('20000824/2300', '2000-08-24 23:00:00.00'),
- ('20000824/0102', '2000-08-24 01:02:00.00'),
- ('20000824', '2000-08-24 00:00:00.00'),
- ('20000824/020301', '2000-08-24 02:03:01.00'),
- ('20000824 020301', '2000-08-24 02:03:01.00'),
- ('-20000824 020301', '-2000-08-24 02:03:01.00'),
- ('20000824T020301', '2000-08-24 02:03:01.00'),
- ('20000824 020301', '2000-08-24 02:03:01.00'),
- ('2000-08-24 02:03:01.00', '2000-08-24 02:03:01.00'),
- ('T020311', '%s 02:03:11.00' % t.date),
- ('2003-12-9', '2003-12-09 00:00:00.00'),
- ('03-12-9', '2003-12-09 00:00:00.00'),
- ('003-12-9', '0003-12-09 00:00:00.00'),
- ('0003-12-9', '0003-12-09 00:00:00.00'),
- ('2003-1-9', '2003-01-09 00:00:00.00'),
- ('03-1-9', '2003-01-09 00:00:00.00'),
- ('003-1-9', '0003-01-09 00:00:00.00'),
- ('0003-1-9', '0003-01-09 00:00:00.00'),
-
- # US formats
- ('06/11/94 08:49:37', '1994-06-11 08:49:37.00'),
- ('11/06/94 08:49:37', '1994-11-06 08:49:37.00'),
- ('9/23/2001', '2001-09-23 00:00:00.00'),
- ('9-23-2001', '2001-09-23 00:00:00.00'),
- ('9/6', '%s-09-06 00:00:00.00' % t.year),
- ('09/6', '%s-09-06 00:00:00.00' % t.year),
- ('9/06', '%s-09-06 00:00:00.00' % t.year),
- ('09/06', '%s-09-06 00:00:00.00' % t.year),
- ('9/6/2001', '2001-09-06 00:00:00.00'),
- ('09/6/2001', '2001-09-06 00:00:00.00'),
- ('9/06/2001', '2001-09-06 00:00:00.00'),
- ('09/06/2001', '2001-09-06 00:00:00.00'),
- ('9-6-2001', '2001-09-06 00:00:00.00'),
- ('09-6-2001', '2001-09-06 00:00:00.00'),
- ('9-06-2001', '2001-09-06 00:00:00.00'),
- ('09-06-2001', '2001-09-06 00:00:00.00'),
- ('2002/05/28 13:10:56.1147 GMT+2', '2002-05-28 13:10:56.11'),
- ('1970/01/01', '1970-01-01 00:00:00.00'),
- ('20021025 12:00 PM', '2002-10-25 12:00:00.00'),
- ('20021025 12:30 PM', '2002-10-25 12:30:00.00'),
- ('20021025 12:00 AM', '2002-10-25 00:00:00.00'),
- ('20021025 12:30 AM', '2002-10-25 00:30:00.00'),
- ('20021025 1:00 PM', '2002-10-25 13:00:00.00'),
- ('20021025 2:00 AM', '2002-10-25 02:00:00.00'),
- ('Thursday, February 06, 2003 12:40 PM', '2003-02-06 12:40:00.00'),
- ('Mon, 18 Sep 2006 23:03:00', '2006-09-18 23:03:00.00'),
-
- # European formats
- ('6.11.2001, 08:49:37', '2001-11-06 08:49:37.00'),
- ('06.11.2001, 08:49:37', '2001-11-06 08:49:37.00'),
- ('06.11. 08:49:37', '%s-11-06 08:49:37.00' % t.year),
- #('21/12/2002', '2002-12-21 00:00:00.00'),
- #('21/08/2002', '2002-08-21 00:00:00.00'),
- #('21-08-2002', '2002-08-21 00:00:00.00'),
- #('13/01/03', '2003-01-13 00:00:00.00'),
- #('13/1/03', '2003-01-13 00:00:00.00'),
- #('13/1/3', '2003-01-13 00:00:00.00'),
- #('13/01/3', '2003-01-13 00:00:00.00'),
-
- # Time only formats
- ('01:03', '%s 01:03:00.00' % t.date),
- ('01:03:11', '%s 01:03:11.00' % t.date),
- ('01:03:11.50', '%s 01:03:11.50' % t.date),
- ('01:03:11.50 AM', '%s 01:03:11.50' % t.date),
- ('01:03:11.50 PM', '%s 13:03:11.50' % t.date),
- ('01:03:11.50 a.m.', '%s 01:03:11.50' % t.date),
- ('01:03:11.50 p.m.', '%s 13:03:11.50' % t.date),
-
- # Invalid formats
- ('6..2001, 08:49:37', '%s 08:49:37.00' % t.date),
- ('9//2001', 'ignore'),
- ('06--94 08:49:37', 'ignore'),
- ('20000824020301', 'ignore'),
- ('20-03 00:00:00.00', 'ignore'),
- ('9/2001', 'ignore'),
- ('9-6', 'ignore'),
- ('09-6', 'ignore'),
- ('9-06', 'ignore'),
- ('09-06', 'ignore'),
- ('20000824/23', 'ignore'),
- ('November 1994 08:49:37', 'ignore'),
- ('Nov. 94', 'ignore'),
- ('Mon, 18 Sep 2006 23:03:00 +1234567890', 'ignore'),
-
- ]
-
- # Add Unicode versions
- try:
- unicode
- except NameError:
- pass
- else:
- k = []
- for text, result in l:
- k.append((unicode(text), result))
- l.extend(k)
-
- for text, reference in l:
- try:
- value = DateTimeFromString(text)
- except:
- if reference is None:
- continue
- else:
- value = str(sys.exc_info()[1])
- valid_datetime = validateDateTimeString(text)
- valid_date = validateDateString(text)
- if str(value) != reference and \
- not reference == 'ignore':
- print 'Failed to parse "%s"' % text
- print ' expected: %s' % (reference or '<exception>')
- print ' parsed: %s' % value
- elif _debug:
- print 'Parsed "%s" successfully' % text
- if _debug:
- if not valid_datetime:
- print ' "%s" failed date/time validation' % text
- if not valid_date:
- print ' "%s" failed date validation' % text
-
- et = DateTime.now()
- print 'done. (after %f seconds)' % ((et-t).seconds)
-
- ###
-
- print 'Testing DateTimeDelta Parser...'
-
- t = DateTime.now()
- l = [
-
- # Literal formats
- ('Sun Nov 6 08:49:37 1994', '08:49:37.00'),
- ('1 day, 8 hours, 49 minutes, 37 seconds', '1:08:49:37.00'),
- ('10 days, 8 hours, 49 minutes, 37 seconds', '10:08:49:37.00'),
- ('8 hours, 49 minutes, 37 seconds', '08:49:37.00'),
- ('49 minutes, 37 seconds', '00:49:37.00'),
- ('37 seconds', '00:00:37.00'),
- ('37.5 seconds', '00:00:37.50'),
- ('8 hours later', '08:00:00.00'),
- ('2 days', '2:00:00:00.00'),
- ('2 days 23h', '2:23:00:00.00'),
- ('2 days 23:57', '2:23:57:00.00'),
- ('2 days 23:57:13', '2:23:57:13.00'),
- ('', '00:00:00.00'),
-
- # ISO formats
- ('1994-11-06 08:49:37', '08:49:37.00'),
- ('10:08:49:37', '10:08:49:37.00'),
- ('08:49:37', '08:49:37.00'),
- ('08:49', '08:49:00.00'),
- ('-10:08:49:37', '-10:08:49:37.00'),
- ('-08:49:37', '-08:49:37.00'),
- ('-08:49', '-08:49:00.00'),
- ('- 10:08:49:37', '-10:08:49:37.00'),
- ('- 08:49:37', '-08:49:37.00'),
- ('- 08:49', '-08:49:00.00'),
- ('10:08:49:37.5', '10:08:49:37.50'),
- ('08:49:37.5', '08:49:37.50'),
- ('10:8:49:37', '10:08:49:37.00'),
- ('8:9:37', '08:09:37.00'),
- ('8:9', '08:09:00.00'),
- ('8', '00:00:00.00'),
-
- # Invalid formats
- #('', None),
- #('8', None),
-
- ]
-
- for text, reference in l:
- try:
- value = DateTimeDeltaFromString(text)
- except:
- if reference is None:
- continue
- else:
- value = str(sys.exc_info()[1])
- if str(value) != reference and \
- not reference == 'ignore':
- print 'Failed to parse "%s"' % text
- print ' expected: %s' % (reference or '<exception>')
- print ' parsed: %s' % value
- elif _debug:
- print 'Parsed "%s" successfully' % text
-
- et = DateTime.now()
- print 'done. (after %f seconds)' % ((et-t).seconds)
-
- ###
-
- print 'Testing Time Parser...'
-
- t = DateTime.now()
- l = [
-
- # Standard formats
- ('08:49:37 AM', '08:49:37.00'),
- ('08:49:37 PM', '20:49:37.00'),
- ('12:00:00 AM', '00:00:00.00'),
- ('12:00:00 PM', '12:00:00.00'),
- ('8:09:37', '08:09:37.00'),
- ('8:09', '08:09:00.00'),
-
- # ISO formats
- ('08:49:37', '08:49:37.00'),
- ('08:49', '08:49:00.00'),
- ('08:49:37.5', '08:49:37.50'),
- ('08:49:37,5', '08:49:37.50'),
- ('08:09', '08:09:00.00'),
-
- # Invalid formats
- ('', None),
- ('8:9:37', 'XXX Should give an exception'),
- ('08:9:37', 'XXX Should give an exception'),
- ('8:9', None),
- ('8', None),
-
- ]
-
- for text, reference in l:
- try:
- value = TimeFromString(text, formats=('standard', 'iso'))
- except:
- if reference is None:
- continue
- else:
- value = str(sys.exc_info()[1])
- if str(value) != reference and \
- not reference == 'ignore':
- print 'Failed to parse "%s"' % text
- print ' expected: %s' % (reference or '<exception>')
- print ' parsed: %s' % value
- elif _debug:
- print 'Parsed "%s" successfully' % text
-
- et = DateTime.now()
- print 'done. (after %f seconds)' % ((et-t).seconds)
-
-if __name__ == '__main__':
- _test()
--- a/embedded/mx/DateTime/Timezone.py Tue Apr 28 13:28:37 2009 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,169 +0,0 @@
-# -*- coding: latin-1 -*-
-
-""" Timezone information.
-
- XXX This module still has prototype status and is undocumented.
-
- XXX Double check the offsets given in the zonetable below.
-
- XXX Add TZ environment variable parsing functions. The REs are already
- there.
-
- Copyright (c) 1998-2000, Marc-Andre Lemburg; mailto:mal@lemburg.com
- Copyright (c) 2000-2007, eGenix.com Software GmbH; mailto:info@egenix.com
- See the documentation for further information on copyrights,
- or contact the author. All Rights Reserved.
-
-"""
-import DateTime
-import re,string
-
-### REs
-
-# time zone parsing
-isozone = ('(?P<zone>[+-]\d\d:?(?:\d\d)?|Z)')
-zone = ('(?P<zone>[A-Z]+|[+-]\d\d?:?(?:\d\d)?)')
-zoneoffset = ('(?:'
- '(?P<zonesign>[+-])?'
- '(?P<hours>\d\d?)'
- ':?'
- '(?P<minutes>\d\d)?'
- '(?P<extra>\d+)?'
- ')'
- )
-
-# TZ environment variable parsing
-dstswitchtime = ('(?P<hour>\d\d?):?'
- '(?P<minute>\d\d)?:?'
- '(?P<second>\d\d)?')
-dstswitch = ('(?:'
- '(?P<doy>\d+)|'
- '(?:J(?P<jdoy>\d+))|'
- '(?:M(?P<month>\d+).(?P<week>\d+).(?P<day>\d+))'
- ')'
- '(?:/' + dstswitchtime + ')?'
- )
-
-# XXX Doesn't work since re doesn't like multiple occurrences of
-# group names.
-#tz = ('(?::(?P<filename>.+))|'
-# '(?P<std>[A-Z]+)' + zoneoffset +
-# '(?:'
-# '(?P<dst>[A-Z]+)' + zoneoffset + '?'+
-# '(?:[;,]' + dstswitch + '[;,]' + dstswitch + ')'
-# ')?'
-# )
-
-# Compiled RE objects
-isozoneRE = re.compile(zone)
-zoneRE = re.compile(zone)
-zoneoffsetRE = re.compile(zoneoffset)
-#tzRE= re.compile(tz)
-
-### Time zone offset table
-#
-# The offset given here represent the difference between UTC and the
-# given time zone.
-#
-# Additions and corrections are always welcome :-)
-#
-# Note that some zone names are ambiguous, e.g. IST can refer to Irish
-# Summer Time, Indian Standard Time, Israel Standard Time. We've
-# usualy chosen meaning with the most wide-spread use.
-#
-zonetable = {
- # Timezone abbreviations
- # Std Summer
-
- # Standards
- 'UT':0,
- 'UTC':0,
- 'GMT':0,
-
- # A few common timezone abbreviations
- 'CET':1, 'CEST':2, 'CETDST':2, # Central European
- 'MET':1, 'MEST':2, 'METDST':2, # Mean European
- 'MEZ':1, 'MESZ':2, # Mitteleuropäische Zeit
- 'EET':2, 'EEST':3, 'EETDST':3, # Eastern Europe
- 'WET':0, 'WEST':1, 'WETDST':1, # Western Europe
- 'MSK':3, 'MSD':4, # Moscow
- 'IST':5.5, # India
- 'JST':9, # Japan
- 'KST':9, # Korea
- 'HKT':8, # Hong Kong
-
- # US time zones
- 'AST':-4, 'ADT':-3, # Atlantic
- 'EST':-5, 'EDT':-4, # Eastern
- 'CST':-6, 'CDT':-5, # Central
- 'MST':-7, 'MDT':-6, # Midwestern
- 'PST':-8, 'PDT':-7, # Pacific
-
- # Australian time zones
- 'CAST':9.5, 'CADT':10.5, # Central
- 'EAST':10, 'EADT':11, # Eastern
- 'WAST':8, 'WADT':9, # Western
- 'SAST':9.5, 'SADT':10.5, # Southern
-
- # US military time zones
- 'Z': 0,
- 'A': 1,
- 'B': 2,
- 'C': 3,
- 'D': 4,
- 'E': 5,
- 'F': 6,
- 'G': 7,
- 'H': 8,
- 'I': 9,
- 'K': 10,
- 'L': 11,
- 'M': 12,
- 'N':-1,
- 'O':-2,
- 'P':-3,
- 'Q':-4,
- 'R':-5,
- 'S':-6,
- 'T':-7,
- 'U':-8,
- 'V':-9,
- 'W':-10,
- 'X':-11,
- 'Y':-12
- }
-
-def utc_offset(zone,
-
- atoi=string.atoi,zoneoffset=zoneoffsetRE,
- zonetable=zonetable,zerooffset=DateTime.DateTimeDelta(0),
- oneMinute=DateTime.oneMinute,upper=string.upper):
-
- """ utc_offset(zonestring)
-
- Return the UTC time zone offset as DateTimeDelta instance.
-
- zone must be string and can either be given as +-HH:MM,
- +-HHMM, +-HH numeric offset or as time zone
- abbreviation. Daylight saving time must be encoded into the
- zone offset.
-
- Timezone abbreviations are treated case-insensitive.
-
- """
- if not zone:
- return zerooffset
- uzone = upper(zone)
- if zonetable.has_key(uzone):
- return zonetable[uzone]*DateTime.oneHour
- offset = zoneoffset.match(zone)
- if not offset:
- raise ValueError,'wrong format or unknown time zone: "%s"' % zone
- zonesign,hours,minutes,extra = offset.groups()
- if extra:
- raise ValueError,'illegal time zone offset: "%s"' % zone
- offset = int(hours or 0) * 60 + int(minutes or 0)
- if zonesign == '-':
- offset = -offset
- return offset*oneMinute
-
--- a/embedded/mx/DateTime/__init__.py Tue Apr 28 13:28:37 2009 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,21 +0,0 @@
-""" mxDateTime - Date and time handling routines and types
-
- Copyright (c) 1998-2000, Marc-Andre Lemburg; mailto:mal@lemburg.com
- Copyright (c) 2000-2007, eGenix.com Software GmbH; mailto:info@egenix.com
- See the documentation for further information on copyrights,
- or contact the author. All Rights Reserved.
-"""
-from DateTime import *
-from DateTime import __version__
-
-## mock strptime implementation
-from datetime import datetime
-
-def strptime(datestr, formatstr, datetime=datetime):
- """mocked strptime implementation"""
- date = datetime.strptime(datestr, formatstr)
- return DateTime(date.year, date.month, date.day,
- date.hour, date.minute, date.second)
-
-# don't expose datetime directly
-del datetime
--- a/embedded/mx/DateTime/mxDateTime_python.py Tue Apr 28 13:28:37 2009 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,614 +0,0 @@
-"""
- Python implementation courtesy of Drew Csillag (StarMedia Network, Inc.)
-
- This version has been somewhat modified by MAL. It is still fairly
- rough though and not necessarily high performance...
-
- XXX Still needs testing and checkup !!!
-
- WARNING: Using this file is only recommended if you really must
- use it for some reason. It is not being actively maintained !
-
-"""
-
-__version__ = '1.2.0 [Python]'
-
-import time,types,exceptions,math
-
-### Errors
-
-class Error(exceptions.StandardError):
- pass
-
-class RangeError(Error):
- pass
-
-### Constants (internal use only)
-
-month_offset=(
- (0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365),
- (0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366),
- )
-
-days_in_month=(
- (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31),
- (31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31),
- )
-
-### Helpers
-
-def _IS_LEAPYEAR(d):
- return ((d.year % 4 == 0)
- and (
- (d.year % 100 != 0)
- or (d.year % 400 == 0)
- )
- )
-
-def _YEAROFFSET(d):
- return (
- (d.year - 1) * 365
- + (d.year - 1) / 4
- - (d.year - 1) / 100
- + (d.year - 1) / 400
- )
-
-class _EmptyClass:
- pass
-
-def createEmptyObject(Class,
- _EmptyClass=_EmptyClass):
-
- o = _EmptyClass()
- o.__class__ = Class
- return o
-
-### DateTime class
-
-class DateTime:
-
- def __init__(self, year, month=1, day=1, hour=0, minute=0, second=0.0):
-
- second=1.0 * second
- if month <= 0:
- raise RangeError, "year out of range (>0)"
-
- #calculate absolute date
- leap = (year % 4 == 0) and ((year % 100 != 0) or (year % 400 == 0))
-
- #Negative values indicate days relative to the years end
- if month < 0:
- month = month + 13
-
- if not (month >= 1 and month <= 12):
- raise RangeError, "month out of range (1-12)"
-
- #Negative values indicate days relative to the months end
- if (day < 0):
- day = day + days_in_month[leap][month - 1] + 1;
-
- if not (day >= 1 and day <= days_in_month[leap][month - 1]):
- raise RangeError, "day out of range"
-
- year = year - 1
- yearoffset = year * 365 + year / 4 - year / 100 + year / 400
- year = year + 1
- absdate = day + month_offset[leap][month - 1] + yearoffset;
-
- self.absdate = absdate
- self.year = year
- self.month = month
- self.day = day
- self.day_of_week = (absdate - 1) % 7
- self.day_of_year = absdate - yearoffset
- self.days_in_month = days_in_month[leap][month - 1]
- comdate = absdate - 693594
-
- if not (hour >=0 and hour <= 23):
- raise RangeError, "hour out of range (0-23)"
- if not (minute >= 0 and minute <= 59):
- raise RangeError, "minute out of range (0-59)"
- if not (second >= 0.0 and
- (second < 60.0 or
- (hour == 23 and minute == 59 and second < 61.0))):
- raise RangeError, "second out of range (0.0 - <60.0; <61.0 for 23:59)"
-
- self.abstime = (hour * 3600 + minute * 60) + second
- self.hour = hour
- self.minute = minute
- self.second = second
- self.dst = -1
- self.tz = "???"
- self.is_leapyear = leap
- self.yearoffset = yearoffset
- self.iso_week = (self.year, self.day, self.day_of_week)
-
- if comdate < 0.0:
- comdate = comdate - self.abstime / 86400.0
- else:
- comdate = comdate + self.abstime / 86400.0
-
- self.comdate = comdate
-
- def COMDate(self):
- return self.comdate
-
- def __str__(self):
- return "%04d-%02d-%02d %02d:%02d:%05.2f" % (
- self.year, self.month, self.day, self.hour, self.minute,
- self.second)
-
- def __getattr__(self, attr):
- if attr == 'mjd':
- return (self - mjd0).days
- elif attr == 'jdn':
- return (self - jdn0).days
- elif attr == 'tjd':
- return (self - jdn0).days % 10000
- elif attr == 'tjd_myriad':
- return int((self - jdn0).days) / 10000 + 240
- elif attr == 'absdays':
- return self.absdate - 1 + self.abstime / 86400.0
- else:
- try:
- return self.__dict__[attr]
- except:
- raise AttributeError, attr
-
- def __mul__(self, other):
- raise TypeError, "bad operand type(s) for *"
-
- def __div__(self, other):
- raise TypeError, "bad operand type(s) for /"
-
- def strftime(self, format_string="%c"):
- "localtime([seconds]) -> (tm_year,tm_mon,tm_day,tm_hour,tm_min,tm_sec,tm_wday,tm_yday,tm_isdst)"
- # The map prevents a deprecation warning on Python 2.5.1 (Mac)
- # DeprecationWarning: integer argument expected, got float
- items = [int(item) for item in self.tuple()]
- return time.strftime(format_string, items)
-
- # Alias
- Format = strftime
-
- def tuple(self):
- return (self.year, self.month, self.day, self.hour, self.minute,
- self.second, self.day_of_week, self.day_of_year, -1)
- #return time.localtime(self.ticks())
-
- def absvalues(self):
- return self.absdate, self.abstime
-
- def __float__(self):
- return self.ticks()
-
- def __int__(self):
- return int(self.ticks)
-
- def ticks(self, offset=0.0, dst=-1):
- tticks=time.mktime(self.year, self.month, self.day, self.hour,
- self.minute, self.second, self.day_of_week, 0, dst)
- if tticks == -1:
- raise OverflowError, "cannot convert value to a time value"
- ticks = (1.0*tticks) + (self.abstime - int(self.abstime)) - offset
- return ticks
-
- def gmticks(self, offset=0.0):
- from mx.DateTime import tz_offset
- return (self-tz_offset(self)).ticks()
-
- def gmtoffset(self):
- gmtime = DateTime(*time.gmtime()[:6])
- return - (now() - gmtime)
-
- def __repr__(self):
- return "<DateTime object for '%d-%02d-%02d %02d:%02d:%05.2f' at %x>"% (
- self.year, self.month, self.day, self.hour, self.minute,
- self.second, id(self))
-
- def __cmp__(self, other,
- cmp=cmp):
-
- if isinstance(other,DateTime):
- cmpdate = cmp(self.absdate,other.absdate)
- if cmpdate == 0:
- return cmp(self.abstime,other.abstime)
- else:
- return cmpdate
- elif type(other) == types.NoneType:
- return -1
- elif type(other) == types.StringType:
- return -1
- elif type(other) in (types.FloatType, types.LongType, types.IntType):
- return 1
- return -1
-
- def __hash__(self):
- return hash(self.tuple())
-
- def __add__(self, other):
- abstime=self.abstime
- absdate=self.absdate
-
- didadd=0
-
- if type(other) == types.InstanceType:
- if other.__class__ == DateTimeDelta:
- abstime = abstime + other.seconds
- didadd=1
- elif other.__class__ == DateTime:
- raise TypeError, "DateTime + DateTime is not supported"
- else:
- return other.__class__.__radd__(other, self)
-
- elif type(other) == types.IntType or type(other) == types.FloatType:
- abstime = abstime + other * 86400.0
- didadd=1
-
- if not didadd:
- raise TypeError, "cannot add these two types"
-
- if abstime >= 86400.0:
- days = abstime / 86400.0
- absdate = absdate + days
- abstime = abstime - (86400.0 * int(days))
- #print "absdate, abstime = ", absdate, abstime
- elif abstime < 0.0:
- days = int(((-abstime - 1) / 86400.0)) + 1
- #days = int(-abstime / 86400.0)
- absdate = absdate - days
- abstime = abstime + 86400.0 * int(days)
-
- if absdate < 1:
- raise RangeError, "underflow while adding"
-
- return DateTimeFromAbsDateTime(absdate, abstime)
-
- def __radd__(self, other):
- return DateTime.__add__(other, self)
-
- def __sub__(self, other):
- abstime=self.abstime
- absdate=self.absdate
-
- didsub=0
- if type(other) == types.InstanceType:
- if other.__class__ == DateTimeDelta:
- abstime = abstime - other.seconds
- didsub = 1
- elif other.__class__ == DateTime:
- absdate = absdate - other.absdate
- abstime = abstime - other.abstime
- return DateTimeDelta(absdate,0.0,0.0,abstime)
- else:
- return other.__rsub__(self)
-
- elif type(other) == types.IntType or type(other) == types.FloatType:
- abstime = abstime - other * 86400.0;
- didsub=1
-
- if not didsub:
- raise TypeError, "cannot subtract these two types"
-
- if abstime >= 86400.0:
- days = abstime / 86400.0
- absdate = absdate + days
- abstime = abstime - (86400.0 * days)
- #print "absdate, abstime = ", absdate, abstime
- elif abstime < 0.0:
- #print "abstime < 0"
- days = int( ((-abstime - 1) / 86400.0) + 1)
- #days = -abstime / 86400.0
- absdate = absdate - int(days)
- abstime = (1.0*abstime) + (86400.0 * days)
- #print "absdate, abstime", absdate, abstime
- if absdate < 1:
- raise RangeError, "underflow while adding"
-
- return DateTimeFromAbsDateTime(absdate, abstime)
-
-# Constants
-mjd0 = DateTime(1858, 11, 17)
-jdn0 = DateTime(-4713, 1, 1, 12, 0, 0.0)
-
-# Other DateTime constructors
-
-def DateTimeFromCOMDate(comdate):
-
- absdate = int(comdate)
- abstime = (comdate - float(absdate)) * 86400.0
- if abstime < 0.0:
- abstime = -abstime
- absdate = absdate + 693594;
- dt = DateTimeFromAbsDateTime(absdate, abstime)
- dt.comdate = comdate
- return dt
-
-def DateTimeFromAbsDateTime(absdate, abstime):
-
- # Create the object without calling its default constructor
- dt = createEmptyObject(DateTime)
-
- # Init. the object
- abstime=1.0 * abstime
- if abstime < 0 and abstime > -0.001: abstime = 0.0
- if not (absdate > 0):
- raise RangeError, "absdate out of range (>0)"
- if not (abstime >= 0.0 and abstime <= 86400.0):
- raise RangeError, "abstime out of range (0.0 - 86400.0) <%s>" % abstime
-
- dt.absdate=absdate
- dt.abstime=abstime
-
- #calculate com date
- comdate = 1.0 * (dt.absdate - 693594)
- if comdate < 0.0:
- comdate = comdate - dt.abstime / 86400.0
- else:
- comdate = comdate + dt.abstime / 86400.0
- dt.comdate = comdate
-
- #calculate the date
- #print "absdate=", absdate
- year = int((1.0 * absdate) / 365.2425)
-
- #newApproximation:
- while 1:
- #print "year=", year
- yearoffset = year * 365 + year / 4 - year / 100 + year / 400
- #print "yearoffset=", yearoffset
- #print "absdate=", absdate
- if yearoffset >= absdate:
- year = year - 1
- #print "year = ", year
- continue #goto newApproximation
-
- year = year + 1
- leap = (year % 4 == 0) and ((year % 100 != 0) or (year % 400 == 0))
- dayoffset = absdate - yearoffset
- #print "dayoffset=", dayoffset
- if dayoffset > 365 and leap == 0:
- #print "dayoffset=", dayoffset
- continue #goto newApproximation
-
- monthoffset = month_offset[leap]
- for month in range(1, 13):
- if monthoffset[month] >= dayoffset:
- break
- dt.year = year
- dt.month = month
- dt.day = dayoffset - month_offset[leap][month-1]
- dt.day_of_week = (dt.absdate - 1) % 7
- dt.day_of_year = dayoffset
- break
-
- #calculate the time
- inttime = int(abstime)
- hour = inttime / 3600
- minute = (inttime % 3600) / 60
- second = abstime - 1.0 * (hour*3600 + minute*60)
- dt.hour = hour;
- dt.minute = minute;
- dt.second = second;
- dt.days_in_month = days_in_month[leap][month - 1]
- dt.dst = -1
- dt.tz = "???"
- dt.is_leapyear = leap
- dt.yearoffset = yearoffset
- return dt
-
-def now(
- time=time.time,float=float,localtime=time.localtime,
- round=round,int=int,DateTime=DateTime,floor=math.floor):
- ticks = time()
- Y,M,D,h,m,s = localtime(ticks)[:6]
- s = s + (ticks - floor(ticks))
- return DateTime(Y,M,D,h,m,s)
-
-def utc(
- time=time.time,float=float,gmtime=time.gmtime,
- round=round,int=int,DateTime=DateTime,floor=math.floor):
-
- ticks = time()
- Y,M,D,h,m,s = gmtime(ticks)[:6]
- s = s + (ticks - floor(ticks))
- return DateTime(Y,M,D,h,m,s)
-
-# Aliases
-Date = Timestamp = DateTime
-
-# XXX Calendars are not supported:
-def notSupported(*args,**kws):
- raise Error,'calendars are not supported by the Python version of mxDateTime'
-JulianDateTime = notSupported
-
-### DateTimeDelta class
-
-class DateTimeDelta:
-
- def __init__(self, days=0, hours=0, minutes=0, seconds=0):
-
- seconds = seconds + (days * 86400.0 + hours * 3600.0 + minutes * 60.0)
- self.seconds = seconds
- if seconds < 0.0:
- seconds = -seconds
- day = long(seconds / 86400.0)
- seconds = seconds - (86400.0 * day)
- wholeseconds = int(seconds)
- hour = wholeseconds / 3600
- minute = (wholeseconds % 3600) / 60
- second = seconds - (hour * 3600.0 + minute * 60.0)
- self.day = day
- self.hour = hour
- self.minute = minute
- self.second = second
- seconds=self.seconds
- self.minutes = seconds / 60.0
- self.hours = seconds / 3600.0
- self.days = seconds / 86400.0
-
- def __str__(self):
- if self.day != 0:
- if self.seconds >= 0.0:
- r="%s:%02d:%02d:%05.2f" % (
- self.day, self.hour, self.minute, self.second)
- else:
- r="-%s:%02d:%02d:%05.2f" % (
- self.day, self.hour, self.minute, self.second)
- else:
- if self.seconds >= 0.0:
- r="%02d:%02d:%05.2f" % (self.hour, self.minute, self.second)
- else:
- r="-%02d:%02d:%05.2f" % (self.hour, self.minute, self.second)
- return r
-
- def absvalues(self):
- days=self.seconds / 86400
- seconds=self.seconds - (days * 86400.0)
- return days, seconds
-
- def tuple(self):
- return (self.day, self.hour, self.minute, self.second)
-
- def strftime(self, format_string):
- raise NotImplementedError
-
- def __int__(self):
- return int(self.seconds)
-
- def __float__(self):
- return self.seconds
-
- def __cmp__(self, other, accuracy=0.0):
- if (type(other) == types.InstanceType
- and other.__class__ == DateTimeDelta):
-
- diff=self.seconds - other.seconds
- if abs(diff) > accuracy:
- if diff > 0: return 1
- return -1
-
- elif type(other) == types.FloatType:
- diff=self.seconds - other
- if abs(diff) > accuracy:
- if diff > 0: return 1
- return -1
-
- elif type(other) == types.IntType:
- diff=self.seconds - other
- if abs(diff) > accuracy:
- if diff > 0: return 1
- return -1
-
- return 0
-
- def __getattr__(self, attr):
- seconds=self.__dict__['seconds']
- if attr in ('hour', 'minute', 'second', 'day'):
- if seconds >= 0.0:
- return self.__dict__[attr]
- else:
- return -self.__dict__[attr]
- else:
- try:
- return self.__dict__[attr]
- except:
- raise AttributeError, attr
-
- def __div__(self, other):
- if type(other) in (types.IntType, types.FloatType):
- return DateTimeDelta(0.0,0.0,0.0,self.seconds / other)
- elif (type(other) == types.InstanceType
- and isinstance(other,DateTimeDelta)):
- return DateTimeDelta(0.0,0.0,0.0,self.seconds / other.seconds)
- raise TypeError, "bad operand types for /"
-
- def __mul__(self, other):
- if type(other) == types.IntType or type(other) == types.FloatType:
- return DateTimeDelta(0.0,0.0,0.0,self.seconds * other)
- else:
- #print "type", type(other)
- raise TypeError, "cannot multiply these two types"
-
- def __rmul__(self, other):
- return self.__mul__(other)
-
- def __neg__(self):
- return DateTimeDelta(0.0,0.0,0.0,-self.seconds)
-
- def __repr__(self):
- if self.day != 0:
- if self.seconds >= 0.0:
- strval="%s:%02d:%02d:%05.2f" % (self.day, self.hour,
- self.minute, self.second)
- else:
- strval="-%s:%02d:%02d:%05.2f" % (self.day, self.hour,
- self.minute, self.second)
- else:
- if self.seconds >= 0.0:
- strval="%02d:%02d:%05.2f" % (self.hour, self.minute,
- self.second)
- else:
- strval="-%02d:%02d:%05.2f" % (self.hour, self.minute,
- self.second)
- return "<DateTimeDelta object for '%s' at %x>" % (strval, id(self))
-
- def __abs__(self):
- if self.seconds < 0:
- return -self
- return self
-
- def __nonzero__(self):
- return self.seconds != 0.0
-
- def __add__(self, other):
- if type(other) == types.InstanceType:
- if isinstance(other,DateTime):
- return other + self
- elif isinstance(other,DateTimeDelta):
- return DateTimeDelta(0.0,0.0,0.0,self.seconds + other.seconds)
-
- # What about __radd__ ?
-
-# Other DateTimeDelta constructors
-
-def TimeDelta(hour=0.0, minute=0.0, second=0.0):
- return DateTimeDelta(0.0, hours, minutes, seconds)
-
-Time=TimeDelta
-
-def DateTimeDeltaFromSeconds(seconds):
- return DateTimeDelta(0.0,0.0,0.0,seconds)
-
-def DateTimeDeltaFromDays(days):
- return DateTimeDelta(days)
-
-### Types
-
-DateTimeType = DateTime
-DateTimeDeltaType = DateTimeDelta
-
-### Functions
-
-def cmp(a,b,acc):
-
- if isinstance(a,DateTime) and isinstance(b,DateTime):
- diff = a.absdays - b.absdays
- if (diff >= 0 and diff <= acc) or (diff < 0 and -diff <= acc):
- return 0
- elif diff < 0:
- return 1
- else:
- return -1
-
- elif isinstance(a,DateTimeDelta) and isinstance(b,DateTimeDelta):
- diff = a.days - b.days
- if (diff >= 0 and diff <= acc) or (diff < 0 and -diff <= acc):
- return 0
- elif diff < 0:
- return 1
- else:
- return -1
-
- else:
- raise TypeError,"objects must be DateTime[Delta] instances"
--- a/entities/__init__.py Tue Apr 28 13:28:37 2009 +0200
+++ b/entities/__init__.py Tue Apr 28 19:12:52 2009 +0200
@@ -23,7 +23,7 @@
"""an entity instance has e_schema automagically set on the class and
instances have access to their issuing cursor
"""
- id = 'Any'
+ id = 'Any'
__implements__ = (IBreadCrumbs, IFeed)
@classmethod
@@ -38,7 +38,7 @@
usercls.id = etype
usercls.__initialize__()
return usercls
-
+
fetch_attrs = ('modification_date',)
@classmethod
def fetch_order(cls, attr, var):
@@ -46,7 +46,7 @@
this type are fetched
"""
return cls.fetch_unrelated_order(attr, var)
-
+
@classmethod
def fetch_unrelated_order(cls, attr, var):
"""class method used to control sort order when multiple entities of
@@ -58,7 +58,7 @@
return None
@classmethod
- def __initialize__(cls):
+ def __initialize__(cls):
super(ANYENTITY, cls).__initialize__() # XXX
# set a default_ATTR method for rich text format fields
# XXX move this away once the old widgets have been dropped!
@@ -66,7 +66,7 @@
for metaattr, (metadata, attr) in eschema.meta_attributes().iteritems():
if metadata == 'format' and not hasattr(cls, 'default_%s' % metaattr):
setattr(cls, 'default_%s' % metaattr, cls._default_format)
-
+
# meta data api ###########################################################
def dc_title(self):
@@ -84,7 +84,7 @@
def dc_long_title(self):
"""return a more detailled title for this entity"""
return self.dc_title()
-
+
def dc_description(self, format='text/plain'):
"""return a suitable description for this entity"""
if self.e_schema.has_subject_relation('description'):
@@ -121,7 +121,7 @@
'internationalizable'):
return self.req._(self.req.user.property_value('ui.language'))
return self.req._(self.vreg.property_value('ui.language'))
-
+
@property
def creator(self):
"""return the CWUser entity which has created this entity, or None if
@@ -157,9 +157,9 @@
def rss_feed_url(self):
return self.absolute_url(vid='rss')
-
+
# abstractions making the whole things (well, some at least) working ######
-
+
def sortvalue(self, rtype=None):
"""return a value which can be used to sort this entity or given
entity's attribute
@@ -172,7 +172,7 @@
return self.printable_value(rtype, format='text/plain').lower()
return value
- # edition helper functions ################################################
+ # edition helper functions ################################################
def linked_to(self, rtype, target, remove=True):
"""if entity should be linked to another using __linkto form param for
@@ -200,9 +200,9 @@
linkedto.append(typed_eid(eid))
self.__linkto[(rtype, target)] = linkedto
return linkedto
-
+
# edit controller callbacks ###############################################
-
+
def after_deletion_path(self):
"""return (path, parameters) which should be used as redirect
information when this entity is being deleted
@@ -216,20 +216,20 @@
Do nothing by default.
"""
pass
-
+
# server side helpers #####################################################
-
+
def notification_references(self, view):
"""used to control References field of email send on notification
for this entity. `view` is the notification view.
-
+
Should return a list of eids which can be used to generate message ids
of previously sent email
"""
return ()
-
+
# XXX deprecates, may be killed once old widgets system is gone ###########
-
+
@classmethod
def get_widget(cls, rschema, x='subject'):
"""return a widget to view or edit a relation
@@ -258,20 +258,20 @@
def object_relation_vocabulary(self, rtype, limit):
from cubicweb.web.form import EntityFieldsForm
return EntityFieldsForm(self.req, None, entity=self).object_relation_vocabulary(rtype, limit)
-
+
@obsolete('use AutomaticEntityForm.[e]relations_by_category')
def relations_by_category(self, categories=None, permission=None):
- from cubicweb.web.views.editforms import AutomaticEntityForm
+ from cubicweb.web.views.autoform import AutomaticEntityForm
return AutomaticEntityForm.erelations_by_category(self, categories, permission)
@obsolete('use AutomaticEntityForm.[e]srelations_by_category')
def srelations_by_category(self, categories=None, permission=None):
- from cubicweb.web.views.editforms import AutomaticEntityForm
+ from cubicweb.web.views.autoform import AutomaticEntityForm
return AutomaticEntityForm.esrelations_by_category(self, categories, permission)
-
+
def _default_format(self):
return self.req.property_value('ui.default-text-format')
-
+
def attribute_values(self, attrname):
if self.has_eid() or attrname in self:
try:
--- a/entity.py Tue Apr 28 13:28:37 2009 +0200
+++ b/entity.py Tue Apr 28 19:12:52 2009 +0200
@@ -41,30 +41,26 @@
return '1'
-MODE_TAGS = set(('link', 'create'))
-CATEGORY_TAGS = set(('primary', 'secondary', 'generic', 'generated')) # , 'metadata'))
+_MODE_TAGS = set(('link', 'create'))
+_CATEGORY_TAGS = set(('primary', 'secondary', 'generic', 'generated')) # , 'metadata'))
try:
- from cubicweb.web import formwidgets
+ from cubicweb.web import formwidgets, uicfg
from cubicweb.web.views.editforms import AutomaticEntityForm
- from cubicweb.web.views.boxes import EditBox
- def dispatch_rtags(tags, rtype, role, stype, otype):
+ def _dispatch_rtags(tags, rtype, role, stype, otype):
for tag in tags:
- if tag in MODE_TAGS:
- EditBox.rmode.set_rtag(tag, rtype, role, stype, otype)
- elif tag in CATEGORY_TAGS:
- AutomaticEntityForm.rcategories.set_rtag(tag, rtype, role, stype, otype)
+ if tag in _MODE_TAGS:
+ uicfg.rmode.set_rtag(tag, rtype, role, stype, otype)
+ elif tag in _CATEGORY_TAGS:
+ uicfg.rcategories.set_rtag(tag, rtype, role, stype, otype)
elif tag == 'inlineview':
- AutomaticEntityForm.rinlined.set_rtag(True, rtype, role, stype, otype)
+ uicfg.rinlined.set_rtag(True, rtype, role, stype, otype)
else:
raise ValueError(tag)
except ImportError:
- AutomaticEntityForm = None
-
- def dispatch_rtags(*args):
- pass
+ _dispatch_rtags = None
def _get_etype(bases, classdict):
try:
@@ -87,14 +83,14 @@
except AttributeError:
continue
-class metaentity(type):
+class _metaentity(type):
"""this metaclass sets the relation tags on the entity class
and deals with the `widgets` attribute
"""
def __new__(mcs, name, bases, classdict):
# collect baseclass' rtags
etype = _get_etype(bases, classdict)
- if etype and AutomaticEntityForm is not None:
+ if etype and _dispatch_rtags is not None:
for name, rtags in _get_defs('__rtags__', name, bases, classdict):
warn('%s: __rtags__ is deprecated' % name, DeprecationWarning)
for relation, tags in rtags.iteritems():
@@ -103,23 +99,23 @@
tags = (tags,)
# relation must become a 3-uple (rtype, targettype, role)
if isinstance(relation, basestring):
- dispatch_rtags(tags, relation, 'subject', etype, '*')
- dispatch_rtags(tags, relation, 'object', '*', etype)
+ _dispatch_rtags(tags, relation, 'subject', etype, '*')
+ _dispatch_rtags(tags, relation, 'object', '*', etype)
elif len(relation) == 1: # useful ?
- dispatch_rtags(tags, relation[0], 'subject', etype, '*')
- dispatch_rtags(tags, relation[0], 'object', '*', etype)
+ _dispatch_rtags(tags, relation[0], 'subject', etype, '*')
+ _dispatch_rtags(tags, relation[0], 'object', '*', etype)
elif len(relation) == 2:
rtype, ttype = relation
ttype = bw_normalize_etype(ttype) # XXX bw compat
- dispatch_rtags(tags, rtype, 'subject', etype, ttype)
- dispatch_rtags(tags, rtype, 'object', ttype, etype)
+ _dispatch_rtags(tags, rtype, 'subject', etype, ttype)
+ _dispatch_rtags(tags, rtype, 'object', ttype, etype)
elif len(relation) == 3:
rtype, ttype, role = relation
ttype = bw_normalize_etype(ttype)
if role == 'subject':
- dispatch_rtags(tags, rtype, 'subject', etype, ttype)
+ _dispatch_rtags(tags, rtype, 'subject', etype, ttype)
else:
- dispatch_rtags(tags, rtype, 'object', ttype, etype)
+ _dispatch_rtags(tags, rtype, 'object', ttype, etype)
else:
raise ValueError('bad rtag definition (%r)' % (relation,))
for name, widgets in _get_defs('widgets', name, bases, classdict):
@@ -132,7 +128,7 @@
wdgname = 'TextInput'
widget = getattr(formwidgets, wdgname)
AutomaticEntityForm.rwidgets.set_rtag(wdgname, rtype, 'subject', etype)
- return super(metaentity, mcs).__new__(mcs, name, bases, classdict)
+ return super(_metaentity, mcs).__new__(mcs, name, bases, classdict)
class Entity(AppRsetObject, dict):
@@ -158,7 +154,7 @@
as composite relations or relations that have '?1' as object
cardinality
"""
- __metaclass__ = metaentity
+ __metaclass__ = _metaentity
__registry__ = 'etypes'
__select__ = yes()
--- a/i18n/en.po Tue Apr 28 13:28:37 2009 +0200
+++ b/i18n/en.po Tue Apr 28 19:12:52 2009 +0200
@@ -196,36 +196,11 @@
msgid "Bytes_plural"
msgstr "Bytes"
-msgid "Card"
-msgstr "Card"
-
-msgid "Card_plural"
-msgstr "Cards"
-
-msgid "Date"
-msgstr "Date"
-
-msgid "Date_plural"
-msgstr "Dates"
-
-msgid "Datetime"
-msgstr "Date and time"
-
-msgid "Datetime_plural"
-msgstr "Dates and times"
-
-#, python-format
-msgid "Debug level set to %s"
-msgstr ""
-
-msgid "Decimal"
-msgstr "Decimal number"
-
-msgid "Decimal_plural"
-msgstr "Decimal numbers"
-
-msgid "Do you want to delete the following element(s) ?"
-msgstr ""
+msgid "CWAttribute"
+msgstr "Attribute"
+
+msgid "CWAttribute_plural"
+msgstr "Attributes"
msgid "CWCache"
msgstr ""
@@ -251,24 +226,12 @@
msgid "CWEType_plural"
msgstr "Entity types"
-msgid "CWAttribute"
-msgstr "Attribute"
-
-msgid "CWAttribute_plural"
-msgstr "Attributes"
-
msgid "CWGroup"
msgstr "Group"
msgid "CWGroup_plural"
msgstr "Groups"
-msgid "CWRelation"
-msgstr "Relation"
-
-msgid "CWRelation_plural"
-msgstr "Relations"
-
msgid "CWPermission"
msgstr "Permission"
@@ -287,13 +250,41 @@
msgid "CWRType_plural"
msgstr "Relation types"
+msgid "CWRelation"
+msgstr "Relation"
+
+msgid "CWRelation_plural"
+msgstr "Relations"
+
msgid "CWUser"
msgstr "User"
msgid "CWUser_plural"
msgstr "Users"
-msgid "Email body: "
+msgid "Date"
+msgstr "Date"
+
+msgid "Date_plural"
+msgstr "Dates"
+
+msgid "Datetime"
+msgstr "Date and time"
+
+msgid "Datetime_plural"
+msgstr "Dates and times"
+
+#, python-format
+msgid "Debug level set to %s"
+msgstr ""
+
+msgid "Decimal"
+msgstr "Decimal number"
+
+msgid "Decimal_plural"
+msgstr "Decimal numbers"
+
+msgid "Do you want to delete the following element(s) ?"
msgstr ""
msgid "EmailAddress"
@@ -314,7 +305,7 @@
msgid "Float_plural"
msgstr "Floats"
-msgid "From: "
+msgid "From:"
msgstr ""
msgid "Int"
@@ -332,8 +323,8 @@
msgid "New Bookmark"
msgstr "New bookmark"
-msgid "New Card"
-msgstr "New card"
+msgid "New CWAttribute"
+msgstr "New attribute"
msgid "New CWCache"
msgstr ""
@@ -347,15 +338,9 @@
msgid "New CWEType"
msgstr "New entity type"
-msgid "New CWAttribute"
-msgstr "New attribute"
-
msgid "New CWGroup"
msgstr "New group"
-msgid "New CWRelation"
-msgstr "New relation"
-
msgid "New CWPermission"
msgstr "New permission"
@@ -365,6 +350,9 @@
msgid "New CWRType"
msgstr "New relation type"
+msgid "New CWRelation"
+msgstr "New relation"
+
msgid "New CWUser"
msgstr "New user"
@@ -401,16 +389,13 @@
msgid "Please note that this is only a shallow copy"
msgstr ""
-msgid "Problem occured"
-msgstr ""
-
msgid "RQLExpression"
msgstr "RQL expression"
msgid "RQLExpression_plural"
msgstr "RQL expressions"
-msgid "Recipients: "
+msgid "Recipients:"
msgstr ""
msgid "Relations"
@@ -444,7 +429,7 @@
msgid "String_plural"
msgstr "Strings"
-msgid "Subject: "
+msgid "Subject:"
msgstr ""
msgid "Submit bug report"
@@ -471,8 +456,8 @@
msgid "This Bookmark"
msgstr "This bookmark"
-msgid "This Card"
-msgstr "This card"
+msgid "This CWAttribute"
+msgstr "This attribute"
msgid "This CWCache"
msgstr ""
@@ -486,15 +471,9 @@
msgid "This CWEType"
msgstr "This entity type"
-msgid "This CWAttribute"
-msgstr "This attribute"
-
msgid "This CWGroup"
msgstr "This group"
-msgid "This CWRelation"
-msgstr "This relation"
-
msgid "This CWPermission"
msgstr "This permission"
@@ -504,6 +483,9 @@
msgid "This CWRType"
msgstr "This relation type"
+msgid "This CWRelation"
+msgstr "This relation"
+
msgid "This CWUser"
msgstr "This user"
@@ -596,11 +578,6 @@
msgstr ""
msgid ""
-"a card is a textual content used as documentation, reference, procedure "
-"reminder"
-msgstr ""
-
-msgid ""
"a simple cache entity characterized by a name and a validity date. The "
"target application is responsible for updating timestamp when necessary to "
"invalidate the cache (typically in hooks). Also, checkout the AppRsetObject."
@@ -682,6 +659,12 @@
msgid "actions_manage_description"
msgstr ""
+msgid "actions_managepermission"
+msgstr ""
+
+msgid "actions_managepermission_description"
+msgstr ""
+
msgid "actions_muledit"
msgstr "modify all"
@@ -754,6 +737,12 @@
msgid "add Bookmark bookmarked_by CWUser object"
msgstr "bookmark"
+msgid "add CWAttribute constrained_by CWConstraint subject"
+msgstr "constraint"
+
+msgid "add CWAttribute relation_type CWRType object"
+msgstr "attribute definition"
+
msgid "add CWEType add_permission RQLExpression subject"
msgstr "rql expression for the add permission"
@@ -766,18 +755,6 @@
msgid "add CWEType update_permission RQLExpression subject"
msgstr "rql expression for the update permission"
-msgid "add CWAttribute constrained_by CWConstraint subject"
-msgstr "constraint"
-
-msgid "add CWAttribute relation_type CWRType object"
-msgstr "attribute definition"
-
-msgid "add CWRelation constrained_by CWConstraint subject"
-msgstr "constraint"
-
-msgid "add CWRelation relation_type CWRType object"
-msgstr "relation definition"
-
msgid "add CWProperty for_user CWUser object"
msgstr "property"
@@ -790,6 +767,12 @@
msgid "add CWRType read_permission RQLExpression subject"
msgstr "rql expression for the read permission"
+msgid "add CWRelation constrained_by CWConstraint subject"
+msgstr "constraint"
+
+msgid "add CWRelation relation_type CWRType object"
+msgstr "relation definition"
+
msgid "add CWUser in_group CWGroup object"
msgstr "user"
@@ -820,8 +803,8 @@
msgid "add a Bookmark"
msgstr "add a bookmark"
-msgid "add a Card"
-msgstr "add a card"
+msgid "add a CWAttribute"
+msgstr "add an attribute"
msgid "add a CWCache"
msgstr ""
@@ -835,15 +818,9 @@
msgid "add a CWEType"
msgstr "add an entity type"
-msgid "add a CWAttribute"
-msgstr "add an attribute"
-
msgid "add a CWGroup"
msgstr "add a group"
-msgid "add a CWRelation"
-msgstr "add a relation"
-
msgid "add a CWPermission"
msgstr "add a permission"
@@ -853,6 +830,9 @@
msgid "add a CWRType"
msgstr "add a relation type"
+msgid "add a CWRelation"
+msgstr "add a relation"
+
msgid "add a CWUser"
msgstr "add a user"
@@ -916,21 +896,6 @@
msgid "allowed_transition_object"
msgstr "incoming states"
-msgid "am/pm calendar (month)"
-msgstr ""
-
-msgid "am/pm calendar (semester)"
-msgstr ""
-
-msgid "am/pm calendar (week)"
-msgstr ""
-
-msgid "am/pm calendar (year)"
-msgstr ""
-
-msgid "an abstract for this card"
-msgstr ""
-
msgid "an electronic mail address associated to a short alias"
msgstr ""
@@ -1079,18 +1044,6 @@
msgid "calendar"
msgstr ""
-msgid "calendar (month)"
-msgstr ""
-
-msgid "calendar (semester)"
-msgstr ""
-
-msgid "calendar (week)"
-msgstr ""
-
-msgid "calendar (year)"
-msgstr ""
-
#, python-format
msgid "can't change the %s attribute"
msgstr ""
@@ -1200,12 +1153,6 @@
msgid "components_rqlinput_description"
msgstr "the rql box in the page's header"
-msgid "components_rss_feed_url"
-msgstr ""
-
-msgid "components_rss_feed_url_description"
-msgstr ""
-
msgid "composite"
msgstr ""
@@ -1236,12 +1183,6 @@
msgid "constraints applying on this relation"
msgstr ""
-msgid "content"
-msgstr ""
-
-msgid "content_format"
-msgstr "content format"
-
msgid "contentnavigation"
msgstr "contextual components"
@@ -1351,28 +1292,31 @@
msgid "creating Bookmark (Bookmark bookmarked_by CWUser %(linkto)s)"
msgstr "creating bookmark for %(linkto)s"
-msgid "creating CWConstraint (CWAttribute %(linkto)s constrained_by CWConstraint)"
-msgstr "creating constraint for attribute %(linkto)s"
-
-msgid "creating CWConstraint (CWRelation %(linkto)s constrained_by CWConstraint)"
-msgstr "creating constraint for relation %(linkto)s"
-
msgid "creating CWAttribute (CWAttribute relation_type CWRType %(linkto)s)"
msgstr "creating attribute %(linkto)s"
+msgid ""
+"creating CWConstraint (CWAttribute %(linkto)s constrained_by CWConstraint)"
+msgstr "creating constraint for attribute %(linkto)s"
+
+msgid ""
+"creating CWConstraint (CWRelation %(linkto)s constrained_by CWConstraint)"
+msgstr "creating constraint for relation %(linkto)s"
+
+msgid "creating CWProperty (CWProperty for_user CWUser %(linkto)s)"
+msgstr "creating property for user %(linkto)s"
+
msgid "creating CWRelation (CWRelation relation_type CWRType %(linkto)s)"
msgstr "creating relation %(linkto)s"
-msgid "creating CWProperty (CWProperty for_user CWUser %(linkto)s)"
-msgstr "creating property for user %(linkto)s"
-
msgid "creating CWUser (CWUser in_group CWGroup %(linkto)s)"
msgstr "creating a new user in group %(linkto)s"
msgid "creating EmailAddress (CWUser %(linkto)s use_email EmailAddress)"
msgstr "creating email address for user %(linkto)s"
-msgid "creating RQLExpression (CWEType %(linkto)s add_permission RQLExpression)"
+msgid ""
+"creating RQLExpression (CWEType %(linkto)s add_permission RQLExpression)"
msgstr "creating rql expression for add permission on %(linkto)s"
msgid ""
@@ -1387,7 +1331,8 @@
"creating RQLExpression (CWEType %(linkto)s update_permission RQLExpression)"
msgstr "creating rql expression for update permission on %(linkto)s"
-msgid "creating RQLExpression (CWRType %(linkto)s add_permission RQLExpression)"
+msgid ""
+"creating RQLExpression (CWRType %(linkto)s add_permission RQLExpression)"
msgstr "creating rql expression for add permission on relations %(linkto)s"
msgid ""
@@ -1556,6 +1501,9 @@
msgid "destination_state_object"
msgstr "destination of"
+msgid "detach attached file"
+msgstr ""
+
#, python-format
msgid "detach attached file %s"
msgstr ""
@@ -1634,9 +1582,18 @@
msgid "entities deleted"
msgstr ""
+msgid "entity copied"
+msgstr ""
+
+msgid "entity created"
+msgstr ""
+
msgid "entity deleted"
msgstr ""
+msgid "entity edited"
+msgstr ""
+
msgid "entity type"
msgstr ""
@@ -1743,6 +1700,10 @@
msgid "from"
msgstr ""
+#, python-format
+msgid "from %(date)s"
+msgstr ""
+
msgid "from_entity"
msgstr "from entity"
@@ -1855,9 +1816,6 @@
msgid "i18n_login_popup"
msgstr "login"
-msgid "i18n_register_user"
-msgstr "register"
-
msgid "i18nprevnext_next"
msgstr "next"
@@ -1948,9 +1906,6 @@
msgid "inlined"
msgstr ""
-msgid "inlined view"
-msgstr ""
-
msgid "internationalizable"
msgstr ""
@@ -2048,11 +2003,6 @@
msgid "link a transition to one or more entity type"
msgstr ""
-msgid ""
-"link a transition to one or more rql expression allowing to go through this "
-"transition"
-msgstr ""
-
msgid "link to each item in"
msgstr ""
@@ -2068,7 +2018,7 @@
msgid "login"
msgstr ""
-msgid "login or email"
+msgid "login or email"
msgstr ""
msgid "login_action"
@@ -2296,9 +2246,6 @@
msgid "pkey"
msgstr "key"
-msgid "planned_delivery"
-msgstr "planned delivery"
-
msgid "please correct errors below"
msgstr ""
@@ -2363,8 +2310,8 @@
msgid "remove this Bookmark"
msgstr "remove this bookmark"
-msgid "remove this Card"
-msgstr "remove this card"
+msgid "remove this CWAttribute"
+msgstr "remove this attribute"
msgid "remove this CWCache"
msgstr ""
@@ -2378,15 +2325,9 @@
msgid "remove this CWEType"
msgstr "remove this entity type"
-msgid "remove this CWAttribute"
-msgstr "remove this attribute"
-
msgid "remove this CWGroup"
msgstr "remove this group"
-msgid "remove this CWRelation"
-msgstr "remove this relation"
-
msgid "remove this CWPermission"
msgstr "remove this permission"
@@ -2396,6 +2337,9 @@
msgid "remove this CWRType"
msgstr "remove this relation type"
+msgid "remove this CWRelation"
+msgstr "remove this relation"
+
msgid "remove this CWUser"
msgstr "remove this user"
@@ -2493,6 +2437,9 @@
msgid "select a"
msgstr ""
+msgid "select a key first"
+msgstr ""
+
msgid "select a relation"
msgstr ""
@@ -2612,9 +2559,6 @@
msgid "symetric"
msgstr ""
-msgid "synopsis"
-msgstr ""
-
msgid "system entities"
msgstr ""
@@ -2676,6 +2620,10 @@
msgid "to"
msgstr ""
+#, python-format
+msgid "to %(date)s"
+msgstr ""
+
msgid "to associate with"
msgstr ""
@@ -2694,6 +2642,9 @@
msgid "todo_by"
msgstr "to do by"
+msgid "toggle check boxes"
+msgstr ""
+
msgid "transition is not allowed"
msgstr ""
@@ -2856,9 +2807,6 @@
"which is the preferred form."
msgstr ""
-msgid "wikiid"
-msgstr "wiki identifier"
-
#, python-format
msgid "workflow for %s"
msgstr ""
@@ -2877,3 +2825,39 @@
msgid "you have been logged out"
msgstr ""
+
+msgid "you should probably delete that property"
+msgstr ""
+
+#~ msgid "Card"
+#~ msgstr "Card"
+
+#~ msgid "Card_plural"
+#~ msgstr "Cards"
+
+#~ msgid "New Card"
+#~ msgstr "New card"
+
+#~ msgid "This Card"
+#~ msgstr "This card"
+
+#~ msgid "add a Card"
+#~ msgstr "add a card"
+
+#~ msgid "content_format"
+#~ msgstr "content format"
+
+#~ msgid "i18n_register_user"
+#~ msgstr "register"
+
+#~ msgid "planned_delivery"
+#~ msgstr "planned delivery"
+
+#~ msgid "remove this Card"
+#~ msgstr "remove this card"
+
+#~ msgid "trcomment"
+#~ msgstr "comment"
+
+#~ msgid "wikiid"
+#~ msgstr "wiki identifier"
--- a/i18n/es.po Tue Apr 28 13:28:37 2009 +0200
+++ b/i18n/es.po Tue Apr 28 19:12:52 2009 +0200
@@ -201,11 +201,71 @@
msgid "Bytes_plural"
msgstr "Datos binarios"
-msgid "Card"
-msgstr "Ficha"
-
-msgid "Card_plural"
-msgstr "Fichas"
+msgid "CWAttribute"
+msgstr "Atributo"
+
+msgid "CWAttribute_plural"
+msgstr "Atributos"
+
+msgid "CWCache"
+msgstr "Memoria Cache"
+
+msgid "CWCache_plural"
+msgstr "Memorias Caches"
+
+msgid "CWConstraint"
+msgstr "Condición"
+
+msgid "CWConstraintType"
+msgstr "Tipo de condición"
+
+msgid "CWConstraintType_plural"
+msgstr "Tipos de condición"
+
+msgid "CWConstraint_plural"
+msgstr "Condiciones"
+
+msgid "CWEType"
+msgstr "Tipo de entidades"
+
+msgid "CWEType_plural"
+msgstr "Tipos de entidades"
+
+msgid "CWGroup"
+msgstr "Groupo"
+
+msgid "CWGroup_plural"
+msgstr "Groupos"
+
+msgid "CWPermission"
+msgstr "Autorización"
+
+msgid "CWPermission_plural"
+msgstr "Autorizaciones"
+
+msgid "CWProperty"
+msgstr "Propiedad"
+
+msgid "CWProperty_plural"
+msgstr "Propiedades"
+
+msgid "CWRType"
+msgstr "Tipo de relación"
+
+msgid "CWRType_plural"
+msgstr "Tipos de relación"
+
+msgid "CWRelation"
+msgstr "Relación"
+
+msgid "CWRelation_plural"
+msgstr "Relaciones"
+
+msgid "CWUser"
+msgstr "Usuario"
+
+msgid "CWUser_plural"
+msgstr "Usuarios"
msgid "Date"
msgstr "Fecha"
@@ -232,75 +292,6 @@
msgid "Do you want to delete the following element(s) ?"
msgstr "Desea suprimir el(los) elemento(s) siguiente(s)"
-msgid "CWCache"
-msgstr "Memoria Cache"
-
-msgid "CWCache_plural"
-msgstr "Memorias Caches"
-
-msgid "CWConstraint"
-msgstr "Condición"
-
-msgid "CWConstraintType"
-msgstr "Tipo de condición"
-
-msgid "CWConstraintType_plural"
-msgstr "Tipos de condición"
-
-msgid "CWConstraint_plural"
-msgstr "Condiciones"
-
-msgid "CWEType"
-msgstr "Tipo de entidades"
-
-msgid "CWEType_plural"
-msgstr "Tipos de entidades"
-
-msgid "CWAttribute"
-msgstr "Atributo"
-
-msgid "CWAttribute_plural"
-msgstr "Atributos"
-
-msgid "CWGroup"
-msgstr "Groupo"
-
-msgid "CWGroup_plural"
-msgstr "Groupos"
-
-msgid "CWRelation"
-msgstr "Relación"
-
-msgid "CWRelation_plural"
-msgstr "Relaciones"
-
-msgid "CWPermission"
-msgstr "Autorización"
-
-msgid "CWPermission_plural"
-msgstr "Autorizaciones"
-
-msgid "CWProperty"
-msgstr "Propiedad"
-
-msgid "CWProperty_plural"
-msgstr "Propiedades"
-
-msgid "CWRType"
-msgstr "Tipo de relación"
-
-msgid "CWRType_plural"
-msgstr "Tipos de relación"
-
-msgid "CWUser"
-msgstr "Usuario"
-
-msgid "CWUser_plural"
-msgstr "Usuarios"
-
-msgid "Email body: "
-msgstr "Contenido del correo electrónico : "
-
msgid "EmailAddress"
msgstr "Correo Electrónico"
@@ -319,8 +310,8 @@
msgid "Float_plural"
msgstr "Números flotantes"
-msgid "From: "
-msgstr "De : "
+msgid "From:"
+msgstr ""
msgid "Int"
msgstr "Número entero"
@@ -337,8 +328,8 @@
msgid "New Bookmark"
msgstr "Nuevo Atajo"
-msgid "New Card"
-msgstr "Nueva ficha"
+msgid "New CWAttribute"
+msgstr "Nueva definición de relación final"
msgid "New CWCache"
msgstr "Nueva memoria cache"
@@ -352,15 +343,9 @@
msgid "New CWEType"
msgstr "Nuevo tipo de entidad"
-msgid "New CWAttribute"
-msgstr "Nueva definición de relación final"
-
msgid "New CWGroup"
msgstr "Nuevo grupo"
-msgid "New CWRelation"
-msgstr "Nueva definición de relación final"
-
msgid "New CWPermission"
msgstr "Nueva autorización"
@@ -370,6 +355,9 @@
msgid "New CWRType"
msgstr "Nuevo tipo de relación"
+msgid "New CWRelation"
+msgstr "Nueva definición de relación final"
+
msgid "New CWUser"
msgstr "Nuevo usuario"
@@ -406,17 +394,14 @@
msgid "Please note that this is only a shallow copy"
msgstr "Recuerde que no es más que una copia superficial"
-msgid "Problem occured"
-msgstr "Ha ocurrido un error"
-
msgid "RQLExpression"
msgstr "Expresión RQL"
msgid "RQLExpression_plural"
msgstr "Expresiones RQL"
-msgid "Recipients: "
-msgstr "Destinatarios : "
+msgid "Recipients:"
+msgstr ""
msgid "Relations"
msgstr "Relaciones"
@@ -449,8 +434,8 @@
msgid "String_plural"
msgstr "Cadenas de caractéres"
-msgid "Subject: "
-msgstr "Objeto : "
+msgid "Subject:"
+msgstr ""
msgid "Submit bug report"
msgstr "Enviar un reporte de error (bug)"
@@ -476,8 +461,8 @@
msgid "This Bookmark"
msgstr "Este atajo"
-msgid "This Card"
-msgstr "Esta Ficha"
+msgid "This CWAttribute"
+msgstr "Esta definición de relación final"
msgid "This CWCache"
msgstr "Esta Memoria Cache"
@@ -491,15 +476,9 @@
msgid "This CWEType"
msgstr "Este tipo de Entidad"
-msgid "This CWAttribute"
-msgstr "Esta definición de relación final"
-
msgid "This CWGroup"
msgstr "Este grupo"
-msgid "This CWRelation"
-msgstr "Esta definición de relación no final"
-
msgid "This CWPermission"
msgstr "Esta autorización"
@@ -509,6 +488,9 @@
msgid "This CWRType"
msgstr "Este tipo de relación"
+msgid "This CWRelation"
+msgstr "Esta definición de relación no final"
+
msgid "This CWUser"
msgstr "Este usuario"
@@ -615,13 +597,6 @@
"representan respectivamente la entidad en transición y el usuarioactual. "
msgid ""
-"a card is a textual content used as documentation, reference, procedure "
-"reminder"
-msgstr ""
-"una ficha es un texto utilizado como documentación, referencia, memoria de "
-"procedimiento..."
-
-msgid ""
"a simple cache entity characterized by a name and a validity date. The "
"target application is responsible for updating timestamp when necessary to "
"invalidate the cache (typically in hooks). Also, checkout the AppRsetObject."
@@ -703,6 +678,12 @@
msgid "actions_manage_description"
msgstr ""
+msgid "actions_managepermission"
+msgstr ""
+
+msgid "actions_managepermission_description"
+msgstr ""
+
msgid "actions_muledit"
msgstr "Edición múltiple"
@@ -775,6 +756,12 @@
msgid "add Bookmark bookmarked_by CWUser object"
msgstr ""
+msgid "add CWAttribute constrained_by CWConstraint subject"
+msgstr "condición"
+
+msgid "add CWAttribute relation_type CWRType object"
+msgstr "definición de atributo"
+
msgid "add CWEType add_permission RQLExpression subject"
msgstr "Definir una expresión RQL de agregación"
@@ -787,18 +774,6 @@
msgid "add CWEType update_permission RQLExpression subject"
msgstr "Definir una expresión RQL de actualización"
-msgid "add CWAttribute constrained_by CWConstraint subject"
-msgstr "condición"
-
-msgid "add CWAttribute relation_type CWRType object"
-msgstr "definición de atributo"
-
-msgid "add CWRelation constrained_by CWConstraint subject"
-msgstr "condición"
-
-msgid "add CWRelation relation_type CWRType object"
-msgstr "definición de relación"
-
msgid "add CWProperty for_user CWUser object"
msgstr "propiedad"
@@ -811,6 +786,12 @@
msgid "add CWRType read_permission RQLExpression subject"
msgstr "expresión RQL de lectura"
+msgid "add CWRelation constrained_by CWConstraint subject"
+msgstr "condición"
+
+msgid "add CWRelation relation_type CWRType object"
+msgstr "definición de relación"
+
msgid "add CWUser in_group CWGroup object"
msgstr "usuario"
@@ -841,8 +822,8 @@
msgid "add a Bookmark"
msgstr "agregar un atajo"
-msgid "add a Card"
-msgstr "agregar una ficha"
+msgid "add a CWAttribute"
+msgstr "agregar un tipo de relación"
msgid "add a CWCache"
msgstr "agregar una memoria cache"
@@ -856,15 +837,9 @@
msgid "add a CWEType"
msgstr "agregar un tipo de entidad"
-msgid "add a CWAttribute"
-msgstr "agregar un tipo de relación"
-
msgid "add a CWGroup"
msgstr "agregar un grupo de usuarios"
-msgid "add a CWRelation"
-msgstr "agregar una relación"
-
msgid "add a CWPermission"
msgstr "agregar una autorización"
@@ -874,6 +849,9 @@
msgid "add a CWRType"
msgstr "agregar un tipo de relación"
+msgid "add a CWRelation"
+msgstr "agregar una relación"
+
msgid "add a CWUser"
msgstr "agregar un usuario"
@@ -939,21 +917,6 @@
msgid "allowed_transition_object"
msgstr "Estados de entrada"
-msgid "am/pm calendar (month)"
-msgstr "calendario am/pm (mes)"
-
-msgid "am/pm calendar (semester)"
-msgstr "calendario am/pm (semestre)"
-
-msgid "am/pm calendar (week)"
-msgstr "calendario am/pm (semana)"
-
-msgid "am/pm calendar (year)"
-msgstr "calendario am/pm (año)"
-
-msgid "an abstract for this card"
-msgstr "un resumen para esta ficha"
-
msgid "an electronic mail address associated to a short alias"
msgstr "una dirección electrónica asociada a este alias"
@@ -1106,18 +1069,6 @@
msgid "calendar"
msgstr "mostrar un calendario"
-msgid "calendar (month)"
-msgstr "calendario (mensual)"
-
-msgid "calendar (semester)"
-msgstr "calendario (semestral)"
-
-msgid "calendar (week)"
-msgstr "calendario (semanal)"
-
-msgid "calendar (year)"
-msgstr "calendario (anual)"
-
#, python-format
msgid "can't change the %s attribute"
msgstr "no puede modificar el atributo %s"
@@ -1232,12 +1183,6 @@
msgid "components_rqlinput_description"
msgstr "la barre de demanda rql, en el encabezado de página"
-msgid "components_rss_feed_url"
-msgstr ""
-
-msgid "components_rss_feed_url_description"
-msgstr ""
-
msgid "composite"
msgstr "composite"
@@ -1268,12 +1213,6 @@
msgid "constraints applying on this relation"
msgstr "condiciones que se aplican a esta relación"
-msgid "content"
-msgstr "contenido"
-
-msgid "content_format"
-msgstr "formato"
-
msgid "contentnavigation"
msgstr "composantes contextuales"
@@ -1399,28 +1338,31 @@
msgid "creating Bookmark (Bookmark bookmarked_by CWUser %(linkto)s)"
msgstr ""
-msgid "creating CWConstraint (CWAttribute %(linkto)s constrained_by CWConstraint)"
-msgstr "creación condicionada por el atributo %(linkto)s"
-
-msgid "creating CWConstraint (CWRelation %(linkto)s constrained_by CWConstraint)"
-msgstr "creación condicionada por la relación %(linkto)s"
-
msgid "creating CWAttribute (CWAttribute relation_type CWRType %(linkto)s)"
msgstr "creación atributo %(linkto)s"
+msgid ""
+"creating CWConstraint (CWAttribute %(linkto)s constrained_by CWConstraint)"
+msgstr "creación condicionada por el atributo %(linkto)s"
+
+msgid ""
+"creating CWConstraint (CWRelation %(linkto)s constrained_by CWConstraint)"
+msgstr "creación condicionada por la relación %(linkto)s"
+
+msgid "creating CWProperty (CWProperty for_user CWUser %(linkto)s)"
+msgstr "creación de una propiedad por el usuario %(linkto)s"
+
msgid "creating CWRelation (CWRelation relation_type CWRType %(linkto)s)"
msgstr "creación relación %(linkto)s"
-msgid "creating CWProperty (CWProperty for_user CWUser %(linkto)s)"
-msgstr "creación de una propiedad por el usuario %(linkto)s"
-
msgid "creating CWUser (CWUser in_group CWGroup %(linkto)s)"
msgstr "creación de un usuario para agregar al grupo %(linkto)s"
msgid "creating EmailAddress (CWUser %(linkto)s use_email EmailAddress)"
msgstr "creación de una dirección electrónica para el usuario %(linkto)s"
-msgid "creating RQLExpression (CWEType %(linkto)s add_permission RQLExpression)"
+msgid ""
+"creating RQLExpression (CWEType %(linkto)s add_permission RQLExpression)"
msgstr ""
"creación de una expresión RQL para la autorización de agregar %(linkto)s"
@@ -1438,7 +1380,8 @@
msgstr ""
"creación de una expresión RQL para la autorización de actualizar %(linkto)s"
-msgid "creating RQLExpression (CWRType %(linkto)s add_permission RQLExpression)"
+msgid ""
+"creating RQLExpression (CWRType %(linkto)s add_permission RQLExpression)"
msgstr ""
"creación de una expresión RQL para la autorización de agregar relaciones %"
"(linkto)s"
@@ -1626,6 +1569,9 @@
msgid "destination_state_object"
msgstr "destino de"
+msgid "detach attached file"
+msgstr "soltar el archivo existente"
+
#, python-format
msgid "detach attached file %s"
msgstr ""
@@ -1706,9 +1652,18 @@
msgid "entities deleted"
msgstr "entidades eliminadas"
+msgid "entity copied"
+msgstr ""
+
+msgid "entity created"
+msgstr ""
+
msgid "entity deleted"
msgstr "entidad eliminada"
+msgid "entity edited"
+msgstr ""
+
msgid "entity type"
msgstr "tipo de entidad"
@@ -1820,6 +1775,10 @@
msgid "from"
msgstr "de"
+#, python-format
+msgid "from %(date)s"
+msgstr ""
+
msgid "from_entity"
msgstr "de la entidad"
@@ -1938,9 +1897,6 @@
msgid "i18n_login_popup"
msgstr "identificarse"
-msgid "i18n_register_user"
-msgstr "registrarse"
-
msgid "i18nprevnext_next"
msgstr "siguiente"
@@ -2034,9 +1990,6 @@
msgid "inlined"
msgstr "puesto en lÃnea"
-msgid "inlined view"
-msgstr "vista incluÃda (en lÃnea)"
-
msgid "internationalizable"
msgstr "internacionalizable"
@@ -2141,11 +2094,6 @@
msgid "link a transition to one or more entity type"
msgstr "lie une transition ‡ un ou plusieurs types d'entitÈs"
-msgid ""
-"link a transition to one or more rql expression allowing to go through this "
-"transition"
-msgstr ""
-
msgid "link to each item in"
msgstr "lier vers chaque ÈlÈment dans"
@@ -2161,6 +2109,9 @@
msgid "login"
msgstr "identifiant"
+msgid "login or email"
+msgstr ""
+
msgid "login_action"
msgstr "identifiez vous"
@@ -2389,9 +2340,6 @@
msgid "pkey"
msgstr "clÈ"
-msgid "planned_delivery"
-msgstr ""
-
msgid "please correct errors below"
msgstr "veuillez corriger les erreurs ci-dessous"
@@ -2456,8 +2404,8 @@
msgid "remove this Bookmark"
msgstr "supprimer ce signet"
-msgid "remove this Card"
-msgstr "supprimer cette fiche"
+msgid "remove this CWAttribute"
+msgstr "supprimer cet attribut"
msgid "remove this CWCache"
msgstr "supprimer ce cache applicatif"
@@ -2471,15 +2419,9 @@
msgid "remove this CWEType"
msgstr "supprimer ce type d'entitÈ"
-msgid "remove this CWAttribute"
-msgstr "supprimer cet attribut"
-
msgid "remove this CWGroup"
msgstr "supprimer ce groupe"
-msgid "remove this CWRelation"
-msgstr "supprimer cette relation"
-
msgid "remove this CWPermission"
msgstr "supprimer cette permission"
@@ -2489,6 +2431,9 @@
msgid "remove this CWRType"
msgstr "supprimer cette dÈfinition de relation"
+msgid "remove this CWRelation"
+msgstr "supprimer cette relation"
+
msgid "remove this CWUser"
msgstr "supprimer cet utilisateur"
@@ -2595,6 +2540,9 @@
msgid "select a"
msgstr "sÈlectionner un"
+msgid "select a key first"
+msgstr ""
+
msgid "select a relation"
msgstr "sÈlectionner une relation"
@@ -2717,9 +2665,6 @@
msgid "symetric"
msgstr "symÈtrique"
-msgid "synopsis"
-msgstr "synopsis"
-
msgid "system entities"
msgstr "entitÈs systËmes"
@@ -2782,6 +2727,10 @@
msgid "to"
msgstr "‡"
+#, python-format
+msgid "to %(date)s"
+msgstr ""
+
msgid "to associate with"
msgstr "pour associer ‡"
@@ -2800,6 +2749,9 @@
msgid "todo_by"
msgstr "‡ faire par"
+msgid "toggle check boxes"
+msgstr ""
+
msgid "transition is not allowed"
msgstr "transition non permise"
@@ -2973,9 +2925,6 @@
"org et python-projects@lists.logilab.org), mettez cette propriÈtÈ ‡ vrai sur "
"l'une d'entre-elle qui sera la forme canonique"
-msgid "wikiid"
-msgstr "identifiant wiki"
-
#, python-format
msgid "workflow for %s"
msgstr "workflow pour %s"
@@ -2995,6 +2944,9 @@
msgid "you have been logged out"
msgstr "vous avez ÈtÈ dÈconnectÈ"
+msgid "you should probably delete that property"
+msgstr ""
+
#~ msgid "%s constraint failed"
#~ msgstr "La contrainte %s n'est pas satisfaite"
@@ -3004,21 +2956,91 @@
#~ msgid "%s, or without time: %s"
#~ msgstr "%s, ou bien sans prÈciser d'heure: %s"
+#~ msgid "Card"
+#~ msgstr "Ficha"
+
+#~ msgid "Card_plural"
+#~ msgstr "Fichas"
+
+#~ msgid "Email body: "
+#~ msgstr "Contenido del correo electrónico : "
+
+#~ msgid "From: "
+#~ msgstr "De : "
+
#~ msgid "Loading"
#~ msgstr "chargement"
+#~ msgid "New Card"
+#~ msgstr "Nueva ficha"
+
+#~ msgid "Problem occured"
+#~ msgstr "Ha ocurrido un error"
+
#~ msgid "Problem occured while setting new value"
#~ msgstr "Un problËme est survenu lors de la mise ‡ jour"
+#~ msgid "Recipients: "
+#~ msgstr "Destinatarios : "
+
+#~ msgid "Subject: "
+#~ msgstr "Objeto : "
+
+#~ msgid "This Card"
+#~ msgstr "Esta Ficha"
+
+#~ msgid ""
+#~ "a card is a textual content used as documentation, reference, procedure "
+#~ "reminder"
+#~ msgstr ""
+#~ "una ficha es un texto utilizado como documentación, referencia, memoria "
+#~ "de procedimiento..."
+
+#~ msgid "add a Card"
+#~ msgstr "agregar una ficha"
+
+#~ msgid "am/pm calendar (month)"
+#~ msgstr "calendario am/pm (mes)"
+
+#~ msgid "am/pm calendar (semester)"
+#~ msgstr "calendario am/pm (semestre)"
+
+#~ msgid "am/pm calendar (week)"
+#~ msgstr "calendario am/pm (semana)"
+
+#~ msgid "am/pm calendar (year)"
+#~ msgstr "calendario am/pm (año)"
+
+#~ msgid "an abstract for this card"
+#~ msgstr "un resumen para esta ficha"
+
#~ msgid "and"
#~ msgstr "et"
#~ msgid "at least one relation %s is required on %s(%s)"
#~ msgstr "au moins une relation %s est nÈcessaire sur %s(%s)"
+#~ msgid "calendar (month)"
+#~ msgstr "calendario (mensual)"
+
+#~ msgid "calendar (semester)"
+#~ msgstr "calendario (semestral)"
+
+#~ msgid "calendar (week)"
+#~ msgstr "calendario (semanal)"
+
+#~ msgid "calendar (year)"
+#~ msgstr "calendario (anual)"
+
#~ msgid "cancel edition"
#~ msgstr "annuler l'Èdition"
+#~ msgid "content"
+#~ msgstr "contenido"
+
+#~ msgid "content_format"
+#~ msgstr "formato"
+
#~ msgid ""
#~ "default language (look at the i18n directory of the application to see "
#~ "available languages)"
@@ -3026,9 +3048,6 @@
#~ "langue par dÈfaut (regarder le rÈpertoire i18n de l'application pour voir "
#~ "les langues disponibles)"
-#~ msgid "detach attached file"
-#~ msgstr "soltar el archivo existente"
-
#~ msgid "filter"
#~ msgstr "filtrer"
@@ -3038,12 +3057,18 @@
#~ msgid "header"
#~ msgstr "en-tÃte de page"
+#~ msgid "i18n_register_user"
+#~ msgstr "registrarse"
+
#~ msgid "iCal"
#~ msgstr "iCal"
#~ msgid "incorrect value for type \"%s\""
#~ msgstr "valeur incorrecte pour le type \"%s\""
+#~ msgid "inlined view"
+#~ msgstr "vista incluÃda (en lÃnea)"
+
#~ msgid "linked"
#~ msgstr "liÈ"
@@ -3058,11 +3083,20 @@
#~ msgid "owned by"
#~ msgstr "appartient ‡"
+#~ msgid "remove this Card"
+#~ msgstr "supprimer cette fiche"
+
#~ msgid "see also"
#~ msgstr "voir aussi"
#~ msgid "status will change from %s to %s"
#~ msgstr "l'Ètat va passer de %s ‡ %s"
+#~ msgid "synopsis"
+#~ msgstr "synopsis"
+
+#~ msgid "wikiid"
+#~ msgstr "identifiant wiki"
+
#~ msgid "workflow history"
#~ msgstr "historique du workflow"
--- a/i18n/fr.po Tue Apr 28 13:28:37 2009 +0200
+++ b/i18n/fr.po Tue Apr 28 19:12:52 2009 +0200
@@ -201,11 +201,71 @@
msgid "Bytes_plural"
msgstr "Données binaires"
-msgid "Card"
-msgstr "Fiche"
-
-msgid "Card_plural"
-msgstr "Fiches"
+msgid "CWAttribute"
+msgstr "Attribut"
+
+msgid "CWAttribute_plural"
+msgstr "Attributs"
+
+msgid "CWCache"
+msgstr "Cache applicatif"
+
+msgid "CWCache_plural"
+msgstr "Caches applicatifs"
+
+msgid "CWConstraint"
+msgstr "Contrainte"
+
+msgid "CWConstraintType"
+msgstr "Type de contrainte"
+
+msgid "CWConstraintType_plural"
+msgstr "Types de contrainte"
+
+msgid "CWConstraint_plural"
+msgstr "Contraintes"
+
+msgid "CWEType"
+msgstr "Type d'entité"
+
+msgid "CWEType_plural"
+msgstr "Types d'entité"
+
+msgid "CWGroup"
+msgstr "Groupe"
+
+msgid "CWGroup_plural"
+msgstr "Groupes"
+
+msgid "CWPermission"
+msgstr "Permission"
+
+msgid "CWPermission_plural"
+msgstr "Permissions"
+
+msgid "CWProperty"
+msgstr "Propriété"
+
+msgid "CWProperty_plural"
+msgstr "Propriétés"
+
+msgid "CWRType"
+msgstr "Type de relation"
+
+msgid "CWRType_plural"
+msgstr "Types de relation"
+
+msgid "CWRelation"
+msgstr "Relation"
+
+msgid "CWRelation_plural"
+msgstr "Relations"
+
+msgid "CWUser"
+msgstr "Utilisateur"
+
+msgid "CWUser_plural"
+msgstr "Utilisateurs"
msgid "Date"
msgstr "Date"
@@ -232,75 +292,6 @@
msgid "Do you want to delete the following element(s) ?"
msgstr "Voulez vous supprimer le(s) élément(s) suivant(s)"
-msgid "CWCache"
-msgstr "Cache applicatif"
-
-msgid "CWCache_plural"
-msgstr "Caches applicatifs"
-
-msgid "CWConstraint"
-msgstr "Contrainte"
-
-msgid "CWConstraintType"
-msgstr "Type de contrainte"
-
-msgid "CWConstraintType_plural"
-msgstr "Types de contrainte"
-
-msgid "CWConstraint_plural"
-msgstr "Contraintes"
-
-msgid "CWEType"
-msgstr "Type d'entité"
-
-msgid "CWEType_plural"
-msgstr "Types d'entité"
-
-msgid "CWAttribute"
-msgstr "Attribut"
-
-msgid "CWAttribute_plural"
-msgstr "Attributs"
-
-msgid "CWGroup"
-msgstr "Groupe"
-
-msgid "CWGroup_plural"
-msgstr "Groupes"
-
-msgid "CWRelation"
-msgstr "Relation"
-
-msgid "CWRelation_plural"
-msgstr "Relations"
-
-msgid "CWPermission"
-msgstr "Permission"
-
-msgid "CWPermission_plural"
-msgstr "Permissions"
-
-msgid "CWProperty"
-msgstr "Propriété"
-
-msgid "CWProperty_plural"
-msgstr "Propriétés"
-
-msgid "CWRType"
-msgstr "Type de relation"
-
-msgid "CWRType_plural"
-msgstr "Types de relation"
-
-msgid "CWUser"
-msgstr "Utilisateur"
-
-msgid "CWUser_plural"
-msgstr "Utilisateurs"
-
-msgid "Email body: "
-msgstr "Contenu du courriel : "
-
msgid "EmailAddress"
msgstr "Adresse électronique"
@@ -319,8 +310,8 @@
msgid "Float_plural"
msgstr "Nombres flottants"
-msgid "From: "
-msgstr "De : "
+msgid "From:"
+msgstr ""
msgid "Int"
msgstr "Nombre entier"
@@ -337,8 +328,8 @@
msgid "New Bookmark"
msgstr "Nouveau signet"
-msgid "New Card"
-msgstr "Nouvelle fiche"
+msgid "New CWAttribute"
+msgstr "Nouvelle définition de relation"
msgid "New CWCache"
msgstr "Nouveau cache applicatif"
@@ -352,15 +343,9 @@
msgid "New CWEType"
msgstr "Nouveau type d'entité"
-msgid "New CWAttribute"
-msgstr "Nouvelle définition de relation finale"
-
msgid "New CWGroup"
msgstr "Nouveau groupe"
-msgid "New CWRelation"
-msgstr "Nouvelle définition de relation non finale"
-
msgid "New CWPermission"
msgstr "Nouvelle permission"
@@ -370,6 +355,9 @@
msgid "New CWRType"
msgstr "Nouveau type de relation"
+msgid "New CWRelation"
+msgstr "Nouvel attribut"
+
msgid "New CWUser"
msgstr "Nouvel utilisateur"
@@ -406,17 +394,14 @@
msgid "Please note that this is only a shallow copy"
msgstr "Attention, cela n'effectue qu'une copie de surface"
-msgid "Problem occured"
-msgstr "Une erreur est survenue"
-
msgid "RQLExpression"
msgstr "Expression RQL"
msgid "RQLExpression_plural"
msgstr "Expressions RQL"
-msgid "Recipients: "
-msgstr "Destinataires : "
+msgid "Recipients:"
+msgstr "Destinataires :"
msgid "Relations"
msgstr "Relations"
@@ -449,8 +434,8 @@
msgid "String_plural"
msgstr "Chaînes de caractères"
-msgid "Subject: "
-msgstr "Sujet : "
+msgid "Subject:"
+msgstr "Sujet :"
msgid "Submit bug report"
msgstr "Soumettre un rapport de bug"
@@ -476,8 +461,8 @@
msgid "This Bookmark"
msgstr "Ce signet"
-msgid "This Card"
-msgstr "Cette fiche"
+msgid "This CWAttribute"
+msgstr "Cette définition de relation"
msgid "This CWCache"
msgstr "Ce cache applicatif"
@@ -491,15 +476,9 @@
msgid "This CWEType"
msgstr "Ce type d'entité"
-msgid "This CWAttribute"
-msgstr "Cette définition de relation finale"
-
msgid "This CWGroup"
msgstr "Ce groupe"
-msgid "This CWRelation"
-msgstr "Cette définition de relation non finale"
-
msgid "This CWPermission"
msgstr "Cette permission"
@@ -509,6 +488,9 @@
msgid "This CWRType"
msgstr "Ce type de relation"
+msgid "This CWRelation"
+msgstr "Cet attribut"
+
msgid "This CWUser"
msgstr "Cet utilisateur"
@@ -617,13 +599,6 @@
"transition et l'utilisateur courant."
msgid ""
-"a card is a textual content used as documentation, reference, procedure "
-"reminder"
-msgstr ""
-"une fiche est un texte utilisé comme documentation, référence, rappel de "
-"procédure..."
-
-msgid ""
"a simple cache entity characterized by a name and a validity date. The "
"target application is responsible for updating timestamp when necessary to "
"invalidate the cache (typically in hooks). Also, checkout the AppRsetObject."
@@ -705,6 +680,12 @@
msgid "actions_manage_description"
msgstr ""
+msgid "actions_managepermission"
+msgstr ""
+
+msgid "actions_managepermission_description"
+msgstr ""
+
msgid "actions_muledit"
msgstr "édition multiple"
@@ -777,6 +758,12 @@
msgid "add Bookmark bookmarked_by CWUser object"
msgstr "signet"
+msgid "add CWAttribute constrained_by CWConstraint subject"
+msgstr "contrainte"
+
+msgid "add CWAttribute relation_type CWRType object"
+msgstr "définition d'attribut"
+
msgid "add CWEType add_permission RQLExpression subject"
msgstr "définir une expression RQL d'ajout"
@@ -789,18 +776,6 @@
msgid "add CWEType update_permission RQLExpression subject"
msgstr "définir une expression RQL de mise à jour"
-msgid "add CWAttribute constrained_by CWConstraint subject"
-msgstr "contrainte"
-
-msgid "add CWAttribute relation_type CWRType object"
-msgstr "définition d'attribut"
-
-msgid "add CWRelation constrained_by CWConstraint subject"
-msgstr "contrainte"
-
-msgid "add CWRelation relation_type CWRType object"
-msgstr "définition de relation"
-
msgid "add CWProperty for_user CWUser object"
msgstr "propriété"
@@ -813,6 +788,12 @@
msgid "add CWRType read_permission RQLExpression subject"
msgstr "expression RQL de lecture"
+msgid "add CWRelation constrained_by CWConstraint subject"
+msgstr "contrainte"
+
+msgid "add CWRelation relation_type CWRType object"
+msgstr "définition de relation"
+
msgid "add CWUser in_group CWGroup object"
msgstr "utilisateur"
@@ -843,8 +824,8 @@
msgid "add a Bookmark"
msgstr "ajouter un signet"
-msgid "add a Card"
-msgstr "ajouter une fiche"
+msgid "add a CWAttribute"
+msgstr "ajouter un attribut"
msgid "add a CWCache"
msgstr "ajouter un cache applicatif"
@@ -858,15 +839,9 @@
msgid "add a CWEType"
msgstr "ajouter un type d'entité"
-msgid "add a CWAttribute"
-msgstr "ajouter un type de relation"
-
msgid "add a CWGroup"
msgstr "ajouter un groupe d'utilisateurs"
-msgid "add a CWRelation"
-msgstr "ajouter une relation"
-
msgid "add a CWPermission"
msgstr "ajouter une permission"
@@ -876,6 +851,9 @@
msgid "add a CWRType"
msgstr "ajouter un type de relation"
+msgid "add a CWRelation"
+msgstr "ajouter une relation"
+
msgid "add a CWUser"
msgstr "ajouter un utilisateur"
@@ -941,21 +919,6 @@
msgid "allowed_transition_object"
msgstr "états en entrée"
-msgid "am/pm calendar (month)"
-msgstr "calendrier am/pm (mois)"
-
-msgid "am/pm calendar (semester)"
-msgstr "calendrier am/pm (semestre)"
-
-msgid "am/pm calendar (week)"
-msgstr "calendrier am/pm (semaine)"
-
-msgid "am/pm calendar (year)"
-msgstr "calendrier am/pm (année)"
-
-msgid "an abstract for this card"
-msgstr "un résumé pour cette fiche"
-
msgid "an electronic mail address associated to a short alias"
msgstr "une addresse électronique associée à un alias"
@@ -1107,18 +1070,6 @@
msgid "calendar"
msgstr "afficher un calendrier"
-msgid "calendar (month)"
-msgstr "calendrier (mensuel)"
-
-msgid "calendar (semester)"
-msgstr "calendrier (semestriel)"
-
-msgid "calendar (week)"
-msgstr "calendrier (hebdo)"
-
-msgid "calendar (year)"
-msgstr "calendrier (annuel)"
-
#, python-format
msgid "can't change the %s attribute"
msgstr "ne peut changer l'attribut %s"
@@ -1233,12 +1184,6 @@
msgid "components_rqlinput_description"
msgstr "la barre de requête rql, dans l'en-tête de page"
-msgid "components_rss_feed_url"
-msgstr "syndication rss"
-
-msgid "components_rss_feed_url_description"
-msgstr ""
-
msgid "composite"
msgstr "composite"
@@ -1269,12 +1214,6 @@
msgid "constraints applying on this relation"
msgstr "contraintes s'appliquant à cette relation"
-msgid "content"
-msgstr "contenu"
-
-msgid "content_format"
-msgstr "format"
-
msgid "contentnavigation"
msgstr "composants contextuels"
@@ -1401,28 +1340,31 @@
msgid "creating Bookmark (Bookmark bookmarked_by CWUser %(linkto)s)"
msgstr "création d'un signet pour %(linkto)s"
-msgid "creating CWConstraint (CWAttribute %(linkto)s constrained_by CWConstraint)"
-msgstr "création d'une contrainte pour l'attribut %(linkto)s"
-
-msgid "creating CWConstraint (CWRelation %(linkto)s constrained_by CWConstraint)"
-msgstr "création d'une contrainte pour la relation %(linkto)s"
-
msgid "creating CWAttribute (CWAttribute relation_type CWRType %(linkto)s)"
msgstr "création d'un attribut %(linkto)s"
+msgid ""
+"creating CWConstraint (CWAttribute %(linkto)s constrained_by CWConstraint)"
+msgstr "création d'une contrainte pour l'attribut %(linkto)s"
+
+msgid ""
+"creating CWConstraint (CWRelation %(linkto)s constrained_by CWConstraint)"
+msgstr "création d'une contrainte pour la relation %(linkto)s"
+
+msgid "creating CWProperty (CWProperty for_user CWUser %(linkto)s)"
+msgstr "création d'une propriété pour l'utilisateur %(linkto)s"
+
msgid "creating CWRelation (CWRelation relation_type CWRType %(linkto)s)"
msgstr "création relation %(linkto)s"
-msgid "creating CWProperty (CWProperty for_user CWUser %(linkto)s)"
-msgstr "création d'une propriété pour l'utilisateur %(linkto)s"
-
msgid "creating CWUser (CWUser in_group CWGroup %(linkto)s)"
msgstr "création d'un utilisateur à rajouter au groupe %(linkto)s"
msgid "creating EmailAddress (CWUser %(linkto)s use_email EmailAddress)"
msgstr "création d'une adresse électronique pour l'utilisateur %(linkto)s"
-msgid "creating RQLExpression (CWEType %(linkto)s add_permission RQLExpression)"
+msgid ""
+"creating RQLExpression (CWEType %(linkto)s add_permission RQLExpression)"
msgstr "création d'une expression RQL pour la permission d'ajout de %(linkto)s"
msgid ""
@@ -1439,7 +1381,8 @@
msgstr ""
"création d'une expression RQL pour la permission de mise à jour de %(linkto)s"
-msgid "creating RQLExpression (CWRType %(linkto)s add_permission RQLExpression)"
+msgid ""
+"creating RQLExpression (CWRType %(linkto)s add_permission RQLExpression)"
msgstr ""
"création d'une expression RQL pour la permission d'ajout des relations %"
"(linkto)s"
@@ -1626,6 +1569,9 @@
msgid "destination_state_object"
msgstr "destination de"
+msgid "detach attached file"
+msgstr "détacher le fichier existant"
+
#, python-format
msgid "detach attached file %s"
msgstr "détacher le fichier existant %s"
@@ -1706,9 +1652,18 @@
msgid "entities deleted"
msgstr "entités supprimées"
+msgid "entity copied"
+msgstr ""
+
+msgid "entity created"
+msgstr ""
+
msgid "entity deleted"
msgstr "entité supprimée"
+msgid "entity edited"
+msgstr ""
+
msgid "entity type"
msgstr "type d'entité"
@@ -1819,6 +1774,10 @@
msgid "from"
msgstr "de"
+#, python-format
+msgid "from %(date)s"
+msgstr ""
+
msgid "from_entity"
msgstr "de l'entité"
@@ -1938,9 +1897,6 @@
msgid "i18n_login_popup"
msgstr "s'authentifier"
-msgid "i18n_register_user"
-msgstr "s'enregister"
-
msgid "i18nprevnext_next"
msgstr "suivant"
@@ -2034,9 +1990,6 @@
msgid "inlined"
msgstr "mise en ligne"
-msgid "inlined view"
-msgstr "vue embarquée (en ligne)"
-
msgid "internationalizable"
msgstr "internationalisable"
@@ -2142,11 +2095,6 @@
msgid "link a transition to one or more entity type"
msgstr "lie une transition à un ou plusieurs types d'entités"
-msgid ""
-"link a transition to one or more rql expression allowing to go through this "
-"transition"
-msgstr ""
-
msgid "link to each item in"
msgstr "lier vers chaque élément dans"
@@ -2393,9 +2341,6 @@
msgid "pkey"
msgstr "clé"
-msgid "planned_delivery"
-msgstr "livraison prévue"
-
msgid "please correct errors below"
msgstr "veuillez corriger les erreurs ci-dessous"
@@ -2460,8 +2405,8 @@
msgid "remove this Bookmark"
msgstr "supprimer ce signet"
-msgid "remove this Card"
-msgstr "supprimer cette fiche"
+msgid "remove this CWAttribute"
+msgstr "supprimer cet attribut"
msgid "remove this CWCache"
msgstr "supprimer ce cache applicatif"
@@ -2475,15 +2420,9 @@
msgid "remove this CWEType"
msgstr "supprimer ce type d'entité"
-msgid "remove this CWAttribute"
-msgstr "supprimer cet attribut"
-
msgid "remove this CWGroup"
msgstr "supprimer ce groupe"
-msgid "remove this CWRelation"
-msgstr "supprimer cette relation"
-
msgid "remove this CWPermission"
msgstr "supprimer cette permission"
@@ -2493,6 +2432,9 @@
msgid "remove this CWRType"
msgstr "supprimer cette définition de relation"
+msgid "remove this CWRelation"
+msgstr "supprimer cette relation"
+
msgid "remove this CWUser"
msgstr "supprimer cet utilisateur"
@@ -2599,6 +2541,9 @@
msgid "select a"
msgstr "sélectionner un"
+msgid "select a key first"
+msgstr ""
+
msgid "select a relation"
msgstr "sélectionner une relation"
@@ -2721,9 +2666,6 @@
msgid "symetric"
msgstr "symétrique"
-msgid "synopsis"
-msgstr "synopsis"
-
msgid "system entities"
msgstr "entités systèmes"
@@ -2786,6 +2728,10 @@
msgid "to"
msgstr "Ã "
+#, python-format
+msgid "to %(date)s"
+msgstr ""
+
msgid "to associate with"
msgstr "pour associer à "
@@ -2804,6 +2750,9 @@
msgid "todo_by"
msgstr "Ã faire par"
+msgid "toggle check boxes"
+msgstr ""
+
msgid "transition is not allowed"
msgstr "transition non permise"
@@ -2977,9 +2926,6 @@
"org et python-projects@lists.logilab.org), mettez cette propriété à vrai sur "
"l'une d'entre-elle qui sera la forme canonique"
-msgid "wikiid"
-msgstr "identifiant wiki"
-
#, python-format
msgid "workflow for %s"
msgstr "workflow pour %s"
@@ -2999,6 +2945,9 @@
msgid "you have been logged out"
msgstr "vous avez été déconnecté"
+msgid "you should probably delete that property"
+msgstr ""
+
#~ msgid "%s constraint failed"
#~ msgstr "La contrainte %s n'est pas satisfaite"
@@ -3008,21 +2957,88 @@
#~ msgid "%s, or without time: %s"
#~ msgstr "%s, ou bien sans préciser d'heure: %s"
+#~ msgid "Card"
+#~ msgstr "Fiche"
+
+#~ msgid "Card_plural"
+#~ msgstr "Fiches"
+
+#~ msgid "Email body: "
+#~ msgstr "Contenu du courriel : "
+
+#~ msgid "From: "
+#~ msgstr "De : "
+
#~ msgid "Loading"
#~ msgstr "chargement"
+#~ msgid "New Card"
+#~ msgstr "Nouvelle fiche"
+
+#~ msgid "Problem occured"
+#~ msgstr "Une erreur est survenue"
+
#~ msgid "Problem occured while setting new value"
#~ msgstr "Un problème est survenu lors de la mise à jour"
+#~ msgid "This Card"
+#~ msgstr "Cette fiche"
+
+#~ msgid ""
+#~ "a card is a textual content used as documentation, reference, procedure "
+#~ "reminder"
+#~ msgstr ""
+#~ "une fiche est un texte utilisé comme documentation, référence, rappel de "
+#~ "procédure..."
+
+#~ msgid "add a Card"
+#~ msgstr "ajouter une fiche"
+
+#~ msgid "am/pm calendar (month)"
+#~ msgstr "calendrier am/pm (mois)"
+
+#~ msgid "am/pm calendar (semester)"
+#~ msgstr "calendrier am/pm (semestre)"
+
+#~ msgid "am/pm calendar (week)"
+#~ msgstr "calendrier am/pm (semaine)"
+
+#~ msgid "am/pm calendar (year)"
+#~ msgstr "calendrier am/pm (année)"
+
+#~ msgid "an abstract for this card"
+#~ msgstr "un résumé pour cette fiche"
+
#~ msgid "and"
#~ msgstr "et"
#~ msgid "at least one relation %s is required on %s(%s)"
#~ msgstr "au moins une relation %s est nécessaire sur %s(%s)"
+#~ msgid "calendar (month)"
+#~ msgstr "calendrier (mensuel)"
+
+#~ msgid "calendar (semester)"
+#~ msgstr "calendrier (semestriel)"
+
+#~ msgid "calendar (week)"
+#~ msgstr "calendrier (hebdo)"
+
+#~ msgid "calendar (year)"
+#~ msgstr "calendrier (annuel)"
+
#~ msgid "cancel edition"
#~ msgstr "annuler l'édition"
+#~ msgid "components_rss_feed_url"
+#~ msgstr "syndication rss"
+
+#~ msgid "content"
+#~ msgstr "contenu"
+
+#~ msgid "content_format"
+#~ msgstr "format"
+
#~ msgid ""
#~ "default language (look at the i18n directory of the application to see "
#~ "available languages)"
@@ -3030,9 +3046,6 @@
#~ "langue par défaut (regarder le répertoire i18n de l'application pour voir "
#~ "les langues disponibles)"
-#~ msgid "detach attached file"
-#~ msgstr "détacher le fichier existant"
-
#~ msgid "filter"
#~ msgstr "filtrer"
@@ -3042,12 +3055,18 @@
#~ msgid "header"
#~ msgstr "en-tête de page"
+#~ msgid "i18n_register_user"
+#~ msgstr "s'enregister"
+
#~ msgid "iCal"
#~ msgstr "iCal"
#~ msgid "incorrect value for type \"%s\""
#~ msgstr "valeur incorrecte pour le type \"%s\""
+#~ msgid "inlined view"
+#~ msgstr "vue embarquée (en ligne)"
+
#~ msgid "linked"
#~ msgstr "lié"
@@ -3062,11 +3081,26 @@
#~ msgid "owned by"
#~ msgstr "appartient à "
+#~ msgid "planned_delivery"
+#~ msgstr "livraison prévue"
+
+#~ msgid "remove this Card"
+#~ msgstr "supprimer cette fiche"
+
#~ msgid "see also"
#~ msgstr "voir aussi"
#~ msgid "status will change from %s to %s"
#~ msgstr "l'état va passer de %s à %s"
+#~ msgid "synopsis"
+#~ msgstr "synopsis"
+
+#~ msgid "trcomment"
+#~ msgstr "commentaire"
+
+#~ msgid "wikiid"
+#~ msgstr "identifiant wiki"
+
#~ msgid "workflow history"
#~ msgstr "historique du workflow"
--- a/misc/migration/3.2.0_Any.py Tue Apr 28 13:28:37 2009 +0200
+++ b/misc/migration/3.2.0_Any.py Tue Apr 28 19:12:52 2009 +0200
@@ -1,3 +1,4 @@
rql('SET X value "main-template" WHERE X is CWProperty, '
'X pkey "ui.main-template", X value "main"')
checkpoint()
+
--- a/misc/migration/bootstrapmigration_repository.py Tue Apr 28 13:28:37 2009 +0200
+++ b/misc/migration/bootstrapmigration_repository.py Tue Apr 28 19:12:52 2009 +0200
@@ -7,6 +7,9 @@
:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
"""
+if applcubicwebversion < (3, 2, 0) and cubicwebversion >= (3, 2, 0):
+ add_cube('card', update_database=False)
+
if applcubicwebversion < (2, 47, 0) and cubicwebversion >= (2, 47, 0):
from cubicweb.server import schemaserial
schemaserial.HAS_FULLTEXT_CONTAINER = False
@@ -15,7 +18,7 @@
schemaserial.HAS_FULLTEXT_CONTAINER = True
-
+
if applcubicwebversion < (2, 50, 0) and cubicwebversion >= (2, 50, 0):
session.set_shared_data('do-not-insert-is_instance_of', True)
add_relation_type('is_instance_of')
@@ -40,4 +43,4 @@
sql('CREATE INDEX deleted_entities_dtime_idx ON deleted_entities(dtime)')
sql('CREATE INDEX deleted_entities_extid_idx ON deleted_entities(extid)')
checkpoint()
-
+
--- a/schema.py Tue Apr 28 13:28:37 2009 +0200
+++ b/schema.py Tue Apr 28 19:12:52 2009 +0200
@@ -77,7 +77,7 @@
## cubicweb provides a RichString class for convenience
class RichString(ybo.String):
"""Convenience RichString attribute type
- The follwing declaration::
+ The following declaration::
class Card(EntityType):
content = RichString(fulltextindexed=True, default_format='text/rest')
--- a/selectors.py Tue Apr 28 13:28:37 2009 +0200
+++ b/selectors.py Tue Apr 28 19:12:52 2009 +0200
@@ -51,7 +51,8 @@
from yams import BASE_TYPES
-from cubicweb import Unauthorized, NoSelectableObject, NotAnEntity, role
+from cubicweb import (Unauthorized, NoSelectableObject, NotAnEntity,
+ role, typed_eid)
from cubicweb.vregistry import (NoSelectableObject, Selector,
chainall, objectify_selector)
from cubicweb.cwconfig import CubicWebConfiguration
@@ -404,7 +405,7 @@
@objectify_selector
@lltrace
def authenticated_user(cls, req, *args, **kwargs):
- """accept if user is anonymous"""
+ """accept if user is authenticated"""
if req.cnx.anonymous_connection:
return 0
return 1
@@ -529,6 +530,20 @@
return score
+class match_transition(match_search_state):
+ @lltrace
+ def __call__(self, cls, req, rset=None, row=None, col=0, **kwargs):
+ try:
+ trname = req.execute('Any XN WHERE X is Transition, X eid %(x)s, X name XN',
+ {'x': typed_eid(req.form['treid'])})[0][0]
+ except (KeyError, IndexError):
+ return 0
+ # XXX check this is a transition that apply to the object?
+ if not trname in self.expected:
+ return 0
+ return 1
+
+
class match_view(match_search_state):
"""accept if the current view is in one of the expected vid given to the
initializer
--- a/server/repository.py Tue Apr 28 13:28:37 2009 +0200
+++ b/server/repository.py Tue Apr 28 19:12:52 2009 +0200
@@ -60,7 +60,7 @@
remove inserted eid from repository type/source cache
"""
self.repo.clear_caches(self.session.query_data('pendingeids', ()))
-
+
def rollback_event(self):
"""the observed connections pool has been rollbacked,
remove inserted eid from repository type/source cache
@@ -84,7 +84,7 @@
session.repo.system_source.fti_unindex_entity(session, entity.eid)
for container in entity.fti_containers():
session.repo.index_entity(session, container)
-
+
def commit_event(self):
pass
@@ -120,14 +120,14 @@
'DELETE X %s Y WHERE NOT X eid %%(x)s, Y eid %%(y)s' % rtype,
{'x': eidfrom, 'y': eidto}, 'y')
-
+
class Repository(object):
"""a repository provides access to a set of persistent storages for
entities and relations
XXX protect pyro access
"""
-
+
def __init__(self, config, vreg=None, debug=False):
self.config = config
if vreg is None:
@@ -155,7 +155,7 @@
for uri, source_config in config.sources().items():
if uri == 'admin':
# not an actual source
- continue
+ continue
source = self.get_source(uri, source_config)
self.sources_by_uri[uri] = source
self.sources.append(source)
@@ -214,16 +214,16 @@
source.init_creating()
# close initialization pool and reopen fresh ones for proper
# initialization now that we know cubes
- self._get_pool().close(True)
+ self._get_pool().close(True)
for i in xrange(config['connections-pool-size']):
self._available_pools.put_nowait(ConnectionsPool(self.sources))
-
+
# internals ###############################################################
def get_source(self, uri, source_config):
source_config['uri'] = uri
return get_source(source_config, self.schema, self)
-
+
def set_schema(self, schema, resetvreg=True):
schema.rebuild_infered_relations()
self.info('set schema %s %#x', schema.name, id(schema))
@@ -259,7 +259,7 @@
except Exception, ex:
import traceback
traceback.print_exc()
- raise Exception('Is the database initialised ? (cause: %s)' %
+ raise Exception('Is the database initialised ? (cause: %s)' %
(ex.args and ex.args[0].strip() or 'unknown')), \
None, sys.exc_info()[-1]
self.info('set the actual schema')
@@ -277,7 +277,7 @@
session.close()
self.config.init_cubes(self.get_cubes())
self.set_schema(appschema)
-
+
def set_bootstrap_schema(self, schema):
"""disable hooks when setting a bootstrap schema, but restore
the configuration for the next time
@@ -295,7 +295,7 @@
config.schema_hooks = True
config.notification_hooks = True
config.application_hooks = True
-
+
def start_looping_tasks(self):
assert isinstance(self._looping_tasks, list), 'already started'
for i, (interval, func) in enumerate(self._looping_tasks):
@@ -308,7 +308,7 @@
def looping_task(self, interval, func):
"""register a function to be called every `interval` seconds.
-
+
looping tasks can only be registered during repository initialization,
once done this method will fail.
"""
@@ -321,7 +321,7 @@
"""start function in a separated thread"""
t = RepoThread(func, self._running_threads)
t.start()
-
+
#@locked
def _get_pool(self):
try:
@@ -332,7 +332,7 @@
'connections) or to much load on the server (in '
'which case you can try to set a bigger '
'connections pools size)')
-
+
def _free_pool(self, pool):
pool.rollback()
self._available_pools.put_nowait(pool)
@@ -382,7 +382,7 @@
((hits + misses) * 100) / (hits + misses + nocache))
except ZeroDivisionError:
pass
-
+
def authenticate_user(self, session, login, password):
"""validate login / password, raise AuthenticationError on failure
return associated CWUser instance on success
@@ -415,9 +415,9 @@
euser.groups
euser.properties
return euser
-
+
# public (dbapi) interface ################################################
-
+
def get_schema(self):
"""return the application schema. This is a public method, not
requiring a session id
@@ -469,7 +469,7 @@
finally:
session.close()
return vcconf
-
+
@cached
def source_defs(self):
sources = self.config.sources().copy()
@@ -526,13 +526,13 @@
finally:
session.close()
return True
-
+
def connect(self, login, password, cnxprops=None):
"""open a connection for a given user
base_url may be needed to send mails
cnxtype indicate if this is a pyro connection or a in-memory connection
-
+
raise `AuthenticationError` if the authentication failed
raise `ConnectionError` if we can't open a connection
"""
@@ -584,7 +584,7 @@
raise
finally:
session.reset_pool()
-
+
def describe(self, sessionid, eid):
"""return a tuple (type, source, extid) for the entity with id <eid>"""
session = self._get_session(sessionid, setpool=True)
@@ -618,12 +618,12 @@
self.debug('begin commit for session %s', sessionid)
try:
self._get_session(sessionid, setpool=True).commit()
- except (ValidationError, Unauthorized):
+ except (ValidationError, Unauthorized):
raise
except:
self.exception('unexpected error')
raise
-
+
def rollback(self, sessionid):
"""commit transaction for the session with the given id"""
self.debug('begin rollback for session %s', sessionid)
@@ -645,7 +645,7 @@
session.close()
del self._sessions[sessionid]
self.info('closed session %s for user %s', sessionid, session.user.login)
-
+
def user_info(self, sessionid, props=None):
"""this method should be used by client to:
* check session id validity
@@ -659,9 +659,9 @@
session.change_property(prop, value)
user = session.user
return user.eid, user.login, user.groups, user.properties
-
+
# public (inter-repository) interface #####################################
-
+
def entities_modified_since(self, etypes, mtime):
"""function designed to be called from an external repository which
is using this one as a rql source for synchronization, and return a
@@ -683,7 +683,7 @@
session.close()
# session handling ########################################################
-
+
def close_sessions(self):
"""close every opened sessions"""
for sessionid in self._sessions.keys():
@@ -705,7 +705,7 @@
self.close(session.id)
nbclosed += 1
return nbclosed
-
+
def internal_session(self, cnxprops=None):
"""return a dbapi like connection/cursor using internal user which
have every rights on the repository. You'll *have to* commit/rollback
@@ -716,7 +716,7 @@
session = InternalSession(self, cnxprops)
session.set_pool()
return session
-
+
def _get_session(self, sessionid, setpool=False):
"""return the user associated to the given session identifier"""
try:
@@ -731,7 +731,7 @@
# * correspondance between eid and (type, source)
# * correspondance between eid and local id (i.e. specific to a given source)
# * searchable text indexes
-
+
def type_and_source_from_eid(self, eid, session=None):
"""return a tuple (type, source, extid) for the entity with id <eid>"""
try:
@@ -771,15 +771,15 @@
rqlcache.pop('Any X WHERE X eid %s' % eid, None)
for source in self.sources:
source.clear_eid_cache(eid, etype)
-
+
def type_from_eid(self, eid, session=None):
"""return the type of the entity with id <eid>"""
return self.type_and_source_from_eid(eid, session)[0]
-
+
def source_from_eid(self, eid, session=None):
"""return the source for the given entity's eid"""
return self.sources_by_uri[self.type_and_source_from_eid(eid, session)[1]]
-
+
def eid2extid(self, source, eid, session=None):
"""get local id from an eid"""
etype, uri, extid = self.type_and_source_from_eid(eid, session)
@@ -848,7 +848,7 @@
except:
session.rollback(reset_pool)
raise
-
+
def add_info(self, session, entity, source, extid=None, complete=True):
"""add type and source info for an eid into the system table,
and index the entity with the full text index
@@ -862,11 +862,11 @@
if self.do_fti:
FTIndexEntityOp(session, entity=entity)
CleanupEidTypeCacheOp(session)
-
+
def delete_info(self, session, eid):
self._prepare_delete_info(session, eid)
self._delete_info(session, eid)
-
+
def _prepare_delete_info(self, session, eid):
"""prepare the repository for deletion of an entity:
* update the fti
@@ -877,7 +877,7 @@
pending = session.query_data('pendingeids', set(), setdefault=True)
pending.add(eid)
CleanupEidTypeCacheOp(session)
-
+
def _delete_info(self, session, eid):
"""delete system information on deletion of an entity:
* delete all relations on this entity
@@ -886,7 +886,7 @@
etype, uri, extid = self.type_and_source_from_eid(eid, session)
self._clear_eid_relations(session, etype, eid)
self.system_source.delete_info(session, eid, etype, uri, extid)
-
+
def _clear_eid_relations(self, session, etype, eid):
"""when a entity is deleted, build and execute rql query to delete all
its relations
@@ -917,7 +917,7 @@
return
alreadydone.add(entity.eid)
self.system_source.fti_index_entity(session, entity)
-
+
def locate_relation_source(self, session, subject, rtype, object):
subjsource = self.source_from_eid(subject, session)
objsource = self.source_from_eid(object, session)
@@ -928,17 +928,17 @@
else:
source = subjsource
return source
-
+
def locate_etype_source(self, etype):
for source in self.sources:
if source.support_entity(etype, 1):
return source
else:
raise ETypeNotSupportedBySources(etype)
-
+
def glob_add_entity(self, session, entity):
"""add an entity to the repository
-
+
the entity eid should originaly be None and a unique eid is assigned to
the entity instance
"""
@@ -981,7 +981,7 @@
self.hm.call_hooks('after_add_relation', attr, session,
entity.eid, attr, value)
return entity.eid
-
+
def glob_update_entity(self, session, entity):
"""replace an entity in the repository
the type and the eid of an entity must not be changed
@@ -1051,7 +1051,7 @@
if source.should_call_hooks:
self.hm.call_hooks('after_delete_entity', etype, session, eid)
# don't clear cache here this is done in a hook on commit
-
+
def glob_add_relation(self, session, subject, rtype, object):
"""add a relation to the repository"""
assert subject is not None
@@ -1089,7 +1089,7 @@
# pyro handling ###########################################################
-
+
def pyro_register(self, host=''):
"""register the repository as a pyro object"""
from Pyro import core
@@ -1108,7 +1108,7 @@
self.info(msg, nsgroup, nsid)
self.pyro_registered = True
return daemon
-
+
def pyro_nameserver(self, host=None, group=None):
"""locate and bind the the name server to the daemon"""
from Pyro import naming, errors
@@ -1123,25 +1123,25 @@
return nameserver
# multi-sources planner helpers ###########################################
-
+
@cached
def rel_type_sources(self, rtype):
return [source for source in self.sources
if source.support_relation(rtype)
or rtype in source.dont_cross_relations]
-
+
@cached
def can_cross_relation(self, rtype):
return [source for source in self.sources
if source.support_relation(rtype)
and rtype in source.cross_relations]
-
+
@cached
def is_multi_sources_relation(self, rtype):
return any(source for source in self.sources
if not source is self.system_source
and source.support_relation(rtype))
-
+
def pyro_unregister(config):
"""unregister the repository from the pyro name server"""
--- a/server/sources/extlite.py Tue Apr 28 13:28:37 2009 +0200
+++ b/server/sources/extlite.py Tue Apr 28 19:12:52 2009 +0200
@@ -22,7 +22,7 @@
timeout -= 0.2
if timeout <= 0:
raise RuntimeError("svn source is busy, can't acquire connection lock")
-
+
class ConnectionWrapper(object):
def __init__(self, source=None):
self.source = source
@@ -34,19 +34,19 @@
timeout_acquire(self.source._cnxlock, 5)
self._cnx = self.source._sqlcnx
return self._cnx
-
+
def commit(self):
if self._cnx is not None:
self._cnx.commit()
-
+
def rollback(self):
if self._cnx is not None:
self._cnx.rollback()
-
+
def cursor(self):
return self.cnx.cursor()
-
+
class SQLiteAbstractSource(AbstractSource):
"""an abstract class for external sources using a sqlite database helper
"""
@@ -59,7 +59,7 @@
native.NONSYSTEM_ETYPES.add(etype)
for rtype in cls.support_relations:
native.NONSYSTEM_RELATIONS.add(rtype)
-
+
options = (
('helper-db-path',
{'type' : 'string',
@@ -69,10 +69,10 @@
'inputlevel': 2,
}),
)
-
+
def __init__(self, repo, appschema, source_config, *args, **kwargs):
# the helper db is used to easy querying and will store everything but
- # actual file content
+ # actual file content
dbpath = source_config.get('helper-db-path')
if dbpath is None:
dbpath = join(repo.config.appdatahome,
@@ -91,7 +91,7 @@
# * create the connection when needed
# * use a lock to be sure only one connection is used
self._cnxlock = threading.Lock()
-
+
@property
def _sqlcnx(self):
# XXX: sqlite connections can only be used in the same thread, so
@@ -138,13 +138,13 @@
self.repo.config['uid'])
chown(self.dbpath, self.repo.config['uid'])
restrict_perms_to_user(self.dbpath, self.info)
-
+
def set_schema(self, schema):
super(SQLiteAbstractSource, self).set_schema(schema)
if self._need_sql_create and self._is_schema_complete() and self.dbpath:
self._create_database()
self.rqlsqlgen = self.sqlgen_class(schema, self.sqladapter.dbhelper)
-
+
def get_connection(self):
return ConnectionWrapper(self)
@@ -168,11 +168,11 @@
cnx._cnx = None
finally:
self._cnxlock.release()
-
+
def syntax_tree_search(self, session, union,
args=None, cachekey=None, varmap=None, debug=0):
- """return result from this source for a rql query (actually from a rql
- syntax tree and a solution dictionary mapping each used variable to a
+ """return result from this source for a rql query (actually from a rql
+ syntax tree and a solution dictionary mapping each used variable to a
possible type). If cachekey is given, the query necessary to fetch the
results (but not the results themselves) may be cached using this key.
"""
@@ -185,7 +185,7 @@
args = self.sqladapter.merge_args(args, query_args)
cursor = session.pool[self.uri]
cursor.execute(sql, args)
- return self.sqladapter.process_result(cursor)
+ return self.sqladapter.process_result(cursor)
def local_add_entity(self, session, entity):
"""insert the entity in the local database.
@@ -198,7 +198,7 @@
attrs = self.sqladapter.preprocess_entity(entity)
sql = self.sqladapter.sqlgen.insert(SQL_PREFIX + str(entity.e_schema), attrs)
cu.execute(sql, attrs)
-
+
def add_entity(self, session, entity):
"""add a new entity to the source"""
raise NotImplementedError()
@@ -213,14 +213,14 @@
cu = session.pool[self.uri]
if attrs is None:
attrs = self.sqladapter.preprocess_entity(entity)
- sql = self.sqladapter.sqlgen.update(SQL_PREFIX + str(entity.e_schema), attrs,
- [SQL_PREFIX + 'eid'])
+ sql = self.sqladapter.sqlgen.update(SQL_PREFIX + str(entity.e_schema),
+ attrs, [SQL_PREFIX + 'eid'])
cu.execute(sql, attrs)
-
+
def update_entity(self, session, entity):
"""update an entity in the source"""
raise NotImplementedError()
-
+
def delete_entity(self, session, etype, eid):
"""delete an entity from the source
@@ -228,11 +228,11 @@
source. Main usage is to delete repository content when a Repository
entity is deleted.
"""
- sqlcursor = session.pool[self.uri]
+ sqlcursor = session.pool[self.uri]
attrs = {SQL_PREFIX + 'eid': eid}
sql = self.sqladapter.sqlgen.delete(SQL_PREFIX + etype, attrs)
sqlcursor.execute(sql, attrs)
-
+
def delete_relation(self, session, subject, rtype, object):
"""delete a relation from the source"""
rschema = self.schema.rschema(rtype)
@@ -246,5 +246,5 @@
else:
attrs = {'eid_from': subject, 'eid_to': object}
sql = self.sqladapter.sqlgen.delete('%s_relation' % rtype, attrs)
- sqlcursor = session.pool[self.uri]
+ sqlcursor = session.pool[self.uri]
sqlcursor.execute(sql, attrs)
--- a/view.py Tue Apr 28 13:28:37 2009 +0200
+++ b/view.py Tue Apr 28 19:12:52 2009 +0200
@@ -51,6 +51,7 @@
cubicweb:variables CDATA #IMPLIED
cubicweb:displayactions CDATA #IMPLIED
cubicweb:fallbackvid CDATA #IMPLIED
+ cubicweb:fname CDATA #IMPLIED
cubicweb:vid CDATA #IMPLIED
cubicweb:rql CDATA #IMPLIED
cubicweb:actualrql CDATA #IMPLIED
@@ -479,10 +480,7 @@
"""base class for components"""
__registry__ = 'components'
__select__ = yes()
- property_defs = {
- _('visible'): dict(type='Boolean', default=True,
- help=_('display the component or not')),
- }
+ property_defs = {}
def div_class(self):
return '%s %s' % (self.propval('htmlclass'), self.id)
--- a/web/box.py Tue Apr 28 13:28:37 2009 +0200
+++ b/web/box.py Tue Apr 28 19:12:52 2009 +0200
@@ -24,13 +24,13 @@
class BoxTemplate(View):
"""base template for boxes, usually a (contextual) list of possible
-
+
actions. Various classes attributes may be used to control the box
rendering.
-
+
You may override on of the formatting callbacks is this is not necessary
for your custom box.
-
+
Classes inheriting from this class usually only have to override call
to fetch desired actions, and then to do something like ::
@@ -39,7 +39,7 @@
__registry__ = 'boxes'
__select__ = match_context_prop()
registered = classmethod(require_group_compat(View.registered))
-
+
categories_in_order = ()
property_defs = {
_('visible'): dict(type='Boolean', default=True,
@@ -76,9 +76,9 @@
if escape:
title = html_escape(title)
return self.box_action(self._action(title, path, **kwargs))
-
+
def _action(self, title, path, **kwargs):
- return UnregisteredAction(self.req, self.rset, title, path, **kwargs)
+ return UnregisteredAction(self.req, self.rset, title, path, **kwargs)
# formating callbacks
@@ -91,12 +91,12 @@
cls = getattr(action, 'html_class', lambda: None)() or self.htmlitemclass
return BoxLink(action.url(), self.req._(action.title),
cls, self.boxitem_link_tooltip(action))
-
+
class RQLBoxTemplate(BoxTemplate):
"""abstract box for boxes displaying the content of a rql query not
related to the current result set.
-
+
It rely on etype, rtype (both optional, usable to control registration
according to application schema and display according to connected
user's rights) and rql attributes
@@ -104,11 +104,11 @@
#XXX __selectors__ = BoxTemplate.__selectors__ + (etype_rtype_selector,)
rql = None
-
+
def to_display_rql(self):
assert self.rql is not None, self.id
return (self.rql,)
-
+
def call(self, **kwargs):
try:
rset = self.req.execute(*self.to_display_rql())
@@ -123,7 +123,7 @@
box.append(self.mk_action(tname, entity.absolute_url()))
box.render(w=self.w)
-
+
class UserRQLBoxTemplate(RQLBoxTemplate):
"""same as rql box template but the rql is build using the eid of the
request's user
@@ -132,14 +132,14 @@
def to_display_rql(self):
assert self.rql is not None, self.id
return (self.rql, {'x': self.req.user.eid}, 'x')
-
+
class EntityBoxTemplate(BoxTemplate):
"""base class for boxes related to a single entity"""
__select__ = BoxTemplate.__select__ & one_line_rset() & primary_view()
registered = accepts_compat(has_relation_compat(condition_compat(BoxTemplate.registered)))
context = 'incontext'
-
+
def call(self, row=0, col=0, **kwargs):
"""classes inheriting from EntityBoxTemplate should define cell_call"""
self.cell_call(row, col, **kwargs)
@@ -165,7 +165,7 @@
subclasses should define at least id, rtype and target
class attributes.
"""
-
+
def cell_call(self, row, col, view=None):
self.req.add_js('cubicweb.ajax.js')
entity = self.entity(row, col)
@@ -178,7 +178,7 @@
def div_id(self):
return self.id
-
+
def box_item(self, entity, etarget, rql, label):
"""builds HTML link to edit relation between `entity` and `etarget`
"""
@@ -189,7 +189,7 @@
label = u'[<a href="%s">%s</a>] %s' % (url, label,
etarget.view('incontext'))
return RawBoxItem(label, liclass=u'invisible')
-
+
def w_related(self, box, entity):
"""appends existing relations to the `box`"""
rql = 'DELETE S %s O WHERE S eid %%(s)s, O eid %%(o)s' % self.rtype
@@ -197,7 +197,7 @@
for etarget in related:
box.append(self.box_item(entity, etarget, rql, u'-'))
return len(related)
-
+
def w_unrelated(self, box, entity):
"""appends unrelated entities to the `box`"""
rql = 'SET S %s O WHERE S eid %%(s)s, O eid %%(o)s' % self.rtype
@@ -220,7 +220,7 @@
rset = self.req.eid_rset(eid)
entities.append(rset.get_entity(0, 0))
return entities
-
+
def related_entities(self, entity):
return entity.related(self.rtype, get_role(self), entities=True)
--- a/web/component.py Tue Apr 28 13:28:37 2009 +0200
+++ b/web/component.py Tue Apr 28 19:12:52 2009 +0200
@@ -62,6 +62,11 @@
id = 'navigation'
__select__ = paginated_rset()
+ property_defs = {
+ _('visible'): dict(type='Boolean', default=True,
+ help=_('display the component or not')),
+ }
+
page_size_property = 'navigation.page-size'
start_param = '__start'
stop_param = '__stop'
--- a/web/data/cubicweb.ajax.js Tue Apr 28 13:28:37 2009 +0200
+++ b/web/data/cubicweb.ajax.js Tue Apr 28 19:12:52 2009 +0200
@@ -9,17 +9,37 @@
var JSON_BASE_URL = baseuri() + 'json?';
+function _loadAjaxHtmlHead(node, head, tag, srcattr) {
+ var loaded = [];
+ jQuery('head ' + tag).each(function(i) {
+ loaded.push(this.getAttribute(srcattr));
+ });
+ node.find(tag).each(function(i) {
+ if (!loaded.contains(this.getAttribute(srcattr))) {
+ jQuery(this).appendTo(head);
+ }
+ });
+ node.find(tag).remove();
+}
+
/*
* inspect dom response, search for a <div class="ajaxHtmlHead"> node and
* put its content into the real document's head.
* This enables dynamic css and js loading and is used by replacePageChunk
*/
function loadAjaxHtmlHead(node) {
- jQuery(node).find('div.ajaxHtmlHead').appendTo(jQuery('head'));
+ var head = jQuery('head');
+ var node = jQuery(node).find('div.ajaxHtmlHead');
+ _loadAjaxHtmlHead(node, head, 'script', 'src');
+ _loadAjaxHtmlHead(node, head, 'link', 'href');
+ node.find('*').appendTo(head);
+}
+
+function preprocessAjaxLoad(node, newdomnode) {
+ loadAjaxHtmlHead(newdomnode);
}
function postAjaxLoad(node) {
- loadAjaxHtmlHead(node);
// find sortable tables if there are some
if (typeof(Sortable) != 'undefined') {
Sortable.sortTables(node);
@@ -37,6 +57,7 @@
if (typeof roundedCornersOnLoad != 'undefined') {
roundedCornersOnLoad();
}
+ loadDynamicFragments(node);
jQuery(CubicWeb).trigger('ajax-loaded');
}
@@ -60,6 +81,7 @@
}
ajax(url, data, function(response) {
var domnode = getDomFromResponse(response);
+ preprocessAjaxLoad(node, domnode);
if (mode == 'swap') {
var origId = node.id;
node = swapDOM(node, domnode);
@@ -83,8 +105,12 @@
/* finds each dynamic fragment in the page and executes the
* the associated RQL to build them (Async call)
*/
-function loadDynamicFragments() {
- var fragments = jQuery('div.dynamicFragment');
+function loadDynamicFragments(node) {
+ if (node) {
+ var fragments = jQuery(node).find('div.dynamicFragment');
+ } else {
+ var fragments = jQuery('div.dynamicFragment');
+ }
if (fragments.length == 0) {
return;
}
@@ -106,7 +132,7 @@
}
}
-jQuery(document).ready(loadDynamicFragments);
+jQuery(document).ready(function() {loadDynamicFragments();});
//============= base AJAX functions to make remote calls =====================//
@@ -282,6 +308,7 @@
var props = {};
if (node) {
props['rql'] = rql;
+ props['fname'] = 'view';
props['pageid'] = pageid;
if (vid) { props['vid'] = vid; }
if (extraparams) { jQuery.extend(props, extraparams); }
--- a/web/form.py Tue Apr 28 13:28:37 2009 +0200
+++ b/web/form.py Tue Apr 28 19:12:52 2009 +0200
@@ -30,28 +30,6 @@
http_cache_manager = NoHTTPCacheManager
add_to_breadcrumbs = False
- def __init__(self, req, rset, **kwargs):
- super(FormViewMixIn, self).__init__(req, rset, **kwargs)
- # get validation session data which may have been previously set.
- # deleting validation errors here breaks form reloading (errors are
- # no more available), they have to be deleted by application's publish
- # method on successful commit
- formurl = req.url()
- forminfo = req.get_session_data(formurl)
- if forminfo:
- req.data['formvalues'] = forminfo['values']
- req.data['formerrors'] = errex = forminfo['errors']
- req.data['displayederrors'] = set()
- # if some validation error occured on entity creation, we have to
- # get the original variable name from its attributed eid
- foreid = errex.entity
- for var, eid in forminfo['eidmap'].items():
- if foreid == eid:
- errex.eid = var
- break
- else:
- errex.eid = foreid
-
def html_headers(self):
"""return a list of html headers (eg something to be inserted between
<head> and </head> of the returned page
@@ -80,22 +58,13 @@
self.req.set_page_data('rql_varmaker', varmaker)
self.varmaker = varmaker
- # XXX deprecated with new form system. Should disappear
-
- domid = 'entityForm'
- category = 'form'
- controller = 'edit'
- http_cache_manager = NoHTTPCacheManager
- add_to_breadcrumbs = False
-
def __init__(self, req, rset, **kwargs):
super(FormMixIn, self).__init__(req, rset, **kwargs)
# get validation session data which may have been previously set.
# deleting validation errors here breaks form reloading (errors are
# no more available), they have to be deleted by application's publish
# method on successful commit
- formurl = req.url()
- forminfo = req.get_session_data(formurl)
+ forminfo = req.get_session_data(req.url())
if forminfo:
req.data['formvalues'] = forminfo['values']
req.data['formerrors'] = errex = forminfo['errors']
@@ -110,6 +79,14 @@
else:
errex.eid = foreid
+ # XXX deprecated with new form system. Should disappear
+
+ domid = 'entityForm'
+ category = 'form'
+ controller = 'edit'
+ http_cache_manager = NoHTTPCacheManager
+ add_to_breadcrumbs = False
+
def html_headers(self):
"""return a list of html headers (eg something to be inserted between
<head> and </head> of the returned page
@@ -371,10 +348,11 @@
values found in 1. and 2. are expected te be already some 'display'
value while those found in 3. and 4. are expected to be correctly typed.
"""
- if field.name in self._previous_values:
- value = self._previous_values[field.name]
- elif field.name in self.req.form:
- value = self.req.form[field.name]
+ qname = self.form_field_name(field)
+ if qname in self._previous_values:
+ value = self._previous_values[qname]
+ elif qname in self.req.form:
+ value = self.req.form[qname]
else:
if field.name in rendervalues:
value = rendervalues[field.name]
@@ -449,6 +427,9 @@
self.form_add_hidden('__linkto', linkto)
msg = '%s %s' % (msg, self.req._('and linked'))
self.form_add_hidden('__message', msg)
+ # in case of direct instanciation
+ self.schema = self.edited_entity.schema
+ self.vreg = self.edited_entity.vreg
def _errex_match_field(self, errex, field):
"""return true if the field has some error in given validation exception
--- a/web/formfields.py Tue Apr 28 13:28:37 2009 +0200
+++ b/web/formfields.py Tue Apr 28 19:12:52 2009 +0200
@@ -220,9 +220,10 @@
else:
# else we want a format selector
# XXX compute vocabulary
- widget = Select
+ widget = Select()
fcstr = FormatConstraint()
choices = [(req._(fmt), fmt) for fmt in fcstr.vocabulary(req=req)]
+ widget.attrs['size'] = 1
field = StringField(name=self.name + '_format', widget=widget,
choices=choices)
req.data[self] = field
@@ -412,11 +413,13 @@
return value
-def stringfield_from_constraints(constraints, **kwargs):
+def stringfield_from_constraints(constraints, card, **kwargs):
field = None
for cstr in constraints:
if isinstance(cstr, StaticVocabularyConstraint):
kwargs.setdefault('widget', Select())
+ if card in '?1':
+ kwargs['widget'].attrs.setdefault('size', 1)
return StringField(choices=cstr.vocabulary, **kwargs)
if isinstance(cstr, SizeConstraint) and cstr.max is not None:
if cstr.max > 257:
@@ -478,7 +481,7 @@
return RichTextField(**kwargs)
# return StringField or TextField according to constraints
constraints = rschema.rproperty(eschema, targetschema, 'constraints')
- return stringfield_from_constraints(constraints, **kwargs)
+ return stringfield_from_constraints(constraints, card, **kwargs)
if fieldclass is FileField:
for metadata in ('format', 'encoding'):
metaschema = eschema.has_metadata(rschema, metadata)
--- a/web/uicfg.py Tue Apr 28 13:28:37 2009 +0200
+++ b/web/uicfg.py Tue Apr 28 19:12:52 2009 +0200
@@ -11,7 +11,7 @@
__docformat__ = "restructuredtext en"
from cubicweb.rtags import RelationTags
-# editforms.AutomaticEntityForm configuration #################################
+# autoform.AutomaticEntityForm configuration ##################################
# relations'category (eg primary/secondary/generic/metadata/generated)
rcategories = RelationTags()
--- a/web/views/actions.py Tue Apr 28 13:28:37 2009 +0200
+++ b/web/views/actions.py Tue Apr 28 19:12:52 2009 +0200
@@ -15,7 +15,7 @@
)
from cubicweb.web.action import Action
from cubicweb.web.views import linksearch_select_url, vid_from_rset
-from cubicweb.web.views.editforms import AutomaticEntityForm
+from cubicweb.web.views.autoform import AutomaticEntityForm
_ = unicode
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/views/autoform.py Tue Apr 28 19:12:52 2009 +0200
@@ -0,0 +1,328 @@
+"""The automatic entity form.
+
+:organization: Logilab
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
+"""
+__docformat__ = "restructuredtext en"
+
+from logilab.common.decorators import iclassmethod
+
+from cubicweb import typed_eid
+from cubicweb.web import stdmsgs, uicfg
+from cubicweb.web.form import FieldNotFound, EntityFieldsForm
+from cubicweb.web.formfields import guess_field
+from cubicweb.web.formwidgets import Button, SubmitButton
+_ = unicode
+
+class AutomaticEntityForm(EntityFieldsForm):
+ """base automatic form to edit any entity.
+
+ Designed to be flly generated from schema but highly configurable through:
+ * rtags (rcategories, rfields, rwidgets, inlined, rpermissions)
+ * various standard form parameters
+
+ You can also easily customise it by adding/removing fields in
+ AutomaticEntityForm instances.
+ """
+ id = 'edition'
+
+ cwtarget = 'eformframe'
+ cssclass = 'entityForm'
+ copy_nav_params = True
+ form_buttons = [SubmitButton(stdmsgs.BUTTON_OK),
+ Button(stdmsgs.BUTTON_APPLY, cwaction='apply'),
+ Button(stdmsgs.BUTTON_CANCEL, cwaction='cancel')]
+ attrcategories = ('primary', 'secondary')
+ # class attributes below are actually stored in the uicfg module since we
+ # don't want them to be reloaded
+ rcategories = uicfg.rcategories
+ rfields = uicfg.rfields
+ rwidgets = uicfg.rwidgets
+ rinlined = uicfg.rinlined
+ rpermissions_overrides = uicfg.rpermissions_overrides
+
+ @classmethod
+ def vreg_initialization_completed(cls):
+ """set default category tags for relations where it's not yet defined in
+ the category relation tags
+ """
+ for eschema in cls.schema.entities():
+ for rschema, tschemas, role in eschema.relation_definitions(True):
+ for tschema in tschemas:
+ if role == 'subject':
+ X, Y = eschema, tschema
+ card = rschema.rproperty(X, Y, 'cardinality')[0]
+ composed = rschema.rproperty(X, Y, 'composite') == 'object'
+ else:
+ X, Y = tschema, eschema
+ card = rschema.rproperty(X, Y, 'cardinality')[1]
+ composed = rschema.rproperty(X, Y, 'composite') == 'subject'
+ if not cls.rcategories.rtag(rschema, role, X, Y):
+ if card in '1+':
+ if not rschema.is_final() and composed:
+ category = 'generated'
+ else:
+ category = 'primary'
+ elif rschema.is_final():
+ category = 'secondary'
+ else:
+ category = 'generic'
+ cls.rcategories.set_rtag(category, rschema, role, X, Y)
+
+ @classmethod
+ def erelations_by_category(cls, entity, categories=None, permission=None, rtags=None):
+ """return a list of (relation schema, target schemas, role) matching
+ categories and permission
+ """
+ if categories is not None:
+ if not isinstance(categories, (list, tuple, set, frozenset)):
+ categories = (categories,)
+ if not isinstance(categories, (set, frozenset)):
+ categories = frozenset(categories)
+ eschema = entity.e_schema
+ if rtags is None:
+ rtags = cls.rcategories
+ permsoverrides = cls.rpermissions_overrides
+ if entity.has_eid():
+ eid = entity.eid
+ else:
+ eid = None
+ for rschema, targetschemas, role in eschema.relation_definitions(True):
+ # check category first, potentially lower cost than checking
+ # permission which may imply rql queries
+ if categories is not None:
+ targetschemas = [tschema for tschema in targetschemas
+ if rtags.etype_rtag(eschema, rschema, role, tschema) in categories]
+ if not targetschemas:
+ continue
+ if permission is not None:
+ # tag allowing to hijack the permission machinery when
+ # permission is not verifiable until the entity is actually
+ # created...
+ if eid is None and '%s_on_new' % permission in permsoverrides.etype_rtags(eschema, rschema, role):
+ yield (rschema, targetschemas, role)
+ continue
+ if rschema.is_final():
+ if not rschema.has_perm(entity.req, permission, eid):
+ continue
+ elif role == 'subject':
+ if not ((eid is None and rschema.has_local_role(permission)) or
+ rschema.has_perm(entity.req, permission, fromeid=eid)):
+ continue
+ # on relation with cardinality 1 or ?, we need delete perm as well
+ # if the relation is already set
+ if (permission == 'add'
+ and rschema.cardinality(eschema, targetschemas[0], role) in '1?'
+ and eid and entity.related(rschema.type, role)
+ and not rschema.has_perm(entity.req, 'delete', fromeid=eid,
+ toeid=entity.related(rschema.type, role)[0][0])):
+ continue
+ elif role == 'object':
+ if not ((eid is None and rschema.has_local_role(permission)) or
+ rschema.has_perm(entity.req, permission, toeid=eid)):
+ continue
+ # on relation with cardinality 1 or ?, we need delete perm as well
+ # if the relation is already set
+ if (permission == 'add'
+ and rschema.cardinality(targetschemas[0], eschema, role) in '1?'
+ and eid and entity.related(rschema.type, role)
+ and not rschema.has_perm(entity.req, 'delete', toeid=eid,
+ fromeid=entity.related(rschema.type, role)[0][0])):
+ continue
+ yield (rschema, targetschemas, role)
+
+ @classmethod
+ def esrelations_by_category(cls, entity, categories=None, permission=None):
+ """filter out result of relations_by_category(categories, permission) by
+ removing final relations
+
+ return a sorted list of (relation's label, relation'schema, role)
+ """
+ result = []
+ for rschema, ttypes, role in cls.erelations_by_category(
+ entity, categories, permission):
+ if rschema.is_final():
+ continue
+ result.append((rschema.display_name(entity.req, role), rschema, role))
+ return sorted(result)
+
+ @iclassmethod
+ def field_by_name(cls_or_self, name, role='subject', eschema=None):
+ """return field with the given name and role. If field is not explicitly
+ defined for the form but `eclass` is specified, guess_field will be
+ called.
+ """
+ try:
+ return super(AutomaticEntityForm, cls_or_self).field_by_name(name, role)
+ except FieldNotFound: # XXX should raise more explicit exception
+ if eschema is None or not name in cls_or_self.schema:
+ raise
+ rschema = cls_or_self.schema.rschema(name)
+ fieldcls = cls_or_self.rfields.etype_rtag(eschema, rschema, role)
+ if fieldcls:
+ return fieldcls(name=name, role=role, eidparam=True)
+ widget = cls_or_self.rwidgets.etype_rtag(eschema, rschema, role)
+ if widget:
+ field = guess_field(eschema, rschema, role,
+ eidparam=True, widget=widget)
+ else:
+ field = guess_field(eschema, rschema, role, eidparam=True)
+ if field is None:
+ raise
+ return field
+
+ def __init__(self, *args, **kwargs):
+ super(AutomaticEntityForm, self).__init__(*args, **kwargs)
+ entity = self.edited_entity
+ if entity.has_eid():
+ entity.complete()
+ for rschema, role in self.editable_attributes():
+ try:
+ self.field_by_name(rschema.type, role)
+ continue # explicitly specified
+ except FieldNotFound:
+ # has to be guessed
+ try:
+ field = self.field_by_name(rschema.type, role,
+ eschema=entity.e_schema)
+ self.fields.append(field)
+ except FieldNotFound:
+ # meta attribute such as <attr>_format
+ continue
+ self.maxrelitems = self.req.property_value('navigation.related-limit')
+ self.force_display = bool(self.req.form.get('__force_display'))
+
+ @property
+ def related_limit(self):
+ if self.force_display:
+ return None
+ return self.maxrelitems + 1
+
+ def relations_by_category(self, categories=None, permission=None):
+ """return a list of (relation schema, target schemas, role) matching
+ given category(ies) and permission
+ """
+ return self.erelations_by_category(self.edited_entity, categories,
+ permission)
+
+ def inlined_relations(self):
+ """return a list of (relation schema, target schemas, role) matching
+ given category(ies) and permission
+ """
+ # we'll need an initialized varmaker if there are some inlined relation
+ self.initialize_varmaker()
+ return self.erelations_by_category(self.edited_entity, True, 'add', self.rinlined)
+
+ def srelations_by_category(self, categories=None, permission=None):
+ """filter out result of relations_by_category(categories, permission) by
+ removing final relations
+
+ return a sorted list of (relation's label, relation'schema, role)
+ """
+ return self.esrelations_by_category(self.edited_entity, categories,
+ permission)
+
+ def action(self):
+ """return the form's action attribute. Default to validateform if not
+ explicitly overriden.
+ """
+ try:
+ return self._action
+ except AttributeError:
+ return self.build_url('validateform')
+
+ def set_action(self, value):
+ """override default action"""
+ self._action = value
+
+ action = property(action, set_action)
+
+ def editable_attributes(self):
+ """return a list of (relation schema, role) to edit for the entity"""
+ return [(rschema, x) for rschema, _, x in self.relations_by_category(
+ self.attrcategories, 'add') if rschema != 'eid']
+
+ def relations_table(self):
+ """yiels 3-tuples (rtype, target, related_list)
+ where <related_list> itself a list of :
+ - node_id (will be the entity element's DOM id)
+ - appropriate javascript's togglePendingDelete() function call
+ - status 'pendingdelete' or ''
+ - oneline view of related entity
+ """
+ entity = self.edited_entity
+ pending_deletes = self.req.get_pending_deletes(entity.eid)
+ for label, rschema, role in self.srelations_by_category('generic', 'add'):
+ relatedrset = entity.related(rschema, role, limit=self.related_limit)
+ if rschema.has_perm(self.req, 'delete'):
+ toggable_rel_link_func = toggable_relation_link
+ else:
+ toggable_rel_link_func = lambda x, y, z: u''
+ related = []
+ for row in xrange(relatedrset.rowcount):
+ nodeid = relation_id(entity.eid, rschema, role,
+ relatedrset[row][0])
+ if nodeid in pending_deletes:
+ status = u'pendingDelete'
+ label = '+'
+ else:
+ status = u''
+ label = 'x'
+ dellink = toggable_rel_link_func(entity.eid, nodeid, label)
+ eview = self.view('oneline', relatedrset, row=row)
+ related.append((nodeid, dellink, status, eview))
+ yield (rschema, role, related)
+
+ def restore_pending_inserts(self, cell=False):
+ """used to restore edition page as it was before clicking on
+ 'search for <some entity type>'
+ """
+ eid = self.edited_entity.eid
+ cell = cell and "div_insert_" or "tr"
+ pending_inserts = set(self.req.get_pending_inserts(eid))
+ for pendingid in pending_inserts:
+ eidfrom, rtype, eidto = pendingid.split(':')
+ if typed_eid(eidfrom) == eid: # subject
+ label = display_name(self.req, rtype, 'subject')
+ reid = eidto
+ else:
+ label = display_name(self.req, rtype, 'object')
+ reid = eidfrom
+ jscall = "javascript: cancelPendingInsert('%s', '%s', null, %s);" \
+ % (pendingid, cell, eid)
+ rset = self.req.eid_rset(reid)
+ eview = self.view('text', rset, row=0)
+ # XXX find a clean way to handle baskets
+ if rset.description[0][0] == 'Basket':
+ eview = '%s (%s)' % (eview, display_name(self.req, 'Basket'))
+ yield rtype, pendingid, jscall, label, reid, eview
+
+ # should_* method extracted to allow overriding
+
+ def should_inline_relation_form(self, rschema, targettype, role):
+ """return true if the given relation with entity has role and a
+ targettype target should be inlined
+ """
+ return self.rinlined.etype_rtag(self.edited_entity.id, rschema, role, targettype)
+
+ def should_display_inline_creation_form(self, rschema, existant, card):
+ """return true if a creation form should be inlined
+
+ by default true if there is no related entity and we need at least one
+ """
+ return not existant and card in '1+'
+
+ def should_display_add_new_relation_link(self, rschema, existant, card):
+ """return true if we should add a link to add a new creation form
+ (through ajax call)
+
+ by default true if there is no related entity or if the relation has
+ multiple cardinality
+ """
+ return not existant or card in '+*'
+
+
+def etype_relation_field(etype, rtype, role='subject'):
+ eschema = AutomaticEntityForm.schema.eschema(etype)
+ return AutomaticEntityForm.field_by_name(rtype, role, eschema)
--- a/web/views/basecomponents.py Tue Apr 28 13:28:37 2009 +0200
+++ b/web/views/basecomponents.py Tue Apr 28 19:12:52 2009 +0200
@@ -20,12 +20,16 @@
_ = unicode
+VISIBLE_PROP_DEF = {
+ _('visible'): dict(type='Boolean', default=False,
+ help=_('display the component or not')),
+ }
class RQLInputForm(Component):
"""build the rql input form, usually displayed in the header"""
id = 'rqlinput'
- visible = False
-
+ property_defs = VISIBLE_PROP_DEF
+
def call(self, view=None):
if hasattr(view, 'filter_box_context_info'):
rset = view.filter_box_context_info()[0]
@@ -53,7 +57,10 @@
class ApplLogo(Component):
"""build the application logo, usually displayed in the header"""
id = 'logo'
- site_wide = True # don't want user to hide this component using an eproperty
+ property_defs = VISIBLE_PROP_DEF
+ # don't want user to hide this component using an cwproperty
+ site_wide = True
+
def call(self):
self.w(u'<a href="%s"><img class="logo" src="%s" alt="logo"/></a>'
% (self.req.base_url(), self.req.external_resource('LOGO')))
@@ -62,6 +69,7 @@
class ApplHelp(Component):
"""build the help button, usually displayed in the header"""
id = 'help'
+ property_defs = VISIBLE_PROP_DEF
def call(self):
self.w(u'<a href="%s" class="help" title="%s"> </a>'
% (self.build_url(_restpath='doc/main'),
@@ -72,8 +80,10 @@
"""if the user is the anonymous user, build a link to login
else a link to the connected user object with a loggout link
"""
+ property_defs = VISIBLE_PROP_DEF
+ # don't want user to hide this component using an cwproperty
+ site_wide = True
id = 'loggeduserlink'
- site_wide = True # don't want user to hide this component using an eproperty
def call(self):
if not self.req.cnx.anonymous_connection:
@@ -93,7 +103,7 @@
box.render(w=self.w)
else:
self.anon_user_link()
-
+
def anon_user_link(self):
if self.config['auth-mode'] == 'cookie':
self.w(self.req._('anonymous'))
@@ -116,7 +126,9 @@
"""
__select__ = yes()
id = 'applmessages'
- site_wide = True # don't want user to hide this component using an eproperty
+ property_defs = VISIBLE_PROP_DEF
+ # don't want user to hide this component using an cwproperty
+ site_wide = True
def call(self):
msgs = [msg for msg in (self.req.get_shared_data('sources_error', pop=True),
@@ -132,11 +144,12 @@
class ApplicationName(Component):
"""display the application name"""
id = 'appliname'
+ property_defs = VISIBLE_PROP_DEF
def call(self):
self.w(u'<span id="appliName"><a href="%s">%s</a></span>' % (self.req.base_url(),
self.req.property_value('ui.site-title')))
-
+
class SeeAlsoVComponent(RelatedObjectsVComponent):
"""display any entity's see also"""
@@ -149,7 +162,7 @@
title = _('contentnavigation_seealso')
help = _('contentnavigation_seealso_description')
-
+
class EtypeRestrictionComponent(Component):
"""displays the list of entity types contained in the resultset
to be able to filter accordingly.
@@ -157,8 +170,11 @@
id = 'etypenavigation'
__select__ = two_etypes_rset() | match_form_params('__restrtype', '__restrtypes',
'__restrrql')
+ property_defs = VISIBLE_PROP_DEF
+ # don't want user to hide this component using an cwproperty
+ site_wide = True
visible = False # disabled by default
-
+
def call(self):
_ = self.req._
self.w(u'<div id="etyperestriction">')
@@ -197,7 +213,7 @@
html.insert(0, u'<span class="selected">%s</span>' % _('Any'))
self.w(u' | '.join(html))
self.w(u'</div>')
-
+
def registration_callback(vreg):
vreg.register_all(globals().values(), __name__, (SeeAlsoVComponent,))
--- a/web/views/baseforms.py Tue Apr 28 13:28:37 2009 +0200
+++ b/web/views/baseforms.py Tue Apr 28 19:12:52 2009 +0200
@@ -21,7 +21,7 @@
from cubicweb.web.controller import NAV_FORM_PARAMETERS
from cubicweb.web.widgets import checkbox, InputWidget, ComboBoxWidget
from cubicweb.web.form import FormMixIn
-from cubicweb.web.views.editforms import AutomaticEntityForm
+from cubicweb.web.views.autoform import AutomaticEntityForm
_ = unicode
--- a/web/views/baseviews.py Tue Apr 28 13:28:37 2009 +0200
+++ b/web/views/baseviews.py Tue Apr 28 19:12:52 2009 +0200
@@ -14,13 +14,11 @@
__docformat__ = "restructuredtext en"
-from warnings import warn
-
from rql import nodes
from logilab.mtconverter import TransformError, html_escape
-from cubicweb import Unauthorized, NoSelectableObject
+from cubicweb import NoSelectableObject
from cubicweb.selectors import yes, empty_rset
from cubicweb.view import EntityView, AnyRsetView, View
from cubicweb.common.uilib import cut, printable_value
@@ -101,219 +99,6 @@
self.wdata(printable_value(self.req, etype, value, props, displaytime=displaytime))
-PRIMARY_SKIP_RELS = set(['is', 'is_instance_of', 'identity',
- 'owned_by', 'created_by',
- 'in_state', 'wf_info_for', 'require_permission',
- 'from_entity', 'to_entity',
- 'see_also'])
-
-class PrimaryView(EntityView):
- """the full view of an non final entity"""
- id = 'primary'
- title = _('primary')
- show_attr_label = True
- show_rel_label = True
- skip_none = True
- skip_attrs = ('eid', 'creation_date', 'modification_date')
- skip_rels = ()
- main_related_section = True
-
- def html_headers(self):
- """return a list of html headers (eg something to be inserted between
- <head> and </head> of the returned page
-
- by default primary views are indexed
- """
- return []
-
- def cell_call(self, row, col):
- self.row = row
- # XXX move render_entity implementation here
- self.render_entity(self.complete_entity(row, col))
-
- def render_entity(self, entity):
- """return html to display the given entity"""
- siderelations = []
- self.render_entity_title(entity)
- self.render_entity_metadata(entity)
- # entity's attributes and relations, excluding meta data
- # if the entity isn't meta itself
- boxes = self._preinit_side_related(entity, siderelations)
- if boxes:
- self.w(u'<table width="100%"><tr><td width="75%">')
- self.w(u'<div>')
- self.w(u'<div class="mainInfo">')
- self.render_entity_attributes(entity, siderelations)
- self.w(u'</div>')
- self.content_navigation_components('navcontenttop')
- if self.main_related_section:
- self.render_entity_relations(entity, siderelations)
- self.w(u'</div>')
- if boxes:
- self.w(u'</td><td>')
- # side boxes
- self.w(u'<div class="primaryRight">')
- self.render_side_related(entity, siderelations)
- self.w(u'</div>')
- self.w(u'</td></tr></table>')
- self.content_navigation_components('navcontentbottom')
-
-
- def content_navigation_components(self, context):
- self.w(u'<div class="%s">' % context)
- for comp in self.vreg.possible_vobjects('contentnavigation',
- self.req, self.rset, row=self.row,
- view=self, context=context):
- try:
- comp.dispatch(w=self.w, row=self.row, view=self)
- except NotImplementedError:
- warn('component %s doesnt implement cell_call, please update'
- % comp.__class__, DeprecationWarning)
- comp.dispatch(w=self.w, view=self)
- self.w(u'</div>')
-
- def iter_attributes(self, entity):
- for rschema, targetschema in entity.e_schema.attribute_definitions():
- if rschema.type in self.skip_attrs:
- continue
- yield rschema, targetschema
-
- def iter_relations(self, entity):
- skip = set(self.skip_rels)
- skip.update(PRIMARY_SKIP_RELS)
- for rschema, targetschemas, x in entity.e_schema.relation_definitions():
- if rschema.type in skip:
- continue
- yield rschema, targetschemas, x
-
- def render_entity_title(self, entity):
- title = self.content_title(entity) # deprecate content_title?
- if title:
- self.w(u'<h1><span class="etype">%s</span> %s</h1>'
- % (entity.dc_type().capitalize(), title))
-
- def content_title(self, entity):
- """default implementation return an empty string"""
- return u''
-
- def render_entity_metadata(self, entity):
- entity.view('metadata', w=self.w)
- summary = self.summary(entity) # deprecate summary?
- if summary:
- self.w(u'<div class="summary">%s</div>' % summary)
-
- def summary(self, entity):
- """default implementation return an empty string"""
- return u''
-
- def render_entity_attributes(self, entity, siderelations):
- for rschema, targetschema in self.iter_attributes(entity):
- attr = rschema.type
- if targetschema.type in ('Password', 'Bytes'):
- continue
- try:
- wdg = entity.get_widget(attr)
- except Exception, ex:
- value = entity.printable_value(attr, entity[attr], targetschema.type)
- else:
- value = wdg.render(entity)
- if self.skip_none and (value is None or value == ''):
- continue
- if rschema.meta:
- continue
- self._render_related_entities(entity, rschema, value)
-
- def _preinit_side_related(self, entity, siderelations):
- self._sideboxes = None
- self._related_entities = []
- if hasattr(self, 'get_side_boxes_defs'):
- self._sideboxes = [(label, rset) for label, rset in self.get_side_boxes_defs(entity)
- if rset]
- else:
- eschema = entity.e_schema
- maxrelated = self.req.property_value('navigation.related-limit')
- for rschema, targetschemas, x in self.iter_relations(entity):
- try:
- related = entity.related(rschema.type, x, limit=maxrelated+1)
- except Unauthorized:
- continue
- if not related:
- continue
- if self.is_side_related(rschema, eschema):
- siderelations.append((rschema, related, x))
- continue
- self._related_entities.append((rschema, related, x))
- self._boxes_in_context = list(self.vreg.possible_vobjects('boxes', self.req, self.rset,
- row=self.row, view=self,
- context='incontext'))
- return self._sideboxes or self._boxes_in_context or self._related_entities or siderelations
-
- def render_entity_relations(self, entity, siderelations):
- if self._related_entities:
- for rschema, related, x in self._related_entities:
- self._render_related_entities(entity, rschema, related, x)
-
-
- def render_side_related(self, entity, siderelations):
- """display side related relations:
- non-meta in a first step, meta in a second step
- """
- if self._sideboxes:
- for label, rset in self._sideboxes:
- self.w(u'<div class="sideRelated">')
- self.wview('sidebox', rset, title=label)
- self.w(u'</div>')
- elif siderelations:
- self.w(u'<div class="sideRelated">')
- for relatedinfos in siderelations:
- # if not relatedinfos[0].meta:
- # continue
- self._render_related_entities(entity, *relatedinfos)
- self.w(u'</div>')
-
- if self._boxes_in_context:
- for box in self._boxes_in_context:
- try:
- box.dispatch(w=self.w, row=self.row)
- except NotImplementedError:
- # much probably a context insensitive box, which only implements
- # .call() and not cell_call()
- box.dispatch(w=self.w)
-
- def is_side_related(self, rschema, eschema):
- return rschema.meta and \
- not rschema.schema_relation() == eschema.schema_entity()
-
- def _render_related_entities(self, entity, rschema, related,
- role='subject'):
- if rschema.is_final():
- value = related
- show_label = self.show_attr_label
- else:
- if not related:
- return
- show_label = self.show_rel_label
- # if not too many entities, show them all in a list
- maxrelated = self.req.property_value('navigation.related-limit')
- if related.rowcount <= maxrelated:
- if related.rowcount == 1:
- value = self.view('incontext', related, row=0)
- elif 1 < related.rowcount <= 5:
- value = self.view('csv', related)
- else:
- value = '<div>' + self.view('simplelist', related) + '</div>'
- # else show links to display related entities
- else:
- rql = related.printable_rql()
- related.limit(maxrelated)
- value = '<div>' + self.view('simplelist', related)
- value += '[<a href="%s">%s</a>]' % (self.build_url(rql=rql),
- self.req._('see them all'))
- value += '</div>'
- label = display_name(self.req, rschema.type, role)
- self.field(label, value, show_label=show_label, tr=False)
-
-
class SecondaryView(EntityView):
id = 'secondary'
title = _('secondary')
@@ -586,7 +371,9 @@
except ImportError:
pass # gae has no tableview module (yet)
-from cubicweb.web.views import boxes, xmlrss
+from cubicweb.web.views import boxes, xmlrss, primary
+PrimaryView = class_moved(primary.PrimaryView)
+PRIMARY_SKIP_RELS = primary.PRIMARY_SKIP_RELS
SideBoxView = class_moved(boxes.SideBoxView)
XmlView = class_moved(xmlrss.XmlView)
XmlItemView = class_moved(xmlrss.XmlItemView)
--- a/web/views/bookmark.py Tue Apr 28 13:28:37 2009 +0200
+++ b/web/views/bookmark.py Tue Apr 28 19:12:52 2009 +0200
@@ -11,13 +11,11 @@
from cubicweb import Unauthorized
from cubicweb.selectors import implements
from cubicweb.web.htmlwidgets import BoxWidget, BoxMenu, RawBoxItem
-from cubicweb.web import action, formwidgets
-from cubicweb.web.box import UserRQLBoxTemplate
+from cubicweb.web import uicfg, action, box, formwidgets
from cubicweb.web.views.baseviews import PrimaryView
-from cubicweb.web.views.editforms import AutomaticEntityForm
-AutomaticEntityForm.rcategories.set_rtag('primary', 'path', 'subject', 'Bookmark')
-AutomaticEntityForm.rwidgets.set_rtag(formwidgets.TextInput, 'path', 'subject', 'Bookmark')
+uicfg.rcategories.set_rtag('primary', 'path', 'subject', 'Bookmark')
+uicfg.rwidgets.set_rtag(formwidgets.TextInput, 'path', 'subject', 'Bookmark')
class FollowAction(action.Action):
@@ -26,14 +24,14 @@
title = _('follow')
category = 'mainactions'
-
+
def url(self):
return self.rset.get_entity(self.row or 0, self.col or 0).actual_url()
class BookmarkPrimaryView(PrimaryView):
__select__ = implements('Bookmark')
-
+
def cell_call(self, row, col):
"""the primary view for bookmark entity"""
entity = self.complete_entity(row, col)
@@ -49,7 +47,7 @@
self.w(u'</div>')
-class BookmarksBox(UserRQLBoxTemplate):
+class BookmarksBox(box.UserRQLBoxTemplate):
"""display a box containing all user's bookmarks"""
id = 'bookmarks_box'
order = 40
@@ -59,8 +57,8 @@
'U eid %(x)s')
etype = 'Bookmark'
rtype = 'bookmarked_by'
-
-
+
+
def call(self, **kwargs):
req = self.req
ueid = req.user.eid
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/views/cwproperties.py Tue Apr 28 19:12:52 2009 +0200
@@ -0,0 +1,329 @@
+"""Specific views for CWProperty
+
+:organization: Logilab
+:copyright: 2007-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
+"""
+__docformat__ = "restructuredtext en"
+
+from logilab.mtconverter import html_escape
+
+from logilab.common.decorators import cached
+
+from cubicweb import UnknownProperty
+from cubicweb.selectors import (one_line_rset, none_rset, implements,
+ match_user_groups, entity_implements)
+from cubicweb.utils import UStringIO
+from cubicweb.view import StartupView
+from cubicweb.web import INTERNAL_FIELD_VALUE, eid_param, uicfg
+from cubicweb.web.views import baseviews
+from cubicweb.web import stdmsgs
+from cubicweb.web.form import CompositeForm, EntityFieldsForm, FormViewMixIn
+from cubicweb.web.formfields import FIELDS, StringField
+from cubicweb.web.formwidgets import Select, Button, SubmitButton
+
+_ = unicode
+
+# some string we want to be internationalizable for nicer display of eproperty
+# groups
+_('navigation')
+_('ui')
+_('actions')
+_('boxes')
+_('components')
+_('contentnavigation')
+
+
+def make_togglable_link(nodeid, label, cookiename):
+ """builds a HTML link that switches the visibility & remembers it"""
+ action = u"javascript: toggle_and_remember_visibility('%s', '%s')" % \
+ (nodeid, cookiename)
+ return u'<a href="%s">%s</a>' % (action, label)
+
+def css_class(someclass):
+ return someclass and 'class="%s"' % someclass or ''
+
+
+class CWPropertyPrimaryView(baseviews.PrimaryView):
+ __select__ = implements('CWProperty')
+ skip_none = False
+
+
+class SystemEPropertiesForm(FormViewMixIn, StartupView):
+ id = 'systemepropertiesform'
+ __select__ = none_rset() & match_user_groups('managers')
+
+ title = _('site configuration')
+ category = 'startupview'
+
+ def linkable(self):
+ return True
+
+ def url(self):
+ """return the url associated with this view. We can omit rql here"""
+ return self.build_url('view', vid=self.id)
+
+ def _cookie_name(self, somestr):
+ return str('%s_property_%s' % (self.config.appid, somestr))
+
+ def _group_status(self, group, default=u'hidden'):
+ """return css class name 'hidden' (collapsed), or '' (open)"""
+ cookies = self.req.get_cookie()
+ cookiename = self._cookie_name(group)
+ cookie = cookies.get(cookiename)
+ if cookie is None:
+ cookies[cookiename] = default
+ self.req.set_cookie(cookies, cookiename, maxage=None)
+ status = default
+ else:
+ status = cookie.value
+ return status
+
+ def call(self, **kwargs):
+ """The default view representing the application's index"""
+ self.req.add_js('cubicweb.preferences.js')
+ self.req.add_css('cubicweb.preferences.css')
+ vreg = self.vreg
+ values = self.defined_keys
+ groupedopts = {}
+ mainopts = {}
+ # "self.id=='systemepropertiesform'" to skip site wide properties on
+ # user's preference but not site's configuration
+ for key in vreg.user_property_keys(self.id=='systemepropertiesform'):
+ parts = key.split('.')
+ if parts[0] in vreg:
+ # appobject configuration
+ reg, oid, propid = parts
+ groupedopts.setdefault(reg, {}).setdefault(oid, []).append(key)
+ else:
+ mainopts.setdefault(parts[0], []).append(key)
+ # precompute form to consume error message
+ for group, keys in mainopts.items():
+ mainopts[group] = self.form(keys, True)
+ for group, objects in groupedopts.items():
+ for oid, keys in objects.items():
+ groupedopts[group][oid] = self.form(keys, True)
+ w = self.w
+ req = self.req
+ _ = req._
+ w(u'<h1>%s</h1>\n' % _(self.title))
+ # we don't want this in each sub-forms
+ w(u'<div id="progress">%s</div>' % self.req._('validating...'))
+ for label, group, form in sorted((_(g), g, f)
+ for g, f in mainopts.iteritems()):
+ status = css_class(self._group_status(group))
+ w(u'<h2 class="propertiesform">%s</h2>\n' %
+ (make_togglable_link('fieldset_' + group, label,
+ self._cookie_name(group))))
+ w(u'<div id="fieldset_%s" %s>' % (group, status))
+ w(form)
+ w(u'</div>')
+ for label, group, objects in sorted((_(g), g, o)
+ for g, o in groupedopts.iteritems()):
+ status = css_class(self._group_status(group))
+ w(u'<h2 class="propertiesform">%s</h2>\n' %
+ (make_togglable_link('fieldset_' + group, label,
+ self._cookie_name(group))))
+ w(u'<div id="fieldset_%s" %s>' % (group, status))
+ for label, oid, form in sorted((self.req.__('%s_%s' % (group, o)), o, f)
+ for o, f in objects.iteritems()):
+ w(u'<fieldset class="subentity">')
+ w(u'<legend class="componentTitle">%s</legend>\n' % label)
+ docmsgid = '%s_%s_description' % (group, oid)
+ doc = _(docmsgid)
+ if doc != docmsgid:
+ w(u'<p class="description">%s</p>' % html_escape(doc))
+ w(form)
+ w(u'</fieldset>')
+ w(u'</div>')
+
+ @property
+ @cached
+ def eprops_rset(self):
+ return self.req.execute('Any P,K,V WHERE P is CWProperty, P pkey K, '
+ 'P value V, NOT P for_user U')
+
+ @property
+ def defined_keys(self):
+ values = {}
+ for i, entity in enumerate(self.eprops_rset.entities()):
+ values[entity.pkey] = i
+ return values
+
+ def entity_for_key(self, key):
+ values = self.defined_keys
+ if key in values:
+ entity = self.eprops_rset.get_entity(values[key], 0)
+ else:
+ entity = self.vreg.etype_class('CWProperty')(self.req, None, None)
+ entity.eid = self.req.varmaker.next()
+ entity['pkey'] = key
+ entity['value'] = self.vreg.property_value(key)
+ return entity
+
+ def form(self, keys, splitlabel=False):
+ buttons = [SubmitButton(),
+ Button(stdmsgs.BUTTON_CANCEL, cwaction='cancel')]
+ form = CompositeForm(self.req, domid=None, action=self.build_url(),
+ form_buttons=buttons,
+ submitmsg=self.req._('changes applied'))
+ path = self.req.relative_path()
+ if '?' in path:
+ path, params = path.split('?', 1)
+ form.form_add_hidden('__redirectparams', params)
+ form.form_add_hidden('__redirectpath', path)
+ for key in keys:
+ self.form_row(form, key, splitlabel)
+ return form.form_render(display_progress_div=False)
+
+ def form_row(self, form, key, splitlabel):
+ entity = self.entity_for_key(key)
+ if splitlabel:
+ label = key.split('.')[-1]
+ else:
+ label = key
+ subform = EntityFieldsForm(self.req, entity=entity, set_error_url=False)
+ subform.append_field(PropertyValueField(name='value', label=label,
+ eidparam=True))
+ subform.vreg = self.vreg
+ subform.form_add_hidden('pkey', key, eidparam=True)
+ form.form_add_subform(subform)
+ return subform
+
+
+def is_user_prefs(cls, req, rset, row=None, col=0, **kwargs):
+ return req.user.eid == rset[row or 0][col]
+
+
+class EPropertiesForm(SystemEPropertiesForm):
+ id = 'epropertiesform'
+ __select__ = (
+ # we don't want guests to be able to come here
+ match_user_groups('users', 'managers') &
+ (none_rset() | ((one_line_rset() & is_user_prefs) &
+ (one_line_rset() & match_user_groups('managers'))))
+ )
+
+ title = _('preferences')
+
+ @property
+ def user(self):
+ if self.rset is None:
+ return self.req.user
+ return self.rset.get_entity(self.row or 0, self.col or 0)
+
+ @property
+ @cached
+ def eprops_rset(self):
+ return self.req.execute('Any P,K,V WHERE P is CWProperty, P pkey K, P value V,'
+ 'P for_user U, U eid %(x)s', {'x': self.user.eid})
+
+ def form_row(self, form, key, splitlabel):
+ subform = super(EPropertiesForm, self).form_row(form, key, splitlabel)
+ # if user is in the managers group and the property is being created,
+ # we have to set for_user explicitly
+ if not subform.edited_entity.has_eid() and self.user.matching_groups('managers'):
+ subform.form_add_hidden('for_user', self.user.eid, eidparam=True)
+
+
+# eproperty form objects ######################################################
+
+class PlaceHolderWidget(object):
+
+ def render(self, form, field):
+ domid = form.context[field]['id']
+ # empty span as well else html validation fail (label is refering to
+ # this id)
+ return '<div id="div:%s"><span id="%s">%s</span></div>' % (
+ domid, domid, form.req._('select a key first'))
+
+
+class NotEditableWidget(object):
+ def __init__(self, value, msg=None):
+ self.value = value
+ self.msg = msg
+
+ def render(self, form, field):
+ domid = form.context[field]['id']
+ value = '<span class="value" id="%s">%s</span>' % (domid, self.value)
+ if self.msg:
+ value + '<div class="helper">%s</div>' % self.msg
+ return value
+
+
+class PropertyKeyField(StringField):
+ """specific field for CWProperty.pkey to set the value widget according to
+ the selected key
+ """
+ widget = Select
+
+ def render(self, form, renderer):
+ wdg = self.get_widget(form)
+ wdg.attrs['tabindex'] = form.req.next_tabindex()
+ wdg.attrs['onchange'] = "javascript:setPropValueWidget('%s', %s)" % (
+ form.edited_entity.eid, form.req.next_tabindex())
+ return wdg.render(form, self)
+
+ def vocabulary(self, form):
+ entity = form.edited_entity
+ _ = form.req._
+ if entity.has_eid():
+ return [(_(entity.pkey), entity.pkey)]
+ # key beginning with 'system.' should usually not be edited by hand
+ choices = entity.vreg.user_property_keys()
+ return [(u'', u'')] + sorted(zip((_(v) for v in choices), choices))
+
+
+class PropertyValueField(StringField):
+ """specific field for CWProperty.value which will be different according to
+ the selected key type and vocabulary information
+ """
+ widget = PlaceHolderWidget
+
+ def render(self, form, renderer=None, tabindex=None):
+ wdg = self.get_widget(form)
+ if tabindex is not None:
+ wdg.attrs['tabindex'] = tabindex
+ return wdg.render(form, self)
+
+ def form_init(self, form):
+ entity = form.edited_entity
+ if not (entity.has_eid() or 'pkey' in entity):
+ # no key set yet, just include an empty div which will be filled
+ # on key selection
+ return
+ try:
+ pdef = form.vreg.property_info(entity.pkey)
+ except UnknownProperty, ex:
+ self.warning('%s (you should probably delete that property '
+ 'from the database)', ex)
+ msg = form.req._('you should probably delete that property')
+ self.widget = NotEditableWidget(entity.printable_value('value'),
+ '%s (%s)' % (msg, ex))
+ if entity.pkey.startswith('system.'):
+ msg = form.req._('value associated to this key is not editable '
+ 'manually')
+ self.widget = NotEditableWidget(entity.printable_value('value'), msg)
+ # XXX race condition when used from CWPropertyForm, should not rely on
+ # instance attributes
+ self.initial = pdef['default']
+ self.help = pdef['help']
+ vocab = pdef['vocabulary']
+ if vocab is not None:
+ if callable(vocab):
+ # list() just in case its a generator function
+ self.choices = list(vocab(form.req))
+ else:
+ self.choices = vocab
+ wdg = Select()
+ else:
+ wdg = FIELDS[pdef['type']].widget()
+ if pdef['type'] == 'Boolean':
+ self.choices = [(form.req._('yes'), '1'), (form.req._('no'), '')]
+ elif pdef['type'] in ('Float', 'Int'):
+ wdg.attrs.setdefault('size', 3)
+ self.widget = wdg
+
+uicfg.rfields.set_rtag(PropertyKeyField, 'pkey', 'subject', 'CWProperty')
+uicfg.rfields.set_rtag(PropertyValueField, 'value', 'subject', 'CWProperty')
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/views/cwuser.py Tue Apr 28 19:12:52 2009 +0200
@@ -0,0 +1,102 @@
+"""Specific views for users
+
+:organization: Logilab
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
+"""
+__docformat__ = "restructuredtext en"
+
+from logilab.mtconverter import html_escape
+
+from cubicweb.selectors import one_line_rset, implements, match_user_groups
+from cubicweb.view import EntityView
+from cubicweb.web import uicfg, action
+from cubicweb.web.views.baseviews import PrimaryView
+
+
+uicfg.rcategories.set_rtag('secondary', 'firstname', 'subject', 'CWUser')
+uicfg.rcategories.set_rtag('secondary', 'surname', 'subject', 'CWUser')
+uicfg.rcategories.set_rtag('metadata', 'last_login_time', 'subject', 'CWUser')
+uicfg.rcategories.set_rtag('primary', 'in_group', 'subject', 'CWUser')
+uicfg.rcategories.set_rtag('generated', 'owned_by', 'object', otype='CWUser')
+uicfg.rcategories.set_rtag('generated', 'created_by', 'object', otype='CWUser')
+uicfg.rcategories.set_rtag('metadata', 'bookmarked_by', 'object', otype='CWUser')
+uicfg.rinlined.set_rtag(True, 'use_email', 'subject', 'CWUser')
+uicfg.rmode.set_rtag('create', 'in_group', 'object', otype='CWGroup')
+uicfg.rmode.set_rtag('link', 'owned_by', 'object', otype='CWUser')
+uicfg.rmode.set_rtag('link', 'created_by', 'object', otype='CWUser')
+uicfg.rmode.set_rtag('create', 'bookmarked_by', 'object', otype='CWUser')
+
+
+class UserPreferencesEntityAction(action.Action):
+ id = 'prefs'
+ __select__ = (one_line_rset() & implements('CWUser') &
+ match_user_groups('owners', 'managers'))
+
+ title = _('preferences')
+ category = 'mainactions'
+
+ def url(self):
+ login = self.rset.get_entity(self.row or 0, self.col or 0).login
+ return self.build_url('euser/%s'%login, vid='epropertiesform')
+
+
+class CWUserPrimaryView(PrimaryView):
+ __select__ = implements('CWUser')
+
+ skip_attrs = ('firstname', 'surname')
+
+ def iter_relations(self, entity):
+ # don't want to display user's entities
+ for rschema, targetschemas, x in super(CWUserPrimaryView, self).iter_relations(entity):
+ if x == 'object' and rschema.type in ('owned_by', 'for_user'):
+ continue
+ yield rschema, targetschemas, x
+
+ def content_title(self, entity):
+ return entity.name()
+
+ def is_side_related(self, rschema, eschema):
+ # XXX only bookmarked_by defined in cw...
+ return rschema.type in ['interested_in', 'tags',
+ 'todo_by', 'bookmarked_by']
+
+
+class FoafView(EntityView):
+ id = 'foaf'
+ __select__ = implements('CWUser')
+
+ title = _('foaf')
+ templatable = False
+ content_type = 'text/xml'
+
+ def call(self):
+ self.w(u'''<?xml version="1.0" encoding="%s"?>
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:rdfs="http://www.w3org/2000/01/rdf-schema#"
+ xmlns:foaf="http://xmlns.com/foaf/0.1/"> '''% self.req.encoding)
+ for i in xrange(self.rset.rowcount):
+ self.cell_call(i, 0)
+ self.w(u'</rdf:RDF>\n')
+
+ def cell_call(self, row, col):
+ entity = self.complete_entity(row, col)
+ self.w(u'''<foaf:PersonalProfileDocument rdf:about="">
+ <foaf:maker rdf:resource="%s"/>
+ <foaf:primaryTopic rdf:resource="%s"/>
+ </foaf:PersonalProfileDocument>''' % (entity.absolute_url(), entity.absolute_url()))
+ self.w(u'<foaf:Person rdf:ID="%s">\n' % entity.eid)
+ self.w(u'<foaf:name>%s</foaf:name>\n' % html_escape(entity.dc_long_title()))
+ if entity.surname:
+ self.w(u'<foaf:family_name>%s</foaf:family_name>\n'
+ % html_escape(entity.surname))
+ if entity.firstname:
+ self.w(u'<foaf:givenname>%s</foaf:givenname>\n'
+ % html_escape(entity.firstname))
+ emailaddr = entity.get_email()
+ if emailaddr:
+ self.w(u'<foaf:mbox>%s</foaf:mbox>\n' % html_escape(emailaddr))
+ self.w(u'</foaf:Person>\n')
+
+from logilab.common.deprecation import class_renamed
+EUserPrimaryView = class_renamed('EUserPrimaryView', CWUserPrimaryView)
--- a/web/views/editforms.py Tue Apr 28 13:28:37 2009 +0200
+++ b/web/views/editforms.py Tue Apr 28 19:12:52 2009 +0200
@@ -11,23 +11,20 @@
from simplejson import dumps
-from logilab.common.decorators import iclassmethod
from logilab.mtconverter import html_escape
-from cubicweb import typed_eid
from cubicweb.selectors import (match_kwargs, one_line_rset, non_final_entity,
specified_etype_implements, yes)
from cubicweb.utils import make_uid
from cubicweb.view import EntityView
from cubicweb.common import tags
-from cubicweb.web import INTERNAL_FIELD_VALUE, stdmsgs, uicfg
-from cubicweb.web.form import (FieldNotFound, CompositeForm, EntityFieldsForm,
- FormViewMixIn)
-from cubicweb.web.formfields import guess_field
+from cubicweb.web import stdmsgs
+from cubicweb.web.form import CompositeForm, EntityFieldsForm, FormViewMixIn
from cubicweb.web.formwidgets import Button, SubmitButton, ResetButton
from cubicweb.web.formrenderers import (FormRenderer, EntityFormRenderer,
EntityCompositeFormRenderer,
EntityInlinedFormRenderer)
+
_ = unicode
def relation_id(eid, rtype, role, reid):
@@ -125,317 +122,6 @@
self.w(form.form_render(renderer=renderer))
-class AutomaticEntityForm(EntityFieldsForm):
- """base automatic form to edit any entity
-
- Designed to be flly generated from schema but highly configurable through:
- * rtags (rcategories, rfields, rwidgets, inlined, rpermissions)
- * various standard form parameters
-
- You can also easily customise it by adding/removing fields in
- AutomaticEntityForm instances.
- """
- id = 'edition'
-
- cwtarget = 'eformframe'
- cssclass = 'entityForm'
- copy_nav_params = True
- form_buttons = [SubmitButton(stdmsgs.BUTTON_OK),
- Button(stdmsgs.BUTTON_APPLY, cwaction='apply'),
- Button(stdmsgs.BUTTON_CANCEL, cwaction='cancel')]
- attrcategories = ('primary', 'secondary')
- # class attributes below are actually stored in the uicfg module since we
- # don't want them to be reloaded
- rcategories = uicfg.rcategories
- rfields = uicfg.rfields
- rwidgets = uicfg.rwidgets
- rinlined = uicfg.rinlined
- rpermissions_overrides = uicfg.rpermissions_overrides
-
- @classmethod
- def vreg_initialization_completed(cls):
- """set default category tags for relations where it's not yet defined in
- the category relation tags
- """
- for eschema in cls.schema.entities():
- for rschema, tschemas, role in eschema.relation_definitions(True):
- for tschema in tschemas:
- if role == 'subject':
- X, Y = eschema, tschema
- card = rschema.rproperty(X, Y, 'cardinality')[0]
- composed = rschema.rproperty(X, Y, 'composite') == 'object'
- else:
- X, Y = tschema, eschema
- card = rschema.rproperty(X, Y, 'cardinality')[1]
- composed = rschema.rproperty(X, Y, 'composite') == 'subject'
- if not cls.rcategories.rtag(rschema, role, X, Y):
- if card in '1+':
- if not rschema.is_final() and composed:
- category = 'generated'
- else:
- category = 'primary'
- elif rschema.is_final():
- category = 'secondary'
- else:
- category = 'generic'
- cls.rcategories.set_rtag(category, rschema, role, X, Y)
-
- @classmethod
- def erelations_by_category(cls, entity, categories=None, permission=None, rtags=None):
- """return a list of (relation schema, target schemas, role) matching
- categories and permission
- """
- if categories is not None:
- if not isinstance(categories, (list, tuple, set, frozenset)):
- categories = (categories,)
- if not isinstance(categories, (set, frozenset)):
- categories = frozenset(categories)
- eschema = entity.e_schema
- if rtags is None:
- rtags = cls.rcategories
- permsoverrides = cls.rpermissions_overrides
- if entity.has_eid():
- eid = entity.eid
- else:
- eid = None
- for rschema, targetschemas, role in eschema.relation_definitions(True):
- # check category first, potentially lower cost than checking
- # permission which may imply rql queries
- if categories is not None:
- targetschemas = [tschema for tschema in targetschemas
- if rtags.etype_rtag(eschema, rschema, role, tschema) in categories]
- if not targetschemas:
- continue
- if permission is not None:
- # tag allowing to hijack the permission machinery when
- # permission is not verifiable until the entity is actually
- # created...
- if eid is None and '%s_on_new' % permission in permsoverrides.etype_rtags(eschema, rschema, role):
- yield (rschema, targetschemas, role)
- continue
- if rschema.is_final():
- if not rschema.has_perm(entity.req, permission, eid):
- continue
- elif role == 'subject':
- if not ((eid is None and rschema.has_local_role(permission)) or
- rschema.has_perm(entity.req, permission, fromeid=eid)):
- continue
- # on relation with cardinality 1 or ?, we need delete perm as well
- # if the relation is already set
- if (permission == 'add'
- and rschema.cardinality(eschema, targetschemas[0], role) in '1?'
- and eid and entity.related(rschema.type, role)
- and not rschema.has_perm(entity.req, 'delete', fromeid=eid,
- toeid=entity.related(rschema.type, role)[0][0])):
- continue
- elif role == 'object':
- if not ((eid is None and rschema.has_local_role(permission)) or
- rschema.has_perm(entity.req, permission, toeid=eid)):
- continue
- # on relation with cardinality 1 or ?, we need delete perm as well
- # if the relation is already set
- if (permission == 'add'
- and rschema.cardinality(targetschemas[0], eschema, role) in '1?'
- and eid and entity.related(rschema.type, role)
- and not rschema.has_perm(entity.req, 'delete', toeid=eid,
- fromeid=entity.related(rschema.type, role)[0][0])):
- continue
- yield (rschema, targetschemas, role)
-
- @classmethod
- def esrelations_by_category(cls, entity, categories=None, permission=None):
- """filter out result of relations_by_category(categories, permission) by
- removing final relations
-
- return a sorted list of (relation's label, relation'schema, role)
- """
- result = []
- for rschema, ttypes, role in cls.erelations_by_category(
- entity, categories, permission):
- if rschema.is_final():
- continue
- result.append((rschema.display_name(entity.req, role), rschema, role))
- return sorted(result)
-
- @iclassmethod
- def field_by_name(cls_or_self, name, role='subject', eschema=None):
- """return field with the given name and role. If field is not explicitly
- defined for the form but `eclass` is specified, guess_field will be
- called.
- """
- try:
- return super(AutomaticEntityForm, cls_or_self).field_by_name(name, role)
- except FieldNotFound: # XXX should raise more explicit exception
- if eschema is None or not name in cls_or_self.schema:
- raise
- rschema = cls_or_self.schema.rschema(name)
- fieldcls = cls_or_self.rfields.etype_rtag(eschema, rschema, role)
- if fieldcls:
- return fieldcls(name=name, role=role, eidparam=True)
- widget = cls_or_self.rwidgets.etype_rtag(eschema, rschema, role)
- if widget:
- field = guess_field(eschema, rschema, role,
- eidparam=True, widget=widget)
- else:
- field = guess_field(eschema, rschema, role, eidparam=True)
- if field is None:
- raise
- return field
-
- def __init__(self, *args, **kwargs):
- super(AutomaticEntityForm, self).__init__(*args, **kwargs)
- entity = self.edited_entity
- if entity.has_eid():
- entity.complete()
- for rschema, role in self.editable_attributes():
- try:
- self.field_by_name(rschema.type, role)
- continue # explicitly specified
- except FieldNotFound:
- # has to be guessed
- try:
- field = self.field_by_name(rschema.type, role,
- eschema=entity.e_schema)
- self.fields.append(field)
- except FieldNotFound:
- # meta attribute such as <attr>_format
- continue
- self.maxrelitems = self.req.property_value('navigation.related-limit')
- self.force_display = bool(self.req.form.get('__force_display'))
-
- @property
- def related_limit(self):
- if self.force_display:
- return None
- return self.maxrelitems + 1
-
- def relations_by_category(self, categories=None, permission=None):
- """return a list of (relation schema, target schemas, role) matching
- given category(ies) and permission
- """
- return self.erelations_by_category(self.edited_entity, categories,
- permission)
-
- def inlined_relations(self):
- """return a list of (relation schema, target schemas, role) matching
- given category(ies) and permission
- """
- # we'll need an initialized varmaker if there are some inlined relation
- self.initialize_varmaker()
- return self.erelations_by_category(self.edited_entity, True, 'add', self.rinlined)
-
- def srelations_by_category(self, categories=None, permission=None):
- """filter out result of relations_by_category(categories, permission) by
- removing final relations
-
- return a sorted list of (relation's label, relation'schema, role)
- """
- return self.esrelations_by_category(self.edited_entity, categories,
- permission)
-
- def action(self):
- """return the form's action attribute. Default to validateform if not
- explicitly overriden.
- """
- try:
- return self._action
- except AttributeError:
- return self.build_url('validateform')
-
- def set_action(self, value):
- """override default action"""
- self._action = value
-
- action = property(action, set_action)
-
- def editable_attributes(self):
- """return a list of (relation schema, role) to edit for the entity"""
- return [(rschema, x) for rschema, _, x in self.relations_by_category(
- self.attrcategories, 'add') if rschema != 'eid']
-
- def relations_table(self):
- """yiels 3-tuples (rtype, target, related_list)
- where <related_list> itself a list of :
- - node_id (will be the entity element's DOM id)
- - appropriate javascript's togglePendingDelete() function call
- - status 'pendingdelete' or ''
- - oneline view of related entity
- """
- entity = self.edited_entity
- pending_deletes = self.req.get_pending_deletes(entity.eid)
- for label, rschema, role in self.srelations_by_category('generic', 'add'):
- relatedrset = entity.related(rschema, role, limit=self.related_limit)
- if rschema.has_perm(self.req, 'delete'):
- toggable_rel_link_func = toggable_relation_link
- else:
- toggable_rel_link_func = lambda x, y, z: u''
- related = []
- for row in xrange(relatedrset.rowcount):
- nodeid = relation_id(entity.eid, rschema, role,
- relatedrset[row][0])
- if nodeid in pending_deletes:
- status = u'pendingDelete'
- label = '+'
- else:
- status = u''
- label = 'x'
- dellink = toggable_rel_link_func(entity.eid, nodeid, label)
- eview = self.view('oneline', relatedrset, row=row)
- related.append((nodeid, dellink, status, eview))
- yield (rschema, role, related)
-
- def restore_pending_inserts(self, cell=False):
- """used to restore edition page as it was before clicking on
- 'search for <some entity type>'
- """
- eid = self.edited_entity.eid
- cell = cell and "div_insert_" or "tr"
- pending_inserts = set(self.req.get_pending_inserts(eid))
- for pendingid in pending_inserts:
- eidfrom, rtype, eidto = pendingid.split(':')
- if typed_eid(eidfrom) == eid: # subject
- label = display_name(self.req, rtype, 'subject')
- reid = eidto
- else:
- label = display_name(self.req, rtype, 'object')
- reid = eidfrom
- jscall = "javascript: cancelPendingInsert('%s', '%s', null, %s);" \
- % (pendingid, cell, eid)
- rset = self.req.eid_rset(reid)
- eview = self.view('text', rset, row=0)
- # XXX find a clean way to handle baskets
- if rset.description[0][0] == 'Basket':
- eview = '%s (%s)' % (eview, display_name(self.req, 'Basket'))
- yield rtype, pendingid, jscall, label, reid, eview
-
- # should_* method extracted to allow overriding
-
- def should_inline_relation_form(self, rschema, targettype, role):
- """return true if the given relation with entity has role and a
- targettype target should be inlined
- """
- return self.rinlined.etype_rtag(self.edited_entity.id, rschema, role, targettype)
-
- def should_display_inline_creation_form(self, rschema, existant, card):
- """return true if a creation form should be inlined
-
- by default true if there is no related entity and we need at least one
- """
- return not existant and card in '1+'
-
- def should_display_add_new_relation_link(self, rschema, existant, card):
- """return true if we should add a link to add a new creation form
- (through ajax call)
-
- by default true if there is no related entity or if the relation has
- multiple cardinality
- """
- return not existant or card in '+*'
-
-def etype_relation_field(etype, rtype, role='subject'):
- eschema = AutomaticEntityForm.schema.eschema(etype)
- return AutomaticEntityForm.field_by_name(rtype, role, eschema)
-
class EditionFormView(FormViewMixIn, EntityView):
"""display primary entity edition form"""
id = 'edition'
--- a/web/views/emailaddress.py Tue Apr 28 13:28:37 2009 +0200
+++ b/web/views/emailaddress.py Tue Apr 28 19:12:52 2009 +0200
@@ -11,16 +11,15 @@
from cubicweb.selectors import implements
from cubicweb.common import Unauthorized
from cubicweb.web.views import baseviews
-from cubicweb.web.views.editforms import AutomaticEntityForm
class EmailAddressPrimaryView(baseviews.PrimaryView):
__select__ = implements('EmailAddress')
-
+
def cell_call(self, row, col, skipeids=None):
self.skipeids = skipeids
super(EmailAddressPrimaryView, self).cell_call(row, col)
-
+
def render_entity_attributes(self, entity, siderelations):
self.w(u'<h3>')
entity.view('oneline', w=self.w)
@@ -70,10 +69,10 @@
entity.view('oneline', w=self.w)
self.w(u'</h5>')
-
+
class EmailAddressOneLineView(baseviews.OneLineView):
__select__ = implements('EmailAddress')
-
+
def cell_call(self, row, col, **kwargs):
entity = self.entity(row, col)
if entity.reverse_primary_email:
@@ -93,7 +92,7 @@
id = 'mailto'
__select__ = implements('EmailAddress')
-
+
def cell_call(self, row, col, **kwargs):
entity = self.entity(row, col)
if entity.reverse_primary_email:
@@ -108,15 +107,15 @@
mailto = "mailto:%s" % entity.display_address()
self.w(u'<a href="%s">%s</a>' % (html_escape(mailto),
html_escape(entity.display_address())))
-
+
if entity.alias:
self.w(u'>\n')
if entity.reverse_primary_email:
self.w(u'</b>')
-
+
class EmailAddressTextView(baseviews.TextView):
__select__ = implements('EmailAddress')
-
+
def cell_call(self, row, col, **kwargs):
self.w(self.entity(row, col).display_address())
--- a/web/views/eproperties.py Tue Apr 28 13:28:37 2009 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,330 +0,0 @@
-"""Specific views for CWProperty
-
-:organization: Logilab
-:copyright: 2007-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
-:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
-"""
-__docformat__ = "restructuredtext en"
-
-from logilab.mtconverter import html_escape
-
-from logilab.common.decorators import cached
-
-from cubicweb import UnknownProperty
-from cubicweb.selectors import (one_line_rset, none_rset, implements,
- match_user_groups, entity_implements)
-from cubicweb.utils import UStringIO
-from cubicweb.view import StartupView
-from cubicweb.web import INTERNAL_FIELD_VALUE, eid_param, uicfg
-from cubicweb.web.views import baseviews
-from cubicweb.web import stdmsgs
-from cubicweb.web.form import CompositeForm, EntityFieldsForm, FormViewMixIn
-from cubicweb.web.formfields import FIELDS, StringField
-from cubicweb.web.formwidgets import Select, Button, SubmitButton
-from cubicweb.web.views.editforms import AutomaticEntityForm
-
-_ = unicode
-
-# some string we want to be internationalizable for nicer display of eproperty
-# groups
-_('navigation')
-_('ui')
-_('actions')
-_('boxes')
-_('components')
-_('contentnavigation')
-
-
-def make_togglable_link(nodeid, label, cookiename):
- """builds a HTML link that switches the visibility & remembers it"""
- action = u"javascript: toggle_and_remember_visibility('%s', '%s')" % \
- (nodeid, cookiename)
- return u'<a href="%s">%s</a>' % (action, label)
-
-def css_class(someclass):
- return someclass and 'class="%s"' % someclass or ''
-
-
-class CWPropertyPrimaryView(baseviews.PrimaryView):
- __select__ = implements('CWProperty')
- skip_none = False
-
-
-class SystemEPropertiesForm(FormViewMixIn, StartupView):
- id = 'systemepropertiesform'
- __select__ = none_rset() & match_user_groups('managers')
-
- title = _('site configuration')
- category = 'startupview'
-
- def linkable(self):
- return True
-
- def url(self):
- """return the url associated with this view. We can omit rql here"""
- return self.build_url('view', vid=self.id)
-
- def _cookie_name(self, somestr):
- return str('%s_property_%s' % (self.config.appid, somestr))
-
- def _group_status(self, group, default=u'hidden'):
- """return css class name 'hidden' (collapsed), or '' (open)"""
- cookies = self.req.get_cookie()
- cookiename = self._cookie_name(group)
- cookie = cookies.get(cookiename)
- if cookie is None:
- cookies[cookiename] = default
- self.req.set_cookie(cookies, cookiename, maxage=None)
- status = default
- else:
- status = cookie.value
- return status
-
- def call(self, **kwargs):
- """The default view representing the application's index"""
- self.req.add_js('cubicweb.preferences.js')
- self.req.add_css('cubicweb.preferences.css')
- vreg = self.vreg
- values = self.defined_keys
- groupedopts = {}
- mainopts = {}
- # "self.id=='systemepropertiesform'" to skip site wide properties on
- # user's preference but not site's configuration
- for key in vreg.user_property_keys(self.id=='systemepropertiesform'):
- parts = key.split('.')
- if parts[0] in vreg:
- # appobject configuration
- reg, oid, propid = parts
- groupedopts.setdefault(reg, {}).setdefault(oid, []).append(key)
- else:
- mainopts.setdefault(parts[0], []).append(key)
- # precompute form to consume error message
- for group, keys in mainopts.items():
- mainopts[group] = self.form(keys, True)
- for group, objects in groupedopts.items():
- for oid, keys in objects.items():
- groupedopts[group][oid] = self.form(keys, True)
- w = self.w
- req = self.req
- _ = req._
- w(u'<h1>%s</h1>\n' % _(self.title))
- # we don't want this in each sub-forms
- w(u'<div id="progress">%s</div>' % self.req._('validating...'))
- for label, group, form in sorted((_(g), g, f)
- for g, f in mainopts.iteritems()):
- status = css_class(self._group_status(group))
- w(u'<h2 class="propertiesform">%s</h2>\n' %
- (make_togglable_link('fieldset_' + group, label,
- self._cookie_name(group))))
- w(u'<div id="fieldset_%s" %s>' % (group, status))
- w(form)
- w(u'</div>')
- for label, group, objects in sorted((_(g), g, o)
- for g, o in groupedopts.iteritems()):
- status = css_class(self._group_status(group))
- w(u'<h2 class="propertiesform">%s</h2>\n' %
- (make_togglable_link('fieldset_' + group, label,
- self._cookie_name(group))))
- w(u'<div id="fieldset_%s" %s>' % (group, status))
- for label, oid, form in sorted((self.req.__('%s_%s' % (group, o)), o, f)
- for o, f in objects.iteritems()):
- w(u'<fieldset class="subentity">')
- w(u'<legend class="componentTitle">%s</legend>\n' % label)
- docmsgid = '%s_%s_description' % (group, oid)
- doc = _(docmsgid)
- if doc != docmsgid:
- w(u'<p class="description">%s</p>' % html_escape(doc))
- w(form)
- w(u'</fieldset>')
- w(u'</div>')
-
- @property
- @cached
- def eprops_rset(self):
- return self.req.execute('Any P,K,V WHERE P is CWProperty, P pkey K, '
- 'P value V, NOT P for_user U')
-
- @property
- def defined_keys(self):
- values = {}
- for i, entity in enumerate(self.eprops_rset.entities()):
- values[entity.pkey] = i
- return values
-
- def entity_for_key(self, key):
- values = self.defined_keys
- if key in values:
- entity = self.eprops_rset.get_entity(values[key], 0)
- else:
- entity = self.vreg.etype_class('CWProperty')(self.req, None, None)
- entity.eid = self.req.varmaker.next()
- entity['pkey'] = key
- entity['value'] = self.vreg.property_value(key)
- return entity
-
- def form(self, keys, splitlabel=False):
- buttons = [SubmitButton(),
- Button(stdmsgs.BUTTON_CANCEL, cwaction='cancel')]
- form = CompositeForm(self.req, domid=None, action=self.build_url(),
- form_buttons=buttons,
- submitmsg=self.req._('changes applied'))
- path = self.req.relative_path()
- if '?' in path:
- path, params = path.split('?', 1)
- form.form_add_hidden('__redirectparams', params)
- form.form_add_hidden('__redirectpath', path)
- for key in keys:
- self.form_row(form, key, splitlabel)
- return form.form_render(display_progress_div=False)
-
- def form_row(self, form, key, splitlabel):
- entity = self.entity_for_key(key)
- if splitlabel:
- label = key.split('.')[-1]
- else:
- label = key
- subform = EntityFieldsForm(self.req, entity=entity, set_error_url=False)
- subform.append_field(PropertyValueField(name='value', label=label,
- eidparam=True))
- subform.vreg = self.vreg
- subform.form_add_hidden('pkey', key, eidparam=True)
- form.form_add_subform(subform)
- return subform
-
-
-def is_user_prefs(cls, req, rset, row=None, col=0, **kwargs):
- return req.user.eid == rset[row or 0][col]
-
-
-class EPropertiesForm(SystemEPropertiesForm):
- id = 'epropertiesform'
- __select__ = (
- # we don't want guests to be able to come here
- match_user_groups('users', 'managers') &
- (none_rset() | ((one_line_rset() & is_user_prefs) &
- (one_line_rset() & match_user_groups('managers'))))
- )
-
- title = _('preferences')
-
- @property
- def user(self):
- if self.rset is None:
- return self.req.user
- return self.rset.get_entity(self.row or 0, self.col or 0)
-
- @property
- @cached
- def eprops_rset(self):
- return self.req.execute('Any P,K,V WHERE P is CWProperty, P pkey K, P value V,'
- 'P for_user U, U eid %(x)s', {'x': self.user.eid})
-
- def form_row(self, form, key, splitlabel):
- subform = super(EPropertiesForm, self).form_row(form, key, splitlabel)
- # if user is in the managers group and the property is being created,
- # we have to set for_user explicitly
- if not subform.edited_entity.has_eid() and self.user.matching_groups('managers'):
- subform.form_add_hidden('for_user', self.user.eid, eidparam=True)
-
-
-# eproperty form objects ######################################################
-
-class PlaceHolderWidget(object):
-
- def render(self, form, field):
- domid = form.context[field]['id']
- # empty span as well else html validation fail (label is refering to
- # this id)
- return '<div id="div:%s"><span id="%s">%s</span></div>' % (
- domid, domid, form.req._('select a key first'))
-
-
-class NotEditableWidget(object):
- def __init__(self, value, msg=None):
- self.value = value
- self.msg = msg
-
- def render(self, form, field):
- domid = form.context[field]['id']
- value = '<span class="value" id="%s">%s</span>' % (domid, self.value)
- if self.msg:
- value + '<div class="helper">%s</div>' % self.msg
- return value
-
-
-class PropertyKeyField(StringField):
- """specific field for CWProperty.pkey to set the value widget according to
- the selected key
- """
- widget = Select
-
- def render(self, form, renderer):
- wdg = self.get_widget(form)
- wdg.attrs['tabindex'] = form.req.next_tabindex()
- wdg.attrs['onchange'] = "javascript:setPropValueWidget('%s', %s)" % (
- form.edited_entity.eid, form.req.next_tabindex())
- return wdg.render(form, self)
-
- def vocabulary(self, form):
- entity = form.edited_entity
- _ = form.req._
- if entity.has_eid():
- return [(_(entity.pkey), entity.pkey)]
- # key beginning with 'system.' should usually not be edited by hand
- choices = entity.vreg.user_property_keys()
- return [(u'', u'')] + sorted(zip((_(v) for v in choices), choices))
-
-
-class PropertyValueField(StringField):
- """specific field for CWProperty.value which will be different according to
- the selected key type and vocabulary information
- """
- widget = PlaceHolderWidget
-
- def render(self, form, renderer=None, tabindex=None):
- wdg = self.get_widget(form)
- if tabindex is not None:
- wdg.attrs['tabindex'] = tabindex
- return wdg.render(form, self)
-
- def form_init(self, form):
- entity = form.edited_entity
- if not (entity.has_eid() or 'pkey' in entity):
- # no key set yet, just include an empty div which will be filled
- # on key selection
- return
- try:
- pdef = form.vreg.property_info(entity.pkey)
- except UnknownProperty, ex:
- self.warning('%s (you should probably delete that property '
- 'from the database)', ex)
- msg = form.req._('you should probably delete that property')
- self.widget = NotEditableWidget(entity.printable_value('value'),
- '%s (%s)' % (msg, ex))
- if entity.pkey.startswith('system.'):
- msg = form.req._('value associated to this key is not editable '
- 'manually')
- self.widget = NotEditableWidget(entity.printable_value('value'), msg)
- # XXX race condition when used from CWPropertyForm, should not rely on
- # instance attributes
- self.initial = pdef['default']
- self.help = pdef['help']
- vocab = pdef['vocabulary']
- if vocab is not None:
- if callable(vocab):
- # list() just in case its a generator function
- self.choices = list(vocab(form.req))
- else:
- self.choices = vocab
- wdg = Select()
- else:
- wdg = FIELDS[pdef['type']].widget()
- if pdef['type'] == 'Boolean':
- self.choices = [(form.req._('yes'), '1'), (form.req._('no'), '')]
- elif pdef['type'] in ('Float', 'Int'):
- wdg.attrs.setdefault('size', 3)
- self.widget = wdg
-
-uicfg.rfields.set_rtag(PropertyKeyField, 'pkey', 'subject', 'CWProperty')
-uicfg.rfields.set_rtag(PropertyValueField, 'value', 'subject', 'CWProperty')
-
--- a/web/views/euser.py Tue Apr 28 13:28:37 2009 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,101 +0,0 @@
-"""Specific views for users
-
-:organization: Logilab
-:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
-:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
-"""
-__docformat__ = "restructuredtext en"
-
-from logilab.mtconverter import html_escape
-
-from cubicweb.selectors import one_line_rset, implements, match_user_groups
-from cubicweb.view import EntityView
-from cubicweb.web import uicfg, action
-from cubicweb.web.views.baseviews import PrimaryView
-
-
-uicfg.rcategories.set_rtag('secondary', 'firstname', 'subject', 'CWUser')
-uicfg.rcategories.set_rtag('secondary', 'surname', 'subject', 'CWUser')
-uicfg.rcategories.set_rtag('metadata', 'last_login_time', 'subject', 'CWUser')
-uicfg.rcategories.set_rtag('primary', 'in_group', 'subject', 'CWUser')
-uicfg.rcategories.set_rtag('generated', 'owned_by', 'object', otype='CWUser')
-uicfg.rcategories.set_rtag('generated', 'created_by', 'object', otype='CWUser')
-uicfg.rcategories.set_rtag('metadata', 'bookmarked_by', 'object', otype='CWUser')
-uicfg.rinlined.set_rtag(True, 'use_email', 'subject', 'CWUser')
-uicfg.rmode.set_rtag('create', 'in_group', 'subject', 'CWGroup')
-uicfg.rmode.set_rtag('link', 'owned_by', 'object', 'CWUser')
-uicfg.rmode.set_rtag('link', 'created_by', 'object', 'CWUser')
-uicfg.rmode.set_rtag('create', 'bookmarked_by', 'object', 'CWUser')
-
-
-class UserPreferencesEntityAction(action.Action):
- id = 'prefs'
- __select__ = (one_line_rset() & implements('CWUser') &
- match_user_groups('owners', 'managers'))
-
- title = _('preferences')
- category = 'mainactions'
-
- def url(self):
- login = self.rset.get_entity(self.row or 0, self.col or 0).login
- return self.build_url('euser/%s'%login, vid='epropertiesform')
-
-
-class CWUserPrimaryView(PrimaryView):
- __select__ = implements('CWUser')
-
- skip_attrs = ('firstname', 'surname')
-
- def iter_relations(self, entity):
- # don't want to display user's entities
- for rschema, targetschemas, x in super(CWUserPrimaryView, self).iter_relations(entity):
- if x == 'object' and rschema.type in ('owned_by', 'for_user'):
- continue
- yield rschema, targetschemas, x
-
- def content_title(self, entity):
- return entity.name()
-
- def is_side_related(self, rschema, eschema):
- return rschema.type in ['interested_in', 'tags',
- 'todo_by', 'bookmarked_by',
-
- ]
-class FoafView(EntityView):
- id = 'foaf'
- __select__ = implements('CWUser')
-
- title = _('foaf')
- templatable = False
- content_type = 'text/xml'
-
- def call(self):
- self.w(u'''<?xml version="1.0" encoding="%s"?>
-<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:rdfs="http://www.w3org/2000/01/rdf-schema#"
- xmlns:foaf="http://xmlns.com/foaf/0.1/"> '''% self.req.encoding)
- for i in xrange(self.rset.rowcount):
- self.cell_call(i, 0)
- self.w(u'</rdf:RDF>\n')
-
- def cell_call(self, row, col):
- entity = self.complete_entity(row, col)
- self.w(u'''<foaf:PersonalProfileDocument rdf:about="">
- <foaf:maker rdf:resource="%s"/>
- <foaf:primaryTopic rdf:resource="%s"/>
- </foaf:PersonalProfileDocument>''' % (entity.absolute_url(), entity.absolute_url()))
- self.w(u'<foaf:Person rdf:ID="%s">\n' % entity.eid)
- self.w(u'<foaf:name>%s</foaf:name>\n' % html_escape(entity.dc_long_title()))
- if entity.surname:
- self.w(u'<foaf:family_name>%s</foaf:family_name>\n'
- % html_escape(entity.surname))
- if entity.firstname:
- self.w(u'<foaf:givenname>%s</foaf:givenname>\n'
- % html_escape(entity.firstname))
- emailaddr = entity.get_email()
- if emailaddr:
- self.w(u'<foaf:mbox>%s</foaf:mbox>\n' % html_escape(emailaddr))
- self.w(u'</foaf:Person>\n')
-
-from logilab.common.deprecation import class_renamed
-EUserPrimaryView = class_renamed('EUserPrimaryView', CWUserPrimaryView)
--- a/web/views/idownloadable.py Tue Apr 28 13:28:37 2009 +0200
+++ b/web/views/idownloadable.py Tue Apr 28 19:12:52 2009 +0200
@@ -43,9 +43,10 @@
id = 'download_box'
# no download box for images
# XXX primary_view selector ?
- __select__ = (one_line_rset() & implements(IDownloadable) & match_context_prop() & ~score_entity(is_image))
+ __select__ = (one_line_rset() & implements(IDownloadable) &
+ match_context_prop() & ~score_entity(is_image))
order = 10
-
+
def cell_call(self, row, col, title=None, label=None, **kwargs):
entity = self.entity(row, col)
download_box(self.w, entity, title, label)
@@ -86,14 +87,14 @@
__select__ = implements(IDownloadable)
title = None # should not be listed in possible views
-
+
def cell_call(self, row, col, title=None, **kwargs):
entity = self.entity(row, col)
url = html_escape(entity.download_url())
self.w(u'<a href="%s">%s</a>' % (url, html_escape(title or entity.dc_title())))
-
+
class IDownloadablePrimaryView(baseviews.PrimaryView):
__select__ = implements(IDownloadable)
# XXX File/Image attributes but this is not specified in the IDownloadable interface
@@ -103,7 +104,7 @@
self.w(u'<h1>%s %s</h1>'
% (entity.dc_type().capitalize(),
html_escape(entity.dc_title())))
-
+
def render_entity_attributes(self, entity, siderelations):
super(IDownloadablePrimaryView, self).render_entity_attributes(entity, siderelations)
self.w(u'<div class="content">')
@@ -121,7 +122,7 @@
msg = self.req._("can't display data, unexpected error: %s") % ex
self.w('<div class="error">%s</div>' % msg)
self.w(u'</div>')
-
+
def is_side_related(self, rschema, eschema):
"""display all relations as side related"""
return True
@@ -143,16 +144,16 @@
class ImageView(baseviews.EntityView):
id = 'image'
__select__ = implements(IDownloadable) & score_entity(is_image)
-
+
title = _('image')
-
+
def call(self):
rset = self.rset
for i in xrange(len(rset)):
self.w(u'<div class="efile">')
self.wview(self.id, rset, row=i, col=0)
self.w(u'</div>')
-
+
def cell_call(self, row, col):
entity = self.entity(row, col)
#if entity.data_format.startswith('image/'):
--- a/web/views/management.py Tue Apr 28 13:28:37 2009 +0200
+++ b/web/views/management.py Tue Apr 28 19:12:52 2009 +0200
@@ -48,7 +48,7 @@
self.owned_by_edit_form(entity)
else:
self.owned_by_information(entity)
- # epermissions
+ # cwpermissions
if 'require_permission' in entity.e_schema.subject_relations():
w('<h3>%s</h3>' % _('permissions for this entity'))
reqpermschema = self.schema.rschema('require_permission')
@@ -116,18 +116,18 @@
w(u'<table class="schemaInfo">')
w(u'<tr><th>%s</th><th>%s</th></tr>' % (_("permission"),
_('granted to groups')))
- for eperm in entity.require_permission:
+ for cwperm in entity.require_permission:
w(u'<tr>')
if dellinktempl:
- w(u'<td>%s%s</td>' % (dellinktempl % eperm.eid,
- eperm.view('oneline')))
+ w(u'<td>%s%s</td>' % (dellinktempl % cwperm.eid,
+ cwperm.view('oneline')))
else:
- w(u'<td>%s</td>' % eperm.view('oneline'))
- w(u'<td>%s</td>' % self.view('csv', eperm.related('require_group'), 'null'))
+ w(u'<td>%s</td>' % cwperm.view('oneline'))
+ w(u'<td>%s</td>' % self.view('csv', cwperm.related('require_group'), 'null'))
w(u'</tr>\n')
w(u'</table>')
else:
- self.w(self.req._('no associated epermissions'))
+ self.w(self.req._('no associated permissions'))
def require_permission_edit_form(self, entity):
w = self.w
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/views/primary.py Tue Apr 28 19:12:52 2009 +0200
@@ -0,0 +1,242 @@
+"""The default primary view
+
+:organization: Logilab
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
+"""
+
+from warnings import warn
+
+from cubicweb import Unauthorized
+from cubicweb.view import EntityView
+
+_ = unicode
+
+PRIMARY_SKIP_RELS = set(['is', 'is_instance_of', 'identity',
+ 'owned_by', 'created_by',
+ 'in_state', 'wf_info_for', 'require_permission',
+ 'from_entity', 'to_entity',
+ 'see_also'])
+
+class PrimaryView(EntityView):
+ """the full view of an non final entity"""
+ id = 'primary'
+ title = _('primary')
+ show_attr_label = True
+ show_rel_label = True
+ skip_none = True
+ skip_attrs = ('eid', 'creation_date', 'modification_date')
+ skip_rels = ()
+ main_related_section = True
+
+ def html_headers(self):
+ """return a list of html headers (eg something to be inserted between
+ <head> and </head> of the returned page
+
+ by default primary views are indexed
+ """
+ return []
+
+ def cell_call(self, row, col):
+ self.row = row
+ # XXX move render_entity implementation here
+ self.render_entity(self.complete_entity(row, col))
+
+ def render_entity(self, entity):
+ """return html to display the given entity"""
+ self.render_entity_title(entity)
+ self.render_entity_metadata(entity)
+ # entity's attributes and relations, excluding meta data
+ # if the entity isn't meta itself
+ boxes = self._preinit_side_related(entity)
+ if boxes:
+ self.w(u'<table width="100%"><tr><td width="75%">')
+ self.w(u'<div>')
+ self.w(u'<div class="mainInfo">')
+ try:
+ self.render_entity_attributes(entity)
+ except TypeError: # XXX bw compat
+ warn('siderelations argument of render_entity_attributes is '
+ 'deprecated')
+ self.render_entity_attributes(entity, [])
+ self.w(u'</div>')
+ self.content_navigation_components('navcontenttop')
+ if self.main_related_section:
+ try:
+ self.render_entity_relations(entity)
+ except TypeError: # XXX bw compat
+ warn('siderelations argument of render_entity_relations is '
+ 'deprecated')
+ self.render_entity_relations(entity, [])
+ self.w(u'</div>')
+ if boxes:
+ self.w(u'</td><td>')
+ # side boxes
+ self.w(u'<div class="primaryRight">')
+ try:
+ self.render_side_related(entity)
+ except TypeError: # XXX bw compat
+ warn('siderelations argument of render_entity_relations is '
+ 'deprecated')
+ self.render_entity_relations(entity, [])
+ self.w(u'</div>')
+ self.w(u'</td></tr></table>')
+ self.content_navigation_components('navcontentbottom')
+
+
+ def content_navigation_components(self, context):
+ self.w(u'<div class="%s">' % context)
+ for comp in self.vreg.possible_vobjects('contentnavigation',
+ self.req, self.rset, row=self.row,
+ view=self, context=context):
+ try:
+ comp.dispatch(w=self.w, row=self.row, view=self)
+ except NotImplementedError:
+ warn('component %s doesnt implement cell_call, please update'
+ % comp.__class__, DeprecationWarning)
+ comp.dispatch(w=self.w, view=self)
+ self.w(u'</div>')
+
+ def iter_attributes(self, entity):
+ for rschema, targetschema in entity.e_schema.attribute_definitions():
+ if rschema.type in self.skip_attrs:
+ continue
+ yield rschema, targetschema
+
+ def iter_relations(self, entity):
+ skip = set(self.skip_rels)
+ skip.update(PRIMARY_SKIP_RELS)
+ for rschema, targetschemas, x in entity.e_schema.relation_definitions():
+ if rschema.type in skip:
+ continue
+ yield rschema, targetschemas, x
+
+ def render_entity_title(self, entity):
+ title = self.content_title(entity) # deprecate content_title?
+ if title:
+ self.w(u'<h1><span class="etype">%s</span> %s</h1>'
+ % (entity.dc_type().capitalize(), title))
+
+ def content_title(self, entity):
+ """default implementation return an empty string"""
+ return u''
+
+ def render_entity_metadata(self, entity):
+ entity.view('metadata', w=self.w)
+ summary = self.summary(entity) # deprecate summary?
+ if summary:
+ self.w(u'<div class="summary">%s</div>' % summary)
+
+ def summary(self, entity):
+ """default implementation return an empty string"""
+ return u''
+
+ def render_entity_attributes(self, entity, siderelations=None):
+ for rschema, targetschema in self.iter_attributes(entity):
+ attr = rschema.type
+ if targetschema.type in ('Password', 'Bytes'):
+ continue
+ try:
+ wdg = entity.get_widget(attr)
+ except Exception, ex:
+ value = entity.printable_value(attr, entity[attr], targetschema.type)
+ else:
+ value = wdg.render(entity)
+ if self.skip_none and (value is None or value == ''):
+ continue
+ if rschema.meta:
+ continue
+ self._render_related_entities(entity, rschema, value)
+
+ def _preinit_side_related(self, entity):
+ self._sideboxes = []
+ if hasattr(self, 'get_side_boxes_defs'):
+ self._sideboxes = [(label, rset, 'sidebox') for label, rset in self.get_side_boxes_defs(entity)
+ if rset]
+ else:
+ eschema = entity.e_schema
+ maxrelated = self.req.property_value('navigation.related-limit')
+ for rschema, targetschemas, role in self.iter_relations(entity):
+ if self.is_side_related(rschema, eschema):
+ try:
+ related = entity.related(rschema.type, role, limit=maxrelated+1)
+ except Unauthorized:
+ continue
+ if not related:
+ continue
+ label = display_name(self.req, rschema.type, role)
+ self._sideboxes.append((label, related, 'autolimited'))
+ self._contextboxes = list(self.vreg.possible_vobjects('boxes', self.req, self.rset,
+ row=self.row, view=self,
+ context='incontext'))
+ return self._sideboxes or self._contextboxes
+
+ def render_entity_relations(self, entity, siderelations=None):
+ eschema = entity.e_schema
+ for rschema, targetschemas, x in self.iter_relations(entity):
+ if not self.is_side_related(rschema, eschema):
+ try:
+ related = entity.related(rschema.type, x, limit=maxrelated+1)
+ except Unauthorized:
+ continue
+ self._render_related_entities(entity, rschema, related, x)
+
+
+ def render_side_related(self, entity, siderelations=None):
+ """display side related relations:
+ non-meta in a first step, meta in a second step
+ """
+ if self._sideboxes:
+ for label, rset, vid in self._sideboxes:
+ self.w(u'<div class="sideRelated">')
+ self.wview(vid, rset, title=label)
+ self.w(u'</div>')
+ if self._contextboxes:
+ for box in self._contextboxes:
+ try:
+ box.dispatch(w=self.w, row=self.row)
+ except NotImplementedError:
+ # much probably a context insensitive box, which only implements
+ # .call() and not cell_call()
+ box.dispatch(w=self.w)
+
+ def is_side_related(self, rschema, eschema):
+ return rschema.meta and \
+ not rschema.schema_relation() == eschema.schema_entity()
+
+ def _render_related_entities(self, entity, rschema, related,
+ role='subject'):
+ if rschema.is_final():
+ value = related
+ show_label = self.show_attr_label
+ else:
+ if not related:
+ return
+ value = self.view('autolimited', related)
+ label = display_name(self.req, rschema.type, role)
+ self.field(label, value, show_label=show_label, tr=False)
+
+
+class RelatedView(EntityView):
+ id = 'autolimited'
+ def call(self):
+ # if not too many entities, show them all in a list
+ maxrelated = self.req.property_value('navigation.related-limit')
+ if self.rset.rowcount <= maxrelated:
+ if self.rset.rowcount == 1:
+ self.wview('incontext', self.rset, row=0)
+ elif 1 < self.rset.rowcount <= 5:
+ self.wview('csv', self.rset)
+ else:
+ self.w(u'<div>')
+ self.wview('simplelist', self.rset)
+ self.w(u'</div>')
+ # else show links to display related entities
+ else:
+ rql = self.rset.printable_rql()
+ self.rset.limit(maxself.rset)
+ self.w(u'<div>')
+ self.wview('simplelist', self.rset)
+ self.w(u'[<a href="%s">%s</a>]' % (self.build_url(rql=rql),
+ self.req._('see them all')))
+ self.w(u'</div>')
--- a/web/views/schema.py Tue Apr 28 13:28:37 2009 +0200
+++ b/web/views/schema.py Tue Apr 28 19:12:52 2009 +0200
@@ -15,49 +15,46 @@
from cubicweb.schemaviewer import SchemaViewer
from cubicweb.view import EntityView, StartupView
from cubicweb.common.uilib import ureport_as_html
-from cubicweb.web.action import Action
-from cubicweb.web.views import baseviews
-from cubicweb.web.views import TmpFileViewMixin
-from cubicweb.web.views.editforms import AutomaticEntityForm
-from cubicweb.web.views.boxes import EditBox
+from cubicweb.web import uicfg, action
+from cubicweb.web.views import TmpFileViewMixin, baseviews
-AutomaticEntityForm.rcategories.set_rtag('primary', 'require_group', 'subject', 'CWPermission')
-AutomaticEntityForm.rcategories.set_rtag('generated', 'final', 'subject', 'EEtype')
-AutomaticEntityForm.rcategories.set_rtag('generated', 'final', 'subject', 'ERtype')
-AutomaticEntityForm.rinlined.set_rtag(True, 'relation_type', 'subject', 'CWRelation')
-AutomaticEntityForm.rinlined.set_rtag(True, 'from_entity', 'subject', 'CWRelation')
-AutomaticEntityForm.rinlined.set_rtag(True, 'to_entity', 'subject', 'CWRelation')
-AutomaticEntityForm.rwidgets.set_rtag('StringWidget', 'expression', 'subject', 'RQLExpression')
+uicfg.rcategories.set_rtag('primary', 'require_group', 'subject', 'CWPermission')
+uicfg.rcategories.set_rtag('generated', 'final', 'subject', 'EEtype')
+uicfg.rcategories.set_rtag('generated', 'final', 'subject', 'ERtype')
+uicfg.rinlined.set_rtag(True, 'relation_type', 'subject', 'CWRelation')
+uicfg.rinlined.set_rtag(True, 'from_entity', 'subject', 'CWRelation')
+uicfg.rinlined.set_rtag(True, 'to_entity', 'subject', 'CWRelation')
+uicfg.rwidgets.set_rtag('StringWidget', 'expression', 'subject', 'RQLExpression')
-EditBox.rmode.set_rtag('create', 'state_of', 'object', 'CWEType')
-EditBox.rmode.set_rtag('create', 'transition_of', 'object', 'CWEType')
-EditBox.rmode.set_rtag('create', 'relation_type', 'object', 'CWRType')
-EditBox.rmode.set_rtag('link', 'from_entity', 'object', 'CWEType')
-EditBox.rmode.set_rtag('link', 'to_entity', 'object', 'CWEType')
+uicfg.rmode.set_rtag('create', 'state_of', 'object', otype='CWEType')
+uicfg.rmode.set_rtag('create', 'transition_of', 'object', otype='CWEType')
+uicfg.rmode.set_rtag('create', 'relation_type', 'object', otype='CWRType')
+uicfg.rmode.set_rtag('link', 'from_entity', 'object', otype='CWEType')
+uicfg.rmode.set_rtag('link', 'to_entity', 'object', otype='CWEType')
-class ViewSchemaAction(Action):
+class ViewSchemaAction(action.Action):
id = 'schema'
__select__ = yes()
-
+
title = _("site schema")
category = 'siteactions'
order = 30
-
+
def url(self):
return self.build_url(self.id)
-
-
+
+
# schema entity types views ###################################################
class _SchemaEntityPrimaryView(baseviews.PrimaryView):
show_attr_label = False
- cache_max_age = 60*60*2 # stay in http cache for 2 hours by default
-
+ cache_max_age = 60*60*2 # stay in http cache for 2 hours by default
+
def content_title(self, entity):
return html_escape(entity.dc_long_title())
-
+
class CWETypePrimaryView(_SchemaEntityPrimaryView):
__select__ = implements('CWEType')
skip_attrs = _SchemaEntityPrimaryView.skip_attrs + ('name', 'meta', 'final')
@@ -73,7 +70,7 @@
class CWETypeOneLineView(baseviews.OneLineView):
__select__ = implements('CWEType')
-
+
def cell_call(self, row, col, **kwargs):
entity = self.entity(row, col)
final = entity.final
@@ -92,7 +89,7 @@
main_related_section = False
skip_rels = ('is', 'is_instance_of', 'identity', 'created_by', 'owned_by',
'has_text',)
-
+
def render_entity_attributes(self, entity, siderelations):
super(CWETypeSchemaView, self).render_entity_attributes(entity, siderelations)
eschema = self.vreg.schema.eschema(entity.name)
@@ -120,7 +117,7 @@
self.w(u'<img src="%s" alt="%s"/>' % (
html_escape(entity.absolute_url(vid='eschemagraph')),
html_escape(self.req._('graphical schema for %s') % entity.name)))
-
+
# schema images ###############################################################
@@ -143,11 +140,11 @@
self.nextcolor = cycle( ('#aa0000', '#00aa00', '#0000aa',
'#000000', '#888888') ).next
self.req = req
-
+
def display_attr(self, rschema):
return not rschema.meta and (rschema.has_local_role('read')
or rschema.has_perm(self.req, 'read'))
-
+
# XXX remove this method once yams > 0.20 is out
def node_properties(self, eschema):
"""return default DOT drawing options for an entity schema"""
@@ -168,7 +165,7 @@
# + 1 line going to the closest edge spline point)
kwargs['decorate'] = 'false'
return kwargs
-
+
class RestrictedSchemaVisitorMiIn:
def __init__(self, req, *args, **kwargs):
@@ -177,12 +174,12 @@
self.__parent = self.__class__.__bases__[1]
self.__parent.__init__(self, *args, **kwargs)
self.req = req
-
+
def nodes(self):
for etype, eschema in self.__parent.nodes(self):
if eschema.has_local_role('read') or eschema.has_perm(self.req, 'read'):
yield eschema.type, eschema
-
+
def edges(self):
for setype, oetype, rschema in self.__parent.edges(self):
if rschema.has_local_role('read') or rschema.has_perm(self.req, 'read'):
@@ -215,7 +212,7 @@
content_type = 'image/png'
__select__ = implements('CWEType')
skip_rels = ('owned_by', 'created_by', 'identity', 'is', 'is_instance_of')
-
+
def _generate(self, tmpfile):
"""display schema information for an entity"""
entity = self.entity(self.row, self.col)
@@ -226,7 +223,7 @@
class CWRTypeSchemaImageView(CWETypeSchemaImageView):
__select__ = implements('CWRType')
-
+
def _generate(self, tmpfile):
"""display schema information for an entity"""
entity = self.entity(self.row, self.col)
--- a/web/views/startup.py Tue Apr 28 13:28:37 2009 +0200
+++ b/web/views/startup.py Tue Apr 28 19:12:52 2009 +0200
@@ -19,12 +19,12 @@
class ManageView(StartupView):
id = 'manage'
- title = _('manage')
+ title = _('manage')
http_cache_manager = EtagHTTPCacheManager
def display_folders(self):
return False
-
+
def call(self, **kwargs):
"""The default view representing the application's management"""
self.req.add_css('cubicweb.manageview.css')
@@ -35,7 +35,7 @@
self.w(u'<table><tr>\n')
self.w(u'<td style="width:40%">')
self._main_index()
- self.w(u'</td><td style="width:60%">')
+ self.w(u'</td><td style="width:60%">')
self.folders()
self.w(u'</td>')
self.w(u'</tr></table>\n')
@@ -63,22 +63,22 @@
href = req.build_url('view', vid='creation', etype='Card', wikiid='index')
label = self.req._('create an index page')
self.w(u'<br/><a href="%s">%s</a>\n' % (html_escape(href), label))
-
+
def folders(self):
self.w(u'<h4>%s</h4>\n' % self.req._('Browse by category'))
self.vreg.select_view('tree', self.req, None).dispatch(w=self.w)
-
+
def startup_views(self):
self.w(u'<h4>%s</h4>\n' % self.req._('Startup views'))
self.startupviews_table()
-
+
def startupviews_table(self):
for v in self.vreg.possible_views(self.req, None):
if v.category != 'startupview' or v.id in ('index', 'tree', 'manage'):
continue
self.w('<p><a href="%s">%s</a></p>' % (
html_escape(v.url()), html_escape(self.req._(v.title).capitalize())))
-
+
def entities(self):
schema = self.schema
self.w(u'<h4>%s</h4>\n' % self.req._('The repository holds the following entities'))
@@ -88,7 +88,7 @@
self.w(u'<tr><th colspan="4">%s</th></tr>\n' % self.req._('application entities'))
self.entity_types_table(eschema for eschema in schema.entities()
if not eschema.meta and not eschema.is_subobject(strict=True))
- if manager:
+ if manager:
self.w(u'<tr><th colspan="4">%s</th></tr>\n' % self.req._('system entities'))
self.entity_types_table(eschema for eschema in schema.entities()
if eschema.meta and not eschema.schema_entity())
@@ -97,7 +97,7 @@
self.entity_types_table(schema.eschema(etype)
for etype in schema.schema_entity_types())
self.w(u'</table>')
-
+
def entity_types_table(self, eschemas):
newline = 0
infos = sorted(self.entity_types(eschemas),
@@ -111,8 +111,8 @@
self.w(u'<td class="addcol">%s</td><td>%s</td>\n' % (addlink, etypelink))
self.w(u'<td class="addcol">%s</td><td>%s</td>\n' % (addlink2, etypelink2))
self.w(u'</tr>\n')
-
-
+
+
def entity_types(self, eschemas):
"""return a list of formatted links to get a list of entities of
a each entity's types
@@ -133,7 +133,7 @@
etypelink = u' <a href="%s">%s</a> (%d)' % (
html_escape(url), label, nb)
yield (label, etypelink, self.add_entity_link(eschema, req))
-
+
def add_entity_link(self, eschema, req):
"""creates a [+] link for adding an entity if user has permission to do so"""
if not eschema.has_perm(req, 'add'):
@@ -142,14 +142,14 @@
html_escape(self.create_url(eschema.type)),
self.req.__('add a %s' % eschema))
-
+
class IndexView(ManageView):
id = 'index'
title = _('index')
-
+
def display_folders(self):
return 'Folder' in self.schema and self.req.execute('Any COUNT(X) WHERE X is Folder')[0][0]
-
+
class SchemaView(StartupView):
--- a/web/views/tabs.py Tue Apr 28 13:28:37 2009 +0200
+++ b/web/views/tabs.py Tue Apr 28 19:12:52 2009 +0200
@@ -38,7 +38,7 @@
'lazyview wants at least : rql, or an eid, or an rset -- or call it with static=True'
w = w or self.w
self.req.add_js('cubicweb.lazy.js')
- urlparams = {'vid' : vid, 'mode' : 'html'}
+ urlparams = {'vid' : vid, 'fname' : 'view'}
if rql:
urlparams['rql'] = rql
elif eid:
--- a/web/views/workflow.py Tue Apr 28 13:28:37 2009 +0200
+++ b/web/views/workflow.py Tue Apr 28 19:12:52 2009 +0200
@@ -23,10 +23,11 @@
from cubicweb.web.views import TmpFileViewMixin
from cubicweb.web.views.boxes import EditBox
+_ = unicode
EditBox.rmode.set_rtag('create', 'destination_state', 'subject', 'Transition')
-EditBox.rmode.set_rtag('create', 'allowed_transition', 'object', 'Transition')
-EditBox.rmode.set_rtag('create', 'destination_state', 'object', 'State')
+EditBox.rmode.set_rtag('create', 'allowed_transition', 'object', otype='Transition')
+EditBox.rmode.set_rtag('create', 'destination_state', 'object', otype='State')
EditBox.rmode.set_rtag('create', 'allowed_transition', 'subject', 'State')
@@ -34,15 +35,15 @@
class ChangeStateForm(form.EntityFieldsForm):
id = 'changestate'
-
+
__method = StringField(name='__method', initial='set_state',
widget=HiddenInput)
- state = StringField(widget=HiddenInput, eidparam=True)
- trcomment = RichTextField(eidparam=True)
+ state = StringField(eidparam=True, widget=HiddenInput)
+ trcomment = RichTextField(label=_('comment:'), eidparam=True)
form_buttons = [SubmitButton(stdmsgs.YES),
Button(stdmsgs.NO, cwaction='cancel')]
-
+
class ChangeStateFormView(FormViewMixIn, view.EntityView):
id = 'statuschange'
title = _('status change')
@@ -91,7 +92,7 @@
rql += ', WF owned_by U?'
displaycols = range(5)
headers = (_('from_state'), _('to_state'), _('comment'), _('date'),
- _('CWUser'))
+ _('CWUser'))
else:
sel += ',C'
displaycols = range(4)
@@ -111,7 +112,7 @@
class CellView(view.EntityView):
id = 'cell'
__select__ = implements('TrInfo')
-
+
def cell_call(self, row, col, cellvid=None):
self.w(self.entity(row, col).printable_value('comment'))
@@ -120,30 +121,30 @@
"""convenience trick, State's incontext view should not be clickable"""
id = 'incontext'
__select__ = implements('State')
-
+
def cell_call(self, row, col):
self.w(html_escape(self.view('textincontext', self.rset,
row=row, col=col)))
# workflow images #############################################################
-
+
class ViewWorkflowAction(action.Action):
id = 'workflow'
__select__ = implements('CWEType') & has_related_entities('state_of', 'object')
-
+
category = 'mainactions'
title = _('view workflow')
def url(self):
entity = self.rset.get_entity(self.row or 0, self.col or 0)
return entity.absolute_url(vid='workflow')
-
+
class CWETypeWorkflowView(view.EntityView):
id = 'workflow'
__select__ = implements('CWEType')
- cache_max_age = 60*60*2 # stay in http cache for 2 hours by default
-
+ cache_max_age = 60*60*2 # stay in http cache for 2 hours by default
+
def cell_call(self, row, col, **kwargs):
entity = self.entity(row, col)
self.w(u'<h1>%s</h1>' % (self.req._('workflow for %s')
@@ -156,10 +157,10 @@
class WorkflowDotPropsHandler(object):
def __init__(self, req):
self._ = req._
-
+
def node_properties(self, stateortransition):
"""return default DOT drawing options for a state or transition"""
- props = {'label': stateortransition.name,
+ props = {'label': stateortransition.name,
'fontname': 'Courier'}
if hasattr(stateortransition, 'state_of'):
props['shape'] = 'box'
@@ -179,7 +180,7 @@
if descr:
props['label'] += escape('\n'.join(descr))
return props
-
+
def edge_properties(self, transition, fromstate, tostate):
return {'label': '', 'dir': 'forward',
'color': 'black', 'style': 'filled'}
@@ -193,11 +194,11 @@
for state in self.entity.reverse_state_of:
state.complete()
yield state.eid, state
-
+
for transition in self.entity.reverse_transition_of:
transition.complete()
yield transition.eid, transition
-
+
def edges(self):
for transition in self.entity.reverse_transition_of:
for incomingstate in transition.reverse_allowed_transition:
@@ -209,7 +210,7 @@
id = 'ewfgraph'
content_type = 'image/png'
__select__ = implements('CWEType')
-
+
def _generate(self, tmpfile):
"""display schema information for an entity"""
entity = self.entity(self.row, self.col)