Can I replace an attribute with a lambda WITHOUT changing access syntax? - python

I have a boolean that is used all over a system I've just joined (it's Django's settings.DEBUG, but that's not really important, since this would be handy for testing, as well.)
I want to prevent non-django use of this attribute. Developers using my system should get an exception, telling them to use a different attribute:
settings.DEBUG = lambda: return_bool_or_throw_exception_if_caller_forbidden()
The trouble is, switching to a lambda requires that accessors change:
#instead of:
if settings.DEBUG:
#now:
if settings.DEBUG():
But this would require changing all the reads of DEBUG in Django code, which is unacceptable in my situation. Can I deliver a lambda or a function with no arguments in such a way that consumers can access the thing without function call semantics?

You could monkey patch the settings class and set DEBUG to a descriptor:
def DEBUG(self):
return return_bool_or_throw_exception_if_caller_forbidden()
settings.__class__.DEBUG = property(DEBUG)

Related

Sphinx revealing my (mailgun) password

I have a simple function
import config
def send_message(mailgunkey=config.MAILGUNKEY):
"""
send an email
"""
It relies on a variable defined in my config.py file. I read the variables from local files on all my machines as I don't want to have my keys etc. in any repository. However, I recently got into the habit of using Sphinx. When generating the html docs the expression config.MAILGUNKEY is getting evaluated and the actual key is revealed in the html file. Is there an option to stop this kind of undesired action?
Consider using this approach:
import config
def send_message(mailgunkey=None):
"""
send an email
"""
if mailgunkey is None:
mailgunkey = config.MAILGUNKEY
In general, this approach gives you some important advantages:
lets your users pass None as the default;
allows changes to config.MAILGUNKEY even if your module has already been imported;
solves the problem of mutable default arguments (not your case, but still it's something to be aware of).
The second point is, in my opinion, something very important, as I would be very surprised to see that changes to a configuration variable at runtime have no effects.
Another option would be to mock the module that has your secrets.
This avoids needing to change your code to generate documentation.
Assuming you are using autodoc; add the below to your conf.py:
autodoc_mock_imports = ["config","secrets",]
https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html?highlight=autodoc_mock_imports%20#confval-autodoc_mock_imports
The autodoc_preserve_defaults configuration option was added in Sphinx 4.0.
The problem is solved by setting this option to True in conf.py. Default argument values of functions will not be evaluated and shown in the generated output.

AssertionError, altough the expected call looks same as actual call

I made a command in django which calls a function.
That function does a django orm call:
def get_notes():
notes = Note.objects.filter(number=2, new=1)
return [x.note for x in notes]
I want to patch the actual lookup:
#mock.patch('Note.objects.filter', autospec=True)
def test_get_all_notes(self, notes_mock):
get_notes()
notes_mock.assert_called_once_with(number=2, new=1)
I get the following assertion error:
AssertionError: Expected call: filter(number=2, new=1)
Actual call: filter(number=2, new=1)
I search on google and stackoverflow for hours, but I still haven't a clue.
Can anyone point me in the right direction, I think it might be an obvious mistake I'm making...
AFAIK you can't use patch() like this. Patch target should be a string in the form package.module.ClassName. I don't know much about django but I suppose Note is a class so Note.objects.filter is not something you can import and hence use in patch(). Also I don't think patch() can handle attributes. Actually I don't quite understand why the patch works at all.
Try using patch.object() which is specifically designed to patch class attributes. It implies Note is already imported in your test module.
#mock.patch.object(Note, 'objects')
def test_get_all_notes(self, objects_mock):
get_notes()
objects_mock.filter.assert_called_once_with(number=2, new=1)
I've removed autospec because I'm not sure it will work correctly in this case. You can try putting it back if it works.
Another option might be to use patch() on whatever you get with type(Note.objects) (probably some django class).
As I've said I don't know much about django so I'm not sure if these things work.

Include variables in template context on every page with Bottle.py

Is there a bottle.py equivalent of context processors that you get in Flask?
If you're using vanilla Bottle with SimpleTemplate, there is a solution I've stumbled upon.
For my site, I needed access to some functions in every template, app.get_url being obviously one of them. This worked for me:
# after app creation, but before the views
SimpleTemplate.defaults["get_url"] = app.get_url
SimpleTemplate.defaults["url"] = lambda: request.url
SimpleTemplate.defaults["fullpath"] = lambda: request.fullpath
SimpleTemplate.defaults["sorted"] = sorted
This works as of Bottle 0.9, I didn't test on more recent versions of the framework.
This behavior is undocumented, but Marcel Hellkamp explained it in this thread. In there, other solutions are also mentioned:
Pass over the globals in _vars or a similar template arg.
Create a decorator to supply the defaults.
Also, in Bottle 0.10, new functions related to the problem were introduced in the SimpleTemplate template namespace: defined, get, and setdefault
Using the previous answer from Helgi, I use this hook to make a context processor like (bottle 0.12.x) :
import bottle
#bottle.hook('before_request')
def _context_processor():
bottle.SimpleTemplate.defaults['foo'] = 'F00'
bottle.SimpleTemplate.defaults['bar'] = 'B#R'
Note: this same solution can be used with the other template engines. The technique is exactly the same, but you use BaseTemplate (it works for all template classes) or the class for the engine you want to use.

django lambda and django-activity-stream

I am not familiar with the lambda function itself, and don't really know how to debug this issue.
Django-1.1.2
I am using, django-activity-stream in order to render activity streams for my users.
In the documentation for this items it says that you need to pass two lambda functions to incorporate with existing newtworks, such as django-friends(the one I am using)
Here are the functions that need to be pasted into your settings.py file.
ACTIVITY_GET_PEOPLE_I_FOLLOW = lambda user: get_people_i_follow(user)
ACTIVITY_GET_MY_FOLLOWERS = lambda user: get_my_followers(user)
I have done so, but now everytime I try and render the page that makes use of this, I get the following traceback.
Caught NameError while rendering: global name 'get_people_i_follow' is not defined
Although this has been set in my settings...
Your help is much appreciated!
Somewhere above where these lambdas are defined, you need to import the names get_people_i_follow and get_my_followers. I'm not familiar with django-activity-stream, but it's probably something like from activity_stream import get_people_i_follow, get_my_follwers.
Lambda is a keyword for creating anonymous functions on the fly, so the meaning of your code is basically the same as if you had written the following.
def ACTIVITY_GET_PEOPLE_I_FOLLOW(user):
return get_people_i_follow(user)
def ACTIVITY_GET_MY_FOLLOWERS(user):
return get_my_followers(user)
You need to make sure that the functions get_people_i_follow and get_my_followers are imported into your settings files.
e.g.:
from activity_stream.models import get_people_i_follow, get_my_followers
Lambda is just a shorthand for defining a function so:
ACTIVITY_GET_PEOPLE_I_FOLLOW = lambda user: get_people_i_follow(user)
Is equivalent to:
def activity_get_people_i_follow(user):
return get_people_i_follow(user)
ACTIVITY_GET_PEOPLE_I_FOLLOW = activity_get_people_i_follow
Which upon reflection means you don't gain a lot in this case. However if you needed to avoid importing those function too early in your settings file (i.e. due to circular import) then you could do:
def activity_get_people_i_follow(user):
from activity_stream.models import get_people_i_follow
return get_people_i_follow(user)
ACTIVITY_GET_PEOPLE_I_FOLLOW = activity_get_people_i_follow
and just import the activity stream function as you need it.
UPDATE: looks like defining these settings is a red-herring:
https://github.com/philippWassibauer/django-activity-stream/blob/master/activity_stream/models.py#L133
As you can see these settings are only needed if you are not using the default activity streams. So simply remove them from your settings file.
The seg-fault is probably due to an infinite recursion occurring, as get_people_i_follow calls whatever function is defined by ACTIVITY_GET_PEOPLE_I_FOLLOW, which in this case calls get_people_i_follow again...
If you are integrating with a pre-existing network I don't believe you're actually supposed to write verbatim:
ACTIVITY_GET_PEOPLE_I_FOLLOW = lambda user: get_people_i_follow(user)
ACTIVITY_GET_MY_FOLLOWERS = lambda user: get_my_followers(user)
I believe the author was just showing an example that ACTIVITY_GET_PEOPLE_I_FOLLOW and
ACTIVITY_GET_MY_FOLLOWERS need to be set to a lambda or function that accepts one user argument and returns a list of users. You should probably be looking for something like friends_for_user in django-friends, or writing your own functions to implement this functionality.
get_people_i_follow is indeed defined in activity_stream.models but it is just importing what's defined in settings.py. So if settings.py has ACTIVITY_GET_PEOPLE_I_FOLLOW = lambda user: get_people_i_follow(user) you're going to get a wild and crazy circular import / infinite recursion.

In Python, what's a good pattern for disabling certain code during unit tests?

In general I want to disable as little code as possible, and I want it to be explicit: I don't want the code being tested to decide whether it's a test or not, I want the test to tell that code "hey, BTW, I'm running a unit test, can you please not make your call to solr, instead can you please stick what you would send to solr in this spot so I can check it". I have my ideas but I don't like any of them, I am hoping that there's a good pythonic way to do this.
You can use Mock objects to intercept the method calls that you do not want to execute.
E.g. You have some class A, where you don't want method no() to be called during a test.
class A:
def do(self):
print('do')
def no(self):
print('no')
A mock object could inherit from A and override no() to do nothing.
class MockA(A):
def no(self):
pass
You would then create MockA objects instead of As in your test code. Another way to do mocking would be to have A and MockA implement a common interface say InterfaceA.
There are tons of mocking frameworks available. See StackOverflow: Python mocking frameworks.
In particular see: Google's Python mocking framework.
Use Michael Foord's Mock
in your unit test do this:
from mock import Mock
class Person(object):
def __init__(self, name):
super(Person, self).__init__()
self.name = name
def say(self, str):
print "%s says \"%s\"" % (self.name, str)
...
#In your unit test....
#create the class as normal
person = Person("Bob")
#now mock all of person's methods/attributes
person = Mock(spec=person)
#talkto is some function you are testing
talkTo(person)
#make sure the Person class's say method was called
self.assertTrue(person.say.called, "Person wasn't asked to talk")
#make sure the person said "Hello"
args = ("Hello")
keywargs = {}
self.assertEquals(person.say.call_args, (args, keywargs), "Person did not say hello")
The big problem that I was having was with the mechanics of the dependency injection. I have now figured that part out.
I need to import the module in the exact same way in both places to successfully inject the new code. For example, if I have the following code that I want to disable:
from foo_service.foo import solr
solr.add(spam)
I can't seem to do this in the in my test runner:
from foo import solr
solr = mock_object
The python interpreter must be treating the modules foo_service.foo and foo as different entries. I changed from foo import solr to the more explicit from foo_service.foo import solr and my mock object was successfully injected.
Typically when something like this arises you use Monkey Patching (also called Duck Punching) to achieve the desired results. Check out this link to learn more about Monkey Patching.
In this case, for example, you would overwrite solr to just print the output you are looking for.
You have two ways to do this is no ,or minimal in the case of DI, modifications to your source code
Dependency injection
Monkey patching
The cleanest way is using dependency injection, but I don't really like extensive monkeypatching, and there are some things that are non-possible/difficult to do that dependency injection makes easy.
I know it's the typical use case for mock objects, but that's also an old argument... are Mock objects necessary at all or are they evil ?
I'm on the side of those who believe mocks are evil and would try to avoid changing tested code at all. I even believe such need to modify tested code is a code smell...
If you wish to change or intercept an internal function call for testing purpose you could also make this function an explicit external dependency set at instanciation time that would be provided both by your production code and test code. If you do that the problem disappear and you end up with a cleaner interface.
Note that doing that there is not need to change the tested code at all neither internally nor by the test being performed.

Categories

Resources