how to print source code of object I defined use %edit magic - ipython

Ipython 0.13.1 can print the source of an object from python library,
such as, os.path.abspath??
But I can't print the source code of any object I defined through %ed magic in ipython,
Is anything wrong I did?
such as, I define a class Name through %ed magic:
%ed
then
class Name(object):
"""docstring for Name"""
name = 'hong'
def __init__(self, arg):
super(Name, self).__init__()
self.arg = arg
def pri():
print 'class Name'
when back to ipython, I can't see the source code of class Name:
In [59]: Name??
Type: type
String Form:<class '__main__.Name'>
Docstring: docstring for Name
Constructor information:
Definition:Name(self, arg)
Is this the bug of IPython?

--Edits after OP mentioned this is seen in ipython iteself.
Is there any error message you get after typying %ed myfunc? Pasting that might help others find the issue.
---update:
I also get a short version of the source code when I try Name??, but Name.pri?? gives me the full source code of the pri() member function of the Name class. So ipython may have some convention to not give full source code of classes.
Here is my interaction:
In [2]: Name??
Type: type
String Form:<class '__main__.Name'>
Docstring: docstring for Name
Constructor information:
Definition:Name(self, arg)
In [3]: Name.pri??
Type: instancemethod
String Form:<unbound method Name.pri>
File: /tmp/ipython_edit_8YOfN9.py
Definition: Name.pri()
Source:
def pri():
print 'class Name'
In [4]:

Recent versions of IPython (not sure of the exact version number) actually do show the source:
IPython 0.13 -- An enhanced Interactive Python.
? -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help -> Python's own help system.
object? -> Details about 'object', use 'object??' for extra details.
In [1]: %ed
IPython will make a temporary file named: /var/folders/88/zgy_z51x1fn2mp_7vmkj3phm0000gn/T/ipython_edit_g9xYY4.py
Editing... done. Executing edited code...
Out[1]: 'def f(a):\n\treturn a + 3\n'
In [2]: f(4)
Out[2]: 7
In [3]: f??
Type: function
String Form:<function f at 0x18ddb30>
File: /var/folders/88/zgy_z51x1fn2mp_7vmkj3phm0000gn/T/ipython_edit_g9xYY4.py
Definition: f(a)
Source:
def f(a):
return a + 3
There are two other ways to get the source. One is if you can go back to the line where you called %ed, the return value should be the source code (here, this is Out[1], so you could do print Out[1]). Another is to call %ed f — this is supposed to load up the current definition of f into the editor, and allow you to edit the definition.

Related

Unknown marker with pytest-bdd only when parameter is declared

When I declare a marker in pytest.ini having a parameter, this is not recognized in pytest-bdd feature file. Markers without parameters seem to work fine.
[pytest]
markers =
swr(issue1): link to Software Requirement
smoke: Smoke Test component
Simple feature file works fine with #smoke:
Feature: Trivial Example
#smoke
Scenario: Add a number to another number
Given 7 is set
When 9 is added
Then new value is 16
Fails with #swr("123"):
Feature: Trivial Example
#swr("123")
Scenario: Add a number to another number
Given 7 is set
When 9 is added
Then new value is 16
Failure is a warning:
../../../../../.local/lib/python3.10/site-packages/pytest_bdd/plugin.py:127
/home/parallels/.local/lib/python3.10/site-packages/pytest_bdd/plugin.py:127: PytestUnknownMarkWarning: Unknown pytest.mark.swr("123") - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/how-to/mark.html
mark = getattr(pytest.mark, tag)
Taking a look in the known issues in the repository I stumbled upon something that is related. The developer mentions there is a hook available which is seen here.
In the conftest.py we can then do the following:
from typing import Callable, cast
import pytest
import ast
def pytest_bdd_apply_tag(tag: str, function) -> Callable:
tree = ast.parse(tag)
body = tree.body[0].value
if isinstance(body, ast.Call):
name = body.func.id
arg = body.args[0].value
mark = getattr(pytest.mark, name).with_args(arg)
else:
mark = getattr(pytest.mark, tag)
marked = mark(function)
return cast(Callable, marked)
Then we can just register the marker as swr and the hook should automatically parametrize the function as needed. It uses ast to parse the marker and dynamically create the new marker. Shown below is what mark looks like when running with swr or swr("123").
platform darwin -- Python 3.9.6, pytest-7.2.0, pluggy-1.0.0
rootdir: ***, configfile: pytest.ini
plugins: bdd-6.1.1
collecting ...
MarkDecorator(mark=Mark(name='swr', args=('123',), kwargs={}))
collected 1 item
platform darwin -- Python 3.9.6, pytest-7.2.0, pluggy-1.0.0
rootdir: ***, configfile: pytest.ini
plugins: bdd-6.1.1
collecting ...
MarkDecorator(mark=Mark(name='swr', args=(), kwargs={}))
collected 1 item
Take note of MarkDecorator in the output for each of the calls.

How to do 2-way data binding using Python+PyGObject's GObject.bind_property function?

The background to this question (and my overall goal) is to structure a Python GTK application in a nice way. I am trying to bind widget properties to model properties using GTK's bidirectional data bindings.
My expectation is that the bidirectional binding should keep two properties in sync. I find instead that changes propagate in one direction only, even though I am using the GObject.BindingFlags.BIDIRECTIONAL flag. I created the following minimal example and the failing test case test_widget_syncs_to_model to illustrate the problem. Note that in a more realistic example, the model object could be an instance of Gtk.Application and the widget object could be an instance of Gtk.Entry.
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GObject
import unittest
class Obj(GObject.Object):
"""A very simple GObject with a `txt` property."""
name = "default"
txt = GObject.Property(type=str, default="default")
def __init__(self, name, *args, **kwargs):
super().__init__(*args, **kwargs)
self.name = name
self.connect("notify", self.log)
def log(self, source, parameter_name):
print(
f"The '{self.name}' object received a notify event, "
f"its txt now is '{self.txt}'."
)
class TestBindings(unittest.TestCase):
def setUp(self):
"""Sets up a bidirectional binding between a model and a widget"""
print(f"\n\n{self.id()}")
self.model = Obj("model")
self.widget = Obj("widget")
self.model.bind_property(
"txt", self.widget, "txt", flags=GObject.BindingFlags.BIDIRECTIONAL
)
#unittest.skip("suceeds")
def test_properties_are_found(self):
"""Verifies that the `txt` properties are correctly set up."""
for obj in [self.model, self.widget]:
self.assertIsNotNone(obj.find_property("txt"))
#unittest.skip("suceeds")
def test_model_syncs_to_widget(self, data="hello"):
"""Verifies that model changes propagate to the widget"""
self.model.txt = data
self.assertEqual(self.widget.txt, data)
def test_widget_syncs_to_model(self, data="world"):
"""Verifies that widget changes propagate back into the model"""
self.widget.txt = data
self.assertEqual(self.widget.txt, data) # SUCCEEDS
self.assertEqual(self.model.txt, data) # FAILS
if __name__ == "__main__":
unittest.main()
The above program outputs:
ssF
======================================================================
FAIL: test_widget_syncs_to_model (__main__.TestBindings)
Verifies that widget changes propagate back into the model
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/jh/.config/JetBrains/PyCharmCE2021.1/scratches/scratch_14.py", line 52, in test_widget_syncs_to_model
self.assertEqual(self.model.txt, data) # FAILS
AssertionError: 'default' != 'world'
- default
+ world
----------------------------------------------------------------------
Ran 3 tests in 0.001s
FAILED (failures=1, skipped=2)
__main__.TestBindings.test_widget_syncs_to_model
The 'widget' object received a notify event, its txt now is 'world'.
Process finished with exit code 1
My specific question is, how can I get the bidirectional data bindings to work?... I would be glad if someone could fix my example or provide another working example.
In a broader sense, are bidirectional bindings the way to go for syncing UI state and model state in a well-structured Python GTK application? What is the intended and well-supported way to do this? thanks!
I got an answer over at the gnome discourse thread about bidirectional property bindings in python.
To make it even more clear, the following code does not work because flags are not passed correctly:
# broken, flags are passed incorrectly as keywords argument:
self.model.bind_property("txt", self.widget, "txt", flags=GObject.BindingFlags.BIDIRECTIONAL)
Instead, flags must be passed as follows:
# functioning, flags are passed correctly as a positional argument:
self.model.bind_property("txt", self.widget, "txt", GObject.BindingFlags.BIDIRECTIONAL)
More example code: Proper use of bidirectional bindings is for example demonstrated in pygobject’s source code in the test_bidirectional_binding test case.

Atom-Editor: Failed to load init.coffee - ERROR: reserved word 'function'

UPDATE: I found a solution/workaround for the problem. I renamed init.coffee to init.js because Atom also supports JavaScript. I would still like to know the cause of the problem. Is the script below not valid CoffeeScript or am I missing some dependence? I Installed Atom from the official Arch repositories.
For some reason my init.coffee cannot be loaded. The following code is from Atom's "Composed" Commands documentation:
atom.commands.add('atom-text-editor', 'custom:cut-line', function () {
const editor = this.getModel();
editor.selectLinesContainingCursors();
editor.cutSelectedText();
});
Atom throws an error when it starts:
Failed to load /home/myname/.atom/init.coffee
reserved word 'function'
I'm not sure if this is a bug, my fault, or a result of out-of-date documentation. The error message isn't super helpful, since I already that "function" is a reserved word, even though I don't know a lot of Coffee/JavaScript.
I replaced function using () -> {...}, which resulted in the same error except this time for the reserved word const.
Finally, I tried defining a named function which I passed as an argument to atom.commands.add() and got the same error.
I'm on Linux. atom --version returns:
Atom : 1.46.0
Electron: 4.2.12
Chrome : 69.0.3497.128
Node : 10.11.0
Your solution is the right direction - that code is JavaScript, not CoffeeScript.
It looks like the '"Composed" Commands' documentation you referenced is using both JavaScript and CoffeeScript in their examples.
To convert from JavaScript:
atom.commands.add('atom-text-editor', 'custom:cut-line', function () {
const editor = this.getModel();
editor.selectLinesContainingCursors();
editor.cutSelectedText();
});
to CoffeeScript:
atom.commands.add 'atom-text-editor', 'custom:cut-line', () ->
editor = #getModel()
editor.selectLinesContainingCursors()
editor.cutSelectedText()
When calling a function with arguments, you can leave out the parenthesis ().
function is removed in CoffeeScript, just use parenthesis and either a single -> or double arrow =>, where a double arrow is the same as .bind(this), so that would be incorrect here.
No const/let/var keywords. Just defined the variable without them.
this. can be replaced with #.
Braces ({}) wrapping function definitions are optional.
No semicolons.
If you want to learn CoffeeScript and help the community, you could fix the documentation yourself by forking, editing and making a pull request of the repository.
Alternatively, you should report this error in the documentations in their repository as an issue.

How to get PyTest fixtures to autocomplete in PyCharm (type hinting)

I had a bear of a time figuring this out, and it was really bugging me, so I thought I'd post this here in case anyone hit the same problem...
(and the answer is so dang simple it hurts :-)
The Problem
The core of the issue is that sometimes, not always, when dealing with fixtures in PyTest that return objects, when you use those fixtures in a test in PyCharm, you don't get autocomplete hints. If you have objects with large numbers of methods you want to reference while writing a test, this can add a lot of overhead and inconvenience to the test writing process.
Here's a simple example to illustrate the issue:
Let's say I've got a class "event_manager" that lives in:
location.game.events
Let's further say that in my conftest.py file (PyTest standard thing for the unfamiliar), I've got a fixture that returns an instance of that class:
from location.game.events import event_manager
...
#pytest.fixture(scope="module")
def event_mgr():
"""Creates a new instance of event generate for use in tests"""
return event_manager()
I've had issues sometimes, (but not always - I can't quite figure out why) with classes like this where autocomplete will not work properly in the test code where I use the fixture, e.g.
def test_tc10657(self, evt_mgr):
"""Generates a Regmod and expects filemod to be searchable on server"""
evt_mgr.(This does not offer autocomplete hints when you type ".")
So the answer is actually quite simple, once you review type hinting in PyCharm:
http://www.jetbrains.com/help/pycharm/2016.1/type-hinting-in-pycharm.html
Here's how to fix the above test code so that autocomplete works properly:
from location.game.events import event_manager
...
def test_tc10657(self, evt_mgr: event_manager):
"""Generates a Regmod and expects filemod to be searchable on server"""
evt_mgr.(This DOES offer hints when you type "." Yay!)
Notice how I explicitly type the fixture as an input parameter of type event_manager.
Also if you add a docstring to a function and specify the type of the the parameters, you will get the code completion for those parameters.
For example using pytest and Selenium:
# The remote webdriver seems to be the base class for the other webdrivers
from selenium.webdriver.remote.webdriver import WebDriver
def test_url(url, browser_driver):
"""
This method is used to see if IBM is in the URL title
:param WebDriver browser_driver: The browser's driver
:param str url: the URL to test
"""
browser_driver.get(url)
assert "IBM" in browser_driver.title
Here's my conftest.py file as well
import pytest
from selenium import webdriver
# Method to handle the command line arguments for pytest
def pytest_addoption(parser):
parser.addoption("--driver", action="store", default="chrome", help="Type in browser type")
parser.addoption("--url", action="store", default='https://www.ibm.com', help="url")
#pytest.fixture(scope='module', autouse=True)
def browser_driver(request):
browser = request.config.getoption("--driver").lower()
# yield the driver to the specified browser
if browser == "chrome":
driver = webdriver.Chrome(executable_path='/path/to/chromedriver')
else:
raise Exception("No driver for browser " + browser)
yield driver
driver.quit()
#pytest.fixture(scope="module")
def url(request):
return request.config.getoption("--url")
Tested using Python 2.7 and PyCharm 2017.1. The docstring format is reStructuredText and the "Analyze Python code in docstrings" checkbox is checked in settings.

Executing Python Code in IPython Kernel

I want to duplicate ipython notebook capability in Emacs / Pymacs; and I need some direction for a simple code that can 1) send python / "magics" code to a ipython kernel 2) receive the display output, as a string. I found this comment by minrk, the "ipython kernel" example did not work, it gave "ImportError: No module named zmq.blockingkernelmanager".
I had better luck with one his other pointers, finally I landed at ipython-1.1.0/IPython/kernel/inprocess/tests/test_kernel.py, I ripped out a minimal part, and coded an Emacs extension called pytexipy-notebook. It's on Github
goo.gl/kQzJW1
If anyone knows of better examples, such as connecting to an existing (out of process), I'd like to hear about these.
Thanks in advance,
Here is a sample for ipython 3.0.
from IPython.testing.globalipapp import get_ipython
from IPython.utils.io import capture_output
ip = get_ipython()
def run_cell(cmd):
with capture_output() as io:
res = ip.run_cell(content)
print 'suc', res.success
print 'res', res.result
res_out = io.stdout
print 'res out', res_out
content = "print (111+222)"
run_cell(content)
content = "alsdkjflajksf"
run_cell(content)
I will soon update
https://github.com/burakbayramli/emacs-ipython