Sunday, December 14, 2014

From 2 to 3

Repeating problem (task) that I encounter during migration from Python 2 to Python 3:

* class advice impossible in python3. use the @implementer class decorator instead...
More or less similar with this issue:
zope.interface has had a feature for 10 years under Python2 which can't be made to work portably under Python3. It is spelled like:
from zope.interface import Implements

class Foo(object):
    implements(IFoo)
There is a newer, Python3-compatible spelling, which the pyramid trunk now uses (as of today):
from zope.interface import implementer

@implementer(IFoo)
class Foo(object):
    pass
(That spelling only works under Python >= 2.6)
* ImportError: No module named 'urlparse'
simply refer to this page:

urlparse is part of the standard Python 2 library. It's shipped as part of Python; it isn't packaged separately on PyPI et al. urlparse.urlparse (the function) was renamed in Python 3 to urllib.parse.

If you need to write code which is Python2 and Python3 compatible you can use the following import
try:
    from urllib.parse import urlparse
except ImportError:
    from urlparse import urlparse
from urllib.parse import urlparse work for me

* ImportError: No module named 'ConfigParser'

What I normally do:
import configparser as ConfigParser
ImportError: No module named 'StringIO' 
The StringIO and cStringIO modules are gone. Instead, import the io module and use io.StringIO or io.BytesIO for text and data respectively.
try:
    from StringIO import StringIO
except ImportError:
    from io import StringIO
ImportError: No module named 'HTMLParser' 
Solution:
from html.parser import HTMLParser
Sample:
from html.parser import HTMLParser

class MyHTMLParser(HTMLParser):
    def handle_starttag(self, tag, attrs):
        print("Encountered a start tag:", tag)
    def handle_endtag(self, tag):
        print("Encountered an end tag :", tag)
    def handle_data(self, data):
        print("Encountered some data  :", data)

parser = MyHTMLParser()
parser.feed('<html><head><title>Test</title></head>'
            '<body><h1>Parse me!</h1></body></html>')
ImportError: No module named httplib
In Python 3, the module has been renamed to http.client
import http.client
httpRequest = ""
conn = http.client.HTTPConnection("localhost",8080)
conn.request("GET","/file.html",httpRequest)
response = conn.getresponse()
print(response.status,response.reason)
conn.close();
ImportError: No module named urllib2
In python 3 urllib2 was merged into urllib. To make Python 2 code work in Python 3:
try:
    import urllib.request as urllib2
except ImportError:
    import urllib2
import urllib.request
wp = urllib.request.urlopen("http://goggle.com")
pw = wp.read()
print(pw)
ImportError: No module named 'BaseHTTPServer'
BaseHTTPServer, SimpleHTTPServer modules in Python 2 have been merged into http.server module in Python 3. Sample:
import http.server
import ssl

httpd = http.server.HTTPServer(('localhost', 4443), http.server.SimpleHTTPRequestHandler)
httpd.socket = ssl.wrap_socket(httpd.socket, certfile='server.pem', server_side=True)
httpd.serve_forever()
* TypeError: the JSON object must be str, not 'bytes'
In short; decode:
result = json.loads(response.readall().decode('utf-8'))
* TypeError: Unicode-objects must be encoded before hashing
Refer to this similar issue:
line.encode('utf-8')
or:
str(line)
* NameError: global name 'unicode' is not defined
Yes, again this is Python 3. Python 3 renamed the unicode type to str, the old str type has been replaced by bytes.
if isinstance(unicode_or_str, str):
    text = unicode_or_str
    decoded = False
else:
    text = unicode_or_str.decode(encoding)
    decoded = True
In short; use str(*)

Monday, December 1, 2014

Field ??? not expected

Stack:
  • Python 3.4 (using virtualenv)
  • Pyramid 1.5.2
  • Jinja2 (as Template Engine)
  • SimpleForm (hacked for compability with Python 3)
  • FormEncode
So I encounter the error which from the stack trace I almost cannot conclude anything. By debugging SimpleForm (yes, you read it correctly... debugging) finally I able to capture the real error messages which is like

field submit not expected
or
field _csrf not expected

With the real error message in hand, the quick googling deliver me to this link: https://github.com/Pylons/pyramid_simpleform/issues/6

Oh ok, seems like I need to add something to my schema
class MySchema(Schema):
    allow_extra_fields = True
    filter_extra_fields = True

    name = validators.UnicodeString(min=5)
    value = validators.Int()
Yes, it's because of allow_extra_fields and filter_extra_fields, and the curiosity of "why" lead me to this page: https://github.com/Pylons/pyramid_simpleform/blob/master/docs/index.rst
which stated:
Note the use of the allow_extra_fields and filter_extra_fields attributes. These are recommended in order to remove unneeded fields (such as the CSRF) and also to prevent extra field values being passed through.
Oh Desson, please RT*M!