Python: import of Modules with mutual dependency - python

I have two files rest_api.py and Contact.py. Contact is similar to a domain object (contains Contact class), while rest_api has functions for setting up the application.
In rest_api I have the following lines:
from Contact import Contact
...
client = MongoClient('localhost',27017)
collection = client.crypto_database.test_collection
def dbcollection(){
return collection
}
...
api.add_resource(Contact,'/contact/<string:contact_id>')
In Contact I try to do the following:
from rest_api import dbcollection
class Contact(Resource):
def get(self,contact_id):
result = {}
result['data'] = dbcollection.find_one({'contact_id':contact_id})
result['code'] = 200 if result['data'] else 404
return make_response(dumps(result), result['code'],{"Content-type": "application/json"})
This fails with the following error:
ImportError: cannot import name Contact
What is the correct way of importing contact, so that it can also use variables/functions from rest_api?
p.s If I move the collection code to a different file, and import that file instead things work, but I assume there is some other way..

This is a circular import dependency, which cannot be solved as such. The problem is, that importing a python module really runs the code, which has to follow some order, one of the modules has to go first.
I would say that having the support code in a different file would be the proper way to go.
In this case however, the dbcollection is not actually needed at import time. Thus you can solve this by removing the import from the module level, into the get function. For example
class Contact(Resource):
def get(self,contact_id):
from rest_api import dbcollection
result = {}
result['data'] = dbcollection.find_one({'contact_id':contact_id})
result['code'] = 200 if result['data'] else 404
return make_response(dumps(result), result['code'],{"Content-type": "application/json"})
A similar approach would be the following:
import rest_api
class Contact(Resource):
def get(self,contact_id):
result = {}
result['data'] = rest_api.dbcollection.find_one({'contact_id':contact_id})
result['code'] = 200 if result['data'] else 404
return make_response(dumps(result), result['code'],{"Content-type": "application/json"})
This should work, as python does some effort to resolve circular import dependencies: When it start importing a module, it creates an empty module dict for that one. Then when it finds a nested import, it proceeds with that one. If that in turn imports a module that is already in the import process it just skips it. Thus at the time Contact.py is being loaded, the import rest_api just takes the module dict that is already there. Since it does not contain dbcollection yet, from rest_api import dbcollection fails. A simple import rest_api does work however, since it's member is only addressed after Contact.py finishes importing (unless you call Contact.get at module level from within).

Assuming you haven't a clue which modules are going to import which ever other ones, you can track that yourself and NOT do the import.
In your __init__.py, define these --
__module_imports__ = {}
def requires_module(name):
return name not in __module_imports__
def importing_module(name):
__module_imports__[name] = True
Then, at the top of each class file, where you define your classes add the following to this_module.py:
from my_modules import requires_module, importing_module
importing('ThisModule')
if requires_module('ThatModule')
from my_modules.that_module import ThatModule
class ThisModule:
""" Real Stuff Goes Here """
pass
and this to that_module.py:
from my_modules import requires_module, importing_module
importing('ThatModule')
if requires_module('ThisModule')
from my_modules.this_module import ThisModule
class ThatModule:
""" Real Stuff Goes Here """
pass
now you get your imports regardless of which gets imported first or whatever.

Related

no value for argument self in unbound method call

Thanks for reading this. I've spent the past 48 hours trying to get this code to work. First of all I must disclose that this is for a college assignment. I'm not looking for any assistance or comment on how I might 'gain' in the assignment, I just need to figure out what I'm doing wrong. I have googled the issue and I've read through tutorials on classes and I do feel like I understand them and have got the examples to work. This one issue is stumping me.
So, I have a class which will read a database as follows:
import mysql.connector
import pandas as pd
class DAOdv:
#dbConn=mysql.connector.connect()
def __init__(self):
# import the config file
config=pd.read_csv('./files/config.ini')
dbName=config.iloc[int(config[config['item']=='databaseName'].index[0])]['setting']
uname=config.iloc[int(config[config['item']=='username'].index[0])]['setting']
hst=config.iloc[int(config[config['item']=='host'].index[0])]['setting']
prt=config.iloc[int(config[config['item']=='port'].index[0])]['setting']
# create the connection
self.dbConn=mysql.connector.connect(
host=hst,
database=dbName,
port=prt,
username=uname,
password='' # no password on Server as yet
)
def allClients(self):
cursor=self.dbConn.cursor()
sSQL = 'SELECT * FROM clients'
cursor.execute(sSQL)
results=cursor.fetchall()
return results
daoDV=DAOdv()
and the 'server' code which is:
from flask import Flask
from daoDV import DAOdv
app=Flask(__name__, static_url_path='',static_folder='')
# curl "http://127.0.0.1:5000/clients"
#app.route('/clients')
def getAll():
results=DAOdv.allClients()
return results
In python, the second last line above, DAOdv is underlined in red and hovering over it produces the message "no value for argument self in unbound method call"
What am I doing wrong? I'm assuming the error is in the class?? but I can't figure out what.
Many thanks for your help with this.
Seamus
DAOdv is the class itself, not the instantiated object which you create at the end with: daoDV=DAOdv().
Change your server code to:
from daoDV import daoDV # note the capitalization - we're importing the object here
#(...)
results = daoDV.allClients()
Your method allClients() is an instance method, not a class method.
That's why you should call it like:
results=DAOdv().allClients()
Methods can be an instance or class method.
Class methods are methods which have #classmethod decorator.

Mock flask.request in python nosetests

I'm writing test cases for code that is called via a route under Flask. I don't want to test the code by setting up a test app and calling a URL that hits the route, I want to call the function directly. To make this work I need to mock flask.request and I can't seem to manage it. Google / stackoverflow searches lead to a lot of answers that show how to set up a test application which again is not what I want to do.
The code would look something like this.
somefile.py
-----------
from flask import request
def method_called_from_route():
data = request.values
# do something with data here
test_somefile.py
----------------
import unittest
import somefile
class SomefileTestCase(unittest.TestCase):
#patch('somefile.request')
def test_method_called_from_route(self, mock_request):
# want to mock the request.values here
I'm having two issues.
(1) Patching the request as I've sketched out above does not work. I get an error similar to "AttributeError: 'Blueprint' object has no attribute 'somefile'"
(2) I don't know how to exactly mock the request object if I could patch it. It doesn't really have a return_value since it isn't a function.
Again I can't find any examples on how to do this so I felt a new question was acceptable.
Try this
test_somefile.py
import unittest
import somefile
import mock
class SomefileTestCase(unittest.TestCase):
def test_method_called_from_route(self):
m = mock.MagicMock()
m.values = "MyData"
with mock.patch("somefile.request", m):
somefile.method_called_from_route()
unittest.main()
somefile.py
from flask import request
def method_called_from_route():
data = request.values
assert(data == "MyData")
This is going to mock the entire request object.
If you want to mock only request.values while keeping all others intact, this would not work.
A few years after the question was asked, but this is how I solved this with python 3.9 (other proposed solutions stopped working with python 3.8 see here). I'm using pytest and pytest-mock, but the idea should be the same across testing frameworks, as long as you are using the native unittest.mock.patch in some capacity (pytest-mock essentially just wraps these methods in an easier to use api). Unfortunately, it does require that you set up a test app, however, you do not need to go through the process of using test_client, and can just invoke the function directly.
This can be easily handled by using the Application Factory Design Pattern, and injecting application config. Then, just use the created app's .test_request_context as a context manager to mock out the request object. using .test_request_context as a context manager, gives everything called within the context access to the request object. Here's an example below.
import pytest
from app import create_app
#pytest.fixture
def request_context():
"""create the app and return the request context as a fixture
so that this process does not need to be repeated in each test
"""
app = create_app('module.with.TestingConfig')
return app.test_request_context
def test_something_that_requires_global_request_object(mocker, request_context):
"""do the test thing"""
with request_context():
# mocker.patch is just pytest-mock's way of using unittest.mock.patch
mock_request = mocker.patch('path.to.where.request.is.used')
# make your mocks and stubs
mock_request.headers = {'content-type': 'application/json'}
mock_request.get_json.return_value = {'some': 'json'}
# now you can do whatever you need, using mock_request, and you do not
# need to remain within the request_context context manager
run_the_function()
mock_request.get_json.assert_called_once()
assert 1 == 1
# etc.
pytest is great because it allows you to easily setup fixtures for your tests as described above, but you could do essentially the same thing with UnitTest's setUp instance methods. Happy to provide an example for the Application Factory design pattern, or more context, if necessary!
with help of Gabrielbertouinataa on this article: https://medium.com/#vladbezden/how-to-mock-flask-request-object-in-python-fdbc249de504:
code:
def print_request_data():
print(flask.request.data)
test:
flask_app = flask.Flask('test_flask_app')
with flask_app.test_request_context() as mock_context:
mock_context.request.data = "request_data"
mock_context.request.path = "request_path"
print_request_data()
Here is an example of how I dealt with it:
test_common.py module
import pytest
import flask
def test_user_name(mocker):
# GIVEN: user is provided in the request.headers
given_user_name = "Some_User"
request_mock = mocker.patch.object(flask, "request")
request_mock.headers.get.return_value = given_user_name
# WHEN: request.header.get method is called
result = common.user_name()
# THEN: user name should be returned
request_mock.headers.get.assert_called_once_with("USERNAME", "Invalid User")
assert result == given_user_name
common.py module
import flask
def user_name():
return flask.request.headers.get("USERNAME", "Invalid User")
What you're trying to do is counterproductive. Following the RFC 2616 a request is:
A request message from a client to a server includes, within the first line of that message, the method to be applied to the resource, the identifier of the resource, and the protocol version in use.
Mocking the Flask request you need to rebuild its structure, what certainly, you will not to want to do!
The best approach should be use something like Flask-Testing or use some recipes like this, and then, test your method.

How to deal with globals in modules?

I try to make a non blocking api calls for OpenWeatherMap, but my problem is:
When i was doing tests on the file, and run it, the global api was taking effect, but when importing the function, global dont work anymore, and api dident change: api = ""?
Just after declaring the function i put global api, and then when I use print 'The API link is: ' + api I get the exact api, but global dident took effect!
Here is the code: https://github.com/abdelouahabb/tornadowm/blob/master/tornadowm.py#L62
What am I doing wrong?
When I import the file:
from tornadowm import *
forecast('daily', q='london', lang='fr')
The API link is: http://api.openweathermap.org/data/2.5/forecast/daily?lang=fr&q=london
api
Out[5]: ''
When executing the file instead of importing it:
runfile('C:/Python27/Lib/site-packages/tornadowm.py', wdir='C:/Python27/Lib/site-packages')
forecast('daily', q='london', lang='fr')
The API link is: http://api.openweathermap.org/data/2.5/forecast/daily?lang=fr&q=london
api
Out[8]: 'http://api.openweathermap.org/data/2.5/forecast/daily?lang=fr&q=london'
Edit: here is the code, if the Git got updated:
from tornado.httpclient import AsyncHTTPClient
import json
import xml.etree.ElementTree as ET
http_client = AsyncHTTPClient()
url = ''
response = ''
args = []
link = 'http://api.openweathermap.org/data/2.5/'
api = ''
result = {}
way = ''
def forecast(way, **kwargs):
global api
if way in ('weather', 'forecast', 'daily', 'find'):
if way == 'daily':
way = 'forecast/daily?'
else:
way += '?'
for i, j in kwargs.iteritems():
args.append('&{0}={1}'.format(i, j))
a = ''.join(set(args))
api = (link + way + a.replace(' ', '+')).replace('?&', '?')
print 'The API link is: ' + api
def handle_request(resp):
global response
if resp.error:
print "Error:", resp.error
else:
response = resp.body
http_client.fetch(api, handle_request)
else:
print "please put a way: 'weather', 'forecast', 'daily', 'find' "
def get_result():
global result
if response.startswith('{'):
print 'the result is JSON, stored in the variable result'
result = json.loads(response)
elif response.startswith('<'):
print 'the result is XML, parse the result variable to work on the nodes,'
print 'or, use response to see the raw result'
result = ET.fromstring(response)
else:
print '''Sorry, no valid response, or you used a parameter that is not compatible with the way!\n please check http://www.openweathermap.com/api for more informations''
It's the side effect of using global.
When you do from tornadowm import * your forecast() function is, we could say metaphorically, "on its own" and is not "hard-linked" to your global space anymore.
Why? Because any effect you make on your global api will "end" with your function, and the definition of api = "" in your global space will take precedence.
Also, as a side note, it's not considered a good practice to use from something import *. You should do from tornadowm import forecast or even better, import tornadown and then use tornadowm.forecast().
OR
Even better, I just noticed your forecast() function doesn't return anything. Which technically makes it not a function anymore, but a procedure (a procedure is like a function but it returns nothing, it just "does" stuff).
Instead of using a global, you should define api in this function and then return api from it. Like this:
def forecast(blablabla):
api = "something"
blablabla
return api
And then
import tornadowm
api = tornadown.forecast(something)
And you're done.
Globals are global only to the module they're defined in. So, normally, you would expect tornadowm.api to be changed when you call forecast, but not api in some other namespace.
The import * is contributing to your understanding of the problem. This imports api (among other names) into the importing namespace. This means that api and tornadowm.api initially point to the same object. But these two names are not linked in any way, and so calling forecast() changes only tornadowm.api and now the two names point to different objects.
To avoid this, don't use import *. It is bad practice anyway and this is just one of the reasons. Instead, import tornadowm and access the variable in the importing module as tornadowm.api.
I'm afraid this is because global is coupled within module, by the time you from tornadowm import * you have imported the api name, but the global api won't take any effects within another module.

How to import own module for mocking? (import error: no module named my_module!)

I want to unit test my class, which is in another file named client_blogger.py.
My unit test file, is in the same directory. All of my other unit tests work, except when I try to mock one of my own methods.
## unit_test_client_blogger.py
import mock
import json
from client_blogger import BloggerClient, requests
Class TestProperties():
#pytest.fixture
def blog(self):
return BloggerClient(api_key='123', url='http://example.com')
#mock.patch('client_blogger._jload')
#mock.patch('client_blogger._send_request')
def test_gets_blog_info(self, mock_send, mock_jload):
""" Get valid blog info from API response. """
valid_blog_info = 'some valid json api response here'
parsed_response = json.loads(valid_blog_info)
correct_blog_id = '7488272653173849119'
mock_jload.return_value = valid_blog_info
id = self.blog().get_blog_info(parsed_response)
assert id == correct_blog_id
And here is the client_blogger.py file contents:
# client_blogger.py
import requests, json
class BloggerClient(object):
""" Client interface for Blogger API. """
def __init__(self, key, url):
# removed some code here for brevity
def _send_request(self, api_request):
""" Sends an HTTP get request to Blogger API.
Returns HTTP response in text format. """
# snip
def _jload(self, api_response):
""" Accepts text API response. Returns JSON encoded response. """
# snip
def get_blog_info(self):
""" Makes an API request. Returns Blog item information. """
request = '{b}/blogs/byurl?url={u}&key={k}'.format(b=self.base, u=self.url, k=self.key)
txt_response = self.send_request(request)
response = self._jload(txt_response)
return response['id']
I want to mock out self.send_request() and self._jload() method calls in the above method.
But Mock module complains: ImportError: No module named client_blogger.
The error must lie here:
#mock.patch('client_blogger._jload')
#mock.patch('client_blogger._send_request')
I've tried many variations in order to get mock.patch to find my module or class. But none of them have worked.
I've tried the following:
#mock.patch('client_blogger.BloggerClient._jload')
#mock.patch('BloggerClient._jload')
#mock.patch('._jload')
None of those work. Any idea how to mock.patch a method from my own module?
(It seems strange, because I can mock.patch other modules, just not my own :-s)
You want this:
#mock.patch('client_blogger.BloggerClient._jload')
#mock.patch('client_blogger.BloggerClient._send_request')
def test_gets_blog_info(self, mock_send, mock_jload):
""" Get valid blog info from API response. """
valid_blog_info = 'some valid json api response here'
parsed_response = json.loads(valid_blog_info)
correct_blog_id = '7488272653173849119'
mock_jload.return_value = valid_blog_info
id = self.blog().get_blog_info(parsed_response)
assert id == correct_blog_id
The BloggerClient implementation is coming from the client_blogger module, so you need to patch client_blogger.BloggerClient. You list that as one of the things you tried that doesn't work, but I just tried it, and it works fine for me. What issue did you have when you tried that?
You need to include the file name of the class in the path, before the object name.
e.g. if I have a method named foo in a class named Event in tools/event.py the path will be as follows:
patch("tools.event.Event.foo", boo)
For python3, the format is as follows:
from unittest.mock import patch
#patch('client_blogger.BloggerClient._jload')
.
.
.
Docs: https://docs.python.org/3/library/unittest.mock.html#patch
This is very, very important:
patch() is straightforward to use. The key is to do the patching in the right namespace. See the section where to patch.

Importing Model / Lib Class and calling from controller

I'm new to python and pylons although experienced in PHP.
I'm trying to write a model class which will act as a my data access to my database (couchdb). My problem is simple
My model looks like this and is called models/BlogModel.py
from couchdb import *
class BlogModel:
def getTitles(self):
# code to get titles here
def saveTitle(self):
# code to save title here
My controller is called controllers/main.py
import logging
from pylons import request, response, session, tmpl_context as c
from pylons.controllers.util import abort, redirect_to
from billion.lib.base import BaseController, render
log = logging.getLogger(__name__)
from billion.model import BlogModel
class MainController(BaseController):
def index(self):
return render('/main.mako')
In my index action, how do I access the method getTitles() in BlogModel?
I've tried
x = BlogModel()
x.getTitles()
But i get
TypeError: 'module' object is not callable
Also
BlogModel.getTitles() results in
AttributeError: 'module' object has no attribute 'getTitles'
Is this down to the way I'm including the class ? Can someone tell me the best way to do this ?
thanks
x = BlogModel.BlogModel()
Or, more verbosely:
After you did the import, you have an object in your namespace called 'BlogModel'. That object is the BlogModel module. (The module name comes from the filename.) Inside that module, there is a class object called 'BlogModel', which is what you were after. (The class name comes from the source code you wrote.)
Instead of:
from billion.model import BlogModel
You could use:
from billion.model.BlogModel import BlogModel
then your
x = BlogModel()
would work.

Categories

Resources