I have an XPath 2.0 formula using XPath variables. The formula is in the "if-then-else" construct.
The if condition itself has a few conditions inside it. I put the conditions in the order I want them to be evaluated.
Here is my formula:
if (empty($NetCashFlowFromInvestingActivities) and exists($NetCashFlowFromOperatingActivities) and exists($NetCashFlowFromFinancingActivities) and exists($NetCashFlow) and not($NetCashFlow - ($NetCashFlowFromOperatingActivities + $NetCashFlowFromFinancingActivities + (if (exists($ExchangeGainsLosses)) then $ExchangeGainsLosses else 0)) = 0)) then ($NetCashFlow - ($NetCashFlowFromOperatingActivities + $NetCashFlowFromFinancingActivities + (if (exists($ExchangeGainsLosses)) then $ExchangeGainsLosses else 0))) else ()
The data supplied to elementpath in Python dict format is:
{
'NetCashFlow': None,
'NetCashFlowFromFinancingActivities': 369100000,
'NetCashFlowFromFinancingActivitiesContinuing': 369100000,
'NetCashFlowFromInvestingActivities': -460300000,
'NetCashFlowFromOperatingActivities': 207400000
}
Here is the source xml:
<root>
<formula>
<variable name="Equity" select="if (empty($Equity) and exists(($EquityAttributableToParent, $EquityAttributableToNoncontrollingInterest))) then sum(($EquityAttributableToParent, $EquityAttributableToNoncontrollingInterest)) else ()"/>
<variable name="OperatingMargin" select="if ((not(exists($OperatingMargin))) and (exists($Revenues) and exists($OperatingExpense))) then (sum(($Revenues, -$OperatingExpense))) else $OperatingMargin"/>
<variable name="NetCashFlowFromInvestingActivities" select="if (empty($NetCashFlowFromInvestingActivities) and exists($NetCashFlowFromOperatingActivities) and exists($NetCashFlowFromFinancingActivities) and exists($NetCashFlow) and not($NetCashFlow - ($NetCashFlowFromOperatingActivities + $NetCashFlowFromFinancingActivities + (if (exists($ExchangeGainsLosses)) then $ExchangeGainsLosses else 0)) = 0)) then ($NetCashFlow - ($NetCashFlowFromOperatingActivities + $NetCashFlowFromFinancingActivities + (if (exists($ExchangeGainsLosses)) then $ExchangeGainsLosses else 0))) else ()"/>
</formula>
</root>
I am using elementpath package in Python 3.6 to evaluate the XPath 2.0, as that was the only way I could find that evaluates XPath 2.0 in Python.
In my formula:
I check for exists($NetCashFlow) first and then try to check:
and not($NetCashFlow - ($NetCashFlowFromOperatingActivities + $NetCashFlowFromFinancingActivities + (if (exists($ExchangeGainsLosses)) then $ExchangeGainsLosses else 0)) = 0)
I assumed that if $NetCashFlow is nil, the next expression will not be evaluated. But, I am getting an error which says that I am trying an operation with a non-existent value, i.e., $NetCashFlow - ...
How can I write this formula so that exists($NetCashFlow) is checked first and if that is false, the rest of the expression is not evaluated.
Is there an order precedence based on parentheses that I should be using?
Related
I´ve noticed that some custom modules that I develop can be installed on databases with records, while others throw the KeyError message, unless the database is empty (no records). Generally the errors appear when the module contains computed fields. So, does anybody know why this happens? and how my code should look like to avoid this kind of errors?
an example computed field that throws this errors looks like this:
from odoo import models, fields, api
from num2words import num2words
Class InheritingAccountMove(models.Model):
_inherit = 'account.move'
total_amount_text = fields.Char(string='Total', compute='_compute_total_amount_text', store=True)
#api.depends('amount_total')
def _compute_total_amount_text(self):
lang_code = self.env.context.get('lang') or self.env.user.lang
language = self.env['res.lang'].search([('iso_code', '=', lang_code)])
separator = language.read()[0]['decimal_point']
for record in self:
decimal_separator = separator
user_language = lang_code[:2]
amount = record.amount_total
amount_list = str(amount).split(decimal_separator)
amount_first_part = num2words(int(amount_list[0]), lang=user_language).title() + ' '
amount_second_part = amount_list[1]
if len(amount_second_part) == 0:
amount_text = amount_first_part + '00/100'
elif len(amount_second_part) < 2:
amount_text = amount_first_part + amount_second_part + '0/100'
else:
amount_text = amount_first_part + amount_second_part[:2] + '/100'
record.total_amount_text = amount_text
UPDATED
The reason your code has a problem in this situation is that when there are no records in the table(at time of installation) your loop won’t run which result in no value assigning of your computed field so
Add the first line of code in function
self.total_amount_text = False This is required to assign value to the computed field in compute function from Odoo 13 and maybe 12
----------------------------------------------------------------
Other reasons could be :
This error occurs when one tries to access a key from a dictionary that doesn't exist like,
language.read()[0]['decimal_point']
the dictionary may not have 'decimal_point' at the time of installation of the module, which may have returned this error a common way to handle this is by checking if the key exists or not before accessing it like,
if 'decimal_point' in language.read()[0].keys()
also, a dictionary can also be empty in that case the language.read()[0] will throw an error
I´ve changed my code making it specifically for spanish and the error doesn´t appear anymore. I appreciate Muhammad´s answer, maybe he´s right but anyway here is the modified code:
#api.depends('invoice_line_ids')
def _compute_total_amount_text(self):
for record in self:
amount = record.amount_total
amount_list = str(amount).split('.')
amount_first_part = num2words(int(amount_list[0]), lang='es').title() + ' '
amount_second_part = amount_list[1]
if len(amount_second_part) == 0:
amount_text = amount_first_part + '00/100'
elif len(amount_second_part) < 2:
amount_text = amount_first_part + amount_second_part + '0/100'
else:
amount_text = amount_first_part + amount_second_part[:2] + '/100'
record.total_amount_text = amount_text
Can I use MSON to specify an example values instead of + Body?
Is it possible to override predefined structure values?
I've tried like this:
+ Request (application/json)
+ Headers
Authorization: JWT <token>
+ Attributes (ClientsideCommand)
+ alias: `show-xc`
+ args (array[AppCommandArg], fixed-type)
+ (AppCommandArg)
+ arg_key: address
+ order: 1
+ required: true
+ skip_arg_name: true
+ (AppCommandArg)
+ arg_key: `-A1`
+ order: 2
+ required: true
+ skip_arg_name: false
But such definition corrupts json-schema, because AppCommandArg descibed as separate objects.
And also in the JSON generated from the MSON has 3 items where first item is deafult AppCommandArg.
Looks like it's not possible to make this things twogether. If you add elements as showed abowe Apiary renders it as it sees it, if an element noted twice the json schema also will describe it twice.
I'm writing an LPeg-based parser. How can I make it so a parsing error returns nil, errmsg?
I know I can use error(), but as far as I know that creates a normal error, not nil, errmsg.
The code is pretty long, but the relevant part is this:
local eof = lpeg.P(-1)
local nl = (lpeg.P "\r")^-1 * lpeg.P "\n" + lpeg.P "\\n" + eof -- \r for winblows compat
local nlnoeof = (lpeg.P "\r")^-1 * lpeg.P "\n" + lpeg.P "\\n"
local ws = lpeg.S(" \t")
local inlineComment = lpeg.P("`") * (1 - (lpeg.S("`") + nl * nl)) ^ 0 * lpeg.P("`")
local wsc = ws + inlineComment -- comments count as whitespace
local backslashEscaped
= lpeg.P("\\ ") / " " -- escaped spaces
+ lpeg.P("\\\\") / "\\" -- escaped escape character
+ lpeg.P("\\#") / "#"
+ lpeg.P("\\>") / ">"
+ lpeg.P("\\`") / "`"
+ lpeg.P("\\n") -- \\n newlines count as backslash escaped
+ lpeg.P("\\") * lpeg.P(function(_, i)
error("Unknown backslash escape at position " .. i) -- this error() is what I wanna get rid of.
end)
local Line = lpeg.C((wsc + (backslashEscaped + 1 - nl))^0) / function(x) return x end * nl * lpeg.Cp()
I want Line:match(...) to return nil, errmsg when there's an invalid escape.
LPeg itself doesn't provide specific functions to help you with error reporting. A quick fix to your problem would be to make a protected call (pcall) to match like this:
local function parse(text)
local ok, result = pcall(function () return Line:match(text) end)
if ok then
return result
else
-- `result` will contain the error thrown. If it is a string
-- Lua will add additional information to it (filename and line number).
-- If you do not want this, throw a table instead like `{ msg = "error" }`
-- and access the message using `result.msg`
return nil, result
end
end
However, this will also catch any other error, which you probably don't want. A better solution would be to use LPegLabel instead. LPegLabel is an extension of LPeg that adds support for labeled failures. Just replace require"lpeg" with require"lpeglabel" and then use lpeg.T(L) to throw labels where L is an integer from 1-255 (0 is used for regular PEG failures).
local unknown_escape = 1
local backslashEscaped = ... + lpeg.P("\\") * lpeg.T(unknown_escape)
Now Line:match(...) will return nil, label, suffix if there is a label thrown (suffix is the remaining unprocessed input, which you can use to compute for the error position via its length). With this, you can print out the appropriate error message based on the label. For more complex grammars, you would probably want a more systematic way of mapping the error labels and messages. Please check the documentation found in the readme of the LPegLabel repository to see examples of how one may do so.
LPegLabel also allows you to catch the labels in the grammar by the way (via labeled choice); this is useful for implementing things like error recovery. For more information on labeled failures and examples, please check the documentation.
I'm using Dojo 1.9.1.
I'm using dojox.charting to draw some charts.
I am using a labelFunc to produce a date/time label for my X-axis. This is working fine in all browsers.
But I want to add a line break to my label so that the date sits above the time, e.g.:
10/01/2014
06:00
I can add a html break tag to the string returned and this works in Chrome and Firefox but not IE9 (to be expected).
Has anybody solved how to do this one that works across all browsers including IE9 (or specifically ones that don't "do" html labels).
Cheers
Ian
My label func:
_labelFull: function (index) {
// Returns a label in the form "dd/mm/yyyy hh:mm" for tooltip labelling
var dt,
d;
dt = new Date(Date.parse(myglobalStartDateTime));
dt.setHours(dt.getHours() + Number(index));
// Full date/time
d = ("0" + dt.getDate()).slice(-2) + '/' +
("0" + (dt.getMonth() + 1)).slice(-2) + '/' +
dt.getFullYear() + ' ' +
("0" + dt.getHours()).slice(-2) + ':' +
("0" + dt.getMinutes()).slice(-2) + 'UTC';
return d;
}
How can I get Mathematica to export/save/write a text file with proper Fortan77 formatting, that is, 72 columns and a continuation marker on the sixth column?
I am using Mathematica to generate large and complex analytic expressions, which I then need to insert into pre-existing Fortran77 code. I have everything working correctly in the front end of Mathematica with FortranForm[] and
SetOptions[$Output, PageWidth -> 72]
However, I can't figure out how to get Mathematica to output correctly to a text file. I want something like this:
MM11 = mH1**2 + (g2**2*v1**2)/2. -
- (g2**2*(v1**2/2. -
- ((v2*Cos(phi2) - (0,1)*v2*Sin(phi2))*
- (v2*Cos(phi2) + (0,1)*v2*Sin(phi2)))/2.))/2.
...
but get either this:
MM11 = FortranForm[mH1^2 + (g2^2*v1^2)/2 - ...
or this:
MM11 = mH1**2 + (g2**2*v1**2)/2. - (g2**2*
(v1**2/2. - ((v2*Cos(phi2) - (0,1)*v2*Sin(phi2))*
...
This is a job for the surprisingly little-known Splice function. First, you make a template file, with the extension ".mf", like so:
file = "test.mf";
out = OpenWrite[file];
WriteString[out, "MH1 = <* form *>"];
Close[out];
Now when you use Splice, Mathematica will automatically replace everything between the <* and *> delimiters with its evaluated form. So if you set
form = 4 + b9^2 + c1^5 + c4^5 + h10^4 + j2 + k10^4 + p10^4 + q5^5 +
q8 + s3^3 + s7^2 + t6^3 + u3^2 + u9^3 + x8^4 + z2^3;
and call
Splice["test.mf", PageWidth -> 72];
which will automatically infer you want FortranForm output from the file extension, and which allows you to set PageWidth as an option, you will get a pretty decent result in the automatically generated file "test.f" (note the new extension):
MH1 = 4 + b9**2 + c1**5 + c4**5 + h10**4 + j2 + k10**4 + p10**4 +
- q5**5 + q8 + s3**3 + s7**2 + t6**3 + u3**2 + u9**3 + x8**4 +
- z2**3
Look at the docs for Splice for more options (changing the name of the output file and the like).