@@ -98,16 +98,44 @@ def module_installed(cr, module):
9898 return modules_installed (cr , module )
9999
100100
101- def uninstall_module (cr , module ):
101+ def module_dependencies (cr , module ):
102+ """Get dependencies of given module.
103+
104+ :param str module: name of the module
105+ :return: list names of the dependencies
106+ :rtype: list(str)
107+ """
108+ cr .execute (
109+ """
110+ SELECT m.name
111+ FROM ir_module_module m
112+ INNER JOIN ir_module_module_dependency d ON d.module_id = m.id
113+ WHERE d.name = %s
114+ """ ,
115+ [module ],
116+ )
117+ return [name for (name ,) in cr .fetchall ()]
118+
119+
120+ def uninstall_module (cr , module , with_dependencies = False ):
102121 """
103122 Uninstall and remove all records owned by a module.
104123
105124 :param str module: name of the module to uninstall
125+ :param bool with_dependencies: whether to also remove dependencies of the module
126+ :return: set of uninstalled module names
127+ :rtype: set(str)
106128 """
129+ result = set ()
107130 cr .execute ("SELECT id FROM ir_module_module WHERE name=%s" , (module ,))
108131 (mod_id ,) = cr .fetchone () or [None ]
109132 if not mod_id :
110- return
133+ return result
134+
135+ if with_dependencies :
136+ dependencies = module_dependencies (cr , module )
137+ for dep in dependencies :
138+ result .union (uninstall_module (cr , dep , with_dependencies = with_dependencies ))
111139
112140 # delete constraints only owned by this module
113141 cr .execute (
@@ -219,14 +247,18 @@ def uninstall_module(cr, module):
219247 if table_exists (cr , "ir_translation" ):
220248 cr .execute ("DELETE FROM ir_translation WHERE module=%s" , [module ])
221249 cr .execute ("UPDATE ir_module_module SET state='uninstalled' WHERE name=%s" , (module ,))
250+ return result | {module }
222251
223252
224- def uninstall_theme (cr , theme , base_theme = None ):
253+ def uninstall_theme (cr , theme , base_theme = None , with_dependencies = False ):
225254 """
226255 Uninstall a theme module and remove it from websites.
227256
228257 :param str theme: name of the theme module to uninstall
229258 :param str or None base_theme: if not `None`, unload first this base theme
259+ :param bool with_dependencies: whether to also remove dependencies of the theme
260+ :return: set of uninstalled module names
261+ :rtype: set(str)
230262
231263 .. warning::
232264
@@ -238,7 +270,7 @@ def uninstall_theme(cr, theme, base_theme=None):
238270 cr .execute ("SELECT id FROM ir_module_module WHERE name=%s AND state in %s" , [theme , INSTALLED_MODULE_STATES ])
239271 (theme_id ,) = cr .fetchone () or [None ]
240272 if not theme_id :
241- return
273+ return None
242274
243275 env_ = env (cr )
244276 IrModuleModule = env_ ["ir.module.module" ]
@@ -253,17 +285,20 @@ def uninstall_theme(cr, theme, base_theme=None):
253285 for website in websites :
254286 IrModuleModule ._theme_remove (website )
255287 flush (env_ ["base" ])
256- uninstall_module (cr , theme )
288+ return uninstall_module (cr , theme , with_dependencies = with_dependencies )
257289
258290
259- def remove_module (cr , module ):
291+ def remove_module (cr , module , with_dependencies = False ):
260292 """
261293 Completely remove a module.
262294
263295 This operation is equivalent to uninstall and removal of *all* references to
264296 the module - no trace of it is left in the database.
265297
266298 :param str module: name of the module to remove
299+ :param bool with_dependencies: whether to also remove dependencies of the module
300+ :return: set of uninstalled module names
301+ :rtype: set(str)
267302
268303 .. warning::
269304 Since this function removes *all* data associated to the module. Ensure to
@@ -273,15 +308,17 @@ def remove_module(cr, module):
273308 # module need to be currently installed and running as deletions
274309 # are made using orm.
275310
276- uninstall_module (cr , module )
277- cr .execute ("DELETE FROM ir_module_module_dependency WHERE name=%s" , (module ,))
278- cr .execute ("DELETE FROM ir_module_module WHERE name=%s RETURNING id" , (module ,))
311+ result = uninstall_module (cr , module , with_dependencies = with_dependencies )
312+ names = list (result )
313+ cr .execute ("DELETE FROM ir_module_module_dependency WHERE name = ANY(%s)" , (names ,))
314+ cr .execute ("DELETE FROM ir_module_module WHERE name = ANY(%s) RETURNING id" , (names ,))
279315 if cr .rowcount :
280- [mod_id ] = cr .fetchone ()
281- cr .execute ("DELETE FROM ir_model_data WHERE model='ir.module.module' AND res_id=%s" , [mod_id ])
316+ ids = [id_ for (id_ ,) in cr .fetchall ()]
317+ cr .execute ("DELETE FROM ir_model_data WHERE model='ir.module.module' AND res_id = ANY(%s)" , (ids ,))
318+ return result
282319
283320
284- def remove_theme (cr , theme , base_theme = None ):
321+ def remove_theme (cr , theme , base_theme = None , with_dependencies = False ):
285322 """
286323 Uninstall a theme module.
287324
@@ -290,12 +327,14 @@ def remove_theme(cr, theme, base_theme=None):
290327
291328 See :func:`remove_module` and :func:`uninstall_theme`.
292329 """
293- uninstall_theme (cr , theme , base_theme = base_theme )
294- cr .execute ("DELETE FROM ir_module_module_dependency WHERE name=%s" , (theme ,))
295- cr .execute ("DELETE FROM ir_module_module WHERE name=%s RETURNING id" , (theme ,))
330+ result = uninstall_theme (cr , theme , base_theme = base_theme , with_dependencies = with_dependencies )
331+ themes = list (result )
332+ cr .execute ("DELETE FROM ir_module_module_dependency WHERE name = ANY(%s)" , (themes ,))
333+ cr .execute ("DELETE FROM ir_module_module WHERE name = ANY(%s) RETURNING id" , (themes ,))
296334 if cr .rowcount :
297- [mod_id ] = cr .fetchone ()
298- cr .execute ("DELETE FROM ir_model_data WHERE model='ir.module.module' AND res_id=%s" , [mod_id ])
335+ ids = [id_ for (id_ ,) in cr .fetchall ()]
336+ cr .execute ("DELETE FROM ir_model_data WHERE model='ir.module.module' AND res_id = ANY(%s)" , (ids ,))
337+ return result
299338
300339
301340def _update_view_key (cr , old , new ):
0 commit comments