TALES expression to compare numeric input in Plone? - plone

TALES expression is new to me. Can I get some good reference for the same? Actually I wish to define a content rule for numeric input field using ploneformgen. Something like:
python: request.form.get('amt', False) <= 5000
then apply the rule.
Here 'amt' is a numeric/whole number field on the input form.

For reference, you should look at the official TALES specification, or refer to the TALES section of the Zope Page Templates reference.
In this case, you are using a plain python expression, and thus the normal rules of python code apply.
The expression request.form.get('amt', False) would return the request parameter 'amt' from the request, and if that's missing, return the boolean False, which you then compare to an integer value.
There are 2 things wrong with that expression: first of all you assume that the 'amt' parameter is an integer value. Even a PFG integer field however, is still a string in the request object. As such you'll need to convert in to an integer first before you can compare it.
Also, you fall back to a boolean, which in integer comparisons will be regarded as the equivalent of 0, better be explicit and use that instead:
python: int(request.form.get('amt', 0)) <= 5000
Note that for a PFG condition, you can also return a string error message instead of boolean True:
python: int(request.form.get('amt', 0)) <= 5000 or 'Amount must be not be greater than 5000'

Usually form parameters are passed in as strings if they are not defined on the application level otherwise e.g.
Zope will under the hood use the fieldname amt:int in order to convert the value to an integer.
So you may want to try to put an int(....) around the first expression.

Related

In ruamel how to start a string with '*' with no quotes like any other string

yaml = ruamel.yaml.YAML()
yaml.indent(mapping=4)
test_yaml_file = open("test.yaml")
test_file = yaml.load(test_yaml_file)
# test = LiteralScalarString('*clvm')
test = "*testing"
test_file['test_perf'] = test
with open("test.yaml", 'w') as changed_file:
yaml.dump(test_file, changed_file)
In this the expected output was
test_perf: *testing
but the output has been
test_perf: '*testing'
how to achieve this using ruamel?
Your scalar starts with a *, which is used in YAML to indicate an alias node. To prevent *testing to be interpreted as an alias during loading (even though the corresponding anchor (&testing) is not specified in the document), the scalar must be quoted or represented as a literal or folded block scalar.
So there is no way to prevent the quotes from happening apart from choosing to represent the scalar as literal or folded block scalar (where you don't get the quotes, but do get the | resp. >)
You should not worry about these quotes, because after loading you'll again have the string *testing and not something that all of a sudden has extra (unwanted) quotes).
There are other characters that have special meaning in YAML (&, !, etc.) and when indicated at the beginning of a scalar cause the scalar to be quoted. What the dump routine actually does is dump the string and read it back and if that results in a different value, the dumper knows that quoting is needed. This also works with strings like 2022-01-28, which when read back result in a date, such strings get quoted automatically when dumped as well (same for strings that look like floats, integers, true/false values).

tdstats.UDFCONCAT parameter varchar limit

I was using tdstats.UDFCONCAT to aggregate result of the query,
This function trims the resulting output, upon looked at the definition of this function, it accepts VARCHAR(128) .
REPLACE FUNCTION tdstats.UDFCONCAT
(aVarchar VARCHAR(128) CHARACTER SET UNICODE)
RETURNS VARCHAR(10000) CHARACTER SET UNICODE
CLASS AGGREGATE (20000)
SPECIFIC udfConcat
LANGUAGE C
NO SQL
NO EXTERNAL DATA
PARAMETER STYLE SQL
NOT DETERMINISTIC
CALLED ON NULL INPUT
EXTERNAL NAME 'SL!staudf!F!udf_concatvarchar'
Can anybody tell if there is any specific reason to keep it limited to 128?
Note: I have duplicated the function and increased the size from 128 to 256 and it worked in my case. If anybody wants to know my use case then I can update here but question is regarding the default character limit mentioned by TD in the in-built function, so have not added my use case here.

Convert string argument to regular expression

Trying to get into Julia after learning python, and I'm stumbling over some seemingly easy things. I'd like to have a function that takes strings as arguments, but uses one of those arguments as a regular expression to go searching for something. So:
function patterncount(string::ASCIIString, kmer::ASCIIString)
numpatterns = eachmatch(kmer, string, true)
count(numpatterns)
end
There are a couple of problems with this. First, eachmatch expects a Regex object as the first argument and I can't seem to figure out how to convert a string. In python I'd do r"{0}".format(kmer) - is there something similar?
Second, I clearly don't understand how the count function works (from the docs):
count(p, itr) → Integer
Count the number of elements in itr for which predicate p returns true.
But I can't seem to figure out what the predicate is for just counting how many things are in an iterator. I can make a simple counter loop, but I figure that has to be built in. I just can't find it (tried the docs, tried searching SO... no luck).
Edit: I also tried numpatterns = eachmatch(r"$kmer", string, true) - no go.
To convert a string to a regex, call the Regex function on the string.
Typically, to get the length of an iterator you an use the length function. However, in this case that won't really work. The eachmatch function returns an object of type Base.RegexMatchIterator, which doesn't have a length method. So, you can use count, as you thought. The first argument (the predicate) should be a one argument function that returns true or false depending on whether you would like to count a particular item in your iterator. In this case that function can simply be the anonymous function x->true, because for all x in the RegexMatchIterator, we want to count it.
So, given that info, I would write your function like this:
patterncount(s::ASCIIString, kmer::ASCIIString) =
count(x->true, eachmatch(Regex(kmer), s, true))
EDIT: I also changed the name of the first argument to be s instead of string, because string is a Julia function. Nothing terrible would have happened if we would have left that argument name the same in this example, but it is usually good practice not to give variable names the same as a built-in function name.

VB Single line with null values

I have the following code that I don't believe is functioning properly and I cannot figure out why.
dim total as decimal? = If(first Is Nothing OrElse second Is Nothing, _
Nothing, _
Math.Abs(If(first, 0D)) - Math.Abs(If(second, 0D)))
If either first or second are nothing, then nothing needs to be placed in the total. However, if they both have values, they both need to be changed to positive values and first - second needs to be calculated. First and second are both nullable decimals (decimal?).
Expected results:
first = nothing
second = nothing
total = nothing
Actual results:
first = nothing
second = nothing
total = 0D
I cannot understand why the if statement is not jumping to the true segment and putting Nothing into the variable total
The If() operator is strongly-typed, but the compiler has to infer the type of the result based on the inputs.
In this case, it can't infer the type from the first option (Nothing), because Nothing by itself has no type, and unlike C#'s null, Nothing can reduce to a value type (this will be important in a moment). Therefore the compiler has to look at the second option: Math.Abs(If(first, 0D)) - Math.Abs(If(second, 0D)). The type of this expression evaluates out to a Decimal... not a Decimal?. Therefore, the resulting type of your entire If() expression is a Decimal, and not a Decimal?. That you assign the result to a Decimal? doesn't matter.
I cannot understand why the if statement is not jumping to the true segment and putting Nothing into the variable total
That is exactly what it's doing. However, as mentioned earlier, Nothing in VB.Net can be assigned to value types. Before the assignment can occur, Nothing is converted to a Decimal, because this is the result type of that If() expression. In case of a Decimal, assigning the value of Nothing results in the default Decimal value of 0D... hence your results.
I haven't tested this, but I think you could fix this to get your desired results by explicitly casting the False expression in your If() operator as a Decimal?/Nullable(Of Decimal). This will tell the compiler to infer Decimal? instead of Decimal for the type of the If() expression, and therefore returning Nothing from that expression will have desired output.
I have reverted to make a compiler extension that allows the absolute value function to be performed on a nullable decimal, returning the value if it is Nothing or non-negative, otherwise multiply by -1 and return. That way if it returns nothing the computation result is as expected.
dim total as decimal? = first.ToAbsoluteValue() - second.ToAbsoluteValue()
<System.Runtime.CompilerServices.Extension()>
Friend Function ToAbsoluteValue(value As Decimal?) As Decimal?
If value Is Nothing OrElse value >= 0 Then Return value
Return Math.Abs(If(value, 0D))
End Function
If anyone knows how to add this to the Math.Abs() overloads that would be a much cleaner option.

How can I prevent SQLite from treating a string as a number?

I would like to query an SQLite table that contains directory paths to find all the paths under some hierarchy. Here's an example of the contents of the column:
/alpha/papa/
/alpha/papa/tango/
/alpha/quebec/
/bravo/papa/
/bravo/papa/uniform/
/charlie/quebec/tango/
If I search for everything under /bravo/papa/, I would like to get:
/bravo/papa/
/bravo/papa/uniform/
I am currently trying to do this like so (see below for the long story of why I can't use more simple methods):
SELECT * FROM Files WHERE Path >= '/bravo/papa/' AND Path < '/bravo/papa0';
This works. It looks a bit weird, but it works for this example. '0' is the unicode code point 1 greater than '/'. When ordered lexicographically, all the paths starting with '/bravo/papa/' compare greater than it and less than 'bravo/papa0'. However, in my tests, I find that this breaks down when we try this:
SELECT * FROM Files WHERE Path >= '/' AND Path < '0';
This returns no results, but it should return every row. As far as I can tell, the problem is that SQLite is treating '0' as a number, not a string. If I use '0Z' instead of '0', for example, I do get results, but I introduce a risk of getting false positives. (For example, if there actually was an entry '0'.)
The simple version of my question is: is there some way to get SQLite to treat '0' in such a query as the length-1 string containing the unicode character '0' (which should sort strings such as '!', '*' and '/', but before '1', '=' and 'A') instead of the integer 0 (which SQLite sorts before all strings)?
I think in this case I can actually get away with special-casing a search for everything under '/', since all my entries will always start with '/', but I'd really like to know how to avoid this sort of thing in general, as it's unpleasantly surprising in all the same ways as Javascript's "==" operator.
First approach
A more natural approach would be to use the LIKE or GLOB operator. For example:
SELECT * FROM Files WHERE Path LIKE #prefix || '%';
But I want to support all valid path characters, so I would need to use ESCAPE for the '_' and '%' symbols. Apparently this prevents SQLite from using an index on Path. (See http://www.sqlite.org/optoverview.html#like_opt ) I really want to be able to benefit from an index here, and it sounds like that's impossible using either LIKE or GLOB unless I can guarantee that none of their special characters will occur in the directory name, and POSIX allows anything other than NUL and '/', even GLOB's '*' and '?' characters.
I'm providing this for context. I'm interested in other approaches to solve the underlying problem, but I'd prefer to accept an answer that directly addresses the ambiguity of strings-that-look-like-numbers in SQLite.
Similar questions
How do I prevent sqlite from evaluating a string as a math expression?
In that question, the values weren't quoted. I get these results even when the values are quoted or passed in as parameters.
EDIT - See my answer below. The column was created with the invalid type "STRING", which SQLite treated as NUMERIC.
* Groan *. The column had NUMERIC affinity because it had accidentally been specified as "STRING" instead of "TEXT". Since SQLite didn't recognize the type name, it made it NUMERIC, and because SQLite doesn't enforce column types, everything else worked as expected, except that any time a number-like string is inserted into that column it is converted into a numeric type.

Resources