Skip to content

Commit

Permalink
empty selection in m2m field template
Browse files Browse the repository at this point in the history
[FIX] other licenses, return lines as well

[FIX] license not shown in __oe__

[FIX] unprefix more names, try to get _name/_inherit right [IMP] group by module in zip

[FIX] fix category and summary being on same line

[FIX] fix export test

[IMP] add tabs for reports/security/workflow/data + partial data/demo generation

unprefix model names in __init__

[FIX] fix data file names in __openerp__.py

[IMP] move Data&Demo after Interface in view

[FIX] unprefix view file names

[IMP] remove prefixes from field attrs in views

[FIX] encode files in zip to utf-8, remove trailing comma in menu groups

remove unused variable in tests

remove AGPL3 or later from license choices: not in base module choices
  • Loading branch information
Vincent Vinet authored and Maxime Chambreuil committed Oct 9, 2015
1 parent 6dfed35 commit 2eebf02
Show file tree
Hide file tree
Showing 13 changed files with 204 additions and 74 deletions.
1 change: 1 addition & 0 deletions module_prototyper/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ Contributors
* Maxime Chambreuil <[email protected]>
* El hadji Dem <[email protected]>
* Savoir-faire Linux <[email protected]>
* Vincent Vinet <[email protected]>

Maintainer
----------
Expand Down
2 changes: 1 addition & 1 deletion module_prototyper/models/ir_model_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class ir_model_fields(models.Model):
"relation table"),
)
limit = fields.Integer('Read limit', help=_("Read limit"))
context = fields.Char(
client_context = fields.Char(
'Context',
help=_("Context to use on the client side when handling the field "
"(python dictionary)"),
Expand Down
2 changes: 1 addition & 1 deletion module_prototyper/models/licenses.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,6 @@ def get_license_text(license):
name, version = GPL_LICENSES[license]
return BASE_GPL.format(name=name, version=version).splitlines()
elif license == OSI:
return BASE_OSI
return BASE_OSI.splitlines()
else:
return ""
125 changes: 110 additions & 15 deletions module_prototyper/models/module_prototyper.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#
##############################################################################
import base64
import logging
import lxml.etree
import os
import re
Expand All @@ -31,10 +32,13 @@
from jinja2 import Environment, FileSystemLoader

from openerp import models, api, fields
from openerp.tools.safe_eval import safe_eval

from .default_description import get_default_description
from . import licenses

_logger = logging.getLogger(__name__)


class ModulePrototyper(models.Model):
"""Module Prototyper gathers different information from all over the
Expand All @@ -53,7 +57,6 @@ class ModulePrototyper(models.Model):
(licenses.LGPL3, 'LGPL-3'),
(licenses.LGPL3_L, 'LGPL-3 or later version'),
(licenses.AGPL3, 'Affero GPL-3'),
(licenses.AGPL3_L, 'Affero GPL-3 or later version'),
(licenses.OSI, 'Other OSI Approved Licence'),
('Other proprietary', 'Other Proprietary')
],
Expand Down Expand Up @@ -170,10 +173,29 @@ class ModulePrototyper(models.Model):
help=('Enter the list of record rules that you have created and '
'want to export in this module.')
)
report_ids = fields.Many2many(
'ir.actions.report.xml', 'prototype_report_rel',
'module_prototyper_id', 'report_id', 'Reports',
help=('Enter the list of reports that you have created and '
'want to export in this module.')
)
activity_ids = fields.Many2many(
'workflow.activity', 'prototype_wf_activity_rel',
'module_prototyper_id', 'activity_id', 'Activities',
help=('Enter the list of workflow activities that you have created '
'and want to export in this module')
)
transition_ids = fields.Many2many(
'workflow.transition', 'prototype_wf_transition_rel',
'module_prototyper_id', 'transition_id', 'Transitions',
help=('Enter the list of workflow transitions that you have created '
'and want to export in this module')
)

__data_files = []
__field_descriptions = {}
_env = None
_data_files = ()
_demo_files = ()
_field_descriptions = None
File_details = namedtuple('file_details', ['filename', 'filecontent'])
template_path = '{}/../templates/'.format(os.path.dirname(__file__))

Expand Down Expand Up @@ -211,10 +233,8 @@ def set_field_descriptions(self):
for attr_name in dir(field)
if not attr_name[0] == '_'
})
# custom fields start with the prefix x_.
# it has to be removed.
field_description['name'] = re.sub(r'^x_', '', field.name)
self.__field_descriptions[field] = field_description
field_description['name'] = self.unprefix(field.name)
self._field_descriptions[field] = field_description

@api.model
def generate_files(self):
Expand All @@ -224,12 +244,17 @@ def generate_files(self):
assert self._env is not None, \
'Run set_env(api_version) before to generate files.'

# Avoid sharing these across instances
self._data_files = []
self._demo_files = []
self._field_descriptions = {}
self.set_field_descriptions()
file_details = []
file_details.extend(self.generate_models_details())
file_details.extend(self.generate_views_details())
file_details.extend(self.generate_menus_details())
file_details.append(self.generate_module_init_file_details())
file_details.extend(self.generate_data_files())
# must be the last as the other generations might add information
# to put in the __openerp__: additional dependencies, views files, etc.
file_details.append(self.generate_module_openerp_file_details())
Expand Down Expand Up @@ -262,7 +287,8 @@ def generate_module_openerp_file_details(self):
'__openerp__.py',
'__openerp__.py.template',
prototype=self,
data_files=self.__data_files,
data_files=self._data_files,
demo_fiels=self._demo_files,
)

@api.model
Expand All @@ -278,7 +304,8 @@ def generate_module_init_file_details(self):

@api.model
def generate_models_details(self):
"""Finds the models from the list of fields and generates
"""
Finds the models from the list of fields and generates
the __init__ file and each models files (one by class).
"""
files = []
Expand All @@ -291,7 +318,8 @@ def generate_models_details(self):
# dependencies = set([dep.id for dep in self.dependencies])

relations = {}
for field in self.__field_descriptions.itervalues():
field_descriptions = self._field_descriptions or {}
for field in field_descriptions.itervalues():
model = field.get('model_id')
relations.setdefault(model, []).append(field)
# dependencies.add(model.id)
Expand Down Expand Up @@ -329,7 +357,7 @@ def generate_views_details(self):
views_details = []
for model, views in relations.iteritems():
filepath = 'views/{}_view.xml'.format(
self.friendly_name(model)
self.friendly_name(self.unprefix(model))
)
views_details.append(
self.generate_file_details(
Expand All @@ -338,7 +366,7 @@ def generate_views_details(self):
views=views
)
)
self.__data_files.append(filepath)
self._data_files.append(filepath)

return views_details

Expand All @@ -348,13 +376,14 @@ def generate_menus_details(self):
relations = {}
for menu in self.menu_ids:
if menu.action and menu.action.res_model:
model = menu.action.res_model
model = self.unprefix(menu.action.res_model)
else:
model = 'ir_ui'
relations.setdefault(model, []).append(menu)

menus_details = []
for model_name, menus in relations.iteritems():
model_name = self.unprefix(model_name)
filepath = 'views/{}_menus.xml'.format(
self.friendly_name(model_name)
)
Expand All @@ -365,7 +394,7 @@ def generate_menus_details(self):
menus=menus,
)
)
self.__data_files.append(filepath)
self._data_files.append(filepath)

return menus_details

Expand All @@ -377,7 +406,7 @@ def generate_model_details(self, model, field_descriptions):
:param field_descriptions: list of ir.model.fields records.
:return: FileDetails instance.
"""
python_friendly_name = self.friendly_name(model.model)
python_friendly_name = self.friendly_name(self.unprefix(model.model))
return self.generate_file_details(
'models/{}.py'.format(python_friendly_name),
'models/model_name.py.template',
Expand All @@ -386,22 +415,87 @@ def generate_model_details(self, model, field_descriptions):
fields=field_descriptions,
)

@api.model
def generate_data_files(self):
""" Generate data and demo files """
data, demo = {}, {}
filters = [
(data, ir_filter)
for ir_filter in self.data_ids
] + [
(demo, ir_filter)
for ir_filter in self.demo_ids
]

for target, ir_filter in filters:
model = ir_filter.model_id
model_obj = self.env[model]
target.setdefault(model, model_obj.browse([]))
target[model] |= model_obj.search(safe_eval(ir_filter.domain))

res = []
for prefix, model_data, file_list in [
('data', data, self._data_files),
('demo', demo, self._demo_files)]:
for model_name, records in model_data.iteritems():
fname = self.friendly_name(self.unprefix(model_name))
filename = '{0}/{1}.xml'.format(prefix, fname)
self._data_files.append(filename)

res.append(self.generate_file_details(
filename,
'data/model_name.xml.template',
model=model_name,
records=records,
))

return res

@classmethod
def unprefix(cls, name):
if not name:
return name
return re.sub('^x_', '', name)

@classmethod
def is_prefixed(cls, name):
return bool(re.match('^x_', name))

@classmethod
def friendly_name(cls, name):
return name.replace('.', '_')

@classmethod
def fixup_domain(cls, domain):
""" Fix a domain according to unprefixing of fields """
res = []
for elem in domain:
if len(elem) == 3:
elem = list(elem)
elem[0] = cls.unprefix(elem[0])
res.append(elem)
return res

@classmethod
def fixup_arch(cls, archstr):
doc = lxml.etree.fromstring(archstr)
for elem in doc.xpath("//*[@name]"):
elem.attrib["name"] = cls.unprefix(elem.attrib["name"])

for elem in doc.xpath("//*[@attrs]"):
try:
attrs = safe_eval(elem.attrib["attrs"])
except Exception:
_logger.error("Unable to eval attribute: %s, skipping",
elem.attrib["attrs"])
continue

if isinstance(attrs, dict):
for key, val in attrs.iteritems():
if isinstance(val, (list, tuple)):
attrs[key] = cls.fixup_domain(val)
elem.attrib["attrs"] = repr(attrs)

for elem in doc.xpath("//field"):
# Make fields self-closed by removing useless whitespace
if elem.text and not elem.text.strip():
Expand All @@ -428,6 +522,7 @@ def generate_file_details(self, filename, template, **kwargs):
'cr': self._cr,
# Utility functions
'fixup_arch': self.fixup_arch,
'is_prefixed': self.is_prefixed,
'unprefix': self.unprefix,
'wrap': wrap,

Expand Down
9 changes: 5 additions & 4 deletions module_prototyper/templates/8.0/__openerp__.py.template
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@
'author': '{{ prototype.author }}',
'maintainer': '{{ prototype.maintainer }}',
'website': '{{ prototype.website }}',
'license': '{{ prototype.licence }}',
'license': '{{ prototype.license }}',

# Categories can be used to filter modules in modules listing
# Check https://github.com/odoo/odoo/blob/master/openerp/addons/base/module/module_data.xml # noqa
# for the full list
'category': '{{ prototype.with_context({}).category_id.name }}',{# In english please! #}
{# Use with_context({}) to get english category #}
'category': '{{ prototype.with_context({}).category_id.name }}',
'summary': '{{ prototype.summary }}',
'description': """
{{ prototype.description }}
Expand Down Expand Up @@ -40,8 +41,8 @@
],
# only loaded in demonstration mode
'demo': [
{% for demo_file in prototype.demo_ids %}
'{{ demo_file.name }}',
{% for demo_file in demo_files %}
'{{ demo_file }}',
{% endfor %}
],

Expand Down
13 changes: 11 additions & 2 deletions module_prototyper/templates/8.0/data/model_name.xml.template
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
<?xml version="1.0"?>
<openerp>
<data>
{% for record in records %}
<!--
<record id="{{ model }}_{{ loop.index }}" model="{{ model }}">
{% for key, val in record.read()[0].items() %}
<field name="{{ key }}">{{ val }}</field>
{% endfor %}
</record>
-->
{% if not loop.last %}

{{ data }}

{% endif %}
{% endfor %}
</data>
</openerp>
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
{% if loop.first %}

{% endif %}
from . import {{ model }}
from . import {{ unprefix(model) }}
{% endfor %}
{% endblock %}
23 changes: 14 additions & 9 deletions module_prototyper/templates/8.0/models/model_name.py.template
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ from openerp.tools.translate import _


class {{ unprefix(name) }}(models.Model):
{% if model.state == 'base' %}
_name = "{{ model.model }}"
{% if model.state == 'base' and not is_prefixed(model.model) %}
_inherit = "{{ unprefix(model.model) }}"
{% else %}
_inherit = "{{ model.model }}"
_name = "{{ unprefix(model.model) }}"
{% endif %}
{% if description %}
_description = "{{ description }}"
Expand All @@ -26,10 +26,13 @@ class {{ unprefix(name) }}(models.Model):
{{ unprefix(field.name) }} = fields.{{ field.ttype|capitalize }}(
string=_("{{ field.field_description }}"),
{% if field.selection %}
selection={{ selection }},
selection={{ field.selection }},
{% endif %}
{% if field.relation %}
comodel_name="{{ field.relation }}",
comodel_name="{{ unprefix(field.relation) }}",
{% endif %}
{% if field.ttype == 'one2many' %}
inverse_name="{{ unprefix(field.relation_field) }}",
{% endif %}
{% if field.column1 %}
column1="{{ field.column1 }}",
Expand All @@ -43,11 +46,13 @@ class {{ unprefix(name) }}(models.Model):
{% if field.size %}
size={{ field.size }},
{% endif %}
{% if field.domain %}
{% if field.ttype in ('many2one', 'many2many', 'one2many') %}
{% if field.domain %}
domain={{ field.domain }},
{% endif %}
{% if field.context %}
context={{ field.context }},
{% endif %}
{% if field.client_context %}
context={{ field.client_context }},
{% endif %}
{% endif %}
{% if field.limit %}
limit={{ field.limit }},
Expand Down
Loading

0 comments on commit 2eebf02

Please sign in to comment.