py2neo v3 AttributeError: object has no attribute 'db_exists' - python-3.x

Trying to import data to a clean neo4j graph database using py2neo version 3. I've defined several node types as below, and everything seemed to be going well – except that I wasn't seeing the nodes show up in my neo4j browser.
Here's the relevant import code; I've verified that the records load properly into Python variables.
for row in data:
ds = DataSource()
# parse Source of Information column as a list, trimming whitespace
ds.uri = list(map(str.strip, row['data_source'].split(',')))
ds.description = row['data_source_description']
graph.merge(ds)
But when I tried to do graph.exists(ds), I got back the following set of errors / tracebacks:
Traceback (most recent call last):
File "mydir/venv/lib/python3.5/site-packages/py2neo/database/__init__.py", line 1139, in exists
return subgraph.__db_exists__(self)
AttributeError: 'DataSource' object has no attribute '__db_exists__'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "mydir/venv/lib/python3.5/site-packages/py2neo/database/__init__.py", line 478, in exists
return self.begin(autocommit=True).exists(subgraph)
File "mydir/venv/lib/python3.5/site-packages/py2neo/database/__init__.py", line 1141, in exists
raise TypeError("No method defined to determine the existence of object %r" % subgraph)
TypeError: No method defined to determine the existence of object <DataSource uri=['my_uri']>
Much to my surprise, I can't find another forum post discussing this problem. I'm guessing that there's a problem inheriting from GraphObject, but there doesn't seem to be an explicit definition of a __db_exists__ property for GraphObject, either. In fact, the only place I can find that property mentioned is in the definition of the exists function, when it generates this error.
Can anyone see what I'm doing wrong here?
The node class definitions are as follows:
class Content(GraphObject): # group Person and Institution
pass
class Person(Content):
__primarykey__ = 'name'
name = Property()
in_scholar_names = Property()
#
mentored = RelatedTo('Person')
mentored_by = RelatedFrom('Person', 'MENTORED')
worked_alongside = Related('Person', 'WORKED_ALONGSIDE')
studied_at = RelatedTo('Institution')
worked_at = RelatedTo('Institution')
tagged = RelatedTo('Tag')
member_of = RelatedTo('Institution')
last_update = RelatedTo('UpdateLog')
def __lt__(self, other):
return self.name.split()[-1] < other.name.split()[-1]
class Institution(Content):
__primarykey__ = 'name'
#
name = Property()
location = Property()
type = Property()
carnegie_class = Property()
#
students = RelatedFrom('Person', 'STUDIED_AT')
employees = RelatedFrom('Person', 'WORKED_AT')
members = RelatedFrom('Person', 'MEMBER_OF')
last_update = RelatedTo('UpdateLog')
def __lt__(self, other):
return self.name < other.name
class User(GraphObject):
__primarykey__ = 'username'
username = Property()
joined = Property()
last_access = Property()
active = Property()
contributed = RelatedTo('UpdateLog')
class Provenance(GraphObject): # group UpdateLog and DataSource
pass
#
class UpdateLog(Provenance):
__primarykey__ = 'id'
id = Property()
timestamp = Property()
query = Property()
previous = RelatedTo('UpdateLog', 'LAST_UPDATE')
next = RelatedFrom('UpdateLog', 'LAST_UPDATE')
based_on = RelatedTo('Provenance', 'BASED_ON')
affected_nodes = RelatedFrom('Content', 'LAST_UPDATE')
contributed_by = RelatedFrom('User', 'CONTRIBUTED')
class DataSource(Provenance):
__primarykey__ = 'uri'
id = Property()
description = Property()
uri = Property()
source_for = RelatedFrom('UpdateLog', 'BASED_ON')
class Tag(GraphObject):
__primarykey__ = 'name'
name = Property()
description = Property()
see_also = Related('Tag')
tagged = RelatedFrom('Content')

Okay, I think I figured it out. I had been learning py2neo in the context of Flask, where all those class definitions are important and useful for generating views (web pages) of the relationships on a given node.
But for the data import script I'm currently writing, i.e. to actually create the nodes and relationships in the first place, I need to use the vanilla classes of 'Node' and 'Relationship', and just specify the types as parameters on the function. This updated version of the original code above produces no errors, and graph.exists(ds) returns true afterward:
for row in data:
ds = Node("DataSource")
# parse Source of Information column as a list, trimming whitespace
ds['uri'] = list(map(str.strip, row['data_source'].split(',')))
ds['description'] = row['data_source_description']
graph.merge(ds)
Two other discoveries of note:
My class inheritance was off the mark to begin with, because I should have been trying to inherit from Node, not GraphObject (even though GraphObject was the correct class to inherit back in the context of Flask)
For the Node class, I have to use dict-style assignment of properties, with the square brackets and key names as quoted strings; the dot notation was off base here, and I'm surprised I didn't get more errors thrown, and sooner.

Related

Error in using instance name as dict values and object attribute as dict keys

I want to create boutiqueDict as type dict which has Boutique objects tagged to different types.
eg: b1, b2, b3 are 3 boutique objects where b1,b2 belong to "shirt" type and b3 "dress" type.
Then boutiqueDict dictionary has values in format
{'shirt':b1,b2, 'dress':b3}
Here is the code i've written
class Boutique:
def __init__(self, boutiqueid, boutiquename, boutiquetype, boutiquerating, points):
self.boutiqueid = boutiqueid
self.boutiquename = boutiquename
self.boutiquetype = boutiquetype
self.boutiquerating = boutiquerating
self.points = points
class OnlineBoutique:
def __init__(self, *argv):
self.boutiqueDict = {}
for arg in argv:
if arg.boutiquetype not in self.boutiqueDict.keys():
self.boutiqueDict = {arg.boutiquetype : list(arg)}
else:
(self.boutiqueDict[arg.boutiquetype]).append(arg)
And this is the error i am getting
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "hello.py", line 14, in __init__
self.boutiqueDict = {arg.boutiquetype : list(arg)}
TypeError: 'Boutique' object is not iterable
I am not sure where/why it is trying to iterate.
From the code above the OnlineBoutique is to be passed multiple instance of Boutique but the problem is you trying to convert such instance to list with the line
list(arg)
Obviously your boutique class didn't override the __iter__() method
And even this is against your initial idea in the first place, as what you should rather do is
self.boutiqueDict[arg.boutiquetype] = arg
Since you said the dresses in the dict should be in the format {'shirt':b1,b2}
Thus things will now look like
for arg in argv:
if arg.boutiquetype not in self.boutiqueDict.keys():
self.boutiqueDict[arg.boutiquetype] = arg
else:
(self.boutiqueDict[arg.boutiquetype]).append(arg)
So that if the boutiquetype key isn't yet present then it's created, else the new value is appended to already existing Key

Class objects not being callable after instantiation

class Swimmers:
""" Creates objects for each swimmer with unique details"""
instances = []
def __init__(self, fName = "None", lName = "None", house = "None", time = "None"):
self.fName = getfName()
self.lName = getlName()
self.house = getHouse()
self.time = getTime()
self.__class__.instances.append(self)
#classmethod
def printInstances(cls):
for instance in cls.instances:
print(instance)
def test():
style, swimmerNumber = raceDetails()
for x in range(int(swimmerNumber)):
y = re.sub(".0", "", str(x))
string = "swimmer" + y
print("\n" + string + "\n")
string = Swimmers()
x -= 1
I need to create a module that takes various inputs and saves each iteration as a class object. The function raceDetails() simply gets the type of race and the number of swimmers, nothing wrong with that part. The functions getX() are simply input functions with some error checking. The issue is that trying to call the objects or any of their variables after everything has been entered simply gives me:
>>> swimmer0.fName
Traceback (most recent call last):
File "<pyshell#0>", line 1, in <module>
swimmer0.fName
NameError: name 'swimmer0' is not defined
I've added a list of every object created by the class ('instances') which prints:
<__main__.Swimmers object at 0x04182F88>
<__main__.Swimmers object at 0x04182E50>
and so on, which, combined with the working getX() functions, means the objects are being instantiated perfectly fine. I've tried everything I can think of, including nonlocals, changing scopes, adding intermediary functions, but none of it seems to work. The only thing I can think of is an issue with reference generation in the module namespace.
It's not essential that I use classes for this, and I could very easily use dictionaries or the like, but I want to try and learn classes as best as I can.
Using Windows 10, Python 3.9.2 32-bit
The problem is you're setting the string variable equal to the variable name you want ('swimmer0', 'swimmer1'...), but then you set string equal to the Swimmers class. Dynamically setting variables names is possible in python, but typically you'll want to use a dictionary (or another collections object) to store the objects.
def test():
style, swimmerNumber = raceDetails()
swimmers_dict = {}
for x in range(int(swimmerNumber)):
y = re.sub(".0", "", str(x))
string = "swimmer" + y
print("\n" + string + "\n")
swimmers_dict[x] = Swimmers()
x -= 1
return swimmers_dict

How do you retrieve an objects name from a list and pass it to a function to retrieve that objects property? 'str' object has no attribute

New to python and OOP. Hopefully I'm using the correct terms. I'm using a list to hold all of my objects. I want to reference this list to get the name of the object that I would like to get a property value for. I then want to pass this name to a function to get one or more properties. But I'm getting a string error (because the list is returning a string of the object name and not the actual object).
Here is the code:
class creature():
def __init__(self, name, legs):
self.name = name
self.legs = legs
rat = creature("rat",4)
mouse = creature("mouse",4)
beaver = creature("beaver",4)
squirrel = creature("squirrel",4)
chimpanzee = creature("chimpanzee",2)
gorilla = creature("gorilla",2)
orangutan = creature("orangutan",2)
spider_monkey = creature("spider_monkey",2)
black_widow = creature("black_widow",8)
recluse = creature("recluse",8)
wolf_spider = creature("wolf_spider",8)
daddy_long_leg = creature("daddy_long_leg",8)
def checkLegs(critter):
nbrLegs = critter.legs
return success
animals = [
['rat', 'mouse', 'beaver', 'squirrel'],
['chimpanzee','gorilla','orangutan','spider_monkey'],
['black_widow','recluse','wolf_spider','daddy_long_leg']
]
numberOfLegs = checkLegs(recluse)
print("The Recluse has: ")
print(numberOfLegs)
print(" legs")
Here is the response:
The test animal is: orangutan
Traceback (most recent call last):
File "/Python37/help.py", line 32, in <module>
numberOfLegs = checkLegs(testAnimal)
File "Python37/help.py", line 20, in checkLegs
nbrLegs = critter.legs
AttributeError: 'str' object has no attribute 'legs'
There's a couple things here that are preventing this from working. Look at your checkLegs function. It is returning something called success...however, that's not being used anywhere, and since you haven't wrapped it in ""s (I assume you were trying to return the word success to check if the function works) it is trying to return it as a variable, but of course it's undefined. You want the function to return the result of the code you use the function to execute. In this case you want to return nbrLegs. You also need to check the indentation of your constructor. You also don't need the array of animals since you're already defining them in your class. Other than that you were pretty close. Here's your code, with the fixes implemented:
class creature():
def __init__(self, name, legs):
self.name = name
self.legs = legs
rat = creature("rat",4)
mouse = creature("mouse",4)
beaver = creature("beaver",4)
squirrel = creature("squirrel",4)
chimpanzee = creature("chimpanzee",2)
gorilla = creature("gorilla",2)
orangutan = creature("orangutan",2)
spider_monkey = creature("spider_monkey",2)
black_widow = creature("black_widow",8)
recluse = creature("recluse",8)
wolf_spider = creature("wolf_spider",8)
daddy_long_leg = creature("daddy_long_leg",8)
def checkLegs(critter):
nbrLegs = critter.legs
return nbrLegs
numberOfLegs = checkLegs(recluse)
print("The Recluse has: " + str(numberOfLegs) + " legs")

Python 3 lxml: Error getting attributes from an xml into a dictionary

I am reading an XML to transfer its attributes to other XML file with the same source. However something is wrong in the loop as I am overwriting the first element of the dictionary with the newest one.
The XMl looks like this:
<sxml locale="en-US" version="1.0" segtype="sentence" options="eol=unix;" createdby="AP 2.24.1" datatype="regexp" targetlocale="DE">
<family blockId="1" mat="33" type="freeOS" seccion="2" datatype="html" subtype="BSD"><section sectionId="1">
<product>FreeBSD</product>
</section></family>
<family blockId="2" mat="32" type="privative" seccion="3" datatype="html" subtype="commercial"><section sectionId="1">
<product>Windows</product><ws> </ws>
</section><section sectionId="2">
<product>Sistema operativo.</product>
</section></family>
</sxml>
And I want to get the attributes: "mat", "seccion", "type" and "subtype".
My code is:
from lxml import etree as et
from pathlib import Path
def add_attributes(files_path_str, proc_path_str, attributes):
"""
Adds the attributes to the frequent files.
"""
product_path = Path(files_path_str)
proc_files = Path(unk_path_str).glob('*.sxml')
dict_notes_src = dict()
list_src_sxml_files = full_sxml_path.glob('**/*.sxml')
for sxml_file in list_full_sxml_files:
xml_parser = et.parse(str(sxml_file))
root_xml = xml_parser.getroot()
print(sxml_file)
dict_notes_src_temp = __generate_notes_product_dict(root_xml, attributes)
dict_notes_src = {**dict_notes_src, **dict_notes_src_temp}
#It is the part where I copy the attributes to the processed files. The bug is not found in this part.
#The bug is somewhere in the generation of the dictionary
#for proc_file in list_proc_sxml_files:
# xml_parser = et.parse(str(unk_file))
# root_unk_xml = xml_parser.getroot()
# tree = __add_notes_to_unk(root_unk_xml, dict_notes_src)
# tree.write(str(unk_file), encoding='utf-8', pretty_print=True)
def __generate_notes_product_dict(root_xml, attributes):
"""
Internal method to process the xml file to get a dictionary product-note.
"""
translatable_elements = root_xml.xpath('family')
notes_product = dict()
dict_values = dict()
for element in translatable_elements:
product_elements = element.xpath('./section/product')
list_attrib_values = []
print(element.tag, element.attrib)
#satt_note = element.attrib['satt_note']
# List comprehension fails if there is a segment without an expected attribute.
#list_attrib_values = [element.attrib[attribute] for attribute in attributes]
# Checks if there are attributes that does not exist in the Full WordFast file.
# If that is the case ignores them and adds a None value.
for attribute in attributes:
try:
list_attrib_values.append(element.attrib[attribute])
print('Reading the attributes. {} : {}'.format(attribute, element.attrib[attribute]))
logging.debug('__generate_notes_product_dict: Add values of the attributes {}: {}'.format(
attribute, element.attrib[attribute]))
except KeyError:
list_attrib_values.append(None)
if len(product_elements) > 0:
for product_element in product_elements:
#product_element = element.xpath('./segment/product')[0]
product_str = str(et.tostring(product_element), 'utf-8')
# Create the string of the content of the product element.
product_str = ' '.join(product_str.split())
if list_attrib_values is not None:
if product_str not in notes_product:
# Generate a dictionary with the product text as key.
#notes_product[product_str] = satt_note
print(product_str)
for attribute in attributes:
try:
print(element.tag, element.attrib)
dict_values[attribute] = element.attrib[attribute]
except KeyError:
dict_values[attribute] = None
#for attribute, value in zip(attributes, list_attrib_values):
# if value is not None:
# print ('Adding the values {}: {}'.format(attribute, value))
# dict_values[attribute] = value
attrib_product[product_str] = dict_values
return attrib_product
add_attributes(folder_where_is_stored_xml, folder_where_save_xml,["mat", "seccion", "type", "subtype"]
It return a dictionary that all the products have the attributes of the last family.
I've been debugging the code and it looks like the when I running attrib_product[product_str] = dict_values is looping through all the values of the dict_values and stores only the last one.
Any ideas where am I doing wrong? I am not able to see why it is happening.

Filling ChoiceBlock with snippet data

I have a snippet for countrycodes and I want to define localized country names on the root pages for each localized site.
The snippet looks like this:
#register_snippet
class Country(models.Model):
iso_code = models.CharField(max_length=2, unique=True)
panels = [
FieldPanel('iso_code'),
]
def get_iso_codes():
try:
countries = Country.objects.all()
result = []
for country in countries:
result.append((country.iso_code,country.iso_code))
return result
except Country.DoesNotExist:
return []
Now I want to call the function get_iso_codes when creating a choiceblock and fill the choices from the snippet.
The block looks like this
class CountryLocalizedBlock(blocks.StructBlock):
iso_code = blocks.ChoiceBlock(choices=Country.get_iso_codes(), unique=True)
localized_name = blocks.CharBlock(required=True)
However, when calling manage.py makemigrations I get the following error:
psycopg2.ProgrammingError: relation "home_country" does not exist
LINE 1: ..."."iso_code", "home_country"."sample_number" FROM "home_coun...
I can bypass this by commenting out 'Country.objects.all()' and then running makemigrations and later readding the line again to the code, however I would prefer a solution that does not require this workaround (also it fails when I run 'manage.py collectstatic' when building before deployment and I don't know how to work around this and am stuck)
I found a solution based on Wagtail, how do I populate the choices in a ChoiceBlock from a different model?
The country class remains untouched (except that the get_iso_codes method is now superflous). I've just extended Chooserblock and use Country as my target_model:
class CountryChooserBlock(blocks.ChooserBlock):
target_model = Country
widget = forms.Select
def value_for_form(self, value):
if isinstance(value, self.target_model):
return value.pk
else:
return value
And used the CountryChooserBlock instead of the ChoiceBlock:
class CountryLocalizedBlock(blocks.StructBlock):
iso_code = CountryChooserBlock(unique=True)
localized_name = blocks.CharBlock(required=True)

Resources