How to fix django-oscar shipping UnboundLocalError? - django

I want to add a shipping methods to django-oscar, but I'm getting the UnboundLocalError error even though I've done everything on the document page.
Request Method: GET
Request URL: http://127.0.0.1:8000/checkout/shipping-address/
Django Version: 2.1.7
Exception Type: UnboundLocalError
Exception Value:
local variable 'methods' referenced before assignment
repository.py
from oscar.apps.shipping import repository
from . import methods
class Repository(repository.Repository):
def get_available_shipping_methods(self, basket, user=None, shipping_addr=None, request=None, **kwargs):
methods = (methods.Standard(),)
if shipping_addr and shipping_addr.country.code == 'GB':
# Express is only available in the UK
methods = (methods.Standard(), methods.Express())
return methods
methods.py
from oscar.apps.shipping import methods
from oscar.core import prices
from decimal import Decimal as D
class Standard(methods.Base):
code = 'standard'
name = 'Shipping (Standard)'
def calculate(self, basket):
return prices.Price(
currency=basket.currency,
excl_tax=D('5.00'), incl_tax=D('5.00'))
class Express(methods.Base):
code = 'express'
name = 'Shipping (Express)'
def calculate(self, basket):
return prices.Price(
currency=basket.currency,
excl_tax=D('4.00'), incl_tax=D('4.00'))

I can see that is in the docs, but they look to have a bug in them.
With UnboundLocalError you're essentially looking at a scope issue. A really simple example would be;
x = 10
def foo():
x += 1
print x
foo()
When foo executes x isn't available to foo. So change the import slightly to avoid this;
from oscar.apps.shipping import repository
from . import methods as shipping_methods
class Repository(repository.Repository):
def get_available_shipping_methods(self, basket, user=None, shipping_addr=None, request=None, **kwargs):
methods = (shipping_methods.Standard(),)
if shipping_addr and shipping_addr.country.code == 'GB':
# Express is only available in the UK
methods = (shipping_methods.Standard(), shipping_methods.Express())
return methods

Related

How to store results from many TestCases (to one file) in django (unittest)?

I have several test cases which all have a similar tearDown:
def tearDown(self):
execution_time = time.time() - self.startTime
result_list = [self._testMethodName]
result = [str(x) for x in sys.exc_info()]
if result[0] == 'None':
result_list.append('PASS')
elif 'Assertion' in result[0]:
result_list.append('FAIL')
else:
result_list.append('ERROR')
result_list.append(result)
result_list.append(str(execution_time))
TEST_RESULTS.append(result_list)
I'm using the tearDown function to store results from each test (in the test case) to a global TEST_RESULTS object (so each TestCase file has a TEST_RESULTS global defined).
Then in the tearDownClass function im doing this to store results to csv:
#classmethod
def tearDownClass(cls):
with open ('tests/results/test_case_1_output.csv', 'wr') as resultFile:
wr = csv.writer(resultFile)
wr.writerows(TEST_RESULTS)
To me this is a terrible implementation. Globals defined everywhere and tearDown/tearDownClass implemented over and over again in each test case rather than defined once.
Furthermore, I would like to create a test result file which collects results from all test cases.
My hunch is this requires defining the file handle at the runner level (or somewhere before the TestCases are being called). This would allow me to reinitialize the csv file at a higher level (rather than arbitrarily in one TestCase).
Does anyone have a suggestion on how this can be accomplished? Did not see a way to do this from the docs and overriding django TestCase seemed hazardous.
I will post my solution (thanks very much to #xyres) since i think it might help some others.
Below is an example of a TestCase which calls SetUp, tearDown and setUpClass from the base class (either TestManager or TestCase. The trick was to call setUpClass from base class 'TestCase' and create another initialization function 'initialize' called on the 'TestManager' base class.
class MyTestCase(TestManager, TestCase)
def setUp(self):
self.param1, self.param2 = super(MyTestCase, self).setUp()
def tearDown(self):
test_name = self._testMethodName
super(MyTestCase, self).get_and_write_results_to_csv(test_name)
#classmethod
def setUpClass(cls):
super(MyTestCase, cls).setUpClass()
super(MyTestCase, cls).initialize('my test case name')
class TestManager():
#classmethod
def initialize(cls, test_case_name):
with open('path/to/my/testresults.csv', 'wr') as resultFile:
wr = csv.writer(resultFile)
wr.writerow("Results for " + test_case_name + "are below:")
def setUp(self):
"""
Do some setup stuff that's the same for each TestCase.
Im not showing the actions here but assume you want this
function to return 2 params that are the same for every
TestCase setup
"""
return param1, param2
def get_and_write_results_to_csv(self, test_name):
execution_time = time.time() - self.startTime
result_list = [test_name]
result = [str(x) for x in sys.exc_info()]
if result[0] == 'None':
result_list.append('PASS')
elif 'Assertion' in result[0]:
result_list.append('FAIL')
else:
result_list.append('ERROR')
result_list.append(result)
result_list.append(str(execution_time))
with open('path/to/my/testresults.csv', 'a') as resultFile:
wr = csv.writer(resultFile)
wr.writerow(result_list)

RecursionError: when using factory boy

I can't use factory boy correctly.
That is my factories:
import factory
from harrispierce.models import Article, Journal, Section
class JournalFactory(factory.Factory):
class Meta:
model = Journal
name = factory.sequence(lambda n: 'Journal%d'%n)
#factory.post_generation
def sections(self, create, extracted, **kwargs):
if not create:
# Simple build, do nothing.
return
if extracted:
# A list of groups were passed in, use them
for section in extracted:
self.sections.add(section)
class SectionFactory(factory.Factory):
class Meta:
model = Section
name = factory.sequence(lambda n: 'Section%d'%n)
and my test:
import pytest
from django.test import TestCase, client
from harrispierce.factories import JournalFactory, SectionFactory
#pytest.mark.django_db
class TestIndex(TestCase):
#classmethod
def setUpTestData(cls):
cls.myclient = client.Client()
def test_index_view(self):
response = self.myclient.get('/')
assert response.status_code == 200
def test_index_content(self):
section0 = SectionFactory()
section1 = SectionFactory()
section2 = SectionFactory()
print('wijhdjk: ', section0)
journal1 = JournalFactory.create(sections=(section0, section1, section2))
response = self.myclient.get('/')
print('wijhdjk: ', journal1)
self.assertEquals(journal1.name, 'Section0')
self.assertContains(response, journal1.name)
But I get this when running pytest:
journal1 = JournalFactory.create(sections=(section0, section1, section2))
harrispierce_tests/test_index.py:22:
RecursionError: maximum recursion depth exceeded while calling a Python object
!!! Recursion detected (same locals & position)
One possible issue would be that you're not using the proper Factory base class: for a Django model, use factory.django.DjangoModelFactory.
This shouldn't cause the issue you have, though; a full stack trace would be useful.
Try to remove the #factory.post_generation section, and see whether you get a proper Journal object; then inspect what parameters where passed.
If this is not enough to fix your code, I suggest opening an issue on the factory_boy repository, with a reproducible test case (there are already some branches/commits attempting to reproduce a reported bug, which can be used as a template).

python problems with super

Ok so I'm having a bit of a problem with the code below. It works as is but if I try to change the part with the comment about me not being able to get super to work correctly to.
pipeline_class_call = super(Error_Popup,self)
broken_file_w_whats_wrong = pipeline_class_call.whats_wrong_with_file()
or to
broken_file_w_whats_wrong = super(Error_Popup,self).whats_wrong_with_file()
and change
class Error_Popup(QtGui.QDialog):
to
class Error_Popup(QtGui.QDialog,Pipeline_UI):
I get the following error
# TypeError: object of type 'instancemethod' has no len() #
Which normally means that I need to call the method, but doesn't super handle all this for me. Or am I goofing this?
from PySide import QtCore, QtGui
from shiboken import wrapInstance
import pymel.core as pm
import maya.OpenMayaUI as omui
from UI.UI import Pipeline_UI
def something_bad_happened_window():
sbh_pointer = omui.MQtUtil.mainWindow()
return wrapInstance(long(sbh_pointer), QtGui.QWidget)
class Error_Popup(QtGui.QDialog):
def __init__(self,parent=something_bad_happened_window()):
super(Error_Popup,self).__init__(parent)
self.setWindowTitle('Something Bad Happened!')
self.setWindowFlags(QtCore.Qt.Tool)
self.popup_layout()
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.connections()
def popup_layout(self):
self.file_description = QtGui.QListWidget()
#cant seem to get super to work appropriately... booo
pipeline_class_call = Pipeline_UI()
broken_file_w_whats_wrong = pipeline_class_call.whats_wrong_with_file()
for display in range(0,len(broken_file_w_whats_wrong)):
broken_list = QtGui.QListWidgetItem()
if display % 2 == 0:
broken_list.setText(broken_file_w_whats_wrong[display][0])
broken_list.asset = broken_file_w_whats_wrong[display][1]
else:
broken_list.setText(" " + broken_file_w_whats_wrong[display][0])
self.file_description.addItem(broken_file_w_whats_wrong[display])
self.import_button = QtGui.QPushButton('Import Replacement(s)')
error_layout = QtGui.QVBoxLayout()
error_layout.setContentsMargins(2,2,2,2)
error_layout.setSpacing(2)
error_layout.addWidget(self.file_description)
error_layout.addWidget(self.import_button)
error_layout.addStretch()
self.setLayout(error_layout)
def connections(self):
self.import_button.clicked.connect(Error_Popup.make_sphere)
#classmethod
def make_sphere(cls):
pm.polySphere()
def show_window():
ui = Error_Popup()
if __name__ == '__main__':
try:
ui.close()
except:
pass
ui.show()
show_window()
Thanks in advance everyone
Looks to me like it's a problem of using super with multiple inheritance. It picks one of the parents in a certain order to use. For example, super(Error_Popup,self).__init__(parent) only calls one of the parents __init__ methods. You have to manually call all of them.
When calling methods or accessing variables, you have to be specific about which parent you want to use or super will pick for you. See this answer and this answer.

Unit testing twisted.web.client.Agent's without the network

I've not done any twisted now for a couple of years and have started using the newer Agent style of client http calls. Using Agent has been OK, but testing is confusing me (it's twisted after all).
I've been through the https://twistedmatrix.com/documents/current/core/howto/trial.html docs and the APIs on trial tools and Agent itself. Also numerous searches.
I've gone with faking out Agent, as I don't need to test that. But then because of the steps to handle the processing and response of an Agent request, my test code has got nasty, implementing the nested layers of the Agent, protocol, etc. Where should I draw the line here and are there some utils I haven't found?
Here's a minimal example (naive implementation of SUT):
from twisted.web.client import Agent, readBody
from twisted.internet import reactor
import json
class SystemUnderTest(object):
def __init__(self, url):
self.url = url
def action(self):
d = self._makeAgent().request("GET", self.url)
d.addCallback(self._cbSuccess)
return d
def _makeAgent(self):
''' It's own method so can be overridden in tests '''
return Agent(reactor)
def _cbSuccess(self, response):
d = readBody(response)
d.addCallback(self._cbParse)
return d
def _cbParse(self, data):
self.result = json.loads(data)
print self.result
with the test module:
from twisted.trial import unittest
from sut import SystemUnderTest
from twisted.internet import defer
from twisted.test import proto_helpers
class Test(unittest.TestCase):
def test1(self):
s_u_t = ExtendedSystemUnderTest(None)
d = s_u_t.action()
d.addCallback(self._checks, s_u_t)
return d
def _checks(self, result, s_u_t):
print result
self.assertEqual({'one':1}, s_u_t.result)
class ExtendedSystemUnderTest(SystemUnderTest):
def _makeAgent(self):
return FakeSuccessfulAgent("{'one':1}")
## Getting ridiculous below here...
class FakeReason(object):
def check(self, _):
return False
def __str__(self):
return "It's my reason"
class FakeResponse(object):
''' Implementation of IResponse '''
def __init__(self, content):
self.content = content
self.prot = proto_helpers.StringTransport()
self.code = 200
self.phrase = ''
def deliverBody(self, prot):
prot.makeConnection(self.prot)
prot.dataReceived(self.content)
# reason = FakeReason()
# prot.connectionLost(reason)
class FakeSuccessfulAgent(object):
''' Implementation of IAgent '''
def __init__(self, response):
self.response = response
def request(self, method, url):
return defer.succeed(FakeResponse(self.response))
but testing is confusing me (it's twisted after all).
Hilarious.
class ExtendedSystemUnderTest(SystemUnderTest):
def _makeAgent(self):
return FakeSuccessfulAgent("{'one':1}")
I suggest you make the agent to use a normal parameter. This is more convenient than a private method like _makeAgent. Composition is great. Inheritance is meh.
class FakeReason(object):
...
There's no reason to make a fake of this. Just use twisted.python.failure.Failure. You don't have to fake every object in the test. Just the ones that get in your way if you don't fake them.
class FakeResponse(object):
...
This is likely good and necessary.
class FakeSuccessfulAgent(object):
...
This is most likely necessary as well. You should make it actually be more like an IAgent implementation though - declare that it implements the interface, use zope.interface.verify.verify{Class,Object} to make sure you get the implementation write, etc (eg request has the wrong signature now).
There's actually a ticket for adding all of these testing tools to Twisted itself - https://twistedmatrix.com/trac/ticket/4024. So I don't think you're actually confused, you're basically on the same track as the project itself. You're just suffering from the fact that Twisted hasn't already done all of this work for you.
Also, note that instead of:
class Test(unittest.TestCase):
def test1(self):
s_u_t = ExtendedSystemUnderTest(None)
d = s_u_t.action()
d.addCallback(self._checks, s_u_t)
return d
You can write something like this instead (and it is preferable):
class Test(unittest.TestCase):
def test1(self):
s_u_t = ExtendedSystemUnderTest(None)
d = s_u_t.action()
self._checks(s_u_t, self.successResultOf(d))
This is because your fake implementation of IAgent is synchronous. You know it is synchronous. By the time request returns, the Deferred it is returning has a result already. Writing the test this way means you can simplify your code a bit (ie, you can ignore the asynchronousness of it to some extent - because it isn't) and it avoids running the global reactor which is what returning a Deferred from a test method in trial does.

how to unittest the template variables passed to jinja2 template from webapp2 request handler

I'm trying to test my webapp2 handlers. To do this, I thought it would be a good idea to send a request to the handler e.g.:
request = webapp2.Request.blank('/')
# Get a response for that request.
response = request.get_response(main.app)
The problem is, response is mostly just a bunch of HTML etc.
I want to look at what was passed to my jinja2 template from the handler before it was turned into HTML.
I want my test to get at the state within the handler class code. I wan't to be able to see what certain variables looked like in the response handler, and then I want to see what the dict templates looks like before it was passed to render_to_response()
I want to test these variables have the correct values.
Here is my test code so far, but I'm stuck because response = request.get_response() just gives me a bunch of html and not the raw variables.
import unittest
import main
import webapp2
class DemoTestCase(unittest.TestCase):
def setUp(self):
pass
def tearDown(self):
pass
def testNothing(self):
self.assertEqual(42, 21 + 21)
def testHomeHandler(self):
# Build a request object passing the URI path to be tested.
# You can also pass headers, query arguments etc.
request = webapp2.Request.blank('/')
# Get a response for that request.
response = request.get_response(main.app)
# Let's check if the response is correct.
self.assertEqual(response.status_int, 200)
self.assertEqual(response.body, 'Hello, world!')
if __name__ == '__main__':
unittest.main()
and here is my handler:
class HomeHandler(BaseHandler):
def get(self, file_name_filter=None, category_filter=None):
file_names = os.listdir('blog_posts')
blogs = []
get_line = lambda file_: file_.readline().strip().replace("<!--","").replace("-->","")
for fn in file_names:
with open('blog_posts/%s' % fn) as file_:
heading = get_line(file_)
link_name = get_line(file_)
category = get_line(file_)
date_ = datetime.strptime(fn.split("_")[0], "%Y%m%d")
blog_dict = {'date': date_, 'heading': heading,
'link_name': link_name,
'category': category,
'filename': fn.replace(".html", ""),
'raw_file_name': fn}
blogs.append(blog_dict)
categories = Counter(d['category'] for d in blogs)
templates = {'categories': categories,
'blogs': blogs,
'file_name_filter': file_name_filter,
'category_filter': category_filter}
assert(len(file_names) == len(set(d['link_name'] for d in blogs)))
self.render_template('home.html', **templates)
and here is my basehandler:
class BaseHandler(webapp2.RequestHandler):
#webapp2.cached_property
def jinja2(self):
return jinja2.get_jinja2(app=self.app)
def render_template(self, filename, **kwargs):
#kwargs.update({})
#TODO() datastore caching here for caching of (handlername, handler parameters, changeable parameters, app_upload_date)
#TODO() write rendered page to its own html file, and just serve that whole file. (includes all posts). JQuery can show/hide posts.
self.response.write(self.jinja2.render_template(filename, **kwargs))
Perhaps I have got the wrong idea of how to do unit testing, or perhaps I should have written my code in a way that makes it easier to test? or is there some way of getting the state of my code?
Also if someone were to re-write the code and change the variable names, then the tests would break.
You can mock BaseHandler.render_template method and test its parameters.
See this question for a list of popular Python mocking frameworks.
Thanks to proppy's suggestion I ended up using a mock.
http://www.voidspace.org.uk/python/mock/
(mock is included as part or unittest.mock in python 3)
So here is my main.py code which is similar to what I have in webapp2:
note instead of BaseHandler.render_template i have BaseHandler.say_yo
__author__ = 'Robert'
print "hello from main"
class BaseHandler():
def say_yo(self,some_number=99):
print "yo"
return "sup"
class TheHandler(BaseHandler):
def get(self, my_number=42):
print "in TheHandler's get()"
print self.say_yo(my_number)
return "TheHandler's return string"
and atest.py:
__author__ = 'Robert'
import unittest
import main
from mock import patch
class DemoTestCase(unittest.TestCase):
def setUp(self):
pass
def tearDown(self):
pass
def testNothing(self):
self.assertEqual(42, 21 + 21)
def testSomeRequests(self):
print "hi"
bh = main.BaseHandler()
print bh.say_yo()
print "1111111"
with patch('main.BaseHandler.say_yo') as patched_bh:
print dir(patched_bh)
patched_bh.return_value = 'double_sup'
bh2 = main.BaseHandler()
print bh2.say_yo()
print "222222"
bh3 = main.BaseHandler()
print bh3.say_yo()
print "3333"
th = main.TheHandler()
print th.get()
print "44444"
with patch('main.BaseHandler.say_yo') as patched_bh:
patched_bh.return_value = 'last_sup'
th = main.TheHandler()
print th.get()
print th.get(123)
print "---"
print patched_bh.called
print patched_bh.call_args_list
print "555555"
if __name__ == '__main__':
unittest.main()
this code gives lots of output, here is a sample:
44444
in TheHandler's get()
last_sup
TheHandler's return string
in TheHandler's get()
last_sup
TheHandler's return string
---
True
[call(42), call(123)]
555555