How can I validate a list which contains floats in a specific range with Cerberus? - cerberus

I would like to validate JSON objects that were parsed into Python dictionaries like the following:
# example with 2 elements
{
'coordinates': [-20.3, 30.6]
}
# example with 3 elements
{
'coordinates': [-20.3, 30.6, 0]
}
So far I was able to define the following schema:
schema = {
'coordinates': {
'required': True,
'type': 'list',
'minlength': 2,
'maxlength': 3,
'schema': {
'type': 'float',
},
}
}
I would also like to check these constraints:
the first item of the coordinates field's value should be between -30.0 and 10.0
the second item should be between -10.0 and 50.0
But I was not able to come up with something useful. Does anyone have suggestions how to achieve this?
Update: Based on accepted answer the schema becomes the following
schema = {
'coordinates': {
'required': True,
'type': 'list',
"oneof_items": (
({"min": -30.0, "max": 10.0}, {"min": -10.0, "max": 50.0}),
({"min": -30.0, "max": 10.0}, {"min": -10.0, "max": 50.0}, {}),
),
}
}
docs: https://docs.python-cerberus.org/en/stable/validation-rules.html#of-rules-typesaver

Add this rule:
{"oneof_items":
(
({"min": -30.0, "max": 10.0}, {"min": -10.0, "max": 50.0}),
({"min": -30.0, "max": 10.0}, {"min": -10.0, "max": 50.0}, {}),
)
}
That makes the length-related rules superfluous. To get rid of the redundancies Python object references or the rule set registry are feasible.

Related

filter nest tree object by object id

I have a tree object like below:
let data = [
{
id: 1,
children: [
{
id: 1.1,
children: [
{
id: 1.2,
children: []
},
{
id: 1.22,
children: []
}
]
}
]
},
{
id: 2,
children: []
}
]
I want to filter out id equal a specific value. In this case, I want to filter out id equal 1.2.
The rusult I want is like below:
let data = [
{
id: 1,
children: [
{
id: 1.1,
children: [
{
id: 1.22,
children: []
}
]
}
]
},
{
id: 2,
children: []
}
]
I have search a few question about filter nest deep object, But still don't know how. I need to use recursion to solve this.
This is my way:
function handleDelete (data) {
return data.filter(t => {
if (t.children.length) {
handleDelete(t.children)
})
} else {
return t.id !== '1.2'
}
})
}
let result = handleDelete(data)
delete a node and its descendants
Here's an effective technique using flatMap and mutual recursion1 -
del accepts an array of nodes, t, a query, q, and calls del1 on each node with the query
del1 accepts a single node, t, a query, q, and calls del on a node's children
const del = (t, q) =>
t.flatMap(v => del1(v, q)) // <-- 1
const del1 = (t, q) =>
q == t.id
? []
: { ...t, children: del(t.children, q) } // <-- 2
const data =
[{id:1,children:[{id:1.1,children:[{id:1.2,children:[]},{id:1.22,children:[]}]}]},{id:2,children:[]}]
const result =
del(data, "1.2")
console.log(result)
In the output, we see node.id 1.2 is removed -
[
{
"id": 1,
"children": [
{
"id": 1.1,
"children": [
{
"id": 1.22,
"children": []
}
]
}
]
},
{
"id": 2,
"children": []
}
]
preserving the descendants
In the program above, if a node.id matches our query, the node and all of its descendent children are removed. If we only want to delete the parent node and keep the children, we can make a single modification (!) to the program -
const del = (t, q) =>
t.flatMap(v => del1(v, q))
const del1 = (t, q) =>
q == t.id
? del(t.children, q) // <-- !
: { ...t, children: del(t.children, q) }
const data =
[{id:1,children:[{id:1.1,children:[{id:1.2,children:[]},{id:1.22,children:[]}]}]},{id:2,children:[]}]
const result =
del(data, "1") // <-- delete node.id equal to "1"
console.log(result)
Notice how the children for 1 are still included in the output -
[
{
"id": 1.1,
"children": [
{
"id": 1.2,
"children": []
},
{
"id": 1.22,
"children": []
}
]
},
{
"id": 2,
"children": []
}
]
without mutual recursion
Mutual recursion isn't the only way to do it, but it's the only way to avoid a dynamic type check, such as the one below. In this final revision, we remove a parent and all of its children, as we did in the first program, but this del is implemented using a single recursive function -
const del = (t, q) =>
Array.isArray(t) // <-- array
? t.flatMap(v => del(v, q))
: Object(t) === t // <-- object
? q == t.id
? []
: { ...t, children: del(t.children, q) }
: t // <-- neither (noop)
const data =
[{id:1,children:[{id:1.1,children:[{id:1.2,children:[]},{id:1.22,children:[]}]}]},{id:2,children:[]}]
const result =
del(data, "1.2")
console.log(result)
The output is the same as the first program, where 1.2 and all descendants are removed -
[
{
"id": 1,
"children": [
{
"id": 1.1,
"children": [
{
"id": 1.22,
"children": []
}
]
}
]
},
{
"id": 2,
"children": []
}
]
1. See this technique used on a different data set in this related Q&A.
2. All programs in this answer produce a new tree. The original input is not modified by del (or del1).

CosmosDb SELECT multiple values with LINQ query

What will be the LINQ equivalent of this cosmos SQL API query:
SELECT c as Person, ST_DISTANCE(c.location, {'type': 'Point', 'coordinates':[-122.3382419, 47.6074856]}) as Distance
FROM c
WHERE c.DocType = 0 AND
ST_DISTANCE(c.location, {'type': 'Point', 'coordinates':[-123.3382419, 47.6074856]}) < 1 AND NOT c.Blocked
which gets back
[
{
"Person": {
"DocType": 0,
"location": {
"type": "Point",
"coordinates": [
-123.3382419,
47.6074856
]
},
"MDS": "Chwal",
"Description": "Bduwhs",
"Contents": null,
"GFree": false,
"Veg": false,
"AllergicContents": null,
"Calorie": 0,
"LinkToRecipe": null,
"Cost": 36,
"DASD": "Mexican",
"ExpirationTime": "2019-12-17T11:30:52Z",
"Images": [
"test/25254932-2898-5fd7-949b-b2feb25a4964"
],
"ProducerUserId": "1b36c0f1-425c-483a-bb01-69b06e69f203",
"ExchangeDateTimeStartInUtc": "2019-12-17T20:30:52Z",
"ExchangeDateTimeEndInUtc": "2019-12-17T19:30:52Z",
"Blocked": false,
"id": "asd,
"_rid": "asd=="
},
"Distance": 0.1
}
]
The problem with ST_DISTANCE is that it can only be calculated on Cosmos db, and can't be post evaluated.
Found a way to do it other than writing SQL query string
DocumentDBRepository.RunQueryAsync(
from c in DocumentDBRepository.DocumentQuery<Person>()
where c.DocType == 0
&& c.Location.Distance(point) < 1
&& !c.Blocked
select new { Person = c, Distance = c.Location.Distance(point) });
Also realized that LINQ lambda is different from a LINQ query. The above is a LINQ query, A LINQ lambda looks like this

Mapbox Distance Matrix API returns all zeroes

I'm trying to implement the Mapbox Distance Matrix API as an alternative to Google, since it was becoming too expensive. I've tried to reduce the example to something minimal, with only two values:
{
code: "Ok",
distances: [
[
0,
0
]
],
durations: [
[
0,
0,
0,
0,
0,
0
]
],
destinations: [
{
distance: 404951.186070298,
name: "",
location: [
48.761423,
5.731594
]
},
{
distance: 402983.402982556,
name: "",
location: [
48.761423,
5.731594
]
}
],
sources: [
{
distance: 401905.604376238,
name: "",
location: [
48.761423,
5.731594
]
}
]
}
I see that the coordinates of the values are the same, even though they do not match the input coordinates from my URL, which are 52.08515,4.2826;52.11703,4.28716;52.11736,4.28939. The problem persists with all modes of transportation. Any help would be appreciated!
The format is lon,lat - not lat,lon - I made the same mistake but the docs are correct.

Understanding FROM_REF_SPEED_LIMIT and TO_REF_SPEED_LIMIT attributes

I want to get speed limits for points in a car track. But instead of one value, I got two: FROM_REF_SPEED_LIMIT and TO_REF_SPEED_LIMIT. What is the meaning of these ones? Where is no documentation about these attributes. How can I use them to get speed limit? Actually speed limit in this place is 40km/h.
import requests
t = [(55.662026, 37.773537),
(55.661813, 37.774049)]
s = ""
for x in t:
s += ' <trkpt lat="' + str(x[0]) + '" lon="' + str(x[1]) + '"/> '
s1 = '<?xml version="1.0"?> <gpx version="1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.topografix.com/GPX/1/0" xsi:schemaLocation="http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd"> <trk> <trkseg> ' + s +'</trkseg></trk></gpx>'
resp = requests.post('http://rme.cit.api.here.com/2/matchroute.json?routemode=carHOV&attributes=SPEED_LIMITS_FCn%28FROM_REF_SPEED_LIMIT,TO_REF_SPEED_LIMIT%29&app_id=iqZ08RnLQHOCQUYqwZ&app_code=oWWPJv9pVx9Y2DdIBBOA', data=s1)
print(resp.text)
Response:
{
"MapVersion": "LATEST",
"RouteLinks": [
{
"attributes": {
"SPEED_LIMITS_FCN": [
{
"FROM_REF_SPEED_LIMIT": "20",
"TO_REF_SPEED_LIMIT": "60"
}
]
},
"confidence": 0.94,
"functionalClass": 3,
"linkId": -1154810237,
"linkLength": 50.75,
"mSecToReachLinkFromStart": 3501,
"offset": 0.42156,
"shape": "55.66226 37.77328 55.66212 37.77352 55.66195 37.77387"
},
{
"attributes": {
"SPEED_LIMITS_FCN": [
{
"FROM_REF_SPEED_LIMIT": "20",
"TO_REF_SPEED_LIMIT": "60"
}
]
},
"confidence": 0.95,
"functionalClass": 3,
"linkId": -1154810236,
"linkLength": 58.13,
"mSecToReachLinkFromStart": 6403,
"offset": 0.69481,
"shape": "55.66195 37.77387 55.66179 37.77431 55.66168 37.77466"
}
],
"TracePoints": [
{
"confidenceValue": 0.5,
"elevation": 0.0,
"headingDegreeNorthClockwise": 10000.0,
"headingMatched": 131.0,
"lat": 55.662026,
"latMatched": 55.66208,
"linkIdMatched": -1154810237,
"lon": 37.773537,
"lonMatched": 37.77361,
"matchDistance": 10.0,
"matchOffsetOnLink": 0.42156269739402924,
"minError": 7.0,
"routeLinkSeqNrMatched": 0,
"speedMps": 0.0,
"timestamp": 0
},
{
"confidenceValue": 0.58,
"elevation": 0.0,
"headingDegreeNorthClockwise": 10000.0,
"headingMatched": 123.0,
"lat": 55.661813,
"latMatched": 55.66186,
"linkIdMatched": -1154810236,
"lon": 37.774049,
"lonMatched": 37.77411,
"matchDistance": 8.59,
"matchOffsetOnLink": 0.69481133508979,
"minError": 7.0,
"routeLinkSeqNrMatched": 1,
"speedMps": 0.0,
"timestamp": 0
}
],
"Warnings": []
}
The link has two different speed limits for each direction in its map data.
If the published speed limit is wrong, you can report it to https://mapcreator.here.com. Right now we will take a look at it.
Please check the attached image.
Thank you!

Watson doesn't get zeros

Let's say I have a conversation services configured in IBM Watson ready to recognize a number given in words and in pieces. For example, if I have the number 1320, it can be sent as thirteen twenty or thirteen two zero, etc.
In the first case I'll get something like this from a conversation service:
{
// ...
"entities": [
{
"entity": "sys-number",
"location": [
0,
5
],
"value": "13",
"confidence": 1,
"metadata": {
"numeric_value": 13
}
},
{
"entity": "sys-number",
"location": [
6,
12
],
"value": "20",
"confidence": 1,
"metadata": {
"numeric_value": 20
}
}
]
// ...
}
In the second case (thirteen two zero):
{
// ...
"entities": [
{
"entity": "sys-number",
"location": [
0,
5
],
"value": "13",
"confidence": 1,
"metadata": {
"numeric_value": 13
}
},
{
"entity": "sys-number",
"location": [
6,
14
],
"value": "2",
"confidence": 1,
"metadata": {
"numeric_value": 2
}
}
]
// ...
}
The big question here is: Where is my zero?
I know this question has been asked more than once, but none of the answers I found solved my current issues.
I've seen examples where a regular expression could be used, but that's for actual numbers, here I have words and Watson is the one who actually guesses the number.
Is there a way to obtain a third entry in my entities for that zero? or another work arround? or configuration I may be lacking?
I just tried this in Watson Assistant and it now gets the zero. With #sys-numbers enabled my utterance is thirteen two zero and I get these entities back:
entities: [
0: {
entity: "sys-number",
location: [0, 8],
value: "13",
confidence: 1,
metadata: {numeric_value: 13}
}
1: {
entity: "sys-number",
location: [9, 12],
value: "2",
confidence: 1,
metadata: {numeric_value: 2}
}
2: {
entity: "sys-number",
location: [13, 17],
value: "0",
confidence: 1,
metadata: {numeric_value: 0}
}
]
It might be the entities matching has been improved.

Resources