Django queryset.first bug? May involve django-polymorphic and mixins - python

I have a model, and I have instantiated several instances and persisted them to the database. Through the python shell I can confirm that the objects exist, but I run into trouble as soon as I try to work with the queryset via the queryset.first() call, as well as indexing into the queryset.all() result. I'm using the django-polymorphic plugin.
>>> Thing.objects.all()
[<Thing: thing1>, <Thing: thing2>, <Thing: thing3>]
>>> Thing.objects.first()
>>> str(Thing.objects.first())
'None'
>>> Thing.objects.all()[0]
Traceback (most recent call last):
File "<console>", line 1, in <module>
File ".../python3.4/site-packages/django/db/models/query.py", line 201, in __getitem__
return list(qs)[0]
IndexError: list index out of range
>>> Thing.objects.all().__class__
<class 'polymorphic.query.PolymorphicQuerySet'>
>>>
I strongly suspect this involves the fact that I'm using a mixin for Thing on top of the polymorphic base class. Here's what my hierarchy looks like (boiled down to make it easier for y'all):
from django.db import models
from polymorphic.polymorphic_model import PolymorphicModel
class AwesomeMixin(object):
def reallyUsefulMethod(self):
print('show me your MOVES')
class BaseThing(PolymorphicModel, AwesomeMixin):
pass
class Thing(BaseThing):
pass
class Doohickey(BaseThing):
pass
class SomethingElse(models.Model, AwesomeMixin):
pass
Anyone know what's going on here? Am I using mixins correctly? Is the issue related to django-polymorphic? Thanks!

Related

FastAPI - "TypeError: issubclass() arg 1 must be a class" with modular imports

When working with modular imports with FastAPI and SQLModel, I am getting the following error if I open /docs:
TypeError: issubclass() arg 1 must be a class
Python 3.10.6
pydantic 1.10.2
fastapi 0.85.2
sqlmodel 0.0.8
macOS 12.6
Here is a reproducible example.
user.py
from typing import List, TYPE_CHECKING, Optional
from sqlmodel import SQLModel, Field
if TYPE_CHECKING:
from item import Item
class User(SQLModel):
id: int = Field(default=None, primary_key=True)
age: Optional[int]
bought_items: List["Item"] = []
item.py
from sqlmodel import SQLModel, Field
class Item(SQLModel):
id: int = Field(default=None, primary_key=True)
price: float
name: str
main.py
from fastapi import FastAPI
from user import User
app = FastAPI()
#app.get("/", response_model=User)
def main():
return {"message": "working just fine"}
I followed along the tutorial from sqlmodel https://sqlmodel.tiangolo.com/tutorial/code-structure/#make-circular-imports-work.
If I would put the models in the same file, it all works fine. As my actual models are quite complex, I need to rely on the modular imports though.
Traceback:
Traceback (most recent call last):
File "/Users/felix/opt/anaconda3/envs/fastapi_test/lib/python3.10/site-packages/fastapi/utils.py", line 45, in get_model_definitions
m_schema, m_definitions, m_nested_models = model_process_schema(
File "pydantic/schema.py", line 580, in pydantic.schema.model_process_schema
File "pydantic/schema.py", line 621, in pydantic.schema.model_type_schema
File "pydantic/schema.py", line 254, in pydantic.schema.field_schema
File "pydantic/schema.py", line 461, in pydantic.schema.field_type_schema
File "pydantic/schema.py", line 847, in pydantic.schema.field_singleton_schema
File "pydantic/schema.py", line 698, in pydantic.schema.field_singleton_sub_fields_schema
File "pydantic/schema.py", line 526, in pydantic.schema.field_type_schema
File "pydantic/schema.py", line 921, in pydantic.schema.field_singleton_schema
File "/Users/felix/opt/anaconda3/envs/fastapi_test/lib/python3.10/abc.py", line 123, in __subclasscheck__
return _abc_subclasscheck(cls, subclass)
TypeError: issubclass() arg 1 must be a class
TL;DR
You need to call User.update_forward_refs(Item=Item) before the OpenAPI setup.
Explanation
So, this is actually quite a bit trickier and I am not quite sure yet, why this is not mentioned in the docs. Maybe I am missing something. Anyway...
If you follow the traceback, you'll see that the error occurs because in line 921 of pydantic.schema in the field_singleton_schema function a check is performed to see if issubclass(field_type, BaseModel) and at that point field_type is not in fact a type instance.
A bit of debugging reveals that this occurs, when the schema for the User model is being generated and the bought_items field is being processed. At that point the annotation is processed and the type argument for List is still a forward reference to Item. Meaning it is not the actual Item class itself. And that is what is passed to issubclass and causes the error.
This is a fairly common problem, when dealing with recursive or circular relationships between Pydantic models, which is why they were so kind to provide a special method just for that. It is explained in the Postponed annotations section of the documentation. The method is update_forward_refs and as the name suggests, it is there to resolve forward references.
What is tricky in this case, is that you need to provide it with an updated namespace to resolve the Item reference. To do that you need to actually have the real Item class in scope because that is what needs to be in that namespace. Where you do it does not really matter. You could for example import User model into your item module and call it there (obviously below the definition of Item):
from sqlmodel import SQLModel, Field
from .user import User
class Item(SQLModel):
id: int = Field(default=None, primary_key=True)
price: float
name: str
User.update_forward_refs(Item=Item)
But that call needs to happen before an attempt is made to set up that schema. Thus you'll at least need to import the item module in your main module:
from fastapi import FastAPI
from .user import User
from . import item
api = FastAPI()
#api.get("/", response_model=User)
def main():
return {"message": "working just fine"}
At that point it is probably simpler to have a sub-package with just the model modules and import all of them in the __init__.py of that sub-package.
The reason I gave the example of putting the User.update_forward_refs call in below your Item definition is that these situations typically occur, when you actually have a circular relationship, i.e. if your Item class had a users field for example, which was typed as list[User]. Then you'd have to import User there anyway and might as well just update the references there.
In your specific example, you don't actually have any circular dependencies, so there is strictly speaking no need for the TYPE_CHECKING escape. You can simply do from .item import Item inside user.py and put the actual class in your annotation as bought_items: list[Item]. But I assume you simplified the actual use case and simply forgot to include the circular dependency.
Maybe I am missing something and someone else here can find a way to call update_forward_refs without the need to provide Item explicitly, but this way should definitely work.
For anyone ending up here who (just like me) got the same error but couldn't resolve it using the solution above, my script looked like this. It seems that SQLModel relies on the pydantic.BaseModel so this solution also applies here.
from pydantic import BaseModel
class Model(BaseModel):
values: list[int, ...]
class SubModel(Model):
values = list[int, int, int]
It took me a long time to realize what my mistake was, but in SubModel I used = (assignment) whereas I should have used : (type hint).
The strangest thing was that it did work in a docker container (Linux) but not locally (Windows). Also, mypy did not pick up on this.

mypy typing leeds to unexpected traceback

I'm trying to use a work-around for the problems described in this GitHub issue ("Class with function fields incorrectly thinks the first argument is self").
from dataclasses import dataclass
from typing import TypeVar, Generic, Any, Iterable, List
T = TypeVar("T")
# See https://github.com/python/mypy/issues/5485
#dataclass
class Box(Generic[T]):
inner: T
#property
def unboxed(self) -> T:
return self.inner
I run into a traceback like this, though:
However, upon importing (only(!) ) the code above from another module I run into a traceback like this:
(py) sugarline:~/src/oss/ormsnack write-compile-eval
Traceback (most recent call last):
[.....]
File "/Users/jacob/src/oss/ormsnack/ormsnack/ng_desc.py", line 8, in <module>
from kingston.kind import Box # type: ignore
File "kingston/kind.py", line 12, in <module>
AttributeError: attribute '__dict__' of 'type' objects is not writable
Googling only lands me in old bugs that seem to have gone stale, though (https://bugs.python.org/issue38099, https://github.com/man-group/arctic/issues/17), etc.
Is anyone able to figure out a work-around?

Error setting attribute of an sdl2 Entity

I am using the pysdl2 library. self.velocity will print, but self.forward_tick with throw a key error.
What is causing only part of the self attributes from being assigned. I am thinking it has something to do with the inheritance.
class Robot(sdl2.ext.Entity):
def __init__(self, world, sprite, posx=0, posy=0):
self.sprite = sprite
self.sprite.position = posx, posy
self.velocity = Velocity()
self.forward_tick = 0
self.go_forward = 0
self.unit_forward = (1,0)
print(self.velocity)
print(self.forward_tick)
Here is the output:
Collins-MacBook-Air:soccer_bots collinbell$ python test_simulation_world.py
<simulation_world.Velocity object at 0x108ecb5c0>
Traceback (most recent call last):
File "/Users/collinbell/.pyenv/versions/3.4.3/lib/python3.4/site-packages/sdl2/ext/ebs.py", line 53, in __getattr__
ctype = self._world._componenttypes[name]
KeyError: 'forward_tick'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "test_simulation_world.py", line 3, in <module>
world = Simulation_World("Test Simulation", 1080, 720)
File "/Users/collinbell/Programs/soccer_bots/simulation_world.py", line 100, in __init__
self.player1 = Robot(self.world, sp_paddle1, 0, 250)
File "/Users/collinbell/Programs/soccer_bots/simulation_world.py", line 22, in __init__
print(self.forward_tick)
File "/Users/collinbell/.pyenv/versions/3.4.3/lib/python3.4/site-packages/sdl2/ext/ebs.py", line 56, in __getattr__
(self.__class__.__name__, name))
AttributeError: object ''Robot'' has no attribute ''forward_tick''
From the docs on component-based design with sdl2.ext, the Entity type is special, and doesn't follow normal Python idioms. In particular, you can't just create arbitrary attributes; you can only create attributes whose value is a component type, and whose name is a lowercased version of that type:
Entity objects define the in-application objects and only consist of component-based attributes.
…
The Entity also requries its attributes to be named exactly as their component class name, but in lowercase letters.
So, when you try to add an attribute named forward_tick, that causes Entity.__setattr__ to go looking for a class named Forward_Tick in the world's component types. Which it apparently does by looking up self._world._componentypes[name], which is the line that's actually raising the exception, as you can see in the tracebacks.
Without knowing anything more about your code and your design than the tiny fragment you showed us, I can't tell you how to fix this. But most likely, it's one of the following:
You actually wanted to create a Component, not an Entity,
You wanted to wrap up forward_tick in a Component type that this Entity can contain, or
You didn't want a Component-oriented design in the first place.
At any rate, as the docs say:
If you are just starting with such a [component-oriented] design, it is recommended to read through the The Pong Game tutorial.

Accessing variable outside class using inheritance

I am trying to inherit a variable from base class but the interpreter throws an error.
Here is my code:
class LibAccess(object):
def __init__(self,url):
self.url = url
def url_lib(self):
self.urllib_data = urllib.request.urlopen(self.url).read()
return self.urllib_data
class Spidering(LibAccess):
def category1(self):
print (self.urllib_data)
scrap = Spidering("http://jabong.com")
scrap.category1()
This is the output:
Traceback (most recent call last):
File "variable_concat.py", line 16, in <module>
scrap.category1()
File "variable_concat.py", line 12, in category1
print (self.urllib_data)
AttributeError: 'Spidering' object has no attribute 'urllib_data'
What is the problem with the code?
You will need to define self.urllib_data prior to accessing it. The simples way would be to create it during initialization, e.g.
class LibAccess(object):
def __init__(self,url):
self.url = url
self.urllib_data = None
That way you can make sure it exists everytime you try to access it. From your code I take it that you do not want to obtain the actual data during initialization. Alternatively, you could call self.url_lib() from __init__(..) to read the data for the first time. Updating it later on would be done in the same way as before.

how to use TTreeReader in PyROOT

I'm trying to get up and running using the TTreeReader approach to reading TTrees in PyROOT. As a guide, I am using the ROOT 6 Analysis Workshop (http://root.cern.ch/drupal/content/7-using-ttreereader) and its associated ROOT file (http://root.cern.ch/root/files/tutorials/mockupx.root).
from ROOT import *
fileName = "mockupx.root"
file = TFile(fileName)
tree = file.Get("MyTree")
treeReader = TTreeReader("MyTree", file)
After this, I am a bit lost. I attempt to access variable information using the TTreeReader object and it doesn't quite work:
>>> rvMissingET = TTreeReaderValue(treeReader, "missingET")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/user/ROOT/v6-03-01/root/lib/ROOT.py", line 198, in __call__
result = _root.MakeRootTemplateClass( *newargs )
SystemError: error return without exception set
Where am I going wrong here?
TTreeReaderValue is a templated class, as shown in the example on the TTreeReader documentation, so you need to specify the template type.
You can do this with
rvMissingET = ROOT.TTreeReaderValue(ROOT.Double)(treeReader, "missingET")
The Python built-ins can be used for int and float types, e.g.
rvInt = ROOT.TTreeReaderValue(int)(treeReader, "intBranch")
rvFloat = ROOT.TTreeReaderValue(float)(treeReader, "floatBranch")
Also note that using TTreeReader in PyROOT is not recommended. (If you're looking for faster ntuple branch access in Python, you might look in to the Ntuple class I wrote.)

Categories