Browse Source

base_manifest_extension

pull/979/head
Holger Brunn 8 years ago
committed by Oleg Bulkin
parent
commit
0696c309a6
  1. 65
      base_manifest_extension/README.rst
  2. 4
      base_manifest_extension/__init__.py
  3. 15
      base_manifest_extension/__openerp__.py
  4. 94
      base_manifest_extension/hooks.py
  5. BIN
      base_manifest_extension/static/description/icon.png
  6. 4
      base_manifest_extension/tests/__init__.py
  7. 31
      base_manifest_extension/tests/test_base_manifest_extension.py

65
base_manifest_extension/README.rst

@ -0,0 +1,65 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
=========================
Extra options in manifest
=========================
This is a technical module to allow developers to make use of a couple of new keys in module manifests.
The following new keys are available currently:
depends_if_installed
Your module will depend on modules listed here, but only if those modules are already installed. This is useful if your module is supposed to override behavior of a third module if present, but it's not a hard dependency of your module. Think of auth_* and their interactions.
Usage
=====
* depend on this module and use the keys described above
Roadmap
=======
* ``breaks`` to mark some modules as being incompatible. This also could be versioned (``'breaks': ['my_module<<0.4.2']``)
* ``demo_if_installed``, ``data_if_installed``, ``qweb_if_installed`` being dicts with module names as keys and a list of files as values in order to pull some data files in case some other module is installed
* ``rdepends_if_installed`` to make another installed module depend on the current module
* ``_if_module`` on models to load certain models only if the appropriate module is installed
Bug Tracker
===========
Bugs are tracked on `GitHub Issues
<https://github.com/OCA/server-tools/issues>`_. In case of trouble, please
check there if your issue has already been reported. If you spotted it first,
help us smashing it by providing a detailed and welcomed feedback.
Credits
=======
Images
------
* Odoo Community Association: `Icon <https://github.com/OCA/maintainer-tools/blob/master/template/module/static/description/icon.svg>`_.
Contributors
------------
* Holger Brunn <hbrunn@therp.nl>
Do not contact contributors directly about help with questions or problems concerning this addon, but use the `community mailing list <mailto:community@mail.odoo.com>`_ or the `appropriate specialized mailinglist <https://odoo-community.org/groups>`_ for help, and the bug tracker linked in `Bug Tracker`_ above for technical issues.
Maintainer
----------
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
This module is maintained by the OCA.
OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
To contribute to this module, please visit https://odoo-community.org.

4
base_manifest_extension/__init__.py

@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
# © 2017 Therp BV <http://therp.nl>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from .hooks import post_load_hook

15
base_manifest_extension/__openerp__.py

@ -0,0 +1,15 @@
# -*- coding: utf-8 -*-
# © 2017 Therp BV <http://therp.nl>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
{
"name": "More options in manifest",
"version": "8.0.1.0.0",
"author": "Therp BV,Odoo Community Association (OCA)",
"license": "AGPL-3",
"category": "Hidden/Dependency",
"summary": "Adds some useful keys to manifest files",
"depends": [
'base',
],
"post_load": 'post_load_hook',
}

94
base_manifest_extension/hooks.py

@ -0,0 +1,94 @@
# -*- coding: utf-8 -*-
# © 2017 Therp BV <http://therp.nl>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import inspect
from openerp.sql_db import Cursor
from openerp.modules import module
from openerp.modules.graph import Graph
original = module.load_information_from_description_file
def load_information_from_description_file(module, mod_path=None):
result = original(module, mod_path=mod_path)
# add the keys you want to react on here
if result.get('depends_if_installed'):
cr = _get_cr()
if cr:
_handle_depends_if_installed(cr, result)
return result
def _handle_depends_if_installed(cr, manifest):
if not manifest.get('depends_if_installed'):
return
cr.execute(
'select name from ir_module_module '
'where state in %s and name in %s',
(
tuple(['installed', 'to install', 'to upgrade']),
tuple(manifest['depends_if_installed']),
),
)
manifest.pop('depends_if_installed')
depends = manifest.setdefault('depends', [])
depends.extend(module for module, in cr.fetchall())
def _get_cr():
cr = None
for frame, filename, lineno, funcname, line, index in inspect.stack():
# walk up the stack until we've found a cursor
if 'cr' in frame.f_locals and isinstance(frame.f_locals['cr'], Cursor):
cr = frame.f_locals['cr']
break
return cr
def _get_graph():
graph = None
for frame, filename, lineno, funcname, line, index in inspect.stack():
# walk up the stack until we've found a graph
if 'graph' in frame.f_locals and isinstance(
frame.f_locals['graph'], Graph
):
graph = frame.f_locals['graph']
break
return graph
def post_load_hook():
cr = _get_cr()
if not cr:
return
cr.execute(
'select id from ir_module_module where name=%s and state in %s',
(
'base_manifest_extension',
tuple(['installed', 'to install', 'to upgrade']),
),
)
# do nothing if we're not installed
if not cr.rowcount:
return
module.load_information_from_description_file =\
load_information_from_description_file
# here stuff can become tricky: On the python level, modules
# are not loaded in dependency order. This means that there might
# be modules loaded depending on us before we could patch the function
# above. So we reload the module graph for all modules coming after us
graph = _get_graph()
if not graph:
return
this = graph['base_manifest_extension']
to_reload = []
for node in graph.itervalues():
if node.depth > this.depth:
to_reload.append(node.name)
for module_name in to_reload:
del graph[module_name]
graph.add_modules(cr, to_reload)

BIN
base_manifest_extension/static/description/icon.png

After

Width: 128  |  Height: 128  |  Size: 9.2 KiB

4
base_manifest_extension/tests/__init__.py

@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
# © 2017 Therp BV <http://therp.nl>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import test_base_manifest_extension

31
base_manifest_extension/tests/test_base_manifest_extension.py

@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
# © 2017 Therp BV <http://therp.nl>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import os
import tempfile
from openerp.tests.common import TransactionCase
from openerp.modules.module import load_information_from_description_file,\
get_module_path, MANIFEST
class TestBaseManifestExtension(TransactionCase):
def test_base_manifest_extension(self):
# write a test manifest
module_path = tempfile.mkdtemp(dir=os.path.join(
get_module_path('base_manifest_extension'), 'static'
))
with open(os.path.join(module_path, MANIFEST), 'w') as manifest:
manifest.write(repr({
'depends_if_installed': [
'base_manifest_extension',
'not installed',
],
}))
# parse it
parsed = load_information_from_description_file(
# this name won't really be used, but avoids a warning
'base', mod_path=module_path,
)
self.assertIn('base_manifest_extension', parsed['depends'])
self.assertNotIn('not installed', parsed['depends'])
self.assertNotIn('depends_if_installed', parsed)
Loading…
Cancel
Save