Convert string as module - python

is there a way to turn a string to an module object? i want to to do a function call after doing an API request but I cant convert the string I got from the request to a module object
I have seen some code that could actually do it however it is done by importing the module.
import controller.mipay.controller as mipay
#api.route('/redirect')
class Request(Resource):
parser = RequestChecker()
def post(self):
req = self.parser.parse_args() # <---- JSON/Dictionary
#method_to_call = getattr(mipay, req['PaymentEndpoint'])
method_to_call = getattr(req['PaymentMethod'], req['PaymentEndpoint'])
return method_to_call()
is there anyway to convert the string to a module object or anything I can do to the string so I could call my function

Using __import__ may be the solution:
module = __import__("module.path")
See importlib — The implementation of import

I assume req['PaymentMethod'] is the module and req['PaymentEndpoint'] is the method. What you can do is use importlib.
#import controller.mipay.controller as mipay
import importlib
my_mapping = {'mipay':'controller.mipay.controller'}
class Request(Resource):
parser = RequestChecker()
def post(self):
req = self.parser.parse_args() # <---- JSON/Dictionary
# method_to_call = getattr(mipay, req['PaymentEndpoint'])
mipay= importlib.import_module(my_mapping[req['PaymentMethod']])
method_to_call = getattr(mymodule, req['PaymentEndpoint'])
return method_to_call()

Related

Any changes in 'functools.lru_cache' from python 2 and python 3?

My code is here works fine in python2.7 but fails inpython 3
functools.lru_cache(maxsize=32) any change in from python 2 to python 3.
The error I am getting is for my configparser object while caching in functools.lru_cacheit says
TypeError: unhashable type: 'ConfigParser'
Want to understand the changes in 'functools.lru_cache' from python 2 and python 3?
#CONFI FILE
[translate]
api_url = https://url
api_version = version_num
api_key = key_value
#code goes here
import functools
from configparser import ConfigParser as SafeConfigParser
config = SafeConfigParser()
path ="./conf/services.ini"
config.read(path)
#functools.lru_cache(maxsize=32)
def build_api_params_key(config):
"""Build the api url and return with key."""
api_url = config.get('translate', 'api_url')
api_version = config.get('translate', 'api_version')
api_key = config.get('translate', 'api_key')
full_api_url = api_url + api_version
return api_key
The issue here is not functools.lru_cache, it is actually the ConfigParser. ConfigParser inherits from RawConfigParser, which in Python 3x, inherits from collections.abc.MutableMapping. The MutableMapping abstract class is not hashable, as it is mutable and does not implement the __hash__ magic method.
Since the ConfigParser instance is not hashable, it cannot be used as a key to the cache dictionary within the functools.lru_cache decorator.
For further reference, see this section of the configparser docs.
Assuming that it is necessary to cache the contents of the config file, another option would be to read the the contents of the file and then pass the contents string to the cached function, like so
import functools
from configparser import ConfigParser as SafeConfigParser
path = "./conf/services.ini"
config_contents = open(path).read()
#functools.lru_cache(maxsize=32)
def build_api_params_key(config_contents: str):
"""Build the api url and return with key."""
config = SafeConfigParser()
config.read_string(config_contents)
api_url = config.get('translate', 'api_url')
api_version = config.get('translate', 'api_version')
api_key = config.get('translate', 'api_key')
full_api_url = api_url + api_version
return api_key
In the solution above, the config file is read to get string containing its contents. Since strings are hashable, this can be passed to the cached function. You can also do something similar with the file pointer if you would rather read the contents of the file within the function. However, these solutions are not compatible to Python 2.7 as read_string is not defined.

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.

Attribute error in python while parsing an XML

I am kinda new to Python. I am working on a project that parses an XML in Python and my Python code to do so is :
from xml.dom import minidom
from copy import copy
class Xmlparse:
def __init__(self, xmlfile):
self = minidom.parse(xmlfile)
def findadress(self):
itemlist =self.getElementsByTagName('addresses')
return itemlist[0].attributes['firstname'].value
if __name__ == '__main__':
with open("sample.xml") as f:
parse = Xmlparse(f)
print parse.findadress()
But when I run this code I get an output error:
AttributeError: Xmlparse instance has no attribute 'findadress'
And findadress function is spelled correctly in the main, but for some reason what so ever i am getting this error.
Any help is really appreciated.
And I also wanted to know, how can I validate the xml with an XSD schema in python?
"self = minidom.parse(xmlfile)" overwrites the Xmlparse object you just created. You want to assign the xml doc to a variable instead:
from xml.dom import minidom
from copy import copy
class Xmlparse:
def __init__(self, xmlfile):
self.doc = minidom.parse(xmlfile)
def findadress(self):
itemlist =self.doc.getElementsByTagName('addresses')
return itemlist[0].attributes['firstname'].value
the evil is in self = minidom.parse(xmlfile)

passing strftime() into Google app engine and jinja2

I have a Google App Engine Python script trying to pass the variable "time" as a strftime() call. I have jinja2 set up to read the html file with {{time}} in it as that variables destination
class MainPage(BlogHandler):
time = ''
def get_time(you):
return strftime('%U %A',gmtime())
def get(self):
time = self.get_time
self.render('front.html',time = time)
When I render/write out the whole thing into a simple div tag I get an object memory locator rendered in html
<bound method MainPage.get_time of <main.MainPage object at 0x1030f0610>>
obviously its not processing this out as a string. Am I using the wrong time function, is this a GAE issue? is this a Jinja2 issue? Is this a python issue? I'm clearly not sure how to follow up and resolve this. Thanks or any good critical advice.
All I want is to render a formattable time function to a string so i can use it in GAE scripts.
All you have to do is call the get_time() method:
time = self.get_time()
By not calling the method, all you do is store a reference to the method, and Jinja2 then takes the str() result of that method to include it in your template output:
>>> from time import strftime, gmtime
>>> class MainPage():
... def get_time(self):
... return strftime('%U %A',gmtime())
...
>>> mp = MainPage()
>>> mp.get_time
<bound method MainPage.get_time of <__main__.MainPage instance at 0x1031c7320>>
>>> mp.get_time()
'07 Saturday'

Unable to perform json.loads(json_data) when calling from parent classes

I forgot to mention, I'm using the following CURL to send the data:
curl -i -H "Content-Type: application/json" -X GET "http://appdev1.ischoolcampus.com/api/assignments" -d '{"guid":"teacherones-class","isTeacher":0}'
I have a method Assignments.GET() that send some data and the format of the data (JSON, XML, etc.) to...
ClientRequest.Receive(data,method) which based on the format, sends it to another method in ClientRequest...
JSON(data) decodes the data using iSCJSON.Decode(data)...
json.loads(data) should spit it out as a dictionary, but instead it is giving me the following error:
AttributeError: 'NoneType' object has no attribute 'loads'
Each class is in a different module:
Assignments - imports:
ClientRequest - imports:
iSCJSON.
I have tried this by just calling iSCJSON.Decode(json_data) from Assignments and it worked fine. I have checked to make sure that json_data actually has content once it drills all the way down, and it does.
But for some reason I still receive an error.
Any ideas?
Classes:
Assignments
import sys
sys.path.insert(1,'/Library/Server/Web/Data/Sites/iconnect/')
import web
if 'iSCModules.mod_ClientRequest' in sys.modules:
del(sys.modules["iSCModules.mod_ClientRequest"])
if 'iSCModules.mod_ServerResponse' in sys.modules:
del(sys.modules["iSCModules.mod_ServerResponse"])
from iSCModules.mod_ClientRequest import ClientRequest
from iSCModules.mod_ServerResponse import ServerResponse
#from iSCModules.mod_iSCJSON import iSCJSON
class Assignments:
def GET(self):
sentData = web.data()
#query = iSCJSON.Decode(sentData)
print "Sent Data is: " + sentData
query = ClientRequest.Receive(sentData, 'JSON')
# \/ Replace With Code \/
print "Query from Assignments is: " + query
data = query
# /\ Replace with Code /\
return ServerResponse.Send(data, 'JSON')
ClientRequest
import sys
sys.path.insert(1,'/Library/Server/Web/Data/Sites/iconnect/')
import web
#if 'iSCModules.mod_iSCJSON' in sys.modules:
# del(sys.modules["iSCModules.mod_iSCJSON"])
from mod_iSCJSON import iSCJSON
class ClientRequest:
#staticmethod
def Receive(data, method):
#sentData = web.data() #Need to figure out why this doesn't work...
# Remove method from parameters, Set method using logic to determine format of data sent from client.
query = getattr(ClientRequest, method)(data)
if (query):
print "Query from ClientRequest is: " + query
return query
#staticmethod
def JSON(data):
decodedData = iSCJSON.Decode(data)
if (decodedData):
return decodedData
iSCJSON
import sys
sys.path.insert(1,'/Library/Server/Web/Data/Sites/iconnect/')
import json
class iSCJSON:
#staticmethod
def Encode(json_string, compact=False):
if (compact):
result = json.dumps(json_string,separators=(',',':'))
else:
result = json.dumps(json_string)
if ( result ):
return result
#staticmethod
def Decode(json_data, encoding=''):
print "JSON Data is: " + json_data
result = json.loads(json_data)
print "Result of iSCJSON is: " + result
if ( result ):
return result
The error message implies that json is None. Perhaps you use json as a variable name, shadowing the module of the same name?
So, I've come up with a way to solve this by combining two classes into one module and reducing the number of methods. I've combined ClientRequest and another class ServerResponse into one class called Server, this class performs the function of both with only two methods, Send and Receive. The two methods then determine what class to call: iSCJSON or iSCXML to do the encoding and decoding. So, I have remedied the problem without actually solving it, with less code.

Categories

Resources