nine-0.3.4/0000775000175000017500000000000012416526703012677 5ustar nandonando00000000000000nine-0.3.4/setup.cfg0000664000175000017500000000007312416526703014520 0ustar nandonando00000000000000[egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 nine-0.3.4/PKG-INFO0000664000175000017500000001112312416526703013772 0ustar nandonando00000000000000Metadata-Version: 1.1 Name: nine Version: 0.3.4 Summary: Python 2 / 3 compatibility, like six, but favouring Python 3 Home-page: https://github.com/nandoflorestan/nine Author: Nando Florestan Author-email: nandoflorestan@gmail.com License: Public domain Description: Let's write Python 3 right now! =============================== When the best Python 2/Python 3 compatibility modules -- especially the famous `*six* library invented by Benjamin Peterson `_ -- were created, they were written from the point of view of a Python 2 programmer starting to grok Python 3. It is 2013. Python 3.3 is here. When thou writeth Python, thou shalt write Python 3 and, just for a while, ensure that the thing worketh on Python 2.7 and, possibly, even 2.6. Just before Python 2 is finally phased out, thine codebase shall look more like 3 than like 2. *nine* facilitates this new point of view. You can write code that is as 3ish as possible while still supporting 2.6. Very comfortable for writing new projects. For instance, you don't type ``unicode`` anymore, you type ``str``, and *nine* makes ``str`` point to ``unicode`` on Python 2 (if you use our boilerplate). Also, ``map``, ``zip`` and ``filter`` have Python 3 behaviour, on Python 2, meaning they return iterators, not lists. The author(s) of *nine* donate this module to the public domain. To understand most of the intricacies involved in achieving 2&3 compatibility in a single codebase, I recommend reading this: http://lucumr.pocoo.org/2013/5/21/porting-to-python-3-redux/ Using nine ========== In your code, start by importing Python 3 behaviours from __future__. Then import variables from *nine*, as per this boilerplate:: # -*- coding: utf-8 -*- from __future__ import (absolute_import, division, print_function, unicode_literals) from nine import (IS_PYTHON2, str, basestring, native_str, chr, long, integer_types, class_types, range, range_list, reraise, iterkeys, itervalues, iteritems, map, zip, filter, input, implements_iterator, implements_to_string, implements_repr, nine, nimport) Importing moved stuff ===================== Next, we deal with the problem of importing moved names. For instance, instead of writing this to import pickle:: try: import cPickle as pickle # Python 2.x except ImportError: import pickle # Python 3 automatically uses the C version. ...you can write this:: pickle = nimport('pickle') For variables that have been moved: In the argument, please separate the module from the variable with a colon:: name2codepoint = nimport('html.entities:name2codepoint') Want StringIO? I recommend you build lists instead. But if you really need it:: if IS_PYTHON2: from cStringIO import StringIO as BytesIO, StringIO NativeStringIO = BytesIO else: from io import BytesIO, StringIO NativeStringIO = StringIO Our coverage of Python version differences probably isn't exhaustive, but contributions are welcome. When in doubt, `use the source `_! See the `project page at GitHub `_! We also have `continuous integration at Travis-CI `_. Keywords: python 2,python 3,python2,python3,migration,compatibility,nine,six,2to3,3to2,future Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: Public Domain Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.2 Classifier: Programming Language :: Python :: 3.3 nine-0.3.4/nine/0000775000175000017500000000000012416526703013630 5ustar nandonando00000000000000nine-0.3.4/nine/decorator.py0000664000175000017500000000341312416526325016165 0ustar nandonando00000000000000# -*- coding: utf-8 -*- '''*nine* is about Python 2 and 3 compatibility, but I have taken the liberty of including something else in it. The *reify* decorator is so useful that it should come with Python, in the standard library. While it doesn't, the next best thing is for it to be included in a "base" package. And *nine* is a base package! The *reify* decorator comes from Pyramid_ source code. This is fair use because it is only one function out of hundreds. .. _Pyramid: https://pypi.python.org/pypi/pyramid ''' from __future__ import (absolute_import, division, print_function, unicode_literals) class reify(object): """ Use as a class method decorator. It operates almost exactly like the Python ``@property`` decorator, but it puts the result of the method it decorates into the instance dict after the first call, effectively replacing the function it decorates with an instance variable. It is, in Python parlance, a non-data descriptor. An example: .. code-block:: python class Foo(object): @reify def jammy(self): print 'jammy called' return 1 And usage of Foo: .. code-block:: text >>> f = Foo() >>> v = f.jammy 'jammy called' >>> print v 1 >>> f.jammy 1 >>> # jammy func not called the second time; it replaced itself with 1 """ def __init__(self, wrapped): self.wrapped = wrapped try: self.__doc__ = wrapped.__doc__ except: # pragma: no cover pass def __get__(self, inst, objtype=None): if inst is None: return self val = self.wrapped(inst) setattr(inst, self.wrapped.__name__, val) return val nine-0.3.4/nine/__init__.py0000664000175000017500000002050412416526557015751 0ustar nandonando00000000000000# -*- coding: utf-8 -*- '''For documentation and usage, please see the file README.rst. This module is donated to the public domain. ''' import sys # Test for Python 2, not 3; don't get bitten when Python 4 appears: IS_PYTHON2 = (sys.version_info[0] == 2) IS_PYPY = hasattr(sys, 'pypy_translation_info') del sys from importlib import import_module if IS_PYTHON2: # Rename Python 2 builtins so they become like Python 3 native_str = bytes str = unicode basestring = basestring byte_chr = chr # does not seem to have an equivalent in Python 3. chr = unichr # takes an int and returns the corresponding unicode char integer_types = (int, long) long = long from types import ClassType class_types = (type, ClassType) del ClassType range_list = range range = xrange iterkeys = lambda d: d.iterkeys() itervalues = lambda d: d.itervalues() iteritems = lambda d: d.iteritems() from itertools import ifilter as filter, imap as map, izip as zip # In Python 2, *input* was equivalent to eval(raw_input(prompt)): input = raw_input else: # For Python 3, declare these variables so they can be chain imported: basestring = native_str = str = str chr = chr # No need to do the same to ord() integer_types = (int,) long = int class_types = type range = range range_list = lambda *a: list(range(*a)) iterkeys = lambda d: iter(d.keys()) itervalues = lambda d: iter(d.values()) iteritems = lambda d: iter(d.items()) filter = filter map = map zip = zip input = input if IS_PYTHON2: # Turn code into string to avoid SyntaxError on Python 3: exec('def reraise(tp, value, tb=None):\n raise tp, value, tb') else: def reraise(tp, value, tb=None): if value.__traceback__ is not tb: raise value.with_traceback(tb) raise value # ===== Class decorators ===== if IS_PYTHON2: def implements_to_string(cls): '''Class decorator. You define __str__() and it is moved to __unicode__() on Python 2. Additionally, if you define __bytes__(), it becomes __str__() on Python 2. If __bytes__() is not defined, __str__() executes __unicode__() and encodes the result to utf-8. ''' cls.__unicode__ = cls.__str__ cls.__str__ = cls.__bytes__ if hasattr(cls, '__bytes__') \ else lambda x: x.__unicode__().encode('utf-8') return cls def implements_iterator(cls): '''Class decorator. next() has been renamed to __next__().''' cls.next = cls.__next__ del cls.__next__ return cls def implements_repr(cls): '''Class decorator. You implement __repr__() returning a unicode string, and in Python 2, I encode it for you. ''' cls.__repr_unicode__ = cls.__repr__ def wrapper(self): return self.__repr_unicode__().encode('utf-8') cls.__repr__ = wrapper return cls def nine(cls): '''Class decorator for Python 2 and 3 compatibility of magic methods. You define the magic methods with their Python 3 names and, on Python 2, they get their corresponding names. You may write: * __next__(). Use the next(iterator) function to iterate. * __str__(): must return a unicode string. * __repr__(): must return a unicode string. * __bytes__(): must return a bytes object. (*nine* is all the above class decorators in one.) ''' if hasattr(cls, '__str__'): cls = implements_to_string(cls) if hasattr(cls, '__next__'): cls = implements_iterator(cls) if hasattr(cls, '__repr__'): cls = implements_repr(cls) return cls else: # On Python 3, these class decorators do nothing: implements_to_string = implements_iterator = implements_repr = nine = \ lambda cls: cls # http://docs.pythonsprints.com/python3_porting/py-porting.html _moved = { # Mapping from Python 3 to Python 2 location. May need improvement. 'builtins': '__builtin__', 'configparser': 'ConfigParser', 'copyreg': 'copy_reg', '_markupbase': 'markupbase', 'pickle': 'cPickle', 'queue': 'Queue', 'reprlib': 'repr', 'socketserver': 'SocketServer', '_thread': 'thread', '_dummy_thread': 'dummy_thread', 'tkinter': 'Tkinter', 'http.client': 'httplib', 'http.cookiejar': 'cookielib', 'http.cookies': 'Cookie', 'html.entities': 'htmlentitydefs', 'html.entities:entitydefs': 'htmlentitydefs:entitydefs', 'html.entities:name2codepoint': 'htmlentitydefs:name2codepoint', 'html.entities:codepoint2name': 'htmlentitydefs:codepoint2name', 'html:escape': 'cgi:escape', 'html.parser:HTMLParser': 'htmllib:HTMLParser', 'urllib.robotparser': 'robotparser', 'urllib.error:ContentTooShortError': 'urllib:ContentTooShortError', 'urllib.parse': 'urlparse', 'urllib.parse:quote': 'urllib:quote', 'urllib.parse:quote_plus': 'urllib:quote_plus', 'urllib.parse:unquote': 'urllib:unquote', 'urllib.parse:unquote_plus': 'urllib:unquote_plus', 'urllib.parse:urlencode': 'urllib:urlencode', 'urllib.request:getproxies': 'urllib:getproxies', 'urllib.request:pathname2url': 'urllib:pathname2url', 'urllib.request:url2pathname': 'urllib:url2pathname', 'urllib.request:urlcleanup': 'urllib:urlcleanup', 'urllib.request:urlretrieve': 'urllib:urlretrieve', 'urllib.request:URLopener': 'urllib:URLopener', 'urllib.request:FancyURLopener': 'urllib:FancyURLopener', 'urllib.request:urlopen': 'urllib2:urlopen', 'urllib.request:install_opener': 'urllib2:install_opener', 'urllib.request:build_opener': 'urllib2:build_opener', 'urllib.error:URLError': 'urllib2:URLError', 'urllib.error:HTTPError': 'urllib2:HTTPError', 'urllib.request:Request': 'urllib2:Request', 'urllib.request:OpenerDirector': 'urllib2:OpenerDirector', 'urllib.request:BaseHandler': 'urllib2:BaseHandler', 'urllib.request:HTTPDefaultErrorHandler': 'urllib2:HTTPDefaultErrorHandler', 'urllib.request:HTTPRedirectHandler': 'urllib2:HTTPRedirectHandler', 'urllib.request:HTTPCookieProcessor': 'urllib2:HTTPCookieProcessor', 'urllib.request:ProxyHandler': 'urllib2:ProxyHandler', 'urllib.request:HTTPPasswordMgr': 'urllib2:HTTPPasswordMgr', 'urllib.request:HTTPPasswordMgrWithDefaultRealm': 'urllib2:HTTPPasswordMgrWithDefaultRealm', 'urllib.request:AbstractBasicAuthHandler': 'urllib2:AbstractBasicAuthHandler', 'urllib.request:HTTPBasicAuthHandler': 'urllib2:HTTPBasicAuthHandler', 'urllib.request:ProxyBasicAuthHandler': 'urllib2:ProxyBasicAuthHandler', 'urllib.request:AbstractDigestAuthHandler': 'urllib2:AbstractDigestAuthHandler', 'urllib.request:HTTPDigestAuthHandler': 'urllib2:HTTPDigestAuthHandler', 'urllib.request:ProxyDigestAuthHandler': 'urllib2:ProxyDigestAuthHandler', 'urllib.request:HTTPHandler': 'urllib2:HTTPHandler', 'urllib.request:HTTPSHandler': 'urllib2:HTTPSHandler', 'urllib.request:FileHandler': 'urllib2:FileHandler', 'urllib.request:FTPHandler': 'urllib2:FTPHandler', 'urllib.request:CacheFTPHandler': 'urllib2:CacheFTPHandler', 'urllib.request:UnknownHandler': 'urllib2:UnknownHandler', } def nimport(spec): '''Given a spec such as "os.path:join", imports either a module or a name from a module, and returns it. Example usage:: join = nimport('os.path:join') The spec should provide the new location of the module or variable. *nine* is supposed to know the corresponding, old Python 2 location. Bug reports and pull requests are welcome. ''' assert spec if IS_PYTHON2: # Get the Python 2 location of the name, first. spec = _moved.get(spec, spec) alist = spec.split(':') if len(alist) > 2: raise ValueError( 'The argument *spec* cannot have more than ' '2 colon-separated parts: "{}"'.format(spec)) elif len(alist) == 2: module, name = alist elif len(alist) == 1: module = alist[0] name = None module = import_module(module) return getattr(module, name) if name else module nine-0.3.4/nine/test_nine.py0000664000175000017500000000135412416526317016176 0ustar nandonando00000000000000# -*- coding: utf-8 -*- '''This module is donated to the public domain.''' from __future__ import (absolute_import, division, print_function, unicode_literals) import unittest class TestNine(unittest.TestCase): def test_import(self): from nine import ( IS_PYTHON2, str, basestring, native_str, integer_types, class_types, range, range_list, reraise, iterkeys, itervalues, iteritems, map, zip, filter, input, implements_iterator, implements_to_string, implements_repr, nine, nimport, _moved) for key in _moved: if key == 'tkinter': continue # travis does not have tk installed :p assert nimport(key) nine-0.3.4/setup.py0000775000175000017500000000321612416526674014425 0ustar nandonando00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # http://peak.telecommunity.com/DevCenter/setuptools#developer-s-guide # from distutils.core import setup from setuptools import setup, find_packages from codecs import open with open('README.rst', encoding='utf-8') as f: long_description = f.read() requires = [] # Python 2.6 does not have importlib, but a package exists for that from sys import version_info if version_info[:2] < (2, 7): requires.append('importlib') setup( name="nine", version='0.3.4', description="Python 2 / 3 compatibility, like six, but favouring Python 3", long_description=long_description, url='https://github.com/nandoflorestan/nine', author='Nando Florestan', author_email="nandoflorestan@gmail.com", license='Public domain', packages=find_packages(), include_package_data=True, zip_safe=False, test_suite='nine', install_requires=requires, keywords=["python 2", 'python 3', 'python2', 'python3', 'migration', 'compatibility', 'nine', 'six', '2to3', '3to2', 'future', ], classifiers=[ # http://pypi.python.org/pypi?:action=list_classifiers "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", 'License :: Public Domain', "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.2", "Programming Language :: Python :: 3.3", ], ) nine-0.3.4/porting.rst0000664000175000017500000000200112325010410015062 0ustar nandonando00000000000000When you are starting to apply *nine* on Python 2 code to achieve Python 3 compatibility, you can start by following this list of tasks. It isn't exhaustive, just a good start: * Replace str(), usually with nine's native_str() or with bytes() * Replace unicode() with str() and ``from nine import str`` * Replace __unicode__() with __str__(); apply the *nine* decorator on the class * Apply the *nine* decorator on classes that define __repr__() * Search for *range* and replace with nine's *range* or *range_list* * Where performance matters, replace d.keys() or d.iterkeys() with nine's *iterkeys(d)* * Where performance matters, replace d.values() or d.itervalues() with nine's *itervalues(d)* * Where performance matters, replace d.items() or d.iteritems() with nine's *iteritems(d)* * Where performance matters, replace map(), zip() and filter() with nine's versions (which always return iterators). If you had been using *six* or another library before: * Replace ``string_types`` with nine's ``basestring`` nine-0.3.4/nine.egg-info/0000775000175000017500000000000012416526703015322 5ustar nandonando00000000000000nine-0.3.4/nine.egg-info/PKG-INFO0000664000175000017500000001112312416526702016414 0ustar nandonando00000000000000Metadata-Version: 1.1 Name: nine Version: 0.3.4 Summary: Python 2 / 3 compatibility, like six, but favouring Python 3 Home-page: https://github.com/nandoflorestan/nine Author: Nando Florestan Author-email: nandoflorestan@gmail.com License: Public domain Description: Let's write Python 3 right now! =============================== When the best Python 2/Python 3 compatibility modules -- especially the famous `*six* library invented by Benjamin Peterson `_ -- were created, they were written from the point of view of a Python 2 programmer starting to grok Python 3. It is 2013. Python 3.3 is here. When thou writeth Python, thou shalt write Python 3 and, just for a while, ensure that the thing worketh on Python 2.7 and, possibly, even 2.6. Just before Python 2 is finally phased out, thine codebase shall look more like 3 than like 2. *nine* facilitates this new point of view. You can write code that is as 3ish as possible while still supporting 2.6. Very comfortable for writing new projects. For instance, you don't type ``unicode`` anymore, you type ``str``, and *nine* makes ``str`` point to ``unicode`` on Python 2 (if you use our boilerplate). Also, ``map``, ``zip`` and ``filter`` have Python 3 behaviour, on Python 2, meaning they return iterators, not lists. The author(s) of *nine* donate this module to the public domain. To understand most of the intricacies involved in achieving 2&3 compatibility in a single codebase, I recommend reading this: http://lucumr.pocoo.org/2013/5/21/porting-to-python-3-redux/ Using nine ========== In your code, start by importing Python 3 behaviours from __future__. Then import variables from *nine*, as per this boilerplate:: # -*- coding: utf-8 -*- from __future__ import (absolute_import, division, print_function, unicode_literals) from nine import (IS_PYTHON2, str, basestring, native_str, chr, long, integer_types, class_types, range, range_list, reraise, iterkeys, itervalues, iteritems, map, zip, filter, input, implements_iterator, implements_to_string, implements_repr, nine, nimport) Importing moved stuff ===================== Next, we deal with the problem of importing moved names. For instance, instead of writing this to import pickle:: try: import cPickle as pickle # Python 2.x except ImportError: import pickle # Python 3 automatically uses the C version. ...you can write this:: pickle = nimport('pickle') For variables that have been moved: In the argument, please separate the module from the variable with a colon:: name2codepoint = nimport('html.entities:name2codepoint') Want StringIO? I recommend you build lists instead. But if you really need it:: if IS_PYTHON2: from cStringIO import StringIO as BytesIO, StringIO NativeStringIO = BytesIO else: from io import BytesIO, StringIO NativeStringIO = StringIO Our coverage of Python version differences probably isn't exhaustive, but contributions are welcome. When in doubt, `use the source `_! See the `project page at GitHub `_! We also have `continuous integration at Travis-CI `_. Keywords: python 2,python 3,python2,python3,migration,compatibility,nine,six,2to3,3to2,future Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: Public Domain Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.2 Classifier: Programming Language :: Python :: 3.3 nine-0.3.4/nine.egg-info/dependency_links.txt0000664000175000017500000000000112416526702021367 0ustar nandonando00000000000000 nine-0.3.4/nine.egg-info/not-zip-safe0000664000175000017500000000000112416525677017561 0ustar nandonando00000000000000 nine-0.3.4/nine.egg-info/top_level.txt0000664000175000017500000000000512416526702020046 0ustar nandonando00000000000000nine nine-0.3.4/nine.egg-info/SOURCES.txt0000664000175000017500000000036712416526703017214 0ustar nandonando00000000000000LICENSE.rst MANIFEST.in README.rst porting.rst setup.py nine/__init__.py nine/decorator.py nine/test_nine.py nine.egg-info/PKG-INFO nine.egg-info/SOURCES.txt nine.egg-info/dependency_links.txt nine.egg-info/not-zip-safe nine.egg-info/top_level.txtnine-0.3.4/LICENSE.rst0000664000175000017500000000045312325010410014473 0ustar nandonando00000000000000I, the copyright holder of this work, hereby release it into the public domain. This applies worldwide. In case this is not legally possible, I grant any entity the right to use, modify and redistribute this work for any purpose, without any conditions, unless such conditions are required by law. nine-0.3.4/README.rst0000664000175000017500000000603412416526617014375 0ustar nandonando00000000000000Let's write Python 3 right now! =============================== When the best Python 2/Python 3 compatibility modules -- especially the famous `*six* library invented by Benjamin Peterson `_ -- were created, they were written from the point of view of a Python 2 programmer starting to grok Python 3. It is 2013. Python 3.3 is here. When thou writeth Python, thou shalt write Python 3 and, just for a while, ensure that the thing worketh on Python 2.7 and, possibly, even 2.6. Just before Python 2 is finally phased out, thine codebase shall look more like 3 than like 2. *nine* facilitates this new point of view. You can write code that is as 3ish as possible while still supporting 2.6. Very comfortable for writing new projects. For instance, you don't type ``unicode`` anymore, you type ``str``, and *nine* makes ``str`` point to ``unicode`` on Python 2 (if you use our boilerplate). Also, ``map``, ``zip`` and ``filter`` have Python 3 behaviour, on Python 2, meaning they return iterators, not lists. The author(s) of *nine* donate this module to the public domain. To understand most of the intricacies involved in achieving 2&3 compatibility in a single codebase, I recommend reading this: http://lucumr.pocoo.org/2013/5/21/porting-to-python-3-redux/ Using nine ========== In your code, start by importing Python 3 behaviours from __future__. Then import variables from *nine*, as per this boilerplate:: # -*- coding: utf-8 -*- from __future__ import (absolute_import, division, print_function, unicode_literals) from nine import (IS_PYTHON2, str, basestring, native_str, chr, long, integer_types, class_types, range, range_list, reraise, iterkeys, itervalues, iteritems, map, zip, filter, input, implements_iterator, implements_to_string, implements_repr, nine, nimport) Importing moved stuff ===================== Next, we deal with the problem of importing moved names. For instance, instead of writing this to import pickle:: try: import cPickle as pickle # Python 2.x except ImportError: import pickle # Python 3 automatically uses the C version. ...you can write this:: pickle = nimport('pickle') For variables that have been moved: In the argument, please separate the module from the variable with a colon:: name2codepoint = nimport('html.entities:name2codepoint') Want StringIO? I recommend you build lists instead. But if you really need it:: if IS_PYTHON2: from cStringIO import StringIO as BytesIO, StringIO NativeStringIO = BytesIO else: from io import BytesIO, StringIO NativeStringIO = StringIO Our coverage of Python version differences probably isn't exhaustive, but contributions are welcome. When in doubt, `use the source `_! See the `project page at GitHub `_! We also have `continuous integration at Travis-CI `_. nine-0.3.4/MANIFEST.in0000664000175000017500000000022512325010410014412 0ustar nandonando00000000000000# http://docs.python.org/3/distutils/sourcedist.html#specifying-the-files-to-distribute include *.rst recursive-include nine * global-exclude *.pyc