Merge lp:~camptocamp/openobject-server/trunk-deprecate-osv_osv into lp:openobject-server

Proposed by Alexandre Fayolle - camptocamp
Status: Needs review
Proposed branch: lp:~camptocamp/openobject-server/trunk-deprecate-osv_osv
Merge into: lp:openobject-server
Diff against target: 435 lines (+108/-30)
11 files modified
openerp/loglevels.py (+3/-4)
openerp/modules/module.py (+4/-0)
openerp/netsvc.py (+7/-0)
openerp/osv/fields.py (+7/-4)
openerp/osv/orm.py (+34/-11)
openerp/osv/osv.py (+16/-6)
openerp/sql_db.py (+6/-3)
openerp/tools/config.py (+5/-1)
openerp/tools/convert.py (+3/-1)
openerp/tools/deprecate.py (+19/-0)
openerp/tools/misc.py (+4/-0)
To merge this branch: bzr merge lp:~camptocamp/openobject-server/trunk-deprecate-osv_osv
Reviewer Review Type Date Requested Status
Stephane Wirtel (OpenERP) Pending
Review via email: mp+124874@code.launchpad.net

Description of the change

use warnings to flag deprecated features

* adds a deprecated decorator to flag methods and functions
* added a new metaclass for deprecated models (osv.osv, osv.osv_memory...)
* use warnings.warn explicitely in some parts of the core framework where comments told that something was deprecated
* added a new command line option to direct the warnings to the logs (default), stderr or hide them completely

To post a comment you must log in.
4447. By Alexandre Fayolle @ camptocamp <email address hidden> on 2012-09-21

[MRG] from trunk

4448. By Alexandre Fayolle @ camptocamp <email address hidden> on 2012-10-03

[MRG] from trunk

Revision history for this message
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) wrote :

updated the MP to the lastest trunk

4449. By Alexandre Fayolle @ camptocamp <email address hidden> on 2012-12-20

[MRG] updated to current trunk

4450. By Alexandre Fayolle - camptocamp on 2012-12-20

[MRG] updated to latest trunk

Revision history for this message
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) wrote :

updated MP to latest trunk

Unmerged revisions

4450. By Alexandre Fayolle - camptocamp on 2012-12-20

[MRG] updated to latest trunk

4449. By Alexandre Fayolle @ camptocamp <email address hidden> on 2012-12-20

[MRG] updated to current trunk

4448. By Alexandre Fayolle @ camptocamp <email address hidden> on 2012-10-03

[MRG] from trunk

4447. By Alexandre Fayolle @ camptocamp <email address hidden> on 2012-09-21

[MRG] from trunk

4446. By Alexandre Fayolle @ camptocamp <email address hidden> on 2012-09-18

[FIX] do not regiser the deprecated base classes

4445. By Alexandre Fayolle @ camptocamp <email address hidden> on 2012-09-18

[IMP] add some DeprecationWarnings where comments say a method/class is deprecated

4444. By Alexandre Fayolle @ camptocamp <email address hidden> on 2012-09-18

[FIX] move deprecated_model metaclass from tools.deprecate to osv.orm

this avoids circular imports via osv.osv

4443. By Alexandre Fayolle @ camptocamp <email address hidden> on 2012-09-18

[IMP] control the display of DeprecationWarning from the command line

4442. By Alexandre Fayolle @ camptocamp <email address hidden> on 2012-09-18

[FIX] fix the deprecation warning in osv.osv

4441. By Alexandre Fayolle @ camptocamp <email address hidden> on 2012-09-17

[IMP] added openerp.tools.deprecate with some utilities to deprecate classes and methods
use these utilities to deprecate osv.osv, osv.osv_memory and osv.osv_abstract

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'openerp/loglevels.py'
2--- openerp/loglevels.py 2012-12-14 13:07:58 +0000
3+++ openerp/loglevels.py 2012-12-20 14:32:31 +0000
4@@ -21,6 +21,7 @@
5
6 import sys
7 import logging
8+from openerp.tools.deprecate import deprecated
9
10 LOG_NOTSET = 'notset'
11 LOG_DEBUG = 'debug'
12@@ -41,11 +42,9 @@
13 "The netsvc.Logger API shouldn't be used anymore, please "
14 "use the standard `logging.getLogger` API instead.")
15 super(Logger, self).__init__()
16-
17+ @deprecated("notifyChannel API shouldn't be used anymore, please use "
18+ "the standard `logging` module instead.")
19 def notifyChannel(self, name, level, msg):
20- _logger.warning(
21- "notifyChannel API shouldn't be used anymore, please use "
22- "the standard `logging` module instead.")
23 from service.web_services import common
24
25 log = logging.getLogger(__name__ + '.deprecated.' + ustr(name))
26
27=== modified file 'openerp/modules/module.py'
28--- openerp/modules/module.py 2012-12-16 19:39:32 +0000
29+++ openerp/modules/module.py 2012-12-20 14:32:31 +0000
30@@ -27,6 +27,7 @@
31 import sys
32 import types
33 import zipimport
34+import warnings
35
36 import openerp.tools as tools
37 import openerp.tools.osutil as osutil
38@@ -312,6 +313,9 @@
39 terp_file = get_module_resource(module, '__openerp__.py')
40 if not terp_file:
41 terp_file = get_module_resource(module, '__terp__.py')
42+ warnings.warn('__terp__.py is deprecated. Use __openerp__.py (%s)' % terp_file,
43+ DeprecationWarning)
44+
45 mod_path = get_module_path(module)
46 if terp_file:
47 info = {}
48
49=== modified file 'openerp/netsvc.py'
50--- openerp/netsvc.py 2012-12-10 13:21:33 +0000
51+++ openerp/netsvc.py 2012-12-20 14:32:31 +0000
52@@ -35,6 +35,7 @@
53 import time
54 import types
55 from pprint import pformat
56+import warnings
57
58 # TODO modules that import netsvc only for things from loglevels must be changed to use loglevels.
59 from loglevels import *
60@@ -232,6 +233,12 @@
61 for logconfig_item in default_config + pseudo_config + logconfig:
62 _logger.debug('logger level set: "%s"', logconfig_item)
63
64+ if tools.config['deprecation_warnings'] == 'show':
65+ warnings.filterwarnings('default', category=DeprecationWarning)
66+ elif tools.config['deprecation_warnings'] == 'log':
67+ warnings.filterwarnings('default', category=DeprecationWarning)
68+ logging.captureWarnings(True)
69+
70 # A alternative logging scheme for automated runs of the
71 # server intended to test it.
72 def init_alternative_logger():
73
74=== modified file 'openerp/osv/fields.py'
75--- openerp/osv/fields.py 2012-12-19 09:36:55 +0000
76+++ openerp/osv/fields.py 2012-12-20 14:32:31 +0000
77@@ -42,6 +42,7 @@
78 import re
79 import xmlrpclib
80 from psycopg2 import Binary
81+import warnings
82
83 import openerp
84 import openerp.tools as tools
85@@ -164,10 +165,11 @@
86 def __init__(self, string='unknown', required=False, **args):
87 super(boolean, self).__init__(string=string, required=required, **args)
88 if required:
89- _logger.debug(
90+ warnings.warn(
91 "required=True is deprecated: making a boolean field"
92 " `required` has no effect, as NULL values are "
93- "automatically turned into False. args: %r",args)
94+ "automatically turned into False. args: %r" % args,
95+ DeprecationWarning, stacklevel=2)
96
97 class integer(_column):
98 _type = 'integer'
99@@ -695,9 +697,10 @@
100 for id in ids:
101 res[id] = []
102 if offset:
103- _logger.warning(
104+ warnings.warn(
105 "Specifying offset at a many2many.get() is deprecated and may"
106- " produce unpredictable results.")
107+ " produce unpredictable results.",
108+ DeprecationWarning, stacklevel=2)
109 obj = model.pool.get(self._obj)
110 rel, id1, id2 = self._sql_names(model)
111
112
113=== modified file 'openerp/osv/orm.py'
114--- openerp/osv/orm.py 2012-12-18 22:39:59 +0000
115+++ openerp/osv/orm.py 2012-12-20 14:32:31 +0000
116@@ -58,6 +58,7 @@
117
118 import psycopg2
119 from lxml import etree
120+import warnings
121
122 import fields
123 import openerp
124@@ -67,6 +68,7 @@
125 from openerp.tools.misc import CountingStream
126 from openerp.tools.safe_eval import safe_eval as eval
127 from openerp.tools.translate import _
128+from openerp.tools.deprecate import deprecated
129 from openerp import SUPERUSER_ID
130 from query import Query
131
132@@ -333,7 +335,6 @@
133 self._cr = cr
134 self._uid = uid
135 self._id = id
136- self._table = table # deprecated, use _model!
137 self._model = table
138 self._table_name = self._table._name
139 self.__logger = logging.getLogger('openerp.osv.orm.browse_record.' + self._table_name)
140@@ -353,6 +354,11 @@
141
142 self._cache = cache
143
144+ @property
145+ def _table(self):
146+ warnings.warn('_table is deprecated. Use _model', DeprecationWarning, stacklevel=2)
147+ return self._model
148+
149 def __getitem__(self, name):
150 if name == 'id':
151 return self._id
152@@ -376,10 +382,8 @@
153 else:
154 return attr
155 else:
156- error_msg = "Field '%s' does not exist in object '%s'" % (name, self)
157+ error_msg = "Field '%s' does not exist in object '%s'" % (name, self)
158 self.__logger.warning(error_msg)
159- if self.__logger.isEnabledFor(logging.DEBUG):
160- self.__logger.debug(''.join(traceback.format_stack()))
161 raise KeyError(error_msg)
162
163 # if the field is a classic one or a many2one, we'll fetch all classic and many2one fields
164@@ -714,9 +718,11 @@
165
166 CONCURRENCY_CHECK_FIELD = '__last_update'
167
168+ @deprecated("log() is deprecated. Please use OpenChatter notification "
169+ "system instead of the res.log mechanism.")
170 def log(self, cr, uid, id, message, secondary=False, context=None):
171- return _logger.warning("log() is deprecated. Please use OpenChatter notification system instead of the res.log mechanism.")
172-
173+ return
174+
175 def view_init(self, cr, uid, fields_list, context=None):
176 """Override this method to do specific things when a view on the object is opened."""
177 pass
178@@ -2059,7 +2065,9 @@
179 """
180 if context is None:
181 context = {}
182-
183+ if submenu:
184+ warnings.warn('using the submenu named argument in Model.fields_view_get is deprecated',
185+ DeprecationWarning, stacklevel=2)
186 def encode(s):
187 if isinstance(s, unicode):
188 return s.encode('utf8')
189@@ -3735,7 +3743,8 @@
190 for f in list(fields_pre) + list(fields_post):
191 field_column = self._all_columns.get(f) and self._all_columns.get(f).column
192 if field_column and field_column.deprecated:
193- _logger.warning('Field %s.%s is deprecated: %s', self._name, f, field_column.deprecated)
194+ warnings.warn('Field %s.%s is deprecated: %s' % (self._name, f, field_column.deprecated),
195+ DeprecationWarning, stacklevel=2)
196
197 readonly = None
198 for vals in res:
199@@ -4124,7 +4133,9 @@
200 for field in vals:
201 field_column = self._all_columns.get(field) and self._all_columns.get(field).column
202 if field_column and field_column.deprecated:
203- _logger.warning('Field %s.%s is deprecated: %s', self._name, field, field_column.deprecated)
204+ warnings.warn('Field %s.%s is deprecated: %s' % (self._name, field,
205+ field_column.deprecated),
206+ DeprecationWarning, stacklevel=2)
207 if field in self._columns:
208 if self._columns[field]._classic_write and not (hasattr(self._columns[field], '_fnct_inv')):
209 if (not totranslate) or not self._columns[field].translate:
210@@ -5038,9 +5049,9 @@
211 cr.execute(query + "WHERE ID IN %s", (tuple(ids),))
212 return [x[0] for x in cr.fetchall()]
213
214+ @deprecated("You are using deprecated Model.check_recursion(). "
215+ "Please use '_check_recursion()' instead!")
216 def check_recursion(self, cr, uid, ids, context=None, parent=None):
217- _logger.warning("You are using deprecated %s.check_recursion(). Please use the '_check_recursion()' instead!" % \
218- self._name)
219 assert parent is None or parent in self._columns or parent in self._inherit_fields,\
220 "The 'parent' parameter passed to check_recursion() must be None or a valid field name"
221 return self._check_recursion(cr, uid, ids, context, parent)
222@@ -5282,12 +5293,24 @@
223 if len(items) == 1:
224 return lambda gettable: (gettable[items[0]],)
225 return operator.itemgetter(*items)
226+
227 class ImportWarning(Warning):
228 """ Used to send warnings upwards the stack during the import process
229 """
230 pass
231
232
233+class deprecated_model(MetaModel):
234+ """issues a DeprecationWarning when the class is used as a parent class
235+ """
236+ def __new__(meta, name, bases, attrs):
237+ for b in bases:
238+ if isinstance(b, deprecated_model):
239+ warning = getattr(b, '__deprecation_warning__', '%(class)s is deprecated')
240+ warnings.warn(warning % {'class': name}, DeprecationWarning, stacklevel=2)
241+ return super(deprecated_model, meta).__new__(meta, name, bases, attrs)
242+
243+
244 def convert_pgerror_23502(model, fields, info, e):
245 m = re.match(r'^null value in column "(?P<field>\w+)" violates '
246 r'not-null constraint\n',
247
248=== modified file 'openerp/osv/osv.py'
249--- openerp/osv/osv.py 2012-12-09 03:49:10 +0000
250+++ openerp/osv/osv.py 2012-12-20 14:32:31 +0000
251@@ -26,6 +26,7 @@
252 import threading
253
254 from psycopg2 import IntegrityError, errorcodes
255+import warnings
256
257 import orm
258 import openerp
259@@ -33,7 +34,7 @@
260 import openerp.pooler as pooler
261 import openerp.sql_db as sql_db
262 from openerp.tools.translate import translate
263-from openerp.osv.orm import MetaModel, Model, TransientModel, AbstractModel
264+from openerp.osv.orm import MetaModel, Model, TransientModel, AbstractModel, deprecated_model
265 import openerp.exceptions
266
267 _logger = logging.getLogger(__name__)
268@@ -41,6 +42,7 @@
269 # Deprecated.
270 class except_osv(Exception):
271 def __init__(self, name, value):
272+ warnings.warn('except_osv is deprecated', DeprecationWarning, stacklevel=2)
273 self.name = name
274 self.value = value
275 self.args = (name, value)
276@@ -208,11 +210,19 @@
277 cr.close()
278 return res
279
280-# deprecated - for backward compatibility.
281-osv = Model
282-osv_memory = TransientModel
283-osv_abstract = AbstractModel # ;-)
284-
285+# deprecated - for backward compatibility
286+class osv(Model):
287+ __metaclass__ = deprecated_model
288+ __deprecation_warning__ = "osv.osv is deprecated. Use orm.Model"
289+ _register=False
290+class osv_memory(TransientModel):
291+ __metaclass__ = deprecated_model
292+ __deprecation_warning__ = "osv.osv_memory is deprecated. Use orm.TransientModel"
293+ _register=False
294+class osv_abstract(AbstractModel):
295+ __metaclass__ = deprecated_model
296+ __deprecation_warning__ = "osv.osv_abstract is deprecated. Use orm.AbstractModel"
297+ _register=False
298
299 def start_object_proxy():
300 object_proxy()
301
302=== modified file 'openerp/sql_db.py'
303--- openerp/sql_db.py 2012-12-14 12:43:10 +0000
304+++ openerp/sql_db.py 2012-12-20 14:32:31 +0000
305@@ -37,11 +37,13 @@
306
307 from functools import wraps
308 import logging
309+import warnings
310 import psycopg2.extensions
311 from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT, ISOLATION_LEVEL_READ_COMMITTED, ISOLATION_LEVEL_REPEATABLE_READ
312 from psycopg2.pool import PoolError
313 from psycopg2.psycopg1 import cursor as psycopg1cursor
314 from threading import currentThread
315+from openerp.tools.deprecate import deprecated
316
317 psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
318
319@@ -476,13 +478,14 @@
320 _logger.debug('create %scursor to %r', cursor_type, self.dbname)
321 return Cursor(self._pool, self.dbname, serialized=serialized)
322
323- # serialized_cursor is deprecated - cursors are serialized by default
324- serialized_cursor = cursor
325+ @deprecated("serialized_cursor is deprecated - cursors are serialized by default")
326+ def serialized_cursor(self):
327+ return self.cursor()
328
329+ @deprecated("__nonzero__() is deprecated. (It is too expensive to test a connection.)")
330 def __nonzero__(self):
331 """Check if connection is possible"""
332 try:
333- _logger.warning("__nonzero__() is deprecated. (It is too expensive to test a connection.)")
334 cr = self.cursor()
335 cr.close()
336 return True
337
338=== modified file 'openerp/tools/config.py'
339--- openerp/tools/config.py 2012-12-20 10:15:11 +0000
340+++ openerp/tools/config.py 2012-12-20 14:32:31 +0000
341@@ -187,6 +187,9 @@
342 group.add_option('--log-response', action="append_const", dest="log_handler", const="openerp.netsvc.rpc.response:DEBUG", help='shortcut for --log-handler=openerp.netsvc.rpc.response:DEBUG')
343 group.add_option('--log-web', action="append_const", dest="log_handler", const="openerp.addons.web.http:DEBUG", help='shortcut for --log-handler=openerp.addons.web.http:DEBUG')
344 group.add_option('--log-sql', action="append_const", dest="log_handler", const="openerp.sql_db:DEBUG", help='shortcut for --log-handler=openerp.sql_db:DEBUG')
345+ group.add_option('--deprecation-warnings', metavar='<log|stderr|hide>',
346+ default='log', dest="deprecation_warnings",
347+ help="log deprecation warnings (default), print them on stderr, or hide them altogether")
348 # For backward-compatibility, map the old log levels to something
349 # quite close.
350 levels = ['info', 'debug_rpc', 'warn', 'test', 'critical',
351@@ -384,7 +387,8 @@
352 'netrpc', 'xmlrpc', 'syslog', 'without_demo', 'timezone',
353 'xmlrpcs_interface', 'xmlrpcs_port', 'xmlrpcs',
354 'static_http_enable', 'static_http_document_root', 'static_http_url_prefix',
355- 'secure_cert_file', 'secure_pkey_file', 'dbfilter', 'log_handler', 'log_level'
356+ 'secure_cert_file', 'secure_pkey_file', 'dbfilter', 'log_handler', 'log_level',
357+ 'deprecation_warnings',
358 ]
359
360 for arg in keys:
361
362=== modified file 'openerp/tools/convert.py'
363--- openerp/tools/convert.py 2012-12-17 14:47:53 +0000
364+++ openerp/tools/convert.py 2012-12-20 14:32:31 +0000
365@@ -25,6 +25,7 @@
366 import os.path
367 import pickle
368 import re
369+import warnings
370
371 # for eval context:
372 import time
373@@ -838,7 +839,8 @@
374 raise Exception( "Mismatch xml format: only terp or openerp as root tag" )
375
376 if de.tag == 'terp':
377- _logger.warning("The tag <terp/> is deprecated, use <openerp/>")
378+ warnings.warn("The tag <terp/> is deprecated, use <openerp/>",
379+ DeprecationWarning, stacklevel=2)
380
381 for n in de.findall('./data'):
382 for rec in n:
383
384=== added file 'openerp/tools/deprecate.py'
385--- openerp/tools/deprecate.py 1970-01-01 00:00:00 +0000
386+++ openerp/tools/deprecate.py 2012-12-20 14:32:31 +0000
387@@ -0,0 +1,19 @@
388+
389+from warnings import warn
390+import openerp
391+
392+
393+
394+def deprecated(message=None, name=None):
395+ def decorator(func):
396+ if message is None:
397+ msg = 'the function %s is deprecated' % func.func_name
398+ else:
399+ msg = message
400+ def wrapper(*args, **kwargs):
401+ warn(msg, DeprecationWarning, stacklevel=2)
402+ return func(*args, **kwargs)
403+ wrapper.__name__ = name or func.__name__
404+ wrapper.__doc__ = func.__doc__
405+ return wrapper
406+ return decorator
407
408=== modified file 'openerp/tools/misc.py'
409--- openerp/tools/misc.py 2012-12-17 15:02:41 +0000
410+++ openerp/tools/misc.py 2012-12-20 14:32:31 +0000
411@@ -36,6 +36,7 @@
412 import threading
413 import time
414 import zipfile
415+import warnings
416 from collections import defaultdict
417 from datetime import datetime
418 from itertools import islice, izip
419@@ -48,6 +49,7 @@
420 except ImportError:
421 html2text = None
422
423+from openerp.tools.deprecate import deprecated
424 from config import config
425 from cache import *
426
427@@ -410,6 +412,8 @@
428 """
429
430 def __init__(self, value, accuracy=2, rounding=None):
431+ warnings.warn('Use res.currency.round instead of currency',
432+ DeprecationWarning, stacklevel=2)
433 if rounding is None:
434 rounding=10**-accuracy
435 self.rounding=rounding