# models/__init__.py
from shared.cache import Cache
class modelA():
pass
class modelB():
pass
class modelC():
pass
# shared/cache.py
class Cache:
def methodA():
modelA.SomeStaticMethod()
Basically what I need is to access modelA from inside the Cache class.
If I try to import the models from cache.py, I get an error due to a circular reference error.
I know it seems a little bit weird but it's a very specific issue.
Is there anyway to do that?
You would usually restructure your files so that there is no circular reference error.
Simply answering your question, and usually seen as a workaround, you can import Cache on demand, only within the functions of models/__init__.py that make use of it. This may not be possible in this case, especially if Cache is used as a decorator at the module level.
See also this question.
Related
Firstly, I do apologise as I'm not quite sure how to word this query within the Python syntax. I've just started learning it today having come from a predominantly PowerShell-based background.
I'm presently trying to obtain a list of projects within our organisation within Google Cloud. I want to display this information in two columns: project name and project number - essentially an object. I then want to be able to query the object to say: where project name is "X", give me the project number.
However, I'm rather having difficulty in creating said object. My code is as follows:
import os
from pprint import pprint
from googleapiclient import discovery
from oauth2client.client import GoogleCredentials
credentials = GoogleCredentials.get_application_default()
service = discovery.build('cloudresourcemanager', 'v1', credentials=credentials)
request = service.projects().list()
response = request.execute()
projects = response.get('projects')
The 'projects' variable then seems to be a list, rather than an object I can explore and run queries against. I've tried running things like:
pprint(projects.name)
projects.get('name')
Both of which return the error:
"AttributeError: 'list' object has no attribute 'name'"
I looked into creating a Class within a For loop as well, which nearly gave me what I wanted, but only displayed one project name and project number at a time, rather than the entire collection I can query against:
projects=[]
for project in response.get('projects', []):
class ProjectClass:
name = project['name']
projectNumber = project['projectNumber']
projects.append(ProjectClass.name)
projects.append(ProjectClass.projectNumber)
I thought if I stored each class in a list it might work, but alas, no such joy! Perhaps I need to have the For loop within the class variables?
Any help with this would be greatly appreciated!
As #Code-Apprentice mentioned in a comment, I think you are missing a critical understanding of object-oriented programming, namely the difference between a class and an object. Think of a class as a "blueprint" for creating objects. I.E. your class ProjectClass tells python that objects of type ProjectClass will have two fields, name and projectNumber. However, ProjectClass itself is just the blueprint, not an object. You then need to create an instance of ProjectClass, which you would do like so:
project_class_1 = ProjectClass()
Great, now you have an object of type ProjectClass, and it will have fields name and projectNumber, which you can reference like so:
project_class_1.name
project_class_1.projectNumber
However, you will notice that all instances of the class that you create will have the same value for name and projectNumber, this just won't do! We need to be able to specify values when we create each instance. Enter init(), a special python method colloquially referred to as the constructor. This function is called by python automatically when we create a new instance of our class as above, and is responsible for setting up all the fields of that class. Another powerful feature of classes and objects is that you can define a collection of different functions that can be called at will.
class ProjectClass:
def __init__(self, name, projectNumber):
self.name = name
self.projectNumber = projectNumber
Much better. But wait, what's that self variable? Well, just as before we were able reference the fields of our instance via the "project_class_1" variable name, we need a way to access the fields of our instance when we're running functions that are a part of that instance, right? Enter self. Self is another python builtin parameter that contains a reference to the current instance of the ProjectClass that is being accessed. That way, we can set fields on the instance of the class that will persist, but not be shared or overwritten by other instances of the ProjectClass. It's important to remember that the first argument passed to any function defined on a class will always be self (except for some edge-cases you don't need to worry about now).
So restructuring your code, you would have something like this:
class ProjectClass:
def __init__(self, name, projectNumber):
self.name = name
self.projectNumber = projectNumber
projects = []
for project in response.get('projects', []):
projects.append(ProjectClass(project["name"], project["projectNumber"])
Hopefully I've explained this well and given you a complete answer on how all these pieces fit together. The hope is for you to be able to write that code on your own and not just give you the answer!
I have a model defined with a field using django-picklefield. Everything was working fine till I refactored our codebase for organizational reasons, but now when I load that model from the db I get back a unicode object instead of the unpickled object. Because the class definition moved pickle cannot find the module it needs to import, I traced the error back to here where pickle tries to import a module that no longer exists.
Is there a way I can resolve this import error by pointing pickle to the correct module or somehow fake the existence of that class definition in the module pickle is looking in with other imports or by creating a class of the same name that inherits from the original class that lives elsewhere?
I was able to resolve this by recreating the old file I had deleted and had it contain only a single line that imports the class that pickle was looking for.
I struggled with the title for this question so let me just lay out the code:
File A:
class SomeClass(Base):
__tablename__ = 'some_classes'
id = Column(Integer, primary_key=True)
my_awesome_property = Column(Unicode(255))
other_class = relationship('OtherClass', backref='some_class', uselist=False)
File B:
class OtherClass(Base):
__tablename__ = 'other_classes'
id = Column(Integer, primary_key=True)
my_sweet_property = Column(Unicode(255))
some_class_id = Column(ForeignKey('some_classes.id'))
Now, in many cases I would refer to both of these files from a "higher-order" file containing some functions like so:
Higher Order File:
from model.alpha import SomeClass
from model.bravo import OtherClass
from sqlalchemy.orm import sessionmaker
session = sessionmaker(bind=some_engine)()
def some_random_query():
return session.query(SomeClass).join(OtherClass).filter(OtherClass.my_sweet_property=='Mike Bayer\'s cat speaks SQL.').first()
So that's pretty normal, nothing wrong with that... until... I decide I want to a put a function into one of the lower-level files like File A (and avoid circular imports)
Back to File A:
# pretend I imported a session here
def frustrating_situation():
session.query(SomeClass).join(SomeClass.other_class).filter(SomeClass.other_class.my_sweet_property=='Get ready for an exception!').first()
This will throw this bad boy right here:
AttributeError: Neither 'InstrumentedAttribute' object nor 'Comparator' object associated with SomeClass.other_class has an attribute 'my_sweet_property'
Now I suppose that makes sense given what I know of the internals of SQLAlchemy, but I also think from an API standpoint that statement should really work.
Here is how I worked around it:
session.query(SomeClass).join(SomeClass.other_class).filter(SomeClass.other_class.property.mapper.c.my_sweet_property == 'verbose, yet it works as desired').first()
So after all that, my question is really quite simple: Does anybody know a better / more idiomatic / proper / less dirty feeling way of doing this?
Suggestions welcome.
Side Note
For anyone who is wondering:
"Why not just import the class you want the reference to for the join/filter operation?"
There are a couple reasons why you might not want to / be able to import the class into the module where you are writing the query.
You have split up your class definitions across many files and decided to avoid circular imports by strictly not importing across same-level modules
You have decided to place functions that operate on 1 or more classes not currently defined or imported in the current module and do not wish to import them because they are not used for any other reason in the module (and see reason 1 again).
SomeClass.other_class.my_sweet_property
doesn't work in sqlalchemy. sorry.
You are referring to OtherClass, in this .filter() clause. how you arrive at that name is your business, but the clearest way, from the point of view of what each statement means and where the arguments come from is still just to import things.
edit: A common cause of problems with circular imports occurs when you try to import the names out of modules directly instead of just importing the modules. If you turn code that looks like:
from foo import Bar
def baz():
Bar.quux()
you'll have an import problem if foo is also trying to import this module (say, because it wants to use baz).
Fix it by importing only the module:
import foo
def baz()
foo.Bar.quux()
since foo.Bar is resolved later, only when baz() is called, you don't have any trouble when this module gets imported, since it doesn't actually try to use the contents of any of the modules it imports.
I want to have dict / list to which I can add values, just like models can be added to the admin register in django !
My attempt : (package -> __init__.py)
# Singleton object
# __init__.py (Package: pack)
class remember:
a = []
def add(data):
a.append[data]
def get():
return a
obj = remember()
# models1.py
import pack
pack.obj.add("data")
# models2.py
import pack
pack.obj.add("data2")
print pack.obj.get()
# We should get: ["data", "data2"]
# We get : ["data2"]
How to achieve the desired functionality ?
Some say that methods can do this if you don't need sub-classing, how to do this with methods ?
Update:
To be more clear :
Just like django admin register any one can import and register itself with admin, so that register is persisted between imports.
If it's a singleton you're after, have a look at this old blog post. It contains a link to a well documented implementation (here).
Don't. If you think you need a global you don't and you should reevaluate how you are approaching the problem because 99% of the time you're doing it wrong.
If you have a really good reason to do it perhaps thread_locals() will really solve the problem you're trying to solve. This allows you to set up thread level global data. Note: This is only slightly better than a true global and should in general be avoided, and it can cause you a lot of headaches.
If you're looking for a cross request "global" then you most likely want to look into storing values in memcached.
I'm creating website based on Django (I know it's pure Python, so maybe it could be also answered by people who knows Python well) and I need to call some methods dynamically.
For example I have few applications (modules) in my website with the method "do_search()" in the views.py. Then I have one module called for example "search" and there I want to have an action which will be able to call all the existing "do_search()" in other applications. Of course I don't like to add each application to the import, then call it directly. I need some better way to do it dynamically.
I can read INSTALLED_APPS variable from settings and somehow run through all of the installed apps and look for the specific method? Piece of code will help here a lot :)
Thanks in advance!
Ignas
I'm not sure if I truly understand the question, but please clarify in a comment to my answer if I'm off.
# search.py
searchables = []
def search(search_string):
return [s.do_search(search_string) for s in searchables]
def register_search_engine(searchable):
if hasattr(searchable, 'do_search'):
# you want to see if this is callable also
searchables.append(searchable)
else:
# raise some error perhaps
# views.py
def do_search(search_string):
# search somehow, and return result
# models.py
# you need to ensure this method runs before any attempt at searching can begin
# like in models.py if this app is within installed_apps. the reason being that
# this module may not have been imported before the call to search.
import search
from views import do_search
search.register_search_engine(do_search)
As for where to register your search engine, there is some sort of helpful documentation in the signals docs for django which relates to this.
You can put signal handling and registration code anywhere you like. However, you'll need to make sure that the module it's in gets imported early on so that the signal handling gets registered before any signals need to be sent. This makes your app's models.py a good place to put registration of signal handlers.
So your models.py file should be a good place to register your search engine.
Alternative answer that I just thought of:
In your settings.py, you can have a setting that declares all your search functions. Like so:
# settings.py
SEARCH_ENGINES = ('app1.views.do_search', 'app2.views.do_search')
# search.py
from django.conf import settings
from django.utils import importlib
def search(search_string):
search_results = []
for engine in settings.SEARCH_ENGINES
i = engine.rfind('.')
module, attr = engine[:i], engine[i+1:]
mod = importlib.import_module(module)
do_search = getattr(mod, attr)
search_results.append(do_search(search_string))
return search_results
This works somewhat similar to registering MIDDLEWARE_CLASSES and TEMPLATE_CONTEXT_PROCESSORS. The above is all untested code, but if you look around the django source, you should be able to flesh this out and remove any errors.
If you can import the other applications through
import other_app
then it should be possible to perform
method = getattr(other_app, 'do_' + method_name)
result = method()
However your approach is questionable.