How to create a decorator that swallows sys.stdout using unittest.mock.patch function? - stdout

I'm trying to create a Python Mixin for my unit-tests testing functions with return values and sys.stdout. I want the Mixin to have a method that will work as a decorator for swallowing the sys.stdout, but I haven't been successful so far.
My custom the decorator should:
swallow sys.stdout produced by the tested function
use the unittest.mock.patch function as decorator to achieve that
not accept any input (to keep the code clean)
My attempt of the decorator:
import io
import sys
import unittest.mock
class StdoutUnittestMixin(unittest.TestCase):
#unittest.mock.patch('sys.stdout', new_callable=io.StringIO)
def monkey_patch_stdout(self, original_function, mock_stdout):
def wrapper_function(*args, **kwargs):
captured_output = io.StringIO() # Create StringIO object
sys.stdout = captured_output # and redirect stdout.
return_value = original_function(*args, **kwargs) # Call unchanged function.
sys.stdout = sys.__stdout__ # Reset redirect.
return return_value
return wrapper_function
Example of tested function:
def foo(some_str):
print(some_str)
return some_str.isnumeric()
Desired use of the decorater in a unit test:
class Testing(unittest.TestCase):
#monkey_patch_stdout # The decorator wants inputs - I don't want that
def test_function_outputs_true(self):
self.assertTrue(foo("123"))
As expected, I get:
TypeError: assert_True() missing 1 required positional argument: 'mock_stdout'
As, I understand mock_stdout needs to be there because the unittest.mock.patch decorator requires that.

I've found out there were two problems:
1) As I was notified by #kdojeteri, thank you, there's a duplication of the monkey patch logic by using the unittest.patch.mock decorator
2) the sys.stdout = sys.__stdout__ line was messing things up. When I saved the reference for sys.stdout into a new variable and then used that to reset sys.stdout it worked.
Although it's not satisfying one of my requirements, the final working code is below.
The mixin method:
import io
import sys
import unittest.mock
class StdoutUnittestMixin(unittest.TestCase):
#staticmethod
def monkey_patch_stdout(original_function):
"""
:param original_function: Decorated function which is expected to have stdout
:return: Wrapped function which uses monkey patching for the sys.stdout object
"""
def wrapper_function(*args, **kwargs):
captured_output = io.StringIO() # Create StringIO object
my_stdout = sys.stdout # Saving reference for sys.stdout
sys.stdout = captured_output # and redirect stdout.
return_value = original_function(*args, **kwargs) # Call unchanged function.
sys.stdout = my_stdout # Reset redirect.
return return_value
return wrapper_function
The tested function:
def foo(some_str):
print(some_str)
return some_str.isnumeric()
The testing method:
class Testing(unittest.TestCase):
#StdoutUnittestMixin.monkey_patch_stdout
def test_wrong_input_outputs_false_with_short_str(self):
self.assertTrue(foo("123"))

Related

Create dummy asyncio.Task

How can I create dummy Task object that will be immediately done?
Why?
I often check if task is not None and task.done() just to check if another task can be spawn and feel it's a boilerplate that can be avoided:
def __init__(self):
self._do_something_task: Optional[asyncio.Task] = None
async def _do_something(self):
await asyncio.sleep(10)
# something
def trigger_do_something(self):
if self._do_something_task is not None and self._do_something_task.done():
asyncio.create_task(self._do_something())
Currently my workaround is:
def __init__(self):
self._do_something_task: asyncio.Task = asyncio.create_task(asyncio.sleep(0))
async def _do_something(self):
await asyncio.sleep(10)
# something
def trigger_do_something(self):
if self._do_something_task.done():
asyncio.create_task(self._do_something())
but I feel its not very readable at the first glance.
Python is a language with duck typing, so as long as some object can answer if it's done(), it should do the job:
class DummyTask:
def done(self):
return True
print(DummyTask().done()) # True
More smart way to do it is to use mock library.

Ruby Converting a variable into a constant at runtime

I'm trying to create a module that will be included in many different classes. It needs to record the caller's path to the class file
so I can reference the path in later code. This code tries to add a method to the calling class, but fails because it just returns the current value of ##x.
# /home/eric/FindMe.rb
class FindMe
include GladeGUI
end
# /home/eric/GladeGUI.rb
module GladeGUI
def self.included(obj)
##x, = caller[0].partition(":") # this works ##x = "/home/eric/FindMe.rb"
obj.class_eval do
def my_class_file_path
return ????? # I want to return "/home/eric/FindMe.rb"
end
end
end
end
The GladeGUI module will be "included" in many different classes, so I can't just add code to the calling class. I need a way to make ##x compile into a constant value, so the method stored in the class looks like this:
def my_class_file_path
return "/home/eric/FindMe.rb"
end
How do I convert a variable to a constant in code?
Thanks.
It seems like you don't actually need it to be a "constant" - you just need some way to make the method return the correct value all the time and not allow other code to come along and change the value (with the current ##x solution, someone can just modify ##x and it will break)
The solution is to store the data in a local variable instead of a class or instance variable, and then access that local variable via a closure.
No other code will have scope to 'see' the local variable and thus it cannot be changed.
But then the problem becomes that when you use def inside a class_eval, the scope of the caller isn't captured, so the code can't see your local variable. You can use define_method instead
Here's an example
# /home/eric/GladeGUI.rb
module GladeGUI
def self.included(obj)
caller_file_path = caller[0].split(":").first
obj.class_eval do
define_method :my_class_file_path do
return caller_file_path
end
end
end
end
# /home/eric/FindMe.rb
class FindMe
include GladeGUI
end
puts FindMe.new.my_class_file_path # prints the correct path
But - what if you want my_class_file_path to be a class method rather than an instance method - use define_singleton_method instead:
module GladeGUI
def self.included(obj)
caller_file_path = caller[0].split(":").first
obj.class_eval do
define_singleton_method :my_class_file_path do
return caller_file_path
end
end
end
end
...
puts FindMe.my_class_file_path
Interesting side note: This is how you can fake "private variables" in javascript :-)

How can I call methods within controller (RoR)?

I am very new to RoR and I have played around the source code. But I have a problem that I already built a 'def A' for creating first CSV file, and 'def B' for creating second CSV file. Each 'def' has its own button, but I have the third button to create all CSVs (to produce output from first and second CSV files.)
What is the possible way to do it?
def first_csv
...
end
def second_csv
..
end
def all_csv
<< how to call get first and second csv >>
end
Thanks in advance,
It should be as simple as you imagine:
def all_csv
first_csv
second_csv
end
Muntasim's answer is correct, but I have to add some additional information.
Ruby provides two types of methods..class methods and instance methods.
class MyClass < AvtiveRecord::Base
# class method
def self.foo
# do something
# within this scope the keyword "self" belongs to the class
end
# another class method which calls internally the first one
def self.bar
something = foo # self.foo could also be written
# do something with something
# within this scope the keyword "self" belongs to the class
end
# instance method
def foo
# do something
# if you use the keyword "self" within an instance method, it belongs to the instance
end
# another instance method which calls class and the first instance method
def bar
mystuff = Myclass.bar # if you want to call the class method you cannot use "self", you must directly call the class
mystuff2 = foo # self.foo is the same, because of the instance scope
return [mystuff, mystuff2]
end
end
You can call the last instance method like following
instance = MyClass.first
instance.bar

Call module subclass without specify the name

I would like to access my subclass using only the name of my module.
module MyModule
class UselessName
include OtherModel
# only self method
def self.x
end
end
# No other class
end
And I would like to write MyModule.x and not MyModule::UselessName.x
I could transform my module in class, but I use RoR Helpers, and I would prefer that MyModule remains a module and not a class.
Is there a way to do this ?
Thanks ;)
OK, let's split problem into two - getting list of such methods and making proxies in the module.
Getting list might be a little tricky:
MyModule::UselessName.public_methods(false) - MyModule::UselessName.superclass.public_methods(false)
Here we start with list of all public class methods and subtract list of all superclass's public class methods from it.
Now, assuming we know method's name, we need to make proxy method.
metaclass = class << MyModule; self; end
metaclass.send(:define_method, :x) do |*args, &block|
MyModule::UselessName.send(:x, *args, &block)
end
This code will just make equivalent of following definition at runtime.
module MyModule
def x(*args, &block)
MyModule::UselessName.send(:x, *args, &block)
end
end
So let's put it together in simple function.
def make_proxies(mod, cls)
methods = cls.public_methods(false) - cls.superclass.public_methods(false)
metaclass = class << mod; self; end
methods.each do |method|
metaclass.send(:define_method, method) do |*args, &block|
cls.send(method, *args, &block)
end
end
end
So now you'll just need to call it for needed modules and classes. Note that "destination" module can be different from "source" module owning the class, so you can slurp all methods (given they have different names or you'll prefix them using class name) to one module. E.g. for your case just make following call.
make_proxies(MyModule, MyModule::UselessName)
Ok, I've found a VERY DIRTY way to accomplish what I THINK you mean:
module MyModule
class UselessName
include OtherModule
# have whatever you want here
end
def self.x
# whatever
end
end
So somewhere in your code you can do, and I repeat THIS IS VERY, VERY DIRTY!
MyModule.methods(false).each do |m|
# m = method
# now you can redefine it in your class
# as an instance method. Not sure if this
# is what you want though
MyModule::UselessName.send(:define_method, :m) do
# in this NEW (it's not the same) method you can
# call the method from the module to get the same
# behaviour
MyModule.send(m)
end
end
I don't know if this overwrites an instance method with the same name if it's in the class before or if it throws an exception, you have to try that.
In my opinion you should overthink your app design, because this is not the way it should be, but here you go...

Ruby: Alter class static method in a code block

Given the Thread class with it current method.
Now inside a test, I want to do this:
def test_alter_current_thread
Thread.current = a_stubbed_method
# do something that involve the work of Thread.current
Thread.current = default_thread_current
end
Basically, I want to alter the method of a class inside a test method and recover it after that.
I know it sound complex for another language, like Java & C# (in Java, only powerful mock framework can do it). But it's ruby and I hope such nasty stuff would be available
You might want to take a look at a Ruby mocking framework like Mocha, but in terms of using plain Ruby it can be done using alias_method (documentation here) e.g.
beforehand:
class Thread
class << self
alias_method :old_current, :current
end
end
then define your new method
class Thread
def self.current
# implementation here
end
end
then afterwards restore the old method:
class Thread
class << self
alias_method :current, :old_current
end
end
Update to illustrate doing this from within a test
If you want to do this from within a test you could define some helper methods as follows:
def replace_class_method(cls, meth, new_impl)
cls.class_eval("class << self; alias_method :old_#{meth}, :#{meth}; end")
cls.class_eval(new_impl)
end
def restore_class_method(cls, meth)
cls.class_eval("class << self; alias_method :#{meth}, :old_#{meth}; end")
end
replace_class_method is expecting a class constant, the name of a class method and the new method definition as a string. restore_class_method takes the class and the method name and then aliases the original method back in place.
Your test would then be along the lines of:
def test
new_impl = <<EOM
def self.current
"replaced!"
end
EOM
replace_class_method(Thread, 'current', s)
puts "Replaced method call: #{Thread.current}"
restore_class_method(Thread, 'current')
puts "Restored method call: #{Thread.current}"
end
You could also write a little wrapper method which would replace a method, yield to a block and then ensure that the original method was reinstated afterwards e.g.
def with_replaced_method(cls, meth, new_impl)
replace_class_method(cls, meth, new_impl)
begin
result = yield
ensure
restore_class_method(cls, meth)
end
return result
end
Inside your test method this could then be used as:
with_replaced_method(Thread, 'current', new_impl) do
# test code using the replaced method goes here
end
# after this point the original method definition is restored
As mentioned in the original answer, you can probably find a framework to do this for you but hopefully the above code is interesting and useful anyway.

Resources