Replace wx.PyLog with what? - python

I'm porting some Python code from 2.7 to 3.x. The original code fails with this error:
class myTextLog(wx.PyLog):
AttributeError: 'module' object has no attribute 'PyLog'
When checking for the presence of wx.PyLog it is indeed not there:
>>> import wx
>>> wx.PyLog
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'PyLog'
>>> wx.version()
u'4.1.0 msw (phoenix) wxWidgets 3.1.4'
When I check for the presence of wx.PyLog in an older version of wx, it is there:
>>> import wx
>>> wx.PyLog
<class 'wx._misc.PyLog'>
>>> wx._misc
<module 'wx._misc' from '/usr/lib/python2.7/site-packages/wx-3.0-gtk2/wx/_misc.pyc'>
>>> wx.version()
'3.0.2.0 gtk2 (classic)'
I see it being used in this old sample code: http://www2.geog.ucl.ac.uk/~plewis/bpms/src/start/Main.py
#---------------------------------------------------------------------------
# Show how to derive a custom wxLog class
class MyLog(wx.PyLog):
def __init__(self, textCtrl, logTime=0):
wx.PyLog.__init__(self)
self.tc = textCtrl
self.logTime = logTime
def DoLogString(self, message, timeStamp):
#print message, timeStamp
#if self.logTime:
# message = time.strftime("%X", time.localtime(timeStamp)) + \
# ": " + message
if self.tc:
self.tc.AppendText(message + '\n')
Somewhere along the line it appears to have been removed. What would be a suitable replacement for the code above given wx.PyLog is no longer available?

In python 3.x you should use: logging
You will want to take a look at Logging HOWTO
import logging
logging.basicConfig(filename='example.log', encoding='utf-8', level=logging.DEBUG)
logging.debug('This message should go to the log file')
logging.info('So should this')
logging.warning('And this, too')
logging.error('And non-ASCII stuff, too, like Øresund and Malmö')

Related

'str' object has no attribute 'from_directory_url' in python

I am trying to make the call
from azure.storage.fileshare import ShareDirectoryClient
shrdDirClient = ShareDirectoryClient.from_directory_url
(detailedFileURI,snapshot=None, credential=None)
but resulted in the error above.
I tried
if hasattr(ShareDirectoryClient, 'from_directory_url'):
print("Present")
But it did not go into the loop.
My full code is too long. This is another approach I tried resulting in 'str' object is not callable error
from azure.storage.fileshare import ShareDirectoryClient
from datetime import timedelta,datetime
now = datetime.now(timezone('UTC'))
sasToken = generate_share_sas(accountName, shareName, accountKey,\
permission=AccountSasPermissions(read=True, \
write=False, \
delete=False, \
list=True, create=True), expiry=now + timedelta(days=3650)\
)
accountURL = "https://nsclusterhdistorage.file.core.windows.net"
shareName = "dev-archived-data"
detailedFileURI = accountURL+'/'+shareName
sh = ShareDirectoryClient()
sh.from_directory_url(detailedFileURI,snapshot=None, credential=sasToken)
I am relatively new to python azure storage file share.
can someone help
Sorry, I can't reproduce this.
I ran the following code:
from azure.storage.fileshare import ShareDirectoryClient
detailedFileURI = "Something"
shrdDirClient = ShareDirectoryClient.from_directory_url(detailedFileURI,snapshot=None, credential=None)
and it generated the following error:
Traceback (most recent call last):
File "D:\StackOverflow\azure_storage_test.py", line 4, in <module>
shrdDirClient = ShareDirectoryClient.from_directory_url(detailedFileURI,snapshot=None, credential=None)
File "C:\Python37\lib\site-packages\azure\storage\fileshare\_directory_client.py", line 164, in from_directory_url
credential=credential, **kwargs)
File "C:\Python37\lib\site-packages\azure\storage\fileshare\_directory_client.py", line 96, in __init__
raise ValueError("Please specify a share name.")
ValueError: Please specify a share name.
Now clearly this isn't successful execution. If I'm honest, I don't know what to set detailedFileURI to. But that's not the point. The point is that the code sample above is enough to prove that I can get in to the from_directory_url method, and this is clear from the traceback.
However, if I run the following code:
from azure.storage.fileshare import ShareDirectoryClient
ShareDirectoryClient = "some string"
detailedFileURI = "Something"
shrdDirClient = ShareDirectoryClient.from_directory_url(detailedFileURI,snapshot=None, credential=None)
then I do encounter the same error:
Traceback (most recent call last):
File "D:\StackOverflow\azure_storage_test.py", line 5, in <module>
shrdDirClient = ShareDirectoryClient.from_directory_url(detailedFileURI,snapshot=None, credential=None)
AttributeError: 'str' object has no attribute 'from_directory_url'
Of course, there's not a lot of point in importing ShareDirectoryClient if you're then going to assign a string to it. You may as well remove the import statement. However, doing this reproduces your error message. In the absence of any further code in your question I can only conclude that your code does the same as this, although perhaps more subtly.
The only other suggestion I have is that your installation of the azure-storage-file-share package has somehow got broken. If you run a Python script containing the following two lines only, you should get either <class 'type'> or <class 'str'> as output. I get <class 'type'>, and I would expect that anyone else using this package would get the same. However, if you get <class 'str'>, then it is likely that the package has got corrupted and you may want to try reinstalling it.
from azure.storage.fileshare import ShareDirectoryClient
print(type(ShareDirectoryClient))
For some reason ‘ ShareDirectoryClient’ is of type {string}. You either import it as a string, i.e. ‘ azure.storage.fileshare’ simply has this defined as a string, or, you assign it to a string later in your code (not visible in the part that has been shared). Please try this:
X = ‘some_string’
X()
… and you will get the string-is-not-callable error which means a string cannot be invoked (i.e. it is not a function one can call)
Then another experiment:
Y = ‘another_string’
Y.bla()
… and you get the other error that a string object has no attribute named ‘bla’.
In Python everything is an object. If you define
class MyClass()
pass
And then try ‘MyClass.bla()’ you will get MyClass does does not have attribute ‘bla’.
Can you try to import ShareDirectoryClient and then type(ShareDirectoryClient) and we’ll see what type of object gets imported.

functools.partial as IronPython EventHandler

I'm currently trying out the IronPython interpreter. While doing the Tutorial i came across delegates and event handlers. The tutorial does something like this:
from System.IO import FileSystemWatcher
w = FileSystemWatcher()
def handle(*args):
print args
w.Changed += handle
So i tried to be smart and do this:
from System.IO import FileSystemWatcher
from __future__ import print_function
from functools import partial
w = FileSystemWatcher()
w.Changed += partial(print, "Changed: ")
Which failed with:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Object is not callable.
Where line 1 refers to the last line in the (interactive session)
So IronPython thinks a partial object is not callable although callable(partial(print, "Changed: ")) returns True
With this workaround the handler is accepted:
w.Changed += partial(print, "Changed: ").__call__
My question:
Why is a partial object not accepted as an event handler. Is this a bug?
This is probably not solution, one could expect, but there is an issue, opened for couple years now - https://github.com/IronLanguages/main/issues/808
Doesn't work in 2.6.2 and 2.7b1 on .NET Version: 4.0.30319.1 ipy26
testcase-26482.py
Object is not callable.
ipy27 testcase-26482.py
Object is not callable.py
testcase-26482.py
Object is not callable.

When can you dynamically add a field to an object?

I'm learning curses in python, and wanted to add an attribute to the curses window object.
my minimal program is:
import curses
try:
stdscr = curses.initscr()
stdscr.cur_line = 0
finally:
#clean-up so your terminal isn't wrecked by above error
curses.nocbreak()
stdscr.keypad(False)
curses.echo()
curses.endwin()
The error is:
$ python3 tmp
Traceback (most recent call last):
File "tmp", line 4, in <module>
stdscr.cur_line = 0
AttributeError: '_curses.curses window' object has no attribute 'cur_line'
However, this works:
class Temp:
def __init__(self):
pass
t = Temp()
t.cur_line = 0 #does not fail
My questions is: When does dynamically adding a field to an instance fail? How is python discerning between an instance of my user defined class, and an instance of the class from the curses library?
Most often, this happens because you're trying to add attributes to libraries written in C, and not pure python objects.
>>> import pickle, cPickle
>>> pickle.dump.a=1
>>> cPickle.dump.a=1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'builtin_function_or_method' object has no attribute 'a'

Coloring exceptions from Python on a terminal

Is there an easy way to get the message of the exception to be colored on the command line? For example
def g(): f()
def f(): 1/0
g()
Gives the error
Traceback (most recent call last):
File "test.py", line 3, in <module>
g()
File "test.py", line 1, in g
def g(): f()
File "test.py", line 2, in f
def f(): 1/0
ZeroDivisionError: integer division or modulo by zero
I would like "integer division or modulo by zero" to be colored or highlighted on the terminal so that I can quickly pick it out of a long traceback (Linux only). Ideally, I wouldn't want to write a custom class for each Exception, but somehow catch and format all kinds.
EDIT: The question linked in the comments gives examples on how to solve the problem with external software, but I'm interested in an internal Python solution.
You can assign a custom function to the sys.excepthook handler. The function is called whenever there is a unhandled exception (so one that exits the interpreter).
def set_highlighted_excepthook():
import sys, traceback
from pygments import highlight
from pygments.lexers import get_lexer_by_name
from pygments.formatters import TerminalFormatter
lexer = get_lexer_by_name("pytb" if sys.version_info.major < 3 else "py3tb")
formatter = TerminalFormatter()
def myexcepthook(type, value, tb):
tbtext = ''.join(traceback.format_exception(type, value, tb))
sys.stderr.write(highlight(tbtext, lexer, formatter))
sys.excepthook = myexcepthook
set_highlighted_excepthook()
This version uses the pygments library to convert the traceback text into one formatted with ANSI coloring, before writing it to stderr.
Someone turned this into a project that detects terminal support and lets you set the pygments style, see colored-traceback.py.
Found another way to do this using the IPython module which is likely a dependency that everyone already has installed:
from IPython.core.ultratb import ColorTB
c = ColorTB()
exc = sys.exc_info()
print(''.join(c.structured_traceback(*exc)))
This takes the solution #freakish shared and makes the colorization part of the exception instead of requiring the user to add color to each exception message. Obviously, it only works for custom exceptions, so it may not be exactly what OP was looking for.
from colorama import Fore, init
init()
class Error (Exception):
def __init__ (self, message):
super().__init__(Fore.RED + message)
class BadConfigFile (Error):
pass
raise BadConfigFile("some error message")
This will print the traceback with "some error message" in red. Having 'Error' as a base class means you can create other exceptions that will all inherit the colorization of the message.
Have a look at colorama ( or any other coloring ) module. Then you can wrap you're entire app with:
import traceback
from colorama import Fore, init
init( )
try:
// your app
except Exception:
print Fore.RED + traceback.format_exc( ) + Fore.RESET
// possibly raise again or log to db

How do I disable and then re-enable a warning?

I'm writing some unit tests for a Python library and would like certain warnings to be raised as exceptions, which I can easily do with the simplefilter function. However, for one test I'd like to disable the warning, run the test, then re-enable the warning.
I'm using Python 2.6, so I'm supposed to be able to do that with the catch_warnings context manager, but it doesn't seem to work for me. Even failing that, I should also be able to call resetwarnings and then re-set my filter.
Here's a simple example which illustrates the problem:
>>> import warnings
>>> warnings.simplefilter("error", UserWarning)
>>>
>>> def f():
... warnings.warn("Boo!", UserWarning)
...
>>>
>>> f() # raises UserWarning as an exception
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in f
UserWarning: Boo!
>>>
>>> f() # still raises the exception
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in f
UserWarning: Boo!
>>>
>>> with warnings.catch_warnings():
... warnings.simplefilter("ignore")
... f() # no warning is raised or printed
...
>>>
>>> f() # this should raise the warning as an exception, but doesn't
>>>
>>> warnings.resetwarnings()
>>> warnings.simplefilter("error", UserWarning)
>>>
>>> f() # even after resetting, I'm still getting nothing
>>>
Can someone explain how I can accomplish this?
EDIT: Apparently this is a known bug: http://bugs.python.org/issue4180
Reading through the docs and few times and poking around the source and shell I think I've figured it out. The docs could probably improve to make clearer what the behavior is.
The warnings module keeps a registry at __warningsregistry__ to keep track of which warnings have been shown. If a warning (message) is not listed in the registry before the 'error' filter is set, any calls to warn() will not result in the message being added to the registry. Also, the warning registry does not appear to be created until the first call to warn:
>>> import warnings
>>> __warningregistry__
------------------------------------------------------------
Traceback (most recent call last):
File "<ipython console>", line 1, in <module>
NameError: name '__warningregistry__' is not defined
>>> warnings.simplefilter('error')
>>> __warningregistry__
------------------------------------------------------------
Traceback (most recent call last):
File "<ipython console>", line 1, in <module>
NameError: name '__warningregistry__' is not defined
>>> warnings.warn('asdf')
------------------------------------------------------------
Traceback (most recent call last):
File "<ipython console>", line 1, in <module>
UserWarning: asdf
>>> __warningregistry__
{}
Now if we ignore warnings, they will get added to the warnings registry:
>>> warnings.simplefilter("ignore")
>>> warnings.warn('asdf')
>>> __warningregistry__
{('asdf', <type 'exceptions.UserWarning'>, 1): True}
>>> warnings.simplefilter("error")
>>> warnings.warn('asdf')
>>> warnings.warn('qwerty')
------------------------------------------------------------
Traceback (most recent call last):
File "<ipython console>", line 1, in <module>
UserWarning: qwerty
So the error filter will only apply to warnings that aren't already in the warnings registry. To make your code work you'll need to clear the appropriate entries out of the warnings registry when you're done with the context manager (or in general any time after you've used the ignore filter and want a prev. used message to be picked up the error filter). Seems a bit unintuitive...
Brian Luft is correct about __warningregistry__ being the cause of the problem. But I wanted to clarify one thing: the way the warnings module appears to work is that it sets module.__warningregistry__ for each module where warn() is called. Complicating things even more, the stacklevel option to warnings causes the attribute to be set for the module the warning was issued "in the name of", not necessarily the one where warn() was called... and that's dependent on the call stack at the time the warning was issued.
This means you may have a lot of different modules where the __warningregistry__ attribute is present, and depending on your application, they may all need clearing before you'll see the warnings again. I've been relying on the following snippet of code to accomplish this... it clears the warnings registry for all modules whose name matches the regexp (which defaults to everything):
def reset_warning_registry(pattern=".*"):
"clear warning registry for all match modules"
import re
import sys
key = "__warningregistry__"
for mod in sys.modules.values():
if hasattr(mod, key) and re.match(pattern, mod.__name__):
getattr(mod, key).clear()
Update: CPython issue 21724 addresses issue that resetwarnings() doesn't clear warning state. I attached an expanded "context manager" version to this issue, it can be downloaded from reset_warning_registry.py.
Brian is spot on about the __warningregistry__. So you need to extend catch_warnings to save/restore the global __warningregistry__ too
Something like this may work
class catch_warnings_plus(warnings.catch_warnings):
def __enter__(self):
super(catch_warnings_plus,self).__enter__()
self._warningregistry=dict(globals.get('__warningregistry__',{}))
def __exit__(self, *exc_info):
super(catch_warnings_plus,self).__exit__(*exc_info)
__warningregistry__.clear()
__warningregistry__.update(self._warningregistry)
Following on from Eli Collins' helpful clarification, here is a modified version of the catch_warnings context manager that clears the warnings registry in a given sequence of modules when entering the context manager, and restores the registry on exit:
from warnings import catch_warnings
class catch_warn_reset(catch_warnings):
""" Version of ``catch_warnings`` class that resets warning registry
"""
def __init__(self, *args, **kwargs):
self.modules = kwargs.pop('modules', [])
self._warnreg_copies = {}
super(catch_warn_reset, self).__init__(*args, **kwargs)
def __enter__(self):
for mod in self.modules:
if hasattr(mod, '__warningregistry__'):
mod_reg = mod.__warningregistry__
self._warnreg_copies[mod] = mod_reg.copy()
mod_reg.clear()
return super(catch_warn_reset, self).__enter__()
def __exit__(self, *exc_info):
super(catch_warn_reset, self).__exit__(*exc_info)
for mod in self.modules:
if hasattr(mod, '__warningregistry__'):
mod.__warningregistry__.clear()
if mod in self._warnreg_copies:
mod.__warningregistry__.update(self._warnreg_copies[mod])
Use with something like:
import my_module_raising_warnings
with catch_warn_reset(modules=[my_module_raising_warnings]):
# Whatever you'd normally do inside ``catch_warnings``
I've run into the same issues, and while all of the other answers are valid I choose a different route. I don't want to test the warnings module, nor know about it's inner workings. So I just mocked it instead:
import warnings
import unittest
from unittest.mock import patch
from unittest.mock import call
class WarningTest(unittest.TestCase):
#patch('warnings.warn')
def test_warnings(self, fake_warn):
warn_once()
warn_twice()
fake_warn.assert_has_calls(
[call("You've been warned."),
call("This is your second warning.")])
def warn_once():
warnings.warn("You've been warned.")
def warn_twice():
warnings.warn("This is your second warning.")
if __name__ == '__main__':
__main__=unittest.main()
This code is Python 3, for 2.6 you need the use an external mocking library as unittest.mock was only added in 2.7.

Categories

Resources