o
    š�ži ã                   @  s~  d Z ddlmZ ddlZddlZddlZddlZddlZddlZddl	Z	ddl
Z
ddlZddlZddlZddlZddlZddlZddlZddlmZmZ ddlmZ ddlmZmZmZmZ ddlmZ ddlmZm Z  dd	l!m"Z" dd
l#m$Z$ ddl%m&Z& ddl'm(Z( ddl)m*Z* ddl+m,Z,m-Z- ddl.m/Z/ ddl0m1Z1m2Z2m3Z3 ddl4m5Z5 ddl6m7Z7 ddl8m9Z9m:Z:m;Z;m<Z<m=Z= ddl>m?Z?m@Z@ ddlAmBZBmCZCmDZDmEZEmFZF ddlGmHZH ddlImJZJmKZKmLZL ddlMmNZNmOZO ddlPmQZQ ddlRmSZS ddlTmUZU ddlPmVZV ddlWmXZXmYZY ddlZm[Z[ ddl>m\Z\m]Z]m^Z^ e _e`¡Zaejbd  e_cd!ejdejc< eE eeDg d"¢ƒ¡eF ZfegZheig d#¢ƒZjeig d$¢ekeCƒ ƒZle	 md%¡Zne	 md&¡Zoe	 md'¡Zpe	 md(¡Zqe	 md)¡Zrh d*£Zsd+Zteƒ Zue	 md,e	jv¡jwZxd-d.„ Zyd/d0„ Zzd1d2„ Z{G d3d4„ d4e|ƒZ}G d5d6„ d6ƒZ~G d7d8„ d8e,ƒZG d9d:„ d:e,ƒZ€G d;d<„ d<ƒZ�G d=d>„ d>e=j‚ƒZƒeƒƒ Z„G d?d@„ d@e2j…ƒZ†dAdB„ Z‡dS )Cur:  
================
IrQweb / ir.qweb
================

Preamble
========

Technical documentation of the python operation of the rendering QWeb engine.

Templating
==========

QWeb is the primary templating engine used by Odoo. It is an XML templating
engine and used mostly to generate XML, HTML fragments and pages.

Template directives are specified as XML attributes prefixed with ``t-``,
for instance ``t-if`` for :ref:`reference/qweb/conditionals`, with elements
and other attributes being rendered directly.

To avoid element rendering, a placeholder element ``<t>`` is also available,
which executes its directive but doesn't generate any output in and of
itself.

To create new XML template, please see :doc:`QWeb Templates documentation
<https://www.odoo.com/documentation/master/developer/reference/frontend/qweb.html>`

Rendering process
=================

In **input** you have an XML template giving the corresponding input etree.
Each etree input nodes are used to generate a python function. This fonction is
called and will give the XML **output**.
The ``_compile`` method is responsible to generate the function from the
etree, that function is a python generator that yield one output line at a
time. This generator is consumed by ``_render``. The generated function is orm
cached.

For performance, the **compile time** (when input, XML template or template
id, is compiled into a function) is less important than the **rendering time**
(when the function is called with the different values). The generation of the
function is only done once (for a set of options, language, branding ...)
because it is cached orm

The output is in ``MarkupSafe`` format. ``MarkupSafe`` escapes characters so
text is safe to use in HTML and XML. Characters that have special meanings
are replaced so that they display as the actual characters. This mitigates
injection attacks, meaning untrusted user input can safely be displayed on a
page.

At **compile time**, each dynamic attribute ``t-*`` will be compiled into
specific python code. (For example ``<t t-out="5 + 5"/>`` will insert the
template "10" inside the output)

At **compile time**, each directive removes the dynamic attribute it uses from
the input node attributes. At the end of the compilation each input node, no
dynamic attributes must remain.

How the code works
==================

In the graphic below you can see theresume of the call of the methods performed
in the IrQweb class.

.. code-block:: rst

    Odoo
     â”—â”�â–º _render (returns MarkupSafe)
        â”—â”�â–º _compile (returns function)                                        â—„â”�â”�â”�â”�â”�â”�â”�â”�â”�â”�â”“
           â”—â”�â–º _compile_node (returns code string array)                       â—„â”�â”�â”�â”�â”�â”�â”�â”�â”“ â”ƒ
              â”ƒ  (skip the current node if found t-qweb-skip)                           â”ƒ â”ƒ
              â”ƒ  (add technical directives: t-tag-open, t-tag-close, t-inner-content)   â”ƒ â”ƒ
              â”ƒ                                                                         â”ƒ â”ƒ
              â”£â”�â–º _directives_eval_order (defined directive order)                      â”ƒ â”ƒ
              â”£â”�â–º _compile_directives (loop)    Consume all remaining directives â—„â”�â”�â”�â”“  â”ƒ â”ƒ
              â”ƒ  â”ƒ                              (e.g.: to change the indentation)    â”ƒ  â”ƒ â”ƒ
              â”ƒ  â”£â”�â–º _compile_directive                                              â”ƒ  â”ƒ â”ƒ
              â”ƒ  â”ƒ    â”—â”�â–º t-groups        â”�â”�â–º _compile_directive_groups             â”�â”«  â”ƒ â”ƒ
              â”ƒ  â”ƒ    â”—â”�â–º t-foreach       â”�â”�â–º _compile_directive_foreach            â”�â”«  â”ƒ â”ƒ
              â”ƒ  â”ƒ    â”—â”�â–º t-if            â”�â”�â–º _compile_directive_if                 â”�â”›  â”ƒ â”ƒ
              â”ƒ  â”ƒ    â”—â”�â–º t-inner-content â”�â”�â–º _compile_directive_inner_content â—„â”�â”�â”�â”�â”�â”“ â”�â”› â”ƒ
              â”ƒ  â”ƒ    â”—â”�â–º t-options       â”�â”�â–º _compile_directive_options             â”ƒ    â”ƒ
              â”ƒ  â”ƒ    â”—â”�â–º t-set           â”�â”�â–º _compile_directive_set           â—„â”�â”�â”“  â”ƒ    â”ƒ
              â”ƒ  â”ƒ    â”—â”�â–º t-call          â”�â”�â–º _compile_directive_call            â”�â”› â”�â”« â”�â”�â”�â”›
              â”ƒ  â”ƒ    â”—â”�â–º t-att           â”�â”�â–º _compile_directive_att                 â”ƒ
              â”ƒ  â”ƒ    â”—â”�â–º t-tag-open      â”�â”�â–º _compile_directive_open          â—„â”�â”�â”“  â”ƒ
              â”ƒ  â”ƒ    â”—â”�â–º t-tag-close     â”�â”�â–º _compile_directive_close         â—„â”�â”�â”«  â”ƒ
              â”ƒ  â”ƒ    â”—â”�â–º t-out           â”�â”�â–º _compile_directive_out             â”�â”› â”�â”« â—„â”�â”�â”“
              â”ƒ  â”ƒ    â”—â”�â–º t-field         â”�â”�â–º _compile_directive_field               â”ƒ   â”�â”«
              â”ƒ  â”ƒ    â”—â”�â–º t-esc           â”�â”�â–º _compile_directive_esc                 â”ƒ   â”�â”›
              â”ƒ  â”ƒ    â”—â”�â–º t-*             â”�â”�â–º ...                                    â”ƒ
              â”ƒ  â”ƒ                                                                   â”ƒ
              â”—â”�â”�â”»â”�â–º _compile_static_node                                           â”�â”›


The QWeb ``_render`` uses the function generated by the ``_compile`` method.
Each XML node will go through the ``_compile_node`` method. If the
node does not have dynamic directives or attributes (``_is_static_node``).
A ``static`` is a node without ``t-*`` attributes, does not require dynamic
rendering for its attributes.
If it's a ``static`` node, the ``_compile_static_node`` method is called,
otherwise it is the ``_compile_directives`` method after having prepared the
order for calling the directives using the ``_directives_eval_order`` method.
In the defined order, for each directive the method ``_compile_directive`` is
called which itself dispatches to the methods corresponding to the directives
``_compile_directive_[name of the directive]`` (for example: ``t-if`` =>
``_compile_directive_if``). After all ordered directives, the directives
attributes still present on the element are compiled.

The ``_post_processing_att`` method is used for the generation of rendering
attributes. If the attributes come from static XML template nodes then the
method is called only once when generating the render function. Otherwise the
method is called during each rendering.

Each expression is compiled by the method ``_compile_expr`` into a python
expression whose values are namespaced.

Directives
----------

``t-debug``
~~~~~~~~~~~
**Values**: `''` (empty string), ``pdb``, ``ipdb``, ``pudb``, ``wdb``

Triggers a debugger breakpoint at that location. With an empty value, calls the
``breakpoint`` builtin invoking whichever breakpoint hook has been set up,
otherwise triggers a breakpoint uses the corresponding debugger.

When dev mode is enabled this allows python developers to have access to the
state of variables being rendered. The code generated by the QWeb engine is
not accessible, only the variables (values, self) can be analyzed or the
methods that called the QWeb rendering.

.. warning:: using a non-empty string is deprecated since 17.0, configure your
             preferred debugger via ``PYTHONBREAKPOINT`` or
             ``sys.setbreakpointhook``.

``t-if``
~~~~~~~~
**Values**: python expression


Add an python ``if`` condition to the code string array, and call
``_compile_directives`` to level and add the code string array corresponding
to the other directives and content.

The structure of the dom is checked to possibly find a ``t-else`` or
``t-elif``. If these directives exist then the compilation is performed and
the nodes are marked not to be rendered twice.

At **rendering time** the other directives code and content will used only if
the expression is evaluated as truely.

The ``t-else``, ``t-elif`` and ``t-if`` are not compiled at the same time like
defined in ``_directives_eval_order`` method.
```
<t t-set="check" t-value="1"/>
<section t-if="False">10</section>
<span t-elif="check == 1" t-foreach="range(3)" t-as="check" t-esc="check"/>

<section t-if="False">10</section>
<div t-else="" t-if="check == 1" t-foreach="range(3)" t-as="check" t-esc="check"/>

Result:

<span>0</span>
<span>1</span>
<span>2</span>

<div>1</div>
```

``t-else``
~~~~~~~~~~
**Values**: nothing

Only validate the **input**, the compilation if inside the ``t-if`` directive.

``t-elif``
~~~~~~~~~~
**Values**: python expression

Only validate the **input**, the compilation if inside the ``t-if`` directive.

``t-groups`` (``groups`` is an alias)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**Values**: name of the allowed odoo user group, or preceded by ``!`` for
prohibited groups

The generated code uses ``has_group`` Odoo method from ``res.users`` model.

``t-foreach``
~~~~~~~~~~~~~
**Values**: an expression returning the collection to iterate on

This directive is used with ``t-as`` directive to defined the key name. The
directive will be converted into a ``for`` loop. In this loop, different values
are added to the dict (``values`` in the generated method) in addition to the
key defined by ``t-name``, these are (``*_value``, ``*_index``, ``*_size``,
``*_first``, ``*_last``).

``t-as``
~~~~~~~~
**Values**: key name

The compilation method only validates if ``t-as`` and ``t-foreach`` are on the
same node.

``t-options`` and ``t-options-*``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**Values**: python expression

It's use on the same node of another directive, it's used to configure the
other directive. Used on the same ``input node`` of the directives ``t-call``,
``t-field`` or ``t-out``.

Create a ``values['__qweb_options__']`` dict from the optional ``t-options``
expression and add each key-value ``t-options-key="expression value"`` to this
dict. (for example: ``t-options="{'widget': 'float'}"`` is equal to
``t-options-widget="'float'"``)

``t-att``, ``t-att-*``, ``t-attf-*`` and ``t-attf-*.translate``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**Values**: python expression (or format string expression for ``t-attf-``)

Compile the attributes to create ``values['__qweb_attrs__']`` dictionary code
in the compiled function. Use the ``t-att`` expression and add each key-value
``t-att-key="expression value"`` to this dict. (for example:
``t-att="{'class': f'float_{1}'}"`` is equal to ``t-att-class="f'float_{1}'"``
and is equal to ``t-attf-class="float_{{1}}")

The attributes come from new namespaces, static elements (not preceded
by ``t-``) and dynamic attributes ``t-att``, attributes prefixed by ``t-att-``
(python expression) or ``t-attf`` (format string expression, translated if
ending by ``.translate``).

``t-call``
~~~~~~~~~~
**Values**: format string expression for template name

Serves the called template in place of the current ``t-call`` node.

Here are the different steps performed by the generated python code:

#. copy the ``values`` dictionary;
#  define values from attributes or attributeName``.f`` for formated string;
#. render the content (``_compile_directive_inner_content``) of the tag in a
   separate method called with the previous copied values. This values can be
   updated via t-set. The visible content of the rendering of the sub-content
   is added as a magical value ``0`` (can be rendered with ``t-out="0"``);
#. copy the ``compile_context`` dictionary;
#. compile the directive ``t-options`` and update the ``compile_context``
    are, in added to the calling template and the ``nsmap`` values;
#. get the compiled function from the ``_compile`` method;
#. use the compiled function to serves the called template.

``t-lang``
~~~~~~~~~~
**Values**: python expression

Used to serve the called template (``t-call``) in another language. Used
together with ``t-call``.

This directive will be evaluate like ``t-options-lang``. Allows you to change
the language in which the called template is rendered. It's in the ``t-call``
directive that the language of the context of the ``ir.qweb`` recordset on
which the ``_compile`` function is called is updated.

``t-call-assets``
~~~~~~~~~~~~~~~~~
**Values**: format string for template name

The generated code call the ``_get_asset_nodes`` method to get the list of
(tagName, attrs and content). From each tuple a tag is created into the
rendering.

``t-out``
~~~~~~~~~
**Values**: python expression

Output the given value or if falsy, display the content as default value.
(for example: ``<t t-out="given_value">Default content</t>``)

The generated code add the value into the ``MarkupSafe`` rendering.
If a widget is defined (``t-options-widget``), the generated code call the
``_get_widget`` method to have the formatted field value and attributes. It's
the ``ir.qweb.field.*`` models that format the value.

``t-field``
~~~~~~~~~~~
**Values**: String representing the path to the field. (for example:
``t-field="record.name"``)

Output the field value or if falsy, display the content as default value.
(for example: ``<span t-field="record.name">Default content</span>``)

Use ``t-out`` compile method but the generated code call ``_get_field``
instead of ``_get_widget``. It's the ``ir.qweb.field.*`` models that format
the value. The rendering model is chosen according to the type of field. The
rendering model can be modified via the ``t-options-widget``.

``t-esc``
~~~~~~~~~
Deprecated, please use ``t-out``

``t-raw``
~~~~~~~~~
Deprecated, please use ``t-out``

``t-set``
~~~~~~~~~
**Values**: key name

The generated code update the key ``values`` dictionary equal to the value
defined by ``t-value`` expression, ``t-valuef`` format string expression or
to the ``MarkupSafe`` rendering come from the content of the node.

``t-value``, ``t-valuef`` and ``t-valuef.translate``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**Values**: python expression (or format string expression for ``t-attf-``)

The compilation method only validates if this directive and ``t-set`` are on the
same node.
The format string expression can be translated if use ``.translate``.


Technical directives
--------------------

Directive added automatically by IrQweb in order to go through the compilation
methods.

``t-tag-open``
~~~~~~~~~~~~~~
Used to generate the opening HTML/XML tags.

``t-tag-close``
~~~~~~~~~~~~~~
Used to generate the closing HTML/XML tags.

``t-inner-content``
~~~~~~~~~~~~~~~~~~~
Used to add the content of the node (text, tail and children nodes).
If namespaces are declared on the current element then a copy of the options
is made.

``t-consumed-options``
~~~~~~~~~~~~~~~~~~~~~~
Raise an exception if the ``t-options`` is not consumed.

``t-qweb-skip``
~~~~~~~~~~~~~~~~~~~~~~
Ignore rendering and directives for the curent **input** node.

``t-else-valid``
~~~~~~~~~~~~~~~~~~~~~~
Mark a node with ``t-else`` or ``t-elif`` having a valid **input** dom
structure.

é    )ÚannotationsN)ÚMarkupÚescape©Údefaultdict)ÚSizedÚMappingÚSequenceÚIterator)Údeepcopy)ÚcountÚchain)Úetree)Úrelativedelta)ÚPath)ÚTransactionRollbackError)ÚReadOnlySqlTransaction)Ú
NamedTupleÚLiteral)ÚFunctionType)ÚapiÚmodelsÚtools)ÚManifest)Ú_REGISTRY_CACHES)ÚconfigÚ	safe_evalÚ
OrderedSetÚ
frozendictÚjson)ÚSUPPORTED_DEBUGGERÚEXTERNAL_ASSET)Úassert_valid_codeobjÚ	_BUILTINSÚ
to_opcodesÚ_EXPR_OPCODESÚ
_BLACKLIST©ÚLRU)Ústr2boolÚ	file_openÚ	file_path)Úimage_data_uriÚFILETYPE_BASE64_MAGICWORD)ÚExecutionContext)ÚFORMAT_REGEX)Úrequest)ÚQwebTracker)Ú	UserErrorÚMissingError)ÚAssetsBundle)ÚSCRIPT_EXTENSIONSÚSTYLE_EXTENSIONSÚTEMPLATE_EXTENSIONSé   ÚQWEB)8ÚMAKE_FUNCTIONÚCALL_FUNCTIONÚCALL_FUNCTION_KWÚCALL_FUNCTION_EXÚCALL_METHODÚLOAD_METHODÚGET_ITERÚFOR_ITERÚYIELD_VALUEÚJUMP_FORWARDÚJUMP_ABSOLUTEÚJUMP_BACKWARDÚJUMP_IF_FALSE_OR_POPÚJUMP_IF_TRUE_OR_POPÚPOP_JUMP_IF_FALSEÚPOP_JUMP_IF_TRUEÚ	LOAD_NAMEÚ	LOAD_ATTRÚ	LOAD_FASTÚ
STORE_FASTÚUNPACK_SEQUENCEÚSTORE_SUBSCRÚLOAD_GLOBALÚEXTENDED_ARGÚRESUMEÚCALLÚPRECALLÚ	PUSH_NULLÚKW_NAMESÚFORMAT_VALUEÚBUILD_STRINGÚRETURN_GENERATORÚSWAPÚPOP_JUMP_FORWARD_IF_FALSEÚPOP_JUMP_FORWARD_IF_TRUEÚPOP_JUMP_BACKWARD_IF_FALSEÚPOP_JUMP_BACKWARD_IF_TRUEÚPOP_JUMP_FORWARD_IF_NONEÚPOP_JUMP_FORWARD_IF_NOT_NONEÚPOP_JUMP_BACKWARD_IF_NONEÚPOP_JUMP_BACKWARD_IF_NOT_NONEÚEND_FORÚLOAD_FAST_AND_CLEARÚPOP_JUMP_IF_NOT_NONEÚPOP_JUMP_IF_NONEÚRERAISEÚCALL_INTRINSIC_1ÚSTORE_SLICEÚCALL_KWÚLOAD_FAST_LOAD_FASTÚSTORE_FAST_STORE_FASTÚSTORE_FAST_LOAD_FASTÚCONVERT_VALUEÚFORMAT_SIMPLEÚFORMAT_WITH_SPECÚSET_FUNCTION_ATTRIBUTE)ÚareaÚbaseÚbrÚcolÚembedÚhrÚimgÚinputÚkeygenÚlinkÚmenuitemÚmetaÚparamÚsourceÚtrackÚwbr)ÚFalseÚNoneÚTrueÚandÚasÚelifÚelseÚforÚifÚinÚisÚnotÚorz	\n[ \t]*$z	^[ \t]*\nz^(\n[ \t]*)+(\n[ \t])z^[A-Za-z_][A-Za-z0-9_]*$z[^A-Za-z0-9_]+>   út-titleút-ignoreút-translationÚ0z2javascript:(?!( ?)((window\.)?)history\.back\(\)$)c                 C  s"   zt | ƒW S  ty   |  Y S w ©N)ÚintÚ
ValueError)Úref© r—   ú;/home/minischoggi19/odoo/odoo/addons/base/models/ir_qweb.pyÚ_id_or_xmlidç  s
   
ÿr™   c                 C  s   t  t  | ¡ ¡ d| ¡S )z-Indent the code to respect the python syntax.ú    )ÚtextwrapÚindentÚdedentÚstrip)ÚcodeÚlevelr—   r—   r˜   Úindent_codeî  s   r¡   c                  O  sr   | s|sd} |  ¡ }trttjjƒng }| D ]}t ||¡D ]}||vr1||v r1tjj |¡||< qqtj	 
|¡S )a‘  
    Generate a query string keeping the current request querystring's parameters specified
    in ``keep_params`` and also adds the parameters specified in ``additional_params``.

    Multiple values query string params will be merged into a single one with comma seperated
    values.

    The ``keep_params`` arguments can use wildcards too, eg:

        keep_query('search', 'shop_*', page=4)
    )Ú*)Úcopyr0   ÚlistÚhttprequestÚargsÚfnmatchÚfilterÚgetlistÚwerkzeugÚurlsÚ
url_encode)Úkeep_paramsÚadditional_paramsÚparamsÚqs_keysÚ
keep_paramr~   r—   r—   r˜   Ú
keep_queryó  s   €þr²   c                      s*   e Zd Zd‡ fdd„Z‡ fdd„Z‡  ZS )Ú	QWebErrorÚqwebÚQWebErrorInfoc                   s   t ƒ  d¡ || _d S )Nz"Error while rendering the template)ÚsuperÚ__init__r´   )Úselfr´   ©Ú	__class__r—   r˜   r·     s   
zQWebError.__init__c                   s   t ƒ  ¡ › d| j› �S )Nz:
    )r¶   Ú__str__r´   ©r¸   r¹   r—   r˜   r»     s   zQWebError.__str__)r´   rµ   )Ú__name__Ú
__module__Ú__qualname__r·   r»   Ú__classcell__r—   r—   r¹   r˜   r³     s    r³   c                   @  s   e Zd Zddd„Zdd„ ZdS )rµ   ÚerrorÚstrÚref_nameústr | int | Noner–   ú
int | NoneÚpathú
str | NoneÚelementr   ú list[tuple[int | str, str, str]]Úsurroundingc                 C  s.   || _ || _|| _|| _|| _|| _|| _d S r“   )rÁ   Útemplater–   rÆ   rÈ   r   rÊ   )r¸   rÁ   rÃ   r–   rÆ   rÈ   r   rÊ   r—   r—   r˜   r·     s   
zQWebErrorInfo.__init__c                 C  sÆ   | j g}| jd ur| d| j› �¡ | jd ur | d| j› �¡ | jd ur.| d| j› �¡ | jd ur<| d| j› �¡ | jrRd dd„ | jD ƒ¡}| d|› �¡ | jr^| d	| j› �¡ d
 |¡S )Nz
Template: zReference: zPath: z	Element: z
          c                 s  s   � | ]}t |ƒV  qd S r“   ©rÂ   )Ú.0Úvr—   r—   r˜   Ú	<genexpr>-  s   € z(QWebErrorInfo.__str__.<locals>.<genexpr>zFrom: zQWeb generated code:
z
    )	rÁ   rË   Úappendr–   rÆ   rÈ   r   ÚjoinrÊ   )r¸   Úinfor   r—   r—   r˜   r»   "  s   




zQWebErrorInfo.__str__N)rÁ   rÂ   rÃ   rÄ   r–   rÅ   rÆ   rÇ   rÈ   rÇ   r   rÉ   rÊ   rÂ   )r½   r¾   r¿   r·   r»   r—   r—   r—   r˜   rµ     s    
	rµ   c                   @  sN   e Zd ZU ded< ded< ded< ded< d	ed
< ded< ded< dd„ ZdS )ÚQwebCallParametersÚdictÚcontextz	str | intÚview_refrÇ   Úmethodúdict | NoneÚvalueszbool | Literal['root']ÚscoperÂ   Ú	directivez!tuple[str | int, str, str] | NoneÚpath_xmlc                   s|   dd„ | j  ¡ D ƒ}| j d¡pi ‰ | jo ‡ fdd„| j ¡ D ƒ}d|›d| j›d| j›d|›d	| j›d
| j›d| j›d�S )Nc                 S  s    i | ]\}}|  d ¡s||“qS )Ú_©Ú
startswith©rÍ   ÚkrÎ   r—   r—   r˜   Ú
<dictcomp>?  s     z/QwebCallParameters.__repr__.<locals>.<dictcomp>Ú__qweb_root_valuesc                   s,   i | ]\}}|d vr|ˆ   |¡ur||“qS ))rã   Ú__qweb_attrs__©Úgetrà   ©Úqweb_root_valuesr—   r˜   râ   A  s    þz<QwebCallParameters context=z
 view_ref=z method=z values=z scope=z directive=z
 path_xml=Ú>)	rÕ   ÚitemsrÙ   ræ   rÖ   r×   rÚ   rÛ   rÜ   )r¸   rÕ   rÙ   r—   rç   r˜   Ú__repr__=  s"   ÿÿÿÿþþÿzQwebCallParameters.__repr__N©r½   r¾   r¿   Ú__annotations__rë   r—   r—   r—   r˜   rÓ   4  s   
 rÓ   c                   @  s>   e Zd ZU ded< ded< ded< ded< d	ed
< dd„ ZdS )ÚQwebStackFramez QwebCallParameters | QwebContentr¯   ÚIrQwebÚirQwebz0Iterator[str | QwebCallParameters | QwebContent]ÚiteratorrÔ   rÙ   rØ   Úoptionsc                 C  ó   d| j ›d�S )Nz<QwebStackFrame ré   )r¯   r¼   r—   r—   r˜   rë   T  ó   zQwebStackFrame.__repr__Nrì   r—   r—   r—   r˜   rî   M  s   
 rî   c                   @  sŒ   e Zd ZU dZded< ded< ded< d"d	d
„Zdd„ Zdd„ Zdd„ Zdd„ Z	dd„ Z
dd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd „ Zd!S )#ÚQwebContentac   QwebContent wraps a snippet to be used as a string value or a fragment.
        If the value is used with a string operation (from a qweb directive
        like `t-att-help="value % 1"`), the QwebContent loads the snippet.
        If the value is inserted in the document (`t-out="value"`), the snippet
        params bubble up to `_render_iterall`.
    rï   rð   rÇ   ÚhtmlrÓ   Úparams__r¯   c                 C  s   || _ d | _|| _d S r“   )rð   rö   r÷   )r¸   rð   r¯   r—   r—   r˜   r·   c  s   
zQwebContent.__init__c                 C  s8   | j d u r| j}d | j |j|j|j|j¡¡| _ | j S )NÚ )	rö   r÷   rÑ   rð   Ú_render_iterallrÖ   r×   rÙ   rÛ   )r¸   r¯   r—   r—   r˜   r»   h  s   

ÿzQwebContent.__str__c                 C  ró   )Nz<QwebContent ré   )r÷   r¼   r—   r—   r˜   rë   p  rô   zQwebContent.__repr__c                 C  s   t t| ƒƒS r“   )ÚlenrÂ   r¼   r—   r—   r˜   Ú__len__s  ó   zQwebContent.__len__c                 C  s   |   ¡ S r“   )r»   r¼   r—   r—   r˜   Ú__html__v  ó   zQwebContent.__html__c                 C  s   |t | ƒv S r“   ©r   ©r¸   Úkeyr—   r—   r˜   Ú__contains__y  rü   zQwebContent.__contains__c                 C  s   t t| ƒ|ƒS r“   )Úgetattrr   )r¸   Únamer—   r—   r˜   Ú__getattr__|  rô   zQwebContent.__getattr__c                 C  s   t | ƒ| S r“   rÿ   r   r—   r—   r˜   Ú__getitem__  rü   zQwebContent.__getitem__c                 C  ó   t | ƒ |¡S r“   )r   Ú__add__©r¸   Úotherr—   r—   r˜   r  ‚  rô   zQwebContent.__add__c                 C  r  r“   )r   Ú__radd__r	  r—   r—   r˜   r  …  rô   zQwebContent.__radd__c                 C  r  r“   )r   Ú__mod__r	  r—   r—   r˜   r  ˆ  rô   zQwebContent.__mod__c                 C  r  r“   )r   Ú__rmod__r	  r—   r—   r˜   r  ‹  rô   zQwebContent.__rmod__N)rð   rï   r¯   rÓ   )r½   r¾   r¿   Ú__doc__rí   r·   r»   rë   rû   rý   r  r  r  r  r  r  r  r—   r—   r—   r˜   rõ   X  s"   
 
rõ   c                      s   e Zd Z‡ fdd„Z‡  ZS )ÚQwebJSONc                   s2   |  ddd„ ¡‰ tƒ j|i |¤d‡ fdd„i¤ŽS )NÚdefaultc                 S  s   | S r“   r—   ©Úobjr—   r—   r˜   Ú<lambda>‘  ó    z QwebJSON.dumps.<locals>.<lambda>c                   s   ˆ t | tƒrt| ƒƒS | ƒS r“   )Ú
isinstancerõ   rÂ   r  ©Úprev_defaultr—   r˜   r  “  ó    )Úpopr¶   Údumps)r¸   r¦   Úkwargsr¹   r  r˜   r  �  s   
ÿzQwebJSON.dumps)r½   r¾   r¿   r  rÀ   r—   r—   r¹   r˜   r  �  s    r  c                   @  s´  e Zd ZdZdZdZejdªd«dd„ƒZd¬d­dd„Z	d®dd„Z
dd„ Zdd„ Zdd„ Ze dejd vejd d!d"d#�¡d¯d%d&„ƒZd°d'd(„Zd°d)d*„Zd+d,„ Zejd-d.„ ƒZd±d1d2„Zd3d4„ Zd5d6„ Zd7d8„ Zd9d:„ Zd;d<„ Zd²d>d?„Zd@dA„ ZdBdC„ Zd³dDdE„Z d²dFdG„Z!d²dHdI„Z"dJdK„ Z#dLdM„ Z$dNdO„ Z%dPdQ„ Z&dRdS„ Z'dTdU„ Z(dVdW„ Z)dXdY„ Z*dZd[„ Z+d\d]„ Z,d^d_„ Z-d`da„ Z.dbdc„ Z/ddde„ Z0dfdg„ Z1dhdi„ Z2djdk„ Z3dldm„ Z4dndo„ Z5dpdq„ Z6drds„ Z7dtdu„ Z8dvdw„ Z9dxdy„ Z:dzd{„ Z;d|d}„ Z<d~d„ Z=d€d�„ Z>d‚dƒ„ Z?d„d…„ Z@d†d‡„ ZAdˆd‰„ ZBdŠd‹„ ZCd´d�dŽ„ZDdµd�d�„ZEe dejd vejd‘d’d“d”d•d–d—d#�¡d¶d˜d™„ƒZFdªdšd›„ZGd·dœd�„ZHd¸dždŸ„ZId¸d d¡„ZJd¹d¢d£„ZKd²d¤d¥„ZLd¦d§„ ZMd¨d©„ ZNdS )ºrï   ai   Base QWeb rendering engine
    * to customize ``t-field`` rendering, subclass ``ir.qweb.field`` and
      create new models called :samp:`ir.qweb.field.{widget}`
    Beware that if you need extensions or alterations which could be
    incompatible with other subsystems, you should create a local object
    inheriting from ``ir.qweb`` and customize that.
    zir.qwebÚQwebNrË   úint | str | etree._ElementrÙ   rØ   Úreturnr   c           
      K  sÌ   t  ¡ }t|di ƒ d¡}t|ddƒ}|s|rd|d< |r!| ¡ ni }t|v r1t d¡ | t¡ | j	di |¤Ž 
|¡}|j	i i i g d¢d	�}t |¡ | ¡ }| |d
< |d
< | |d|¡}	td |	¡ƒS )ag   Render the template specified by the given name.

        :param template: etree, xml_id, template name (see _get_template)
            * Call the method ``load`` is not an etree.
        :param dict values: template values to be used for rendering
        :param options: used to compile the template
            Options will be add into the IrQweb.env.context for the rendering.

            * ``lang`` (str) used language to render the template
            * ``inherit_branding`` (bool) add the tag node branding
            * ``inherit_branding_auto`` (bool) add the branding on fields
            * ``minimal_qcontext``(bool) To use the minimum context and options
              from ``_prepare_environment``

        :returns: bytes marked as markup-safe (decode to :class:`markupsafe.Markup`
                  instead of `str`)
        :rtype: MarkupSafe
        Úprofiler_paramsÚexecution_context_qwebÚ
qweb_hooksr—   TÚprofilezVvalues[0] should be unset when call the _render method and only set into the template.©NNN)Ú__qweb_loaded_functionsÚ__qweb_loaded_codesÚ__qweb_loaded_optionsÚ_qweb_error_path_xmlrã   Nrø   )Ú	threadingÚcurrent_threadr  ræ   r£   ÚT_CALL_SLOTÚ_loggerÚwarningr  Úwith_contextÚ_prepare_environmentr   Úcheck_valuesrù   r   rÑ   )
r¸   rË   rÙ   rò   r)  Úexecution_context_enabledr!  rð   Úroot_valuesrñ   r—   r—   r˜   Ú_render¥  s*   

ù

zIrQweb._renderÚrenderúIterator[str]c                 #  sÞ  � |d }| j jd }ti ||dd|dd�}t|| t|gƒ|dƒg}�z|�r%t|ƒdkr1tdƒ‚|d }	|	jD ]ã}
t|
t	ƒrC|
V  q8t|
t
ƒ }rX|
jdurT|
jV  q8|
j}n|
}|	j}|	j}|jrl|jdi |j¤Ž}| |j¡}|sŠ| |j¡\}}}| |¡ ||jp‡| }n| |j¡d	 }|jr |jd
krœ|}| ¡ }|jr©| |j¡ tg ƒ}z8|||ƒ}W |rÚ| j jd d rÚt|dd… t| j jd ƒf Ž }| t||g ||ƒ¡ | t|||||ƒ¡ n4|�r| j jd d �rt|dd… t| j jd ƒf Ž }| t||g ||ƒ¡ | t|||||ƒ¡ w  n| ¡  |s'W dS W dS  ttf�y2   ‚  t�yî } z°|  |||d ¡}|jdu �rR|jdu �rR||_t |dƒ�r||j!�re|j!|j"j! |j"_!|j"j�su|	j#j�ru|	j#j|j"_|j"}||_"‚ t|t$ƒ�sæd}|j%}|j&g}|j'du�r |j'}| |j&¡ |j'du�s‘|ddd… D ]6‰ ˆ j( d¡t)k�sÇtˆ j* d¡t+j,ƒ�rËˆ j*d j-| j-k�rËd} nt.‡ fdd„t/j0d D ƒƒ�rÜ n�q§|�ræt1|ƒ|‚||_"‚ d}~ww )zU Iterate over the generator method.
            Generator elements are a str
        rã   r$  NF)rÕ   rÖ   r×   rÙ   rÚ   rÛ   rÜ   é2   z Qweb template infinite recursionéÿÿÿÿé   Úrootr'  r8   r   r´   r½   r¸   Tc                 3  s   � | ]	}|ˆ j jv V  qd S r“   )Úf_codeÚco_filename©rÍ   rÆ   ©Útb_framer—   r˜   rÏ   N  ó   € z)IrQweb._render_iterall.<locals>.<genexpr>Úaddons_pathr—   )2ÚenvrÕ   rÓ   rî   Úiterrú   ÚRecursionErrorrñ   r  rÂ   rõ   rö   r÷   rÙ   rð   r-  ræ   r×   Ú_compilerÖ   ÚupdaterÚ   r£   ÚtuplerÐ   r  r   r   Ú	ExceptionÚ_get_error_inforË   r–   Úhasattrr   r´   r¯   r2   Ú__traceback__r=  Útb_nextÚ	f_globalsr½   Úf_localsr   ÚAbstractModelÚ_nameÚanyr   r   r³   )r¸   rÖ   r×   rÙ   rÛ   r1  Úloaded_functionsr¯   ÚstackÚframeÚitemÚ
is_contentrð   Úrender_templateÚtemplate_functionsÚdef_namerò   rñ   Ú	logParamsrÁ   Úqweb_error_infoÚisQwebÚtraceÚ	tb_framesr—   r<  r˜   rù   Ú  sÀ   €ù	




"ü"ÀBèþÿÿ
€ÝzIrQweb._render_iterallrQ  úlist[QwebStackFrame]rR  rî   rµ   c                 C  sx  d}d }d }| j jd }|jj|v rt|tƒrt|ƒdkrj|jp!i }d|vr3| j jd  |jj¡p2i }| d¡p;|jj}	| d¡pBd }
| |jj¡pN| |¡}|	| j jd d kri| j jd d }| j jd d	 }n+|d
 jppi }| d¡}	| d¡}
| |	¡p„| |¡}|jj	r•|jj	d }|jj	d	 }|	|kr›d n|	}d}t
 ¡ }t| d¡ƒD ]$}d|› d�|v s¼|	d u rÎd|v rÎ| d¡d }t| d¡d ƒ} nqªdd„ |D ƒ}|pÙd d¡}d}t|d |… ƒD ]G}| d¡rð n?t d|¡}|sý|rü n3qç|�r|	|d dd… |d	 dd… f}||v�r| |¡ qçd}|d dd… }|d	 dd… }qç|�r:| |	||f¡ d }| j j d¡�r¤|�r¤|�rcd|v �rcdd ||d	 |d … ¡v �rc|d8 }d |t|d dƒ|d … ¡}||d  }d |||d … ¡}t d|¡ d¡}t t |› d|› d|› d|› d|› �	¡d ¡}t|jj› d!|› �|
d u �r´|	n|
|	||||ƒS )"Núetree._Elementr%  r8   r–   r&  rÃ   r'  r   r7  éþÿÿÿÚ
zFile "<z>"z, line ú,c                 S  s   g | ]
}|j jr|j j‘qS r—   )r¯   rÜ   )rÍ   rÒ   r—   r—   r˜   Ú
<listcomp>z  r  z*IrQweb._get_error_info.<locals>.<listcomp>rø   Fúdef z\s*# element: (.*) , (.*)r6  TÚdev_modez t-if=z if é   é   z^(\s*)z3########### Line triggering the error ############
z3##################################################
z        z: )r@  rÕ   r¯   rÖ   r  rB  rú   rò   ræ   rÜ   Ú	tracebackÚ
format_excÚreversedÚsplitr”   rß   ÚreÚmatchrÐ   rÑ   ÚmaxÚsearchÚgroupr›   rœ   r�   rµ   rº   r½   )r¸   rÁ   rQ  rR  Ú	no_id_refrÆ   rö   Úloaded_codesrò   r–   rÃ   rŸ   Úsource_file_refÚline_nbr[  Ú
error_lineÚline_functionr   Ú
code_linesÚfoundÚ	code_linerl  rÒ   rÊ   Úprevious_linesÚlineÚ
next_linesrœ   r—   r—   r˜   rG  W  s–   "
€

 €
"

€0 ÿÿþþÿú0	zIrQweb._get_error_infoc                 C  ó   g d¢S )zB Return the list of context keys to use for caching ``_compile``. )ÚlangÚinherit_brandingÚinherit_branding_autoÚedit_translationsr"  r—   r¼   r—   r—   r˜   Ú_get_template_cache_keys¦  s   zIrQweb._get_template_cache_keysc                 C  s   | j d  |¡S )Nú
ir.ui.view)r@  Ú_get_cached_template_info)r¸   rË   r—   r—   r˜   Ú_get_template_infoª  ó   zIrQweb._get_template_infoc                   sN  d ‰ t |tƒrG| d¡rGt t|ƒjd ¡j}dtt|ƒƒ 	|¡jvr(t
d|ƒ‚t|ddd��}t | ¡ ¡}W d   ƒ n1 sAw   Y  nt |tjƒsT|  |¡d ‰ ˆ r_|  ˆ ¡\}}}n|  |¡\}}}|| }| d	¡r¢|jd
kr¢| d¡‰ | d¡ }r…t|ƒnd ‰‡ ‡fdd„}	| ¡ D ]\}
}t |tƒr¡|	|ƒ||
< q’|||fS )Nú.xmlr   Ú	templateszGThe templates file %s must be under a subfolder 'templates' of a moduleÚrb)r†  )Ú
filter_extÚidr"  Úprofiled_method_compiler–   Úref_xmlc                   s   ‡ ‡‡fdd„}|S )Nc                   s`   t ˆˆ| jjƒ}| j|d�} |jr+tˆd�� ˆ | |ƒW  d   ƒ S 1 s&w   Y  ˆ | |ƒS )N)Úqweb_tracker)rË   )r1   r@  Úcrr-  r0  r.   )r¸   rÙ   r�  )Úfunctionr–   rŒ  r—   r˜   r‹  Ä  s    ÿ
z>IrQweb._compile.<locals>.wrap.<locals>.profiled_method_compiler—   )r�  r‹  ©r–   rŒ  )r�  r˜   ÚwrapÃ  s   zIrQweb._compile.<locals>.wrap)r  rÂ   Úendswithr   Ú	for_addonr   ÚpartsrÆ   r+   Úrelative_tor•   r*   r   Ú
fromstringÚreadÚ_Elementr„  Ú_generate_code_cachedÚ_generate_code_uncachedræ   r½   rê   r   )r¸   rË   Úmodule_pathÚfilerV  rW  rò   rU  Úvalr‘  r  r�  r—   r�  r˜   rC  ­  s0   
ÿ€

€
zIrQweb._compileÚxmlrd  r–   zPtuple(self.env.context.get(k) or False for k in self._get_template_cache_keys())r‡  ©Úcacher”   c                 C  s
   |   |¡S r“   )rš  ©r¸   r–   r—   r—   r˜   r™  Ô  s   
zIrQweb._generate_code_cachedc           
        sÊ   t ˆttfƒr|  ˆ¡d nd }|  ˆ¡\}}}|d u r5|d \‰ ‰‰‡ ‡‡‡fdd„}d|idt|ƒfS d dt|dƒd	|›�d
g¡}t|d|› d�dƒ}|  	¡ }	|	|	d< t
||	ƒ |	d ƒ |t|ƒfS )NrŠ  rÁ   c                   s>   t jd r
t ˆ¡ | jj dd¡rˆ ˆƒ‚t dˆˆ¡ dS )Nrd  Úraise_if_not_foundTzCannot load template %s: %srø   )r   r   r+  rÒ   r@  rÕ   ræ   r,  ©r¸   rÙ   ©ÚErrorÚmessagerQ  rË   r—   r˜   Únot_found_templateã  s   

z:IrQweb._generate_code_uncached.<locals>.not_found_templater§  r`  zdef generate_functions():r8   z    code = z    return template_functionsÚ<ré   ÚexecÚ__builtins__Úgenerate_functions)r  r”   rÂ   r„  Ú_generate_coder   rÑ   r¡   ÚcompileÚ_IrQweb__prepare_globalsÚunsafe_eval)
r¸   rË   r–   rŸ   rò   rW  r§  Ú	wrap_codeÚcompiledÚglobals_dictr—   r¤  r˜   rš  Û  s"    ü
zIrQweb._generate_code_uncachedc                   sx  t |tttjfƒst|ƒ}| jj ¡ ‰ z
|  |¡\}}}W nI t	t
fyf } z;‡ fdd„|  ¡ D ƒ}t|ƒ}t|dƒrM|j d¡rM|› d|jd j› d�}|j|t ¡ f|d< d|d	fW  Y d}~S d}~ww ˆ  d
d¡ |j dd¡}t |tƒs‚t |tƒr‹d|vr‹|  |¡d pŠ|}|ˆ d< |ˆ d< |r™t|ƒndˆ d< |ˆ d< | ¡ ˆ d< ˆ  dg d¢¡ˆ d< dd„ ˆ  di ¡ ¡ D ƒˆ d< ‡ fdd„|  ¡ ddg D ƒ}ˆ d pÔd}t |tjƒrçt ddttƒ› �¡‰nt ddd|vrñ|nd› d|› �¡‰tƒ ‰‡‡fdd„ˆ d< |j�rt d|j¡|_i ˆ d < g ˆ d!< |  dˆ ¡ d"ˆ› d#�g|  |ˆ d$¡ | j ˆ d$d%d&� ˆ d  ˆ› d'�< t!d(ˆ› d)|d ›d*|d ›d+|d ›d,|d ›d-|d ›d.|d ›d/ˆ› d0�d1ƒgˆ d  ˆ< g }	|	 "d2t#j$|d3d4�› �¡ |	 "d5¡ |	 "d6¡ ˆ d   %¡ D ]}
|	 &|
¡ �qŠˆ d  D ]}|	 "d7|›d8|› �¡ �q—d9 '|	¡}| d:¡�r·ˆ d |d< ||ˆfS );a[   Compile the given template into a rendering function (generator)::

            render_template(qweb, values)

        This method can be called only by :meth:`_render` method or by
        the compiled code of t-call from an other template.

        An ``options`` dictionary is created and attached to the function.
        It contains rendering options that are part of the cache key in
        addition to template references.

        where ``qweb`` is a QWeb instance and ``values`` are the values to
        render.

        :returns: tuple containing code, options and main method name
        c                   ó   i | ]	}|ˆ   |d ¡“qS ©Frå   )rÍ   rá   ©Úcompile_contextr—   r˜   râ     ó    z)IrQweb._generate_code.<locals>.<dictcomp>rÕ   Úviewz (view: ú)rÁ   Nr§  r¢  út-namer¨  r  r–   rÃ   rŒ  rË   r8  r'  r#  c                 S  ó   i | ]	\}}|t |ƒ“qS r—   rÌ   )rÍ   Ú	ns_prefixÚns_definitionr—   r—   r˜   râ   0  s    ÿÿÚnsmapc                   r³  r´  rå   ©rÍ   r  rµ  r—   r˜   râ   :  s    ÿÿrø   rÝ   Útemplate_etree_Ú	template_c                   s   ˆ › d| › dt ˆƒ› �S )NrÝ   )Únext)Úprefix)rW  Úname_genr—   r˜   r  G  s    z'IrQweb._generate_code.<locals>.<lambda>Ú	make_namez\2rV  Ú_text_concatrc  z_content(self, values):r7  T©ÚrstripÚ_contentz
            def z`(self, values):
                if 'xmlid' not in values:
                    values['xmlid'] = z(
                    values['viewid'] = z’
                self.env.context['__qweb_loaded_functions'].update(template_functions)
                self.env.context['__qweb_loaded_options'][z.] = self.env.context['__qweb_loaded_options'][zM] = template_options
                self.env.context['__qweb_loaded_codes'][z,] = self.env.context['__qweb_loaded_codes'][z$] = code
                yield from z'_content(self, values)
                r   ztemplate_options = é   )rœ   zcode = Noneztemplate_functions = {}ztemplate_functions[ú] = r`  r"  )(r  r”   rÂ   r   r˜  r@  rÕ   r£   Ú_get_templater•   r2   r�  rH  ræ   r  rº   rg  rh  r  Úattribr„  Úgetroottreerê   ÚTO_VARNAME_REGEXPÚsubrÂ  ÚETREE_TEMPLATE_REFr   ÚtextÚFIRST_RSTRIP_REGEXPÚ_append_textÚ_compile_nodeÚ_flush_textr¡   rÐ   ÚpprintÚpformatrÙ   ÚextendrÑ   )r¸   rË   rÈ   Údocumentr–   Úerò   r¦  rÃ   rv  Úlinesr  rŸ   r—   )r¶  rW  rÄ  r˜   r¬  ù  sœ   €ù	
þ

þ$ÿþÿÿýüúúùùø	÷



zIrQweb._generate_codec           	      C  sà   |dvsJ dƒ‚t |tjƒr3|}tj|dd�}| ¡ D ]}| d¡}|r-||t|ƒf  S q||dfS t |tƒr@d|v r@tdƒ‚t|ƒ}|  	|g¡ |¡}| d	¡rV|d	 ‚d
t
jd v rct|d ƒn|d }||d |d fS )aO   Retrieve the given template, and return it as a tuple ``(etree,
        xml, ref)``, where ``element`` is an etree, ``document`` is the
        string document that contains ``element``, and ``ref`` if the uniq
        reference of the template (id, t-name or template).

        :param template: template identifier or etree
        )FNrø   útemplate is requiredÚunicode©Úencodingrº  r^  r¨  z4Inline templates must be passed as `etree` documentsrÁ   rž  rd  ÚtreerË   r–   )r  r   r˜  ÚtostringrA  ræ   r™   rÂ   r•   Ú_preload_treesr   r   r   )	r¸   rË   rÈ   rÚ  Únoder–   Úid_or_xmlidÚvalueÚ
value_treer—   r—   r˜   rÌ  t  s$   
ÿ

"zIrQweb._get_templatec                 C  s   dgS )Nút-callr—   r¼   r—   r—   r˜   Ú_get_preload_attribute_xmlids�  s   z$IrQweb._get_preload_attribute_xmlidsÚrefsúSequence[int | str]c                   sH  | j d  |¡‰ ttt|ƒƒ}‡ fdd„|D ƒ}|sˆ S t|ƒ}t| ¡ ƒ}| j d  ¡ jdd„ |D ƒŽ }| ¡ }t	|||ƒD ]\}}‰ˆt
jˆdd�dœ}	ˆ |j  |	¡ ˆ |  |	¡ q?|  ¡ }
tƒ }|D ]‰| ‡fd	d
„|
D ƒ¡ qgtdd
„ |D ƒƒrƒJ dƒ‚|  t|ƒ¡ |D ]}|ˆ vr¡||t| j  d|¡ƒdœˆ |< qŒˆ S )aÊ   Preload all tree and subtree (from t-call and other '_get_preload_attribute_xmlids' values).

            Returns::

                {
                    id or xmlId/key: {
                        'xmlid': str | None,
                        'ref': int | None,
                        'tree': etree | None,
                        'template': str | None,
                        'error': None | MissingError
                    }
                }
        r‚  c                   s.   i | ]}d ˆ | vrˆ | d s|ˆ | “qS )rË   rÁ   r—   )rÍ   r–   )Úcompile_batchr—   r˜   râ   ³  s   . z)IrQweb._preload_trees.<locals>.<dictcomp>c                 S  s   g | ]}|d  ‘qS )r¸  r—   )rÍ   Údatar—   r—   r˜   rb  ¹  s    z)IrQweb._preload_trees.<locals>.<listcomp>rÞ  rß  )rá  rË   c                 3  sp   � | ]3}ˆ   d |› d�¡D ]'}tdd„ |jD ƒƒs4d| |¡vrd| |¡vrd| |¡vr| |¡V  qqdS )z//*[@ú]c                 s  s*   � | ]}|  d ¡p|dkp|dkV  qdS )ú
t-options-ú	t-optionsút-langNrÞ   ©rÍ   Úattr—   r—   r˜   rÏ   Î  s   €( z2IrQweb._preload_trees.<locals>.<genexpr>.<genexpr>Ú{r¨  ú/N)ÚxpathrO  rÍ  ræ   )rÍ   rÃ   Úel)rá  r—   r˜   rÏ   Ê  s   € ýü*üûz(IrQweb._preload_trees.<locals>.<genexpr>c                 s  s   � | ]}| V  qd S r“   r—   )rÍ   Úfr—   r—   r˜   rÏ   Ñ  s   € rÝ  z!External ID can not be loaded: %s)Úxmlidr–   rÁ   )r@  Ú_preload_viewsr¤   Úmapr™   rÙ   ÚsudoÚunionÚ_get_view_etreesÚzipr   râ  rŠ  rD  ré  r   rO  rã  r3   rÝ   )r¸   rê  Úmissing_refsÚxmlidsÚmissing_refs_valuesÚviewsÚtreesrù  r¸  rí  Ú	ref_namesÚsub_refsr–   r—   )rì  rá  r˜   rã  ¡  s>   þ
þ
ý€zIrQweb._preload_treesc           	      C  s¬   | j j d¡rRt |d d… d¡}d|v rRt |¡}| j d }| |¡}| ¡  g d¢dd|gg¡}|rRg d¢g d	¢d
d|j	gg d¢g}| ¡ j|dd�}|rR|j
}t|ƒS )NÚwebp_as_jpgr8   ÚpngÚwebpúir.attachment)rŠ  z!=FÚchecksumÚ=)Ú	res_modelr  r
  Úres_idr‹   )Úmimetyper  z
image/jpeg)Úlimit)r@  rÕ   ræ   r-   Úbase64Ú	b64decodeÚ_compute_checksumrü  rn  ÚidsÚdatasr,   )	r¸   Úbase64_sourcer  Ú
bin_sourceÚ
Attachmentr  ÚoriginsÚconverted_domainÚ	convertedr—   r—   r˜   Ú_get_converted_image_data_uriá  s(   


þ
üz$IrQweb._get_converted_image_data_uric                 C  sÈ   t rt jjpd}|jddd� | jj d¡sS| d|¡ | d| jj 	| j¡¡ | d| jj
 ¡ ¡ |jt td	 ttjjtjtjt| jtjtj| j| jj d
¡td� ddtjd v i}| jdi |¤ŽS )zÒ Prepare the values and context that will sent to the
        compiled and evaluated function.

        :param values: template values to be used for rendering

        :returns self (with new context)
        rø   TF)ÚtrueÚfalseÚminimal_qcontextÚdebugÚuser_idÚres_companyÚtest_enabler}  )r0   Útest_mode_enabledr   Ú
quote_plusÚtimeÚdatetimer   r,   ÚfloorÚceilr@  r}  r²   rd  r´   Nr—   )r0   Úsessionr   rD  r@  rÕ   ræ   Ú
setdefaultÚuserÚwith_envÚcompanyrü  r   ÚqwebJSONrª   r«   Úurl_quote_plusr   r&  r'  r   r  Úmathr(  r)  r²   r   r-  )r¸   rÙ   r   rÕ   r—   r—   r˜   r.  ù  s4   þòzIrQweb._prepare_environmentc              
   C  s   t ttttttttdœ	t	¥S )z\ Prepare the global context that will sent to eval the qweb
        generated code.
        )	r½   r   r   r   r   ÚVOID_ELEMENTSrÓ   rõ   r•   )
r½   r   r   r   r   r2  rÓ   rõ   r•   r#   r¼   r—   r—   r˜   Ú__prepare_globals  s   ÷
özIrQweb.__prepare_globalsc                 C  s   |d   |  |¡¡ dS )zí Add an item (converts to a string) to the list.
            This will be concatenated and added during a call to the
            `_flush_text` method. This makes it possible to return only one
            yield containing all the parts.rÆ  N)rÐ   Ú_compile_to_str)r¸   rÒ  r¶  r—   r—   r˜   rÔ  1  s   zIrQweb._append_textc                 C  sH   |d }|sdS t  |d ¡}|r| d¡nd}t  d|d ¡|d< |S )z] The text to flush is right stripped, and the stripped content are
        returned.
        rÆ  rø   r6  r   )ÚRSTRIP_REGEXPrn  ro  rÐ  )r¸   r¶  Útext_concatÚresultrž   r—   r—   r˜   Ú_rstrip_text8  s   zIrQweb._rstrip_textFc                 C  sD   |d }|sg S |r|   |¡ d |¡}| ¡  d| › d|›�gS )zøConcatenate all the textual chunks added by the `_append_text`
            method into a single yield.
            If no text to flush, return an empty list

            If rstrip the text is right stripped.

            @returns list(str)
        rÆ  rø   rš   zyield )r8  rÑ   Úclear)r¸   r¶  r    rÈ  r6  rÒ  r—   r—   r˜   rÖ  F  s   	

zIrQweb._flush_textc                 C  s*   |j dkod|jvotdd„ |jD ƒƒ S )z¥ Test whether the given element is purely static, i.e. (there
        are no t-* attributes), does not require dynamic rendering for its
        attributes.
        ÚtÚgroupsc                 s  s"   � | ]}|  d ¡o|dvV  qdS )út-)ú
t-tag-openút-inner-contentNrÞ   rò  r—   r—   r˜   rÏ   ]  s
   € ÿ
ÿz)IrQweb._is_static_node.<locals>.<genexpr>)ÚtagrÍ  rO  )r¸   r÷  r¶  r—   r—   r˜   Ú_is_static_nodeX  s   
þzIrQweb._is_static_nodec                   sN   ‡ fdd„t  |¡D ƒ}tt  d| dd¡¡ƒ}|r%|dd |¡› d�7 }|S )	z¼ Parses the provided format string and compiles it to a single
        expression python, uses string with format method.
        Use format is faster to concat string and values.
        c                   s.   g | ]}d ˆ   | d¡p| d¡¡› d�‘qS )zself._compile_to_str(r8   r7  r¹  )Ú_compile_exprro  )rÍ   Úmr¼   r—   r˜   rb  l  s     ÿÿz*IrQweb._compile_format.<locals>.<listcomp>z%sú%z%%z % (ú, z,))r/   ÚfinditerÚreprrÐ  ÚreplacerÑ   )r¸   ÚexprrÙ   rŸ   r—   r¼   r˜   Ú_compile_formatd  s   
þzIrQweb._compile_formatc                 C  sH  d}d}d}|p	g }t |ƒD ]¦\}}	|	jtjtjtjfv r"|d7 }q|	jtjtjtjfv r2|d8 }q|dkr´|	jtj	kr´|	j
}
|
dkr}t|d t|ƒƒD ]/}|| }	|	jtj	kr_| |	j
¡ qL|	jtjkrfqL|	jtjkrn n|	jtjkrxtdƒ‚tdƒ‚q|
dkr´t|d t|ƒƒD ])}|| }	|	jtj	kr¤|	j
d	kr� n| |	j
¡ qŠ|	jtjtjtjfv r°qŠtd
ƒ‚qd}d}d}|t|ƒk �r1|| }	|	j
}
|	jtjtjtjfv rß|dkrÚ|}|d7 }nH|	jtjtjtjfv �r'|d8 }|dk�r'|  ||d |… t|ƒt|ƒ|¡}|| j
| |	j
 }t tj||| j|	jd¡g|||d …< |}|d7 }|t|ƒk sÂg }d}|�o<|d j}|t|ƒk �rŸ|| }	|	j
}
|	jd |d k�r\|	jd df}|	jd |d  }|�ro| d| ¡ |	j}|	jtj	k�rnd|
v �r…td|
›�ƒ‚|
dk�rì| d¡ |d7 }|t|ƒk �rÖ|| }	|	jtj	k�r³|	j
|v �r³| ||	j
 ¡ |	jtjtjfv �rÃ| |	j
¡ |	jtjk�rËn|d7 }|t|ƒk �sš|	jd |d k�rè|	jd df}n—|	j}n“|
|v �rú| ||	j
 ¡ n…|
|v �r| |
¡ nz|d t|ƒk �r||d  jtjk�r| |
¡ n`|dk�r<||d  �r<||d  jtjk�r<| |
¡ nC|�sZ|d t|ƒk �rd||d  jtjtjtjtjfv �rd| d|
›d�¡ n| d|
›d�¡ n|	jtjtjtjfv�r| |
¡ |	jd |d k�r‘|	jd df}n|	j}|d7 }|t|ƒk �sDd |¡S )a   Transform the list of token coming into a python instruction in
            textual form by adding the namepaces for the dynamic values.

            Example: `5 + a + b.c` to be `5 + values.get('a') + values['b'].c`
            Unknown values are considered to be None, but using `values['b']`
            gives a clear error message in cases where there is an attribute for
            example (have a `KeyError: 'b'`, instead of `AttributeError: 'NoneType'
            object has no attribute 'c'`).

            @returns str
        r6  r   z	_arg_%s__r8   Úlambdaz'Lambda default values are not supportedz*This lambda code style is not implemented.r‰   r‹   z(This loop code style is not implemented.rø   Ú Ú__ú/Using variable names with '__' is not allowed: zlambda úvalues[rî  zvalues.get(r¹  ) Ú	enumerateÚ
exact_typeÚtokenÚLPARÚLSQBÚLBRACEÚRPARÚRSQBÚRBRACEÚNAMEÚstringÚrangerú   rÐ   ÚCOMMAÚCOLONÚEQUALÚNotImplementedErrorÚ_compile_expr_tokensr¤   ÚtokenizeÚ	TokenInfor9   ÚstartÚendÚSyntaxErrorÚDOTÚtypeÚENCODINGÚ	ENDMARKERÚDEDENTrÑ   )r¸   ÚtokensÚallowed_keysÚargument_namesÚraise_on_missingÚopen_bracket_indexÚbracket_depthÚargument_nameÚindexr:  rY  ÚirŸ   ÚposÚspacer—   r—   r˜   r_  u  sÚ   

€
€

ü*ë


ø	

(.<
Ê
8zIrQweb._compile_expr_tokensc                 C  s€   t  d|pd› d� d¡¡}z
tt |j¡ƒ}W n tjy'   td|› �ƒ‚w | j|t	|d�}t
tt|ddƒ|ƒ d|› d�S )	a  Transform string coming into a python instruction in textual form by
        adding the namepaces for the dynamic values.
        This method tokenize the string and call ``_compile_expr_tokens``
        method.

        :param expr: string: python expression
        :param bool raise_on_missing:
            Compile has `values['product'].price` instead of
            `values.get('product').price` to raise an error when get the
            'product' value and not an 'NoneType' object has no attribute
            'price' error.
        ú(rø   r¹  zutf-8zCan not compile expression: ©rm  z<>Úeval)ÚioÚBytesIOÚencoder¤   r`  ÚreadlineÚ
TokenErrorr•   r_  ÚALLOWED_KEYWORDr"   Ú_SAFE_QWEB_OPCODESr­  )r¸   rH  rm  Úreadablerj  Ú
expressionr—   r—   r˜   rA    s   ÿzIrQweb._compile_exprc                 C  s8   |r|du rdS |  ¡ }|dv rdS |dv rdS t|ƒS )z$Convert the statements as a boolean.T)r  r’   F)r  Ú1)ÚlowerÚbool)r¸   Úattrr  r—   r—   r˜   Ú_compile_bool.  s   zIrQweb._compile_boolc                 C  s<   |du s|du r
dS t |tƒr|S t |tƒr| ¡ S t|ƒS )za Generates a text value (an instance of text_type) from an arbitrary
            source.
        NFrø   )r  rÂ   ÚbytesÚdecode)r¸   rH  r—   r—   r˜   r4  :  s   

zIrQweb._compile_to_strc                 C  r|  )a#   List all supported directives in the order in which they should be
        evaluated on a given element. For instance, a node bearing both
        ``foreach`` and ``if`` should see ``foreach`` executed before ``if``
        aka

        .. code-block:: xml

            <el t-foreach="foo" t-as="bar" t-if="bar">

        should be equivalent to

        .. code-block:: xml

            <t t-foreach="foo" t-as="bar">
                <t t-if="bar">
                    <el>

        then this method should return ``['foreach', 'if']``.
        )r‡   rˆ   r   r;  r†   ÚforeachrŠ   zcall-assetsr}  rò   Úcallró  ÚfieldÚescÚrawÚoutútag-openÚsetúinner-contentú	tag-closer—   r¼   r—   r—   r˜   Ú_directives_eval_orderJ  s   zIrQweb._directives_eval_orderc           	      C  s2  d|j v rg S |  ||¡r|  |||¡S |d  |¡}tjt |j|j ¡dd�}|d |d d< ||d d< ||d d	< td
|›d|›�|ƒg}t	|  
¡ ƒ|d< |jsY|j }}nt |j¡j}|}|jrm|j› d|› �}|dkr�| d|¡ |tvr�| d|¡ h d£t|j ƒ@ s�| dd¡ ||  |||¡ S )a@   Compile the given element into python code.

            The t-* attributes (directives) will be converted to a python instruction. If there
            are no t-* attributes, the element will be considered static.

            Directives are compiled using the order provided by the
            ``_directives_eval_order`` method (an create the
            ``compile_context['iter_directives']`` iterator).
            For compilation, the directives supported are those with a
            compilation method ``_compile_directive_*``

        :return: list of string
        út-qweb-skipr8  rÞ  rß  r–   r'  r   r8   r7  ú# element: ú , Úiter_directivesú:r:  r=  út-tag-close>   út-escút-outút-rawút-fieldr>  r„   )rÍ  r@  Ú_compile_static_nodeÚgetpathr   râ  ÚElementr?  r¡   rA  r’  r¾  ÚQNameÚ	localnamerÃ  r�  r2  Ú_compile_directives)	r¸   r÷  r¶  r    rÆ   rž  ÚbodyÚunqualified_el_tagÚel_tagr—   r—   r˜   rÕ  s  s0   
zIrQweb._compile_nodec                 C  s  |j s|j }}|  |ji |j¥ddi¥¡}n‰t |j¡j}|}|jr+|j› d|› �}i }t|j  	¡ ƒt|d  	¡ ƒ D ]\}}|du rI||d< q<||d|› �< q<t
|d  	¡ |j  	¡ ƒ}	dd	„ |	D ƒ}
|j 	¡ D ]#\}}| d
¡}t |¡}|jrˆ|||
|j › d|j› �< qi|||< qi|  |ji |¥ddi¥¡}t|d ƒ}|dkrÏd dd„ | 	¡ D ƒ¡}|  d|› d |¡› �|¡ |tv rÉ|  d|¡ n|  d|¡ |j ¡  |j rì|d  |j ¡ |  ||d|¡}||d< n|  ||d|¡}|dk�r|tv�r|  d|› d�|¡ |S )z8 Compile a purely static element into a list of string. Ú__is_static_nodeTr—  r¾  NÚxmlnsúxmlns:c                 S  ó   i | ]\}}||“qS r—   r—   rà   r—   r—   r˜   râ   Å  ó    z/IrQweb._compile_static_node.<locals>.<dictcomp>ú
.translater:  rø   c                 s  sB   � | ]\}}|st |tƒrd | d¡› dtt|ƒƒ› d�V  qdS )rK  r«  z="ú"N)r  rÂ   Úremovesuffixr   )rÍ   r  ræ  r—   r—   r˜   rÏ   ×  s   € ÿ*ÿz.IrQweb._compile_static_node.<locals>.<genexpr>r¨  ú/>ré   r�  ú</)r¾  r?  Ú_post_processing_attrÍ  r   r   r¡  rÃ  r�  rê   r   r­  Ú	namespacerÔ   rÑ   rÔ  r2  r9  rD  Ú_compile_directive)r¸   r÷  r¶  r    r¤  r¥  rÍ  r¼  r½  ÚnsÚnsprefixmapr  ræ  r  Úattrib_qnameÚoriginal_nsmapÚ
attributesr£  r—   r—   r˜   r�  «  sP   
&




ÿ



zIrQweb._compile_static_nodec              	   C  sv  |   ||¡r"|j dd¡ |j dd¡ |j dd¡ |  |||¡S g }|d D ]S}d| |jv r=| |  ||||¡¡ q(|dkrR||jv rQ| |  ||||¡¡ q(|dkrb| |  ||||¡¡ q(|d	kr{td
d„ |jD ƒƒr{| |  ||||¡¡ q(|jD ]'}|tvr¦| d¡r¦t	| d|dd…  
dd¡› �dƒr¦| |  ||||¡¡ qt|jƒt }|r¹t d||d ¡ |S )zÒ Compile the given element, following the directives given in the
        iterator ``compile_context['iter_directives']`` create by
        `_compile_node`` method.

        :return: list of code lines
        r=  Nr>  r˜  r–  r<  r;  ró  rò   c                 s  s   � | ]}|  d ¡V  qdS )rï  NrÞ   )rÍ   r  r—   r—   r˜   rÏ     s   € z-IrQweb._compile_directives.<locals>.<genexpr>Ú_compile_directive_r7  Ú-rÝ   z1Unknown directives or unused attributes: %s in %srË   )r@  rÍ  r  r�  rÙ  r²  rO  ÚSPECIAL_DIRECTIVESrß   r  rG  r�  r+  r,  )r¸   r÷  r¶  r    rŸ   rÛ   ró  Ú	remainingr—   r—   r˜   r¢  î  s6   
€€
4€zIrQweb._compile_directivesc           	      C  s²   t | d| dd¡› �d ƒ}| d¡rQ|dvrQd| › d|›d|j›d|d	 d
 ›d�}d| › d|›d|j›d|d	 d
 ›d�}||||ƒ}|rO|g|¢|‘}|S ||||ƒ}|S )Nr¸  r¹  rÝ   r"  )r�  rŽ  r‘  rš   z1self.env.context['qweb_tracker'].enter_directive(rD  r'  r8   r¹  z1self.env.context['qweb_tracker'].leave_directive()r  rG  ræ   rÍ  )	r¸   r÷  r¶  rÛ   r    Úcompile_handlerÚenterÚleaveÚcode_directiver—   r—   r˜   r²    s   **ÿzIrQweb._compile_directivec                 C  sD   |j  d¡}g }| d¡r| td|›d�|ƒ¡ |S t d¡ |S )z´Compile `t-debug` expressions into a python code as a list of
        strings.

        The code will contains the call to the debugger chosen from the valid
        list.
        zt-debugrd  zself._debug_trace(z	, values)z7@t-debug in template is only available in qweb dev mode)rÍ  r  ræ   rÐ   r¡   r+  r,  )r¸   r÷  r¶  r    ÚdebuggerrŸ   r—   r—   r˜   Ú_compile_directive_debug#  s   

ÿzIrQweb._compile_directive_debugc           
   	   C  s  g }g }t |jƒD ] }| d¡r)|j |¡}|dd… }| |›d|  |¡› �¡ q	|j dd¡}	|	rK|rK| td|  |	¡› dd |¡› d�|ƒ¡ n+|r]| td	d |¡› d�|ƒ¡ n|	rn| td
|  |	¡› �|ƒ¡ n| td|ƒ¡ | dt	t
|ƒƒ¡ |S )zž
        compile t-options and add to the dict the t-options-xxx. Will create
        the dictionary ``values['__qweb_options__']`` in compiled code.
        rï  é
   Nr—  rð  z values['__qweb_options__'] = {**rD  Ú}zvalues['__qweb_options__'] = {zvalues['__qweb_options__'] = zvalues['__qweb_options__'] = {}út-consumed-options)r¤   rÍ  rß   r  rÐ   rA  r¡   rÑ   r�  rÂ   rƒ  )
r¸   r÷  r¶  r    rŸ   Údict_optionsr  ræ  Úoption_nameÚ	t_optionsr—   r—   r˜   Ú_compile_directive_options2  s$   
€, z!IrQweb._compile_directive_optionsc                 C  ó   t dƒ‚)Nzkthe t-options must be on the same tag as a directive that consumes it (for example: t-out, t-field, t-call)©rd  ©r¸   r÷  r¶  r    r—   r—   r˜   Ú#_compile_directive_consumed_optionsM  rþ   z*IrQweb._compile_directive_consumed_optionsc              
   C  sè  t d|ƒg}|jr6t|j ¡ ƒt|d  ¡ ƒ D ]\}}d}|dur'd|› �}| t d|›d|›�|ƒ¡ qtdd	„ |jD ƒƒrŠd
d„ t|d  ¡ |j ¡ ƒD ƒ}t|jƒD ]3}| 	d¡s‰|j 
|¡}	| d¡}
t |
¡}|jr{||j › d|j› �}
| t d|
›d|	›�|ƒ¡ qVt|jƒD ]b}| 	d¡r·|j 
|¡}	|dd…  d¡}
| t d|
›d|  |	¡› �|ƒ¡ q�| 	d¡rØ|j 
|¡}	| t d|dd… ›d|  |	¡› �|ƒ¡ q�|dkrñ|j 
|¡}	| t d|  |	¡› d�|ƒ¡ q�|S )a¶   Compile the attributes of the given elements.

        The compiled function will create the ``values['__qweb_attrs__']``
        dictionary. Then the dictionary will be output.


        The new namespaces of the current element.

        The static attributes (not prefixed by ``t-``) are add to the
        dictionary in first.

        The dynamic attributes values will be add after. The dynamic
        attributes has different origins.

        - value from key equal to ``t-att``: python dictionary expression;
        - value from keys that start with ``t-att-``: python expression;
        - value from keys that start with ``t-attf-``: format string
            expression.
        z%attrs = values['__qweb_attrs__'] = {}r¾  r§  Nr¨  zattrs[rË  c                 s  ó   � | ]	}|  d ¡ V  qdS ©r<  NrÞ   r¿  r—   r—   r˜   rÏ   w  r>  z0IrQweb._compile_directive_att.<locals>.<genexpr>c                 S  r©  r—   r—   rà   r—   r—   r˜   râ   x  rª  z1IrQweb._compile_directive_att.<locals>.<dictcomp>r<  r«  r—  zt-attf-é   zt-att-é   zt-attú"
                    atts_value = a–  
                    if isinstance(atts_value, dict):
                        attrs.update(atts_value)
                    elif isinstance(atts_value, (list, tuple)) and not isinstance(atts_value[0], (list, tuple)):
                        attrs.update([atts_value])
                    elif isinstance(atts_value, (list, tuple)):
                        attrs.update(dict(atts_value))
                    )r¡   r¾  r�  rê   rÐ   rO  rÍ  r   r¤   rß   r  r­  r   r   r±  r¡  rI  rA  )r¸   r÷  r¶  r    rŸ   r¼  r½  r  r´  ræ  r  rµ  r—   r—   r˜   Ú_compile_directive_attP  sF   &
"


€
$
,ÿø€
zIrQweb._compile_directive_attc                 C  sx   |j  dd¡}|sg S |  d|› �|¡ |  ||¡}| td|j›d�|ƒ¡ d|j v r4|  d|¡ |S |  d|¡ |S )	aÙ   Compile the opening tag with attributes of the given element into
        a list of python code line.

        The compiled function will fill the ``attrs`` dictionary. Then the
        ``attrs`` dictionary will be output and reset the value of ``attrs``.

        The static attributes (not prefixed by ``t-``) are add to the
        ``attrs`` dictionary in first.

        The dynamic attributes values will be add after. The dynamic
        attributes has different origins.

        - value from key equal to ``t-att``: python dictionary expression;
        - value from keys that start with ``t-att-``: python expression;
        - value from keys that start with ``t-attf-``: format string
            expression.
        r=  Nr¨  zh
            attrs = values.pop('__qweb_attrs__', None)
            if attrs:
                tagName = a  
                attrs = self._post_processing_att(tagName, attrs)
                for name, value in attrs.items():
                    if value or isinstance(value, str):
                        yield f' {escape(str(name))}="{escape(str(value))}"'
        r˜  ré   r®  )rÍ  r  rÔ  rÖ  rÐ   r¡   r?  )r¸   r÷  r¶  r    r¥  rŸ   r—   r—   r˜   Ú_compile_directive_tag_open›  s   ýø
þz"IrQweb._compile_directive_tag_openc                 C  s*   |j  dd¡}|r|  d|› d�|¡ g S )z‡ Compile the closing tag of the given element into string.
        Returns an empty list because it's use only `_append_text`.
        r˜  Nr¯  ré   )rÍ  r  rÔ  )r¸   r÷  r¶  r    r¥  r—   r—   r˜   Ú_compile_directive_tag_closeÏ  s   z#IrQweb._compile_directive_tag_closec                 C  s°  | j |||j ¡ dkd�}d|jv �rV|j d¡}|dkr!tdƒ‚|tkr4|d dkr4t |¡s4t	dƒ‚d|v r?t	d	|›�ƒ‚d
|jv sTd|jv sTd|jv sT|d dkrb|j d¡ |tkrbt	dƒ‚d
|jv r‚|j d
¡pnd}| 
td|›d|  |¡› �|ƒ¡ |S d|jv r |j d¡}| 
td|›d|  |¡› �|ƒ¡ |S d|jv rÙ|j d¡}| jj d¡rÆ| 
td|›d|  |¡› d�|ƒ¡ |S | 
td|›d|  |¡› �|ƒ¡ |S |d dkrð| 
td|  |¡› d�|ƒ¡ |S |d \}}	}
|  ||dd¡|   |d¡ }|�rJ|d dƒ}d|› d�g}| 
td|	›d|
›�dƒ¡ | |¡ ||d |< | 
td |›d!|d" ›d#|›d$|	›d#|
›d%�|ƒ¡ |S | 
td|›d&�|ƒ¡ |S )'aº  Compile `t-set` expressions into a python code as a list of
        strings.

        There are 3 kinds of `t-set`:
        * `t-value` containing python code;
        * `t-valuef` containing strings to format;
        * `t-valuef.translate` containing translated strings to format;
        * whose value is the content of the tag (being Markup safe).

        The code will contain the assignment of the dynamically generated value.
        r:  rÇ  út-setrø   r   rô  zEThe varname can only contain alphanumeric characters and underscores.rL  rM  zt-valuezt-valuefzt-valuef.translater>  z4t-set="0" should not be set from t-value or t-valuefrƒ   rN  rË  r€  ú] = Markup(r¹  zvalues.update(r'  r�  r8   rÅ  Út_setrc  ú(self, values):r”  r•  rV  z 
                        values[z;] = QwebContent(self, QwebCallParameters(self.env.context, r–   rD  z<, values.copy(), 'root', 't-set', (template_options['ref'], z)))
                    z] = '')rÖ  r?  r‚  rÍ  r  ÚKeyErrorr*  ÚVARNAME_REGEXPrl  rd  rÐ   r¡   rA  rI  r@  rÕ   ræ   r²  rÙ  )r¸   r÷  r¶  r    rŸ   ÚvarnamerH  ÚexprfÚ_refrÆ   rž  ÚcontentrW  Údef_coder—   r—   r˜   Ú_compile_directive_setØ  st   *
"
â"
å$"êëï
ÿÿ
ÿÿÿÿÿþþzIrQweb._compile_directive_setc                 C  rÉ  )z·Compile `t-value` expressions into a python code as a list of strings.

        This method only check if this attributes is on the same node of a
         `t-set` attribute.
        z)t-value must be on the same node of t-setrÊ  rË  r—   r—   r˜   Ú_compile_directive_value  ó   zIrQweb._compile_directive_valuec                 C  rÉ  )z¸Compile `t-valuef` expressions into a python code as a list of strings.

        This method only check if this attributes is on the same node of a
         `t-set` attribute.
        z*t-valuef must be on the same node of t-setrÊ  rË  r—   r—   r˜   Ú_compile_directive_valuef   râ  z IrQweb._compile_directive_valuefc                 C  sà   |j  dd¡ |jrt||jd�}|jdur|  |j|¡ g }t|ƒD ]J}t|tj	ƒr<| 
d¡r;|  d|j› d�|¡ n%t|tjƒrW| 
d¡rV|  d|j› d|j› d	�|¡ n
| |  |||¡¡ |jdurm|  |j|¡ q#|S )
a-  Compiles the content of the element (is the technical `t-inner-content`
        directive created by QWeb) into a python code as a list of
        strings.

        The code will contains the text content of the node or the compliled
        code from the recursive call of ``_compile_node``.
        r>  N)r¾  Úpreserve_commentsz<!--z-->z<?rK  z?>)rÍ  r  r¾  rÔ   rÒ  rÔ  r¤   r  r   Ú_Commentræ   Ú_ProcessingInstructionÚtargetrÙ  rÕ  Útail)r¸   r÷  r¶  r    r£  rS  r—   r—   r˜   Ú _compile_directive_inner_content(  s(   

€
€
€z'IrQweb._compile_directive_inner_contentc                 C  sæ  |j  d|j  dd¡¡}| ¡ rJ dƒ‚|  |¡}|j ¡ dkr+|jr+t |j¡r+d}|  	||¡}| 
td|  |¡› d�|ƒ¡ g }|rJ|  ||¡ | |  |||d	 ¡| j	||d	 d
d� ¡ | |pktd|d	 ƒg¡ | ¡ }g }	t|tjƒrˆ|	 
|¡ | ¡ }t|tjƒsy|durñddht|j ƒ@ rñd|j d< | ¡ }
|	D ]}|
 |¡ q |jr´|j ¡ s´tdƒ‚d|_| 
td|ƒ¡ g }|rÉ|  ||¡ | |  |||d	 ¡| j	||d	 d
d� ¡ | |pêtd|d	 ƒg¡ d|j d< |S )z×Compile `t-if` expressions into a python code as a list of strings.

        The code will contain the condition `if`, `else` and `elif` part that
        wrap the rest of the compiled code of this element.
        zt-ifzt-elifNz.t-if or t-elif expression should not be empty.r:  rø   zif r—  r8   TrÇ  Úpassút-elser„   út-else-validzGUnexpected non-whitespace characters between t-if and t-else directivesúelse:r“  )rÍ  r  Úisspacer8  r?  r‚  rÒ  ÚLSTRIP_REGEXPrn  rÖ  rÐ   r¡   rA  rÔ  rÙ  r¢  Úgetnextr  r   rå  r�  Ú	getparentÚremoverè  rd  rÕ  )r¸   r÷  r¶  r    rH  rž   rŸ   r£  Únext_elÚcomments_to_removeÚparentÚcommentr—   r—   r˜   Ú_compile_directive_ifJ  sT   
 ÿÿ
þ
ÿÿ
zIrQweb._compile_directive_ifc                 C  s$   |j  dd¡stdƒ‚|  |||¡S )zêCompile `t-elif` expressions into a python code as a list of
        strings. This method is linked with the `t-if` directive.

        Check if this directive is valide, the t-qweb-skip flag and call
        `t-if` directive
        rì  Nú=t-elif directive must be preceded by t-if or t-elif directive)rÍ  r  rd  r÷  rË  r—   r—   r˜   Ú_compile_directive_elif‘  s   zIrQweb._compile_directive_elifc                 C  s&   |j  dd¡stdƒ‚|j  d¡ g S )zÐCompile `t-else` expressions into a python code as a list of strings.
        This method is linked with the `t-if` directive.

        Check if this directive is valide and add the t-qweb-skip flag.
        rì  Nrø  rë  )rÍ  r  rd  rË  r—   r—   r˜   Ú_compile_directive_else�  s   zIrQweb._compile_directive_elsec              	   C  s¨   |j  d|j  dd¡¡}|  |¡}|  ||¡}| td|›d�|ƒ¡ |r2|j ¡ dkr2|  ||¡ | 	g |  
|||d ¡¢| j||d dd	�¢pPtd
|d ƒg¡ |S )zñCompile `t-groups` expressions into a python code as a list of
        strings.

        The code will contain the condition `if self.env.user.has_groups(groups)`
        part that wrap the rest of the compiled code of this element.
        zt-groupsr;  Nzif self.env.user.has_groups(z):r:  r8   TrÇ  rê  )rÍ  r  r8  rÖ  rÐ   r¡   r?  r‚  rÔ  rÙ  r¢  )r¸   r÷  r¶  r    r;  rž   rŸ   r—   r—   r˜   Ú_compile_directive_groups¨  s   
ÿþýz IrQweb._compile_directive_groupsc                 C  sÞ  |j  d¡}|j  d¡}|stdƒ‚t |¡std|›d�ƒ‚|j ¡ dkr+|  |¡ |  	||¡}|  
|||d ¡| j	||d dd� }|d	 d
ƒ}|d	 dƒ}	|d	 dƒ}
| ¡ rz| td|d ›d|	› dt|ƒ› d|› d|	› d|
› d�|ƒ¡ nn| td g d‘|› ‘d‘|  |¡› ‘d‘|› ‘d‘|d ›‘d‘|	› ‘d‘|› ‘d‘|› ‘d‘|d ›‘d‘|	› ‘d‘|› ‘d‘|› ‘d‘|	› ‘d‘|	› ‘d‘|
› ‘d‘|› ‘d‘|› ‘d‘|› ‘d ‘|
› ‘d!‘¡|ƒ¡ | td g d"‘|› ‘d#‘|d$ ›‘d%‘|
› ‘d&‘|›‘d'‘|d( ›‘d)‘|›‘d*‘|d( ›‘d+‘|d, ›‘d*‘|d$ ›‘d-‘|	› ‘d.‘|d/ ›‘d0‘|	› ‘d1‘|d2 ›‘d3‘|d4 ›‘d5‘|d2 ›‘d6‘|d7 ›‘d8‘|d2 ›‘d9‘¡|ƒ¡ | |�pktd:|d ƒ¡ |S );að  Compile ``t-foreach`` expressions into a python code as a list of
        strings.

        * ``t-as`` is used to define the key name.
        * ``t-foreach`` compiled value can be an iterable, an dictionary or a
          number.

        The code will contain loop ``for`` that wrap the rest of the compiled
        code of this element.

        Some key into values dictionary are create automatically::

            *_size, *_index, *_value, *_first, *_last, *_odd, *_even, *_parity
        ú	t-foreachzt-aszThe varname z: can only contain alphanumeric characters and underscores.r:  r8   TrÇ  rÅ  Ú	t_foreachÚsizeÚ	has_valuez
                values[Ú_sizerË  z = z
                z	 = range(z)
                z = False
            rø   z% or []
                if isinstance(z%, Sized):
                    values[z = len(z)
                elif (z/).__class__ == int:
                    values[z
                    z,)
                else:
                    z = None
                z' = False
                if isinstance(z , Mapping):
                    z.items()
                    z = True
            z.
                for index, item in enumerate(z):
                    values[Ú_indexz!] = index
                    if z!:
                        values[z
], values[Ú_valuezB] = item
                    else:
                        values[z] = values[z$] = item
                    values[Ú_firstz] == 0
                    if z- is not None:
                        values[Ú_lastz] = index + 1 == z
                    values[Ú_oddz)] = index % 2
                    values[Ú_evenz] = not values[z]
                    values[Ú_parityz] = 'odd' if values[z] else 'even'
            Úcontinue)rÍ  r  rÙ  rÚ  rl  r•   r?  r‚  r8  rÖ  r¢  ÚisdigitrÐ   r¡   r”   rÑ   rA  rÙ  )r¸   r÷  r¶  r    Úexpr_foreachÚexpr_asrŸ   Úcontent_foreachrý  rþ  rÿ  r—   r—   r˜   Ú_compile_directive_foreach¼  sÜ   

ÿÿÿÿÿþþýüÿÿþýýýüûûûúúø	÷
öõõ
ôóÿþýüüúúùùø	÷	÷
öõõô
ôóz!IrQweb._compile_directive_foreachc                 C  s   d|j vr	tdƒ‚g S )z¸Compile `t-as` expressions into a python code as a list of strings.

        This method only check if this attributes is on the same node of a
         `t-foreach` attribute.
        rü  z*t-as must be on the same node of t-foreach)rÍ  rd  rË  r—   r—   r˜   Ú_compile_directive_as
	  s   
zIrQweb._compile_directive_asc                 C  s$  d}|j  dd¡}|du r/d}|j  dd¡}|du r/d}|j  dd¡}|du r/d}|j  d¡}|  ||¡}|d \}}}	|j  dd¡}
|  ||d	|d
 ¡|  ||d
 ¡ }|  ||d|d
 ¡|  ||d
 ¡ }|  ||d|d
 ¡|  ||d
 ¡ }|tkr£|
dkr£| td|ƒ¡ | |¡ | tdt› d�|d
 ƒ¡ | |¡ |S |dkrÍ| dd
¡\}}| td| j	|dd�› d|›d|›d|j
›d�	|ƒ¡ d}nF|tkrÞ| tdt› d�|ƒ¡ n| td|  	|¡› �|ƒ¡ |
dk�r| td|›d|j
›d�|ƒ¡ d}nd}|dk�r| td|ƒ¡ |j  dd¡ | td|ƒ¡ | |¡ | td|›d |	›d!�|d
 ƒ¡ | |¡ |�sE|d" �rqt|d" ƒ}|d"  ¡  | td#|ƒ¡ | |¡ | |¡ |d"  |¡ | |¡ |S |�r�|| �rˆ| td$|ƒ¡ | || ¡ | td%|ƒ¡ |S )&aT  Compile `t-out` expressions into a python code as a list of
        strings.

        The code will contain evalution and rendering of the compiled value. If
        the compiled value is None or False, the tag is not added to the render
        (Except if the widget forces rendering or there is default content).
        (eg: `<t t-out="my_value">Default content if falsy</t>`)

        The output can have some rendering option with `t-options-widget` or
        `t-options={'widget': ...}. At rendering time, The compiled code will
        call ``_get_widget`` method or ``_get_field`` method for `t-field`.

        A `t-field` will necessarily be linked to the value of a record field
        (eg: `<span t-field="record.field_name"/>`), a t-out` can be applied
        to any value (eg: `<span t-out="10" t-options-widget="'float'"/>`).
        rš  Nrœ  r™  r›  r'  rÄ  rƒ   rŽ  r8   r‘  r�  r„   zif True:zyield values.get(z, '')Ú.zG
                field_attrs, content, force_display = self._get_field(Trv  rD  a†  , values.pop('__qweb_options__', {}), values)
                if values.get('__qweb_attrs__') is None:
                    values['__qweb_attrs__'] = field_attrs
                else:
                    values['__qweb_attrs__'].update(field_attrs)
                if content is not None and content is not False:
                    content = self._compile_to_str(content)
                zcontent = values.get(z
content = zV
                    widget_attrs, content, force_display = self._get_widget(content, a[  , values.pop('__qweb_options__', {}), values)
                    if values.get('__qweb_attrs__') is None:
                        values['__qweb_attrs__'] = widget_attrs
                    else:
                        values['__qweb_attrs__'].update(widget_attrs)
                    content = self._compile_to_str(content)
                    Fzˆ
                    if content is not None and content is not False:
                        content = Markup(content)
                zt-tagz0if content is not None and content is not False:zÆ
            if isinstance(content, QwebContent):
                self.env.context['_qweb_error_path_xml'][0] = template_options['ref']
                self.env.context['_qweb_error_path_xml'][1] = z?
                self.env.context['_qweb_error_path_xml'][2] = zd
                yield content
            else:
                yield str(escape(content))
        rÆ  rí  zelif force_display:z(else: values.pop('__qweb_attrs__', None))rÍ  r  rÖ  r²  r*  rÐ   r¡   rÙ  ÚrsplitrA  r?  r¤   r9  )r¸   r÷  r¶  r    ÚttyperH  rŸ   rÝ  rÆ   rž  Úcode_optionsÚtag_openÚ	tag_closeÚdefault_bodyÚrecordÚ
field_nameÚforce_display_dependentrÆ  r—   r—   r˜   Ú_compile_directive_out	  s²   ÿÿÿÿÿÿ	

ÿÿÿÿø	
ÿÿù
ý	
ýüø
	


ö
zIrQweb._compile_directive_outc                 C  s4   |  d¡rt d|  d¡|  dd¡¡ |  |||¡S )Nrd  zFFound deprecated directive @t-esc=%r in template %r. Replace by @t-outr™  r–   ú	<unknown>)ræ   r+  r,  r  rË  r—   r—   r˜   Ú_compile_directive_esc¡	  s   

ýzIrQweb._compile_directive_escc                 C  s*   t  d| d¡| dd¡¡ |  |||¡S )NzœFound deprecated directive @t-raw=%r in template %r. Replace by @t-out, and explicitely wrap content in `Markup` if necessary (which likely is not the case)r›  r–   r  )r+  r,  ræ   r  rË  r—   r—   r˜   Ú_compile_directive_raw«	  s   
ûzIrQweb._compile_directive_rawc                 C  sN   |j }|dvsJ d| ƒ‚|dksJ dƒ‚d| d¡v s J dƒ‚|  |||¡S )aQ  Compile ``t-field`` expressions into a python code as a list of
        strings.

        The compiled code will call ``_get_field`` method at rendering time
        using the type of value supplied by the field. This behavior can be
        changed with ``t-options-widget`` or ``t-options={'widget': ...}``.

        The code will contain evalution and rendering of the compiled value
        value from the record field. If the compiled value is None or False,
        the tag is not added to the render
        (Except if the widget forces rendering or there is default content.).
        )ÚtableÚtbodyÚtheadÚtfootÚtrÚtdÚliÚulÚolÚdlÚdtÚddz1QWeb widgets do not work correctly on %r elementsr:  zCt-field can not be used on a t element, provide an actual HTML noder  rœ  z9t-field must have at least a dot like 'record.field_name')r?  ræ   r  )r¸   r÷  r¶  r    ÚtagNamer—   r—   r˜   Ú_compile_directive_field¶	  s   
þ
ÿÿzIrQweb._compile_directive_fieldc                 C  sü  |j  d¡}|jrt |j¡jn|j}|dkrtd|› d�ƒ‚|j  d¡r0|j  	d|j  d¡¡ | d¡}| j
|||j ¡ dkd�}|d	 \}}	}
|j  d
d¡ | td|ƒ¡ |rŽg }|d  ¡ D ]\}}t|tƒrv| |›d|›�¡ qb| d|›�¡ qb| tdd |¡› d�|ƒ¡ tt|ƒp•|jƒ�rtdd„ |j D ƒƒ o«tdd„ |D ƒƒ}|d dƒ}d|› d�g}| td|	›d|
›�dƒ¡ | |  ||dd¡¡ |  d|¡ | | j
|ddd�¡ ||d |< | td |d! ›d|›d"|	›d|
›d#t› d$�|ƒ¡ |�r| td%t› d&�|ƒ¡ n| td't› d(�|ƒ¡ t|j ƒD ]£}| d)¡�rJ| d)¡}|j  |¡}| td*|›d+|  |¡› �|ƒ¡ �q$| d,¡�r�| d)¡ d,¡}|j  |¡}| jj d-¡�rz| td*|›d.|  |¡› d/�|ƒ¡ �q$| td*|›d+|  |¡› �|ƒ¡ �q$| d0¡�s¬|j  |¡}| td*|›d+|   |¡› �|ƒ¡ �q$|d1k�rÆ|j  |¡}| td2|   |¡› d3�|ƒ¡ �q$| !¡ �rÏ|n|  |¡}| td4|› d5�|ƒ¡ d6|v �rí| td7|ƒ¡ | td8|	›d|
›d9�|ƒ¡ |S ):a?  Compile `t-call` expressions into a python code as a list of
        strings.

        `t-call` allow formating string dynamic at rendering time.
        Can use `t-options` used to call and render the sub-template at
        rendering time.
        The sub-template is called with a copy of the rendering values
        dictionary. The dictionary contains the key 0 coming from the
        compilation of the contents of this element

        The code will contain the call of the template and a function from the
        compilation of the content of this element.
        rè  r:  z.t-call must be on a <t> element (actually on <z>).zt-call-optionsrð  r¾  rÇ  r'  rÄ  Nz3t_call_options = values.pop('__qweb_options__', {})r—  zNone:zt_call_options.update(nsmap={rD  z})c                 s  rÍ  rÎ  rÞ   r¿  r—   r—   r˜   rÏ   ú	  r>  z1IrQweb._compile_directive_call.<locals>.<genexpr>c                 s  s   � | ]	}|j  d ¡V  qdS )rÕ  N)rÍ  ræ   )rÍ   Únr—   r—   r˜   rÏ   ú	  r>  rÅ  Út_callrc  rØ  r”  r•  r8   r�  rø   TrV  zŒ
                t_call_content_values = values.copy()
                qwebContent = QwebContent(self, QwebCallParameters(self.env.context, r–   zL, t_call_content_values, 'root', 'inner-content', (template_options['ref'], z&)))
                t_call_values = { z: qwebContent}
            z
                    str(qwebContent)
                    new_values = {k: v for k, v in t_call_content_values.items() if k != z| and k != '__qweb_attrs__' and values.get(k) is not v}
                    t_call_values.update(new_values)
                zt_call_values = { z: '' }z.fzt_call_values[rË  r«  r€  rÖ  r¹  r<  zt-argsrÑ  a®  
                    if isinstance(atts_value, dict):
                        t_call_values.update(atts_value)
                    elif isinstance(atts_value, (list, tuple)) and not isinstance(atts_value[0], (list, tuple)):
                        t_call_values.update([atts_value])
                    elif isinstance(atts_value, (list, tuple)):
                        t_call_values.update(dict(atts_value))
                    z
            template = z
            rC  zg
                if template.isnumeric():
                    template = int(template)
                zryield QwebCallParameters(t_call_options, template, None, t_call_values, True, 't-call', (template_options['ref'], z)))"rÍ  r  r¾  r   r   r?  r¡  rd  ræ   r�  rÖ  r‚  rÐ   r¡   rê   r  rÂ   rÑ   rƒ  r¤   rÒ  rO  rÙ  r²  rÔ  r*  r’  r­  rI  r@  rÕ   rß   rA  Ú	isnumeric)r¸   r÷  r¶  r    rH  r¥  r¾  rŸ   rÝ  rÆ   rž  r  ræ  Úis_deprecated_versionrW  Úcode_contentr  rË   r—   r—   r˜   Ú_compile_directive_callÎ	  s¤   

(þþþþýüþü€
&(&&
ÿø€
ÿþ
ýzIrQweb._compile_directive_callc                 C  s2   d|j vr	tdƒ‚|j  d¡|j d< |  |||¡S )Nrè  zRt-lang is an alias of t-options-lang but only available on the same node of t-callrñ  zt-options-lang)rÍ  rd  r  rÕ  rË  r—   r—   r˜   Ú_compile_directive_langA
  s   
zIrQweb._compile_directive_langc                 C  sò   t |ƒdkr
tdƒ‚|  ||¡}|j d¡}|  |j dd¡¡}|  |j dd¡¡}|  |j dd¡¡}|  |j d	d¡¡}	|j d
d¡}
|  |j dd¡¡}| td|›d|› d|› d|› d|	› d|
›d|› d� ¡ |ƒ¡ | td|ƒ¡ |S )zd This special 't-call-assets' tag can be used in order to aggregate/minify javascript and css assetsr   z+t-call-assets cannot contain children nodesút-call-assetsút-cssTút-jsÚ
defer_loadFÚ	lazy_loadÚmediazt-autoprefixzJ
            t_call_assets_nodes = self._get_asset_nodes(
                z,
                css=z,
                js=zH,
                debug=values.get("debug"),
                defer_load=z,
                lazy_load=z,
                media=z,
                autoprefix=z
            )
        a»  
            for index, (tagName, asset_attrs) in enumerate(t_call_assets_nodes):
                if index:
                    yield '\n        '
                yield '<'
                yield tagName

                attrs = self._post_processing_att(tagName, asset_attrs)
                for name, value in attrs.items():
                    if value or isinstance(value, str):
                        yield f' {escape(str(name))}="{escape(str(value))}"'

                if tagName in VOID_ELEMENTS:
                    yield '/>'
                else:
                    yield '>'
                    yield '</'
                    yield tagName
                    yield '>'
                )	rú   rd  rÖ  rÍ  r  r…  rÐ   r¡   rž   )r¸   r÷  r¶  r    rŸ   rù  ÚcssÚjsr5  r6  r7  Ú
autoprefixr—   r—   r˜   Ú_compile_directive_call_assetsG
  s>   þýüúùø	÷õíz%IrQweb._compile_directive_call_assetsc                 C  sD   |st ƒ  dS |tv rtjdtdd� t|ƒ ¡  dS td|› �ƒ‚)z/Method called at running time to load debugger.z�Using t-debug with an explicit debugger is deprecated since Odoo 17.0, keep the value empty and configure the ``breakpoint`` builtin instead.r7  )ÚcategoryÚ
stacklevelzunsupported t-debug value: N)Ú
breakpointr    ÚwarningsÚwarnÚDeprecationWarningÚ
__import__Ú	set_tracer•   )r¸   rÀ  rÙ   r—   r—   r˜   Ú_debug_trace{
  s   
ûzIrQweb._debug_tracec                 C  s2   |  dd¡s| d¡ }rtt|ƒƒrd|d< |S )a^   Method called at compile time for the static node and called at
            runing time for the dynamic attributes.

            This method may be overwrited to filter or modify the attributes
            (during compilation for static node or after they compilation in
            the case of dynamic elements).

            @returns dict
        r¦  FÚhrefrø   )r  ræ   ÚMALICIOUS_SCHEMESrÂ   )r¸   r)  ÚattsrE  r—   r—   r˜   r°  ‹
  s   &
zIrQweb._post_processing_attc                 C  sà   |j | }||d< ||d< | d|j¡|d< d| jjv r"| jjd n| jj d¡o-| d¡}||d< | jj d¡o@| d	¡o@|j}	|	|d
< d|d  }
|
| jv rU| j|
 n| jd }| |||¡}| ||||¡}|||pn|	fS )a  Method called at compile time to return the field value.

        :returns: tuple:
            * dict: attributes
            * string or None: content
            * boolean: force_display display the tag if the content and default_content are None
        r)  r€  Úwidgetrf  r~  r  Úwriter€  ÚtranslatableÚ	translateúir.qweb.field.úir.qweb.field)	Ú_fieldsræ   rf  r@  rÕ   Ú
has_accessrK  Úrecord_to_htmlr·  )r¸   r  r  r€  r)  Úfield_optionsrÙ   rŠ  r~  rK  ÚmodelÚ	converterrÞ  r·  r—   r—   r˜   Ú
_get_field™
  s    
ÿýzIrQweb._get_fieldc                 C  sŽ   |d |d< ||d< ||d< | j j d¡}||d< d|d  }|| j v r)| j | n| j d }| ||¡}	i }
|d |
d< |d |
d	< |
|	|fS )
a  Method called at compile time to return the widget value.

        :returns: tuple:
            * dict: attributes
            * string or None: content
            * boolean: force_display display the tag if the content and default_content are None
        rH  rf  r)  r€  r~  rL  rM  zdata-oe-typezdata-oe-expression)r@  rÕ   ræ   Úvalue_to_html)r¸   ræ  r€  r)  rQ  rÙ   r~  rR  rS  rÞ  r·  r—   r—   r˜   Ú_get_widget¹
  s   
zIrQweb._get_widgetTc	           
      C  s2   |r|pd}| j |||||d�}	| j|	|||d�S )úÙGenerates asset nodes.
        If debug=assets, the assets will be regenerated when a file which composes them has been modified.
        Else, the assets will be generated only once and then stored in cache.
        N)r8  r9  r   r:  ©r5  r6  r7  )Ú_get_asset_linksÚ_links_to_nodes)
r¸   Úbundler8  r9  r   r5  r6  r7  r:  Úlinksr—   r—   r˜   Ú_get_asset_nodesÓ
  s   zIrQweb._get_asset_nodesc           	   	   C  sv   | j d  ¡ j| j jp| j jjd�jdk}| j d  ¡ }|o!d|v }|r0| j|||d|||d�S | j||||||d�S )	rW  zres.lang)rŸ   Úrtlúir.assetÚassetsT)r8  r9  Údebug_assetsÚassets_paramsr^  r:  )r8  r9  rb  r^  r:  )	r@  rü  Ú	_get_datar}  r,  Ú	directionÚ_get_asset_paramsÚ_generate_asset_linksÚ_generate_asset_links_cache)	r¸   r[  r8  r9  r   r:  r^  rb  ra  r—   r—   r˜   rY  Ü
  s   *zIrQweb._get_asset_linksr[  r8  r9  z$tuple(sorted(assets_params.items()))r^  r:  r`  c              	   C  s   | j |||d|||d�S )NF)r:  )rf  )r¸   r[  r8  r9  rb  r^  r:  r—   r—   r˜   rg  ë
  s   z"IrQweb._generate_asset_links_cachec           
      C  st   |d u r| j d  ¡ }| j d j||d�}g }g }|D ]\}}}}	|tur0| ||d|	dœ¡ q| |¡ q||fS )Nr_  )r[  rb  rø   )ÚurlÚfilenamerÞ  Úlast_modified)r@  re  Ú_get_asset_pathsr!   rÐ   )
r¸   r[  rb  Úasset_pathsÚfilesÚexternal_assetrÆ   Ú	full_pathÚ_bundlerj  r—   r—   r˜   Ú_get_asset_contentô
  s   
üzIrQweb._get_asset_contentc           
      C  sD   |d u r| j d  ¡ }|  ||¡\}}	t|||	| j ||||||d�
S )Nr_  )r@  r8  r9  ra  r^  rb  r:  )r@  re  rq  r4   )
r¸   Úbundle_namer8  r9  ra  r^  rb  r:  rm  Úexternal_assetsr—   r—   r˜   Ú_get_asset_bundle  s   zIrQweb._get_asset_bundlec                   s   ‡ ‡‡‡fdd„|D ƒS )Nc                   s   g | ]}ˆj |ˆ ˆˆd �‘qS )rX  )Ú_link_to_noder;  ©r5  r6  r7  r¸   r—   r˜   rb    s    z*IrQweb._links_to_nodes.<locals>.<listcomp>r—   )r¸   Úpathsr5  r6  r7  r—   rv  r˜   rZ    s   zIrQweb._links_to_nodesc                 C  sÄ   |r|j ddd�d nd}|tv }|tv }|tv }|rC|o!| d¡}	ddi}
|r,d	|
d	< |r9|r5||
d
< n||
d< |	r?d|
d< d|
fS |rSd|› �d||dœ}
d|
fS |r`ddd|dœ}
d|
fS d S )Nr  r8   )Úmaxsplitr6  r9  z/web/assets/rf  ztext/javascriptÚdeferúdata-srcÚsrcz__odooAssetError=1ÚonerrorÚscriptztext/Ú
stylesheet)rf  ÚrelrE  r7  r{   ztext/xmlÚasyncÚprefetch)rf  r€  r  rz  )r  r5   r7   r6   rß   )r¸   rÆ   r5  r6  r7  ÚextÚis_jsÚis_xmlÚis_cssÚis_asset_bundler·  r—   r—   r˜   ru    s@   ÿ
üüzIrQweb._link_to_nodec           	   	   C  s    | j |||||||d�}| ¡ S )N)r8  r9  ra  r^  rb  r:  )rt  Ú	get_links)	r¸   r[  r8  r9  ra  rb  r^  r:  Úasset_bundler—   r—   r˜   rf  ?  s   zIrQweb._generate_asset_linksc                 C  s   | j |d|d�}dd„ |D ƒS )NF)r9  r   c                 S  s$   g | ]}|d  dkr|d d ‘qS )r   r{   r8   rE  r—   )rÍ   rä  r—   r—   r˜   rb  E  s   $ z/IrQweb._get_asset_link_urls.<locals>.<listcomp>)r]  )r¸   r[  r   Úasset_nodesr—   r—   r˜   Ú_get_asset_link_urlsC  s   zIrQweb._get_asset_link_urlsc                 C  s¢   t  d¡ |  ¡ \}}g }t ¡ }t|ƒD ]}|| j|ddd� ¡ 7 }qt  dt ¡ | ¡ t ¡ }t|ƒD ]}|| j|ddd� ¡ 7 }q6t  dt ¡ | ¡ |S )af  
        Pregenerates all assets that may be used in web pages to speedup first loading.
        This may is mainly usefull for tests.

        The current version is looking for all t-call-assets in view to generate the minimal
        set of bundles to generate.

        Current version only generate assets without extra, not taking care of rtl.
        zPregenerating assets bundlesFT)r8  r9  z)JS Assets bundles generated in %s secondsz*CSS Assets bundles generated in %s seconds)	r+  ÚrunbotÚ_get_bundles_to_pregenarater&  Úsortedrt  r9  rÒ   r8  )r¸   Ú
js_bundlesÚcss_bundlesr\  rb  r[  r—   r—   r˜   Ú_pregenerate_assets_bundlesG  s   

z"IrQweb._pregenerate_assets_bundlesc           	      C  s�   | j d  ddg¡}tƒ }tƒ }|D ]1}t |j¡ d¡D ]%}| d¡}t| dd¡ƒ}t| dd¡ƒ}|r;| 	|¡ |rB| 	|¡ qq||fS )	z=
        Returns the list of bundles to pregenerate.
        r‚  )rf  r  r´   )Úarch_dbÚliker2  z//*[@t-call-assets]r2  r4  r„   r3  )
r@  rn  r�  r   r–  r‘  rö  ræ   r)   Úadd)	r¸   r  rŽ  r�  r¸  Ú
call_assetÚassetr9  r8  r—   r—   r˜   rŒ  `  s   


€ùz"IrQweb._get_bundles_to_pregenarater“   )rË   r  rÙ   rØ   r  r   )r3  )r  r4  )rQ  r]  rR  rî   r  rµ   )r–   r”   )rË   r  )rê  rë  r´  )NF)TTFFFNF)TTNF)TTNFF)TTFFNF)FFN)TTFNFF)Or½   r¾   r¿   r  rN  Ú_descriptionr   rR  r2  rù   rG  r�  r„  rC  r   Úconditionalr   Úormcacher™  rš  r¬  rÌ  ré  rã  r  r.  r®  rÔ  r8  rÖ  r@  rI  r_  rA  r…  r4  r’  rÕ  r�  r¢  r²  rÁ  rÈ  rÌ  rÒ  rÓ  rÔ  rà  rá  rã  ré  r÷  rù  rú  rû  r  r  r  r  r  r*  r0  r1  r;  rD  r°  rT  rV  r]  rY  rg  rq  rt  rZ  ru  rf  rŠ  r�  rŒ  r—   r—   r—   r˜   rï   š  s¦    4
}O'þ

{)

@%

 

)8C'K4	@"GN
 
s4 

	ü




0
rï   c                   sr   G dd„ dƒ‰G ‡fdd„dt ƒ}G dd„ dƒ‰ G ‡ ‡fdd„dtƒ‰|ˆƒ tƒ tƒ ƒ}|j| |f|d	d
œ|¤ŽS )ak   Rendering of a qweb template without database and outside the registry.
    (Widget, field, or asset rendering is not implemented.)
    :param (string|int) template_name: template identifier
    :param dict values: template values to be used for rendering
    :param def load: function like `load(template_name)` which returns an etree
        from the given template name (from initial rendering or template
        `t-call`).
    :param options: used to compile the template
    :returns: bytes marked as markup-safe (decode to :class:`markupsafe.Markup`
                instead of `str`)
    :rtype: MarkupSafe
    c                   @  sT   e Zd ZdZdd„ e ¡ D ƒZi Ze ¡ D ]\ZZ	e 
e d¡d g ¡ e	¡ qdS )zrender.<locals>.MockPoolNc                 S  r»  r—   r'   )rÍ   Ú
cache_nameÚ
cache_sizer—   r—   r˜   râ   ‚  r·  z#render.<locals>.MockPool.<dictcomp>r  r   )r½   r¾   r¿   Údb_namer   rê   Ú_Registry__cachesÚ_Registry__caches_groupsr™  r   r+  rj  rÐ   r—   r—   r—   r˜   ÚMockPool€  s    ÿrž  c                      sN   e Zd ZdZ” ƒ Zdd„ Zdd„ Zdd„ Zdd	„ Zd
d„ Z	dd„ Z
dd„ ZdS )zrender.<locals>.MockIrQWebFc                 S  s   t dd„ |d�S )Nc                   S  s   d S r“   r—   r—   r—   r—   r˜   r  �  r  z?render.<locals>.MockIrQWeb._get_template_info.<locals>.<lambda>)rŠ  r   )r¸   rå  r—   r—   r˜   r„  Œ  r…  z-render.<locals>.MockIrQWeb._get_template_infoc                 S  sJ   i }|D ]}| j jd |ƒ\}}|tj|dd�|d dœ ||< ||< q|S )NÚloadrÞ  rß  )rá  rË   rù  r–   )r@  rÕ   r   râ  )r¸   rê  rÙ   r–   rá  Úvidr—   r—   r˜   rã  �  s   üz)render.<locals>.MockIrQWeb._preload_treesc                 S  s   | j jd |ƒS )zæ
            Load the template referenced by ``ref``.

            :returns: The loaded template (as string or etree) and its
                identifier
            :rtype: Tuple[Union[etree, str], Optional[str, int]]
            rŸ  )r@  rÕ   r¡  r—   r—   r˜   Ú_load›  s   z render.<locals>.MockIrQWeb._loadc                 S  s   d|d< d|d< | j i d�S )NTr  Fr  )r$  )r-  r£  r—   r—   r˜   r.  ¥  s   z/render.<locals>.MockIrQWeb._prepare_environmentc                 W  rÉ  )NzYFields are not allowed in this rendering mode. Please use "env['ir.qweb']._render" method©r^  ©r¸   r¦   r—   r—   r˜   rT  ª  rþ   z%render.<locals>.MockIrQWeb._get_fieldc                 W  rÉ  )NzZWidgets are not allowed in this rendering mode. Please use "env['ir.qweb']._render" methodr¢  r£  r—   r—   r˜   rV  ­  rþ   z&render.<locals>.MockIrQWeb._get_widgetc                 W  rÉ  )NzYAssets are not allowed in this rendering mode. Please use "env['ir.qweb']._render" methodr¢  r£  r—   r—   r˜   r]  °  rþ   z+render.<locals>.MockIrQWeb._get_asset_nodesN)r½   r¾   r¿   Ú	_registerÚpoolr„  rã  r¡  r.  rT  rV  r]  r—   )rž  r—   r˜   Ú
MockIrQWeb‡  s    
r¦  c                   @  s   e Zd Zdd„ ZdS )zrender.<locals>.MockCrc                 S  s
   i | _ d S r“   rŸ  r¼   r—   r—   r˜   r·   ´  s   
zrender.<locals>.MockCr.__init__N)r½   r¾   r¿   r·   r—   r—   r—   r˜   ÚMockCr³  s    r§  c                      s,   e Zd Z‡‡ fdd„Zd‡fdd„	Z‡  ZS )zrender.<locals>.MockEnvc                   s   t ƒ  ¡  i | _ˆ ƒ | _d S r“   )r¶   r·   rÕ   rŽ  r¼   )r§  rº   r—   r˜   r·   ¸  s   
z render.<locals>.MockEnv.__init__Nc                   s*   ˆ ƒ }|j  |du r| j ¡ |S |¡ |S )z— Return an mocked environment based and update the sent context.
                Allow to use `ir_qweb.with_context` with sand boxed qweb.
            N)rÕ   rD  )r¸   rŽ  r,  rÕ   Úsur@  )ÚMockEnvr—   r˜   Ú__call__½  s
   ÿz render.<locals>.MockEnv.__call__)NNNN)r½   r¾   r¿   r·   rª  rÀ   r—   )r§  r©  r¹   r˜   r©  ·  s    r©  T)rŸ  r  )rï   rÔ   rE  r2  )Útemplate_namerÙ   rŸ  rò   r¦  Úrendererr—   )r§  r©  rž  r˜   r3  s  s   ,r3  )ˆr  Ú
__future__r   r  r§   rx  Úloggingr1  r×  rk  r›   r(  r&  rQ  r`  rg  r?  rª   Ú
markupsafer   r   Úcollectionsr   Úcollections.abcr   r   r	   r
   r£   r   Ú	itertoolsr   r   Úlxmlr   Údateutil.relativedeltar   Úpathlibr   Úpsycopg2.extensionsr   Úpsycopg2.errorsr   Útypingr   r   Útypesr   Úodoor   r   r   Úodoo.modulesr   Úodoo.modules.registryr   Ú
odoo.toolsr   r   r   r   r   Úodoo.tools.constantsr    r!   Úodoo.tools.safe_evalr"   r#   r$   r%   r&   Úodoo.tools.lrur(   Úodoo.tools.miscr)   r*   r+   Úodoo.tools.imager,   r-   Úodoo.tools.profilerr.   Úodoo.tools.translater/   Ú	odoo.httpr0   r1   Úodoo.exceptionsr2   r3   Ú$odoo.addons.base.models.assetsbundler4   r5   r6   r7   Ú	getLoggerr½   r+  Ú	NT_OFFSETr9   Útok_namerý  r~  rw  r¯  Ú	frozensetr2  r¤   r}  r­  r5  rï  rÓ  rÚ  rÏ  rº  r*  rÑ  ÚIÚfindallrF  r™   r¡   r²   rF  r³   rµ   rÓ   rî   rõ   ÚJSONr  r/  rM  rï   r3  r—   r—   r—   r˜   Ú<module>   s¼     j
&Ú*




	7                 j