Neo4j FAST API add labels dynamically - python

from fastapi import FastAPI
from pydantic import BaseModel
import os
from dotenv import load_dotenv
from neo4j import GraphDatabase
load_dotenv()
uri=os.getenv("uri")
user=os.getenv("user")
pwd=os.getenv("pwd")
class nodemodel(BaseModel):
label:str
name:str
def connection():
driver=GraphDatabase.driver(uri=uri,auth=(user,pwd))
return driver
app=FastAPI()
#app.post("/createNode")
def createnode(node:nodemodel):
driver_neo4j=connection()
session=driver_neo4j.session()
q1="""
CREATE(n{name:$name}) WITH n
CALL apoc.create.addLabels(n, [$label]) YIELD node
return n.name as name
"""
x={"name":node.name, "label":node.label}
results=session.run(q1,x)
return {"response" +results}
Thats my current code for a Neo4j REST API and it is working but i want to add labels more dynamically instead of just one. I want to type into the Request Body of my API:
{
"labels": "Label1:Label2:Label3",
"name": "string"
}
or just
{
"labels": "Label1",
"name": "string"
}
and i want both Options to work. Is there a way to do this, can someone show me an example with code?
Kind Regards
Tim

I fix some of the syntax errors on your script. See below:
The APOC apoc.create.addLabels parameters are both list so make (nodes, $labels) as lists. Pass nodes as collect(n) and labels as ["Label1", "Label2", "Label3"]
In the query, during CREATE you need to use a node class name so I used SampleNode
In your query, use node.name rather than n.name
Sample value of x:
x= {"labels": ["Label1", "Label2", "Label3"], "name": "Sample Name"}
q1="""
CREATE (n:SampleNode {name:$name})
WITH collect(n) as nodes
CALL apoc.create.addLabels(nodes, $labels) YIELD node
return node.name as name"""
"""
x={"name":node.name, "labels":node.labels}
results=session.run(q1,x)
I tested it in my python notebook and it looks like this:

Related

How to de-serialize JSON data into a class and then access the values as class variables and use intellisense to access in Python

I have a JSON configuration below
body =
{
"objectId": "068acfee-e5bc-4b27-ad80-59cf0adac4d9",
"name": "abc",
"address": {
"doorNo": 23,
"pinCode": "456"
}
}
I need to deserialize and access the values in an intuitive way by typing using IntelliSense. Currently I am doing as below
import json
class Payload(object):
def __init__(self, j):
self.__dict__ = j
I am accessing for instance doorNo field as below
p = Payload(body)
doorNumber = p.address['doorNo']
I wish to access it as below
doorNumber = p.address.doorNo
How to acheive this way in Python?
In C# I used to achieve this using the Newtonsoft library by de-serializing it into the equivalent class created with respective properties.
p = JsonConvert.DeserializeObject<Payload>(body);
var doorNo = p.address.doorNo
Python Version: 3.9.10
Editor: PyCharm 2022.1 (Community Edition)
Try using types.SimpleNamespace
import json
from types import SimpleNamespace
your_json_data = '{"a":2, "b":{"c":3"}}'
convt_data = json.loads(your_json_data, object_hook=lambda d: SimpleNamespace(**d))
# you can use it like this -> convt_data.b.c will have value 3

Blob name patterns of Azure Functions in Python

I am implementing an Azure Function in Python which is triggered by a file uploaded to blob storage. I want to specify the pattern of the filename and use its parts inside my code as follows:
function.json:
{
"scriptFile": "__init__.py",
"bindings": [
{
"name": "inputblob",
"type": "blobTrigger",
"direction": "in",
"path": "dev/sources/{filename}.csv",
"connection": "AzureWebJobsStorage"
}
]
}
The executed __init__.py file looks as follows:
import logging
import azure.functions as func
def main(inputblob: func.InputStream):
logging.info('Python Blob trigger function processed %s', inputblob.filename)
The error message that I get is: AttributeError: 'InputStream' object has no attribute 'filename'.
As a reference, I used this documentation.
Did I do something wrong or is it not possible to achieve what I want in Python?
Your function code should be this:
import logging
import os
import azure.functions as func
def main(myblob: func.InputStream):
head, filename = os.path.split(myblob.name)
name = os.path.splitext(filename)[0]
logging.info(f"Python blob trigger function processed blob \n"
f"Name without extension: {name}\n"
f"Filename: {filename}")
It should be name instead of filename.:)
I know its really late but I was going through the same problem and I got a getaway so I decided to answer you here.
You can just do reassemble the string in python.
inside init.py -
filenameraw = inputblob.name
filenameraw = filenameraw.split('/')[-1]
filenameraw = filenameraw.replace(".csv","")
with this you'll get your desired output. :)

Python script for outputting JSON has wrong output for attribute-value pair

I'm writing a Python script to output some JSON files to Cosmos DB on Azure. My script looks as follows:
import logging
import uuid
import json
import azure.functions as func
def main(event: func.EventHubEvent, message: func.Out[func.Document]) -> None:
event_body = event.get_body().decode('utf-8')
logging.info('Python event trigger function processed an event item: %s',event_body)
data = {
"value": event_body,
"insertion_time": event_body
}
message.set(func.Document.from_json(json.dumps(data)))
The output is written like:
{
"value": "{\n \"value\": \"66\",\n \"insertion_time\": \"2020-06-02T05:50:00+00:00\"\n}",
"insertion_time": "{\n \"value\": \"66\",\n \"insertion_time\": \"2020-06-02T05:50:00+00:00\"\n}"
}
However, I'd like it to be like:
{
"value": "66",
"insertion_time": "2020-06-02T05:50:00+00:00"
}
How do I correct this?
Your event_body appears to be a JSON string which already contains exactly what you want. It appears you don’t need to do anything and just use it directly:
message.set(func.Document.from_json(event_body))

Flask returning namedtuples as dicts, but not all the time

I have a very small Flask app that looks very much like this:
Point = namedtuple('Point', ['lat', 'lng', 'alt'])
p1 = Point(38.897741, -77.036450, 20)
def create_app():
app = flask.Flask(__name__)
#app.route('/position')
def position():
return flask.jsonify({
'vehicle': p1,
})
return app
It exists only to feed position data to a web ui. I was expecting that the Point namedtuple would be rendered as a JSON array, but to my surprise I was getting:
{
"vehicle": {
"alt": 20,
"lat": 38.897741,
"lng": -77.03645
}
}
...which, you know, that's fine. I can work with that. But then I was writing some unit tests, which look something like this:
from unittest import TestCase
import json
import tupletest
class TupleTestTest(TestCase):
def setUp(self):
_app = tupletest.create_app()
_app.config['TESTING'] = True
self.app = _app.test_client()
def test_position(self):
rv = self.app.get('/position')
assert rv.status_code == 200
assert rv.mimetype == 'application/json'
data = json.loads(rv.get_data())
assert data['vehicle']['lat'] = 38.897741
...and they failed, because suddenly I wasn't get dictionaries:
> assert data['vehicle']['lat'] == 38.897741
E TypeError: list indices must be integers, not str
And indeed, if in the test I wrote the return value out to a file I had:
{
"vehicle": [
38.897741,
-77.03645,
20
]
}
What.
What is going on here? I can't even reproduce this for the purposes of this question; the unit test above renders dictionaries. As does my actual webapp, when it is running, but not when it's being tested. But on another system I appear to be getting arrays from the actual app.
Looking at the sourcecode, this is in the flask's jsonify.py:
# Use the same json implementation as itsdangerous on which we
# depend anyways.
from itsdangerous import json as _json
and in the itstangerous.py there is:
try:
import simplejson as json
except ImportError:
import json
The simplejson library has an option namedtuple_as_object which is enabled by default.
So when the 3rd party simplejson is installed, the app uses it and serializes a namedtuple to a JSON object (a dict in Python).
On systems where that library is not installed, the app falls back to standard json and serializes a namedtuple to an array (list).
But if the simplejson is installed and imported by flask, the test program imports directly the standard json overwriting it and thus changing the behaviour between running and testing.

Generating json in python for app engine

I am somewhat new to python and I am wondering what the best way is to generate json in a loop. I could just mash a bunch of strings together in the loop, but I'm sure there is a better way. Here's some more specifics. I am using app engine in python to create a service that returns json as a response.
So as an example, let's say someone requests a list of user records from the service. After the service queries for the records, it needs to return json for each record it found. Maybe something like this:
{records:
{record: { name:bob, email:blah#blah.com, age:25 } },
{record: { name:steve, email:blah#blahblah.com, age:30 } },
{record: { name:jimmy, email:blah#b.com, age:31 } },
}
Excuse my poorly formatted json. Thanks for your help.
Creating your own JSON is silly. Use json or simplejson for this instead.
>>> json.dumps(dict(foo=42))
'{"foo": 42}'
My question is how do I add to the
dictionary dynamically? So foreach
record in my list of records, add a
record to the dictionary.
You may be looking to create a list of dictionaries.
records = []
record1 = {"name":"Bob", "email":"bob#email.com"}
records.append(record1)
record2 = {"name":"Bob2", "email":"bob2#email.com"}
records.append(record2)
Then in app engine, use the code above to export records as json.
Few steps here.
First import simplejson
from django.utils import simplejson
Then create a function that will return json with the appropriate data header.
def write_json(self, data):
self.response.headers['Content-Type'] = 'application/json'
self.response.out.write(simplejson.dumps(data))
Then from within your post or get handler, create a python dictionary with the desired data and pass that into the function you created.
ret = {"records":{
"record": {"name": "bob", ...}
...
}
write_json(self, ret)

Categories