diff -r e9c8d5d9f622 -r 3a78894effbd demo.py --- a/demo.py Wed Dec 24 17:34:48 2014 +0400 +++ b/demo.py Mon Mar 02 19:06:45 2015 +0300 @@ -3,5 +3,6 @@ import roundup from roundup.demo import main +import pdb; pdb.set_trace() # XXX BREAKPOINT sys.exit(main()) diff -r e9c8d5d9f622 -r 3a78894effbd roundup/backends/back_anydbm.py --- a/roundup/backends/back_anydbm.py Wed Dec 24 17:34:48 2014 +0400 +++ b/roundup/backends/back_anydbm.py Mon Mar 02 19:06:45 2015 +0300 @@ -998,6 +998,12 @@ except ValueError: raise TypeError('new property "%s" not numeric'%key) + elif value is not None and isinstance(prop, hyperdb.Integer): + try: + int(value) + except ValueError: + raise TypeError('new property "%s" not an integer'%key) + elif value is not None and isinstance(prop, hyperdb.Boolean): try: int(value) @@ -1339,6 +1345,13 @@ raise TypeError('new property "%s" not ' 'numeric'%propname) + elif value is not None and isinstance(prop, hyperdb.Integer): + try: + int(value) + except ValueError: + raise TypeError('new property "%s" not ' + 'numeric'%propname) + elif value is not None and isinstance(prop, hyperdb.Boolean): try: int(value) @@ -1745,6 +1758,14 @@ v = [v] l.append((OTHER, k, [float(val) for val in v])) + elif isinstance(propclass, hyperdb.Integer): + if type(v) != type([]): + try : + v = v.split(',') + except AttributeError : + v = [v] + l.append((OTHER, k, [int(val) for val in v])) + filterspec = l # now, find all the nodes that are active and pass filtering diff -r e9c8d5d9f622 -r 3a78894effbd roundup/backends/back_mysql.py --- a/roundup/backends/back_mysql.py Wed Dec 24 17:34:48 2014 +0400 +++ b/roundup/backends/back_mysql.py Mon Mar 02 19:06:45 2015 +0300 @@ -129,6 +129,7 @@ hyperdb.Password : 'VARCHAR(255)', hyperdb.Boolean : 'BOOL', hyperdb.Number : 'REAL', + hyperdb.Integer : 'INTEGER', } hyperdb_to_sql_value = { @@ -140,6 +141,7 @@ hyperdb.Password : str, hyperdb.Boolean : int, hyperdb.Number : lambda x: x, + hyperdb.Integer : int, hyperdb.Multilink : lambda x: x, # used in journal marshalling } @@ -299,6 +301,8 @@ v = date.Interval(v) elif isinstance(prop, Password) and v is not None: v = password.Password(encrypted=v) + elif isinstance(prop, Integer) and v is not None: + v = int(v) elif (isinstance(prop, Boolean) or isinstance(prop, Number)) and v is not None: v = float(v) @@ -614,7 +618,7 @@ # create the node. Fortunately, MySQL gives us a unique error # code for this situation, so we can detect it here and handle # it appropriately. - # + # # The details of the race condition are as follows, where # "X" is a classname, and the term "thread" is meant to # refer generically to both threads and processes: @@ -648,7 +652,7 @@ raise ValueError, 'node with key "%s" exists' % key # We don't know what this exception is; reraise it. raise - + class Class(MysqlClass, rdbms_common.Class): pass diff -r e9c8d5d9f622 -r 3a78894effbd roundup/backends/back_sqlite.py --- a/roundup/backends/back_sqlite.py Wed Dec 24 17:34:48 2014 +0400 +++ b/roundup/backends/back_sqlite.py Mon Mar 02 19:06:45 2015 +0300 @@ -51,6 +51,7 @@ hyperdb.Password : 'VARCHAR(255)', hyperdb.Boolean : 'BOOLEAN', hyperdb.Number : 'REAL', + hyperdb.Integer : 'INTEGER', } hyperdb_to_sql_value = { hyperdb.String : str, @@ -59,6 +60,7 @@ hyperdb.Interval : str, hyperdb.Password : str, hyperdb.Boolean : int, + hyperdb.Integer : int, hyperdb.Number : lambda x: x, hyperdb.Multilink : lambda x: x, # used in journal marshalling } @@ -69,6 +71,7 @@ hyperdb.Interval : date.Interval, hyperdb.Password : lambda x: password.Password(encrypted=x), hyperdb.Boolean : int, + hyperdb.Integer : int, hyperdb.Number : rdbms_common._num_cvt, hyperdb.Multilink : lambda x: x, # used in journal marshalling } diff -r e9c8d5d9f622 -r 3a78894effbd roundup/cgi/actions.py --- a/roundup/cgi/actions.py Wed Dec 24 17:34:48 2014 +0400 +++ b/roundup/cgi/actions.py Mon Mar 02 19:06:45 2015 +0300 @@ -362,6 +362,8 @@ value = value.lower() in ('yes', 'true', 'on', '1') elif isinstance(prop, hyperdb.Number): value = float(value) + elif isinstance(prop, hyperdb.Integer): + value = int(value) d[name] = value elif exists: # nuke the existing value diff -r e9c8d5d9f622 -r 3a78894effbd roundup/cgi/form_parser.py --- a/roundup/cgi/form_parser.py Wed Dec 24 17:34:48 2014 +0400 +++ b/roundup/cgi/form_parser.py Mon Mar 02 19:06:45 2015 +0300 @@ -142,7 +142,7 @@ they are valid for the class). Otherwise, the property is set to the form value. - For Date(), Interval(), Boolean(), and Number() + For Date(), Interval(), Boolean(), and Number(), Integer() properties, the form value is converted to the appropriate @@ -509,7 +509,7 @@ # some backends store "missing" Strings as empty strings if existing == self.db.BACKEND_MISSING_STRING: existing = None - elif isinstance(proptype, hyperdb.Number): + elif isinstance(proptype, hyperdb.Number) or isinstance(proptype, hyperdb.Integer): # some backends store "missing" Numbers as 0 :( if existing == self.db.BACKEND_MISSING_NUMBER: existing = None diff -r e9c8d5d9f622 -r 3a78894effbd roundup/cgi/templating.py --- a/roundup/cgi/templating.py Wed Dec 24 17:34:48 2014 +0400 +++ b/roundup/cgi/templating.py Mon Mar 02 19:06:45 2015 +0300 @@ -1196,7 +1196,7 @@ return _HTMLItem(client, classname, nodeid, anonymous) class HTMLProperty(HTMLInputMixin, HTMLPermissions): - """ String, Number, Date, Interval HTMLProperty + """ String, Integer, Number, Date, Interval HTMLProperty Has useful attributes: @@ -1600,6 +1600,38 @@ """ return float(self._value) +class IntegerHTMLProperty(HTMLProperty): + def plain(self, escape=0): + """ Render a "plain" representation of the property + """ + if not self.is_view_ok(): + return self._('[hidden]') + + if self._value is None: + return '' + + return str(self._value) + + def field(self, size=30, **kwargs): + """ Render a form edit field for the property. + + If not editable, just display the value via plain(). + """ + if not self.is_edit_ok(): + return self.plain(escape=1) + + value = self._value + if value is None: + value = '' + + return self.input(name=self._formname, value=value, size=size, + **kwargs) + + def __int__(self): + """ Return an int of me + """ + return int(self._value) + class BooleanHTMLProperty(HTMLProperty): def plain(self, escape=0): @@ -2353,6 +2385,7 @@ propclasses = [ (hyperdb.String, StringHTMLProperty), (hyperdb.Number, NumberHTMLProperty), + (hyperdb.Integer, IntegerHTMLProperty), (hyperdb.Boolean, BooleanHTMLProperty), (hyperdb.Date, DateHTMLProperty), (hyperdb.Interval, IntervalHTMLProperty), diff -r e9c8d5d9f622 -r 3a78894effbd roundup/hyperdb.py --- a/roundup/hyperdb.py Wed Dec 24 17:34:48 2014 +0400 +++ b/roundup/hyperdb.py Mon Mar 02 19:06:45 2015 +0300 @@ -41,7 +41,7 @@ ' more useful for dumps ' return '<%s.%s>'%(self.__class__.__module__, self.__class__.__name__) def get_default_value(self): - """The default value when creating a new instance of this property.""" + """The default value when creating a new instance of this property.""" return self.__default_value def sort_repr (self, cls, val, name): """Representation used for sorting. This should be a python @@ -183,7 +183,7 @@ super(Multilink, self).__init__(classname, do_journal, required = required, - default_value = []) + default_value = []) def from_raw(self, value, db, klass, propname, itemid, translator=translation, **kw): if not value: @@ -280,6 +280,17 @@ raise HyperdbValueError, translator.gettext('property %s: %r is not a number')%( kw['propname'], value) return value + +class Integer(_Type): + """An object designating an integer property""" + def from_raw(self, value, translator=translation, **kw): + value = value.strip() + try: + value = int(value) + except ValueError: + raise HyperdbValueError, translator.gettext('property %s: %r is not an integer')%( + kw['propname'], value) + return value # # Support for splitting designators # diff -r e9c8d5d9f622 -r 3a78894effbd roundup/instance.py --- a/roundup/instance.py Wed Dec 24 17:34:48 2014 +0400 +++ b/roundup/instance.py Mon Mar 02 19:06:45 2015 +0300 @@ -101,6 +101,7 @@ 'Interval': hyperdb.Interval, 'Boolean': hyperdb.Boolean, 'Number': hyperdb.Number, + 'Integer': hyperdb.Integer, 'db': backend.Database(self.config, name) }