{"id":7726,"date":"2019-10-13T14:34:34","date_gmt":"2019-10-13T21:34:34","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=7726"},"modified":"2025-06-13T21:25:16","modified_gmt":"2025-06-14T04:25:16","slug":"tips-and-tricks-for-upgrading-from-python-2-to-python-3","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/tips-and-tricks-for-upgrading-from-python-2-to-python-3\/","title":{"rendered":"How to Update Python 2 to Python 3 &amp; The Differences Between Them"},"content":{"rendered":"<h2><span style=\"font-weight: 400\">Introduction<\/span><\/h2>\n<p><span style=\"font-weight: 400\">The last major Python upgrade &#8212; to version 3 &#8212; arrived in Dec. 2008, nearly 12 years ago. And yet there is a good chance that you are still working on the Python 2 product or test code. If so, then you may be\u00a0 seeing the below deprecation message as a reminder to update the Python version you&#8217;re working with.<\/span><\/p>\n<p><span style=\"font-weight: 400\">&#8220;DEPRECATION: Python 2.7 will reach the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 won\u2019t be maintained after that date. A future version of pip will drop support for Python 2.7.&#8221;<\/span><\/p>\n<p><span style=\"font-weight: 400\">Please take this seriously and plan accordingly: Python updates to 3.x are not backward compatible. What you write with Python 2.x versions may not function properly when using 3.x<\/span><span style=\"font-weight: 400\">.<\/span><\/p>\n<p class=\"\"><span style=\"font-weight: 400\">Be sure to also read the fine print. According to the website for the programming language, the final Python upgrade release date is still TBD: \u201cBeing the last of the 2.x series, 2.7 will receive bugfix support until 2020. Support officially stops January 1 2020, but the final release will occur after that date.\u201d [<a href=\"https:\/\/www.python.org\/dev\/peps\/pep-0373\/#update\">1<\/a>]<\/span><\/p>\n<p><span style=\"font-weight: 400\">So, Python 2 is entering into unsupported mode by the end of this year. If you haven\u2019t yet done so, now is a good time to migrate the current Python 2 code to Python 3 syntax and stick to Python 3 going forward. <\/span><\/p>\n<p><span style=\"font-weight: 400\">Why don\u2019t teams just jump start on this Python 2 to 3 migration? One of the major hurdles is that the majority of working code simply breaks (read more at <\/span><a href=\"https:\/\/python-notes.curiousefficiency.org\/en\/latest\/python3\/questions_and_answers.html#why-was-python-3-made-incompatible-with-python-2\"><span style=\"font-weight: 400\">why-was-python-3-made-incompatible-with-python-2<\/span><\/a><span style=\"font-weight: 400\">), either because of the direct language syntax or issues with third party APIs. Let\u2019s be fair here: few of us would bother with migration if the new Python updates were backwards compatible. Instead, version 2 will go unsupported, forcing many &#8212; including us here at Couchbase &#8212; to prioritize migration. Even if the team crosses the bug fix support deadline, it&#8217;s ok (because your code is still working). As a team, we decided it\u2019s better to migrate as close to this date as possible so that we are on the same page with other Python community members and learn alongside them.\u00a0\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400\">This document is a collection of tips and tricks we learned while upgrading to Python 3 along with common problems we encountered during the Couchbase test infra migration process. As you&#8217;ll see we manually update python by command line after kick-starting with an automated process. Your approach may be different. Regardless, start as soon as you can. Updating python from version 2 to version 3 is important.<\/span><\/p>\n<p><a href=\"https:\/\/www.couchbase.com\/downloads\/\"><span style=\"font-weight: 400\">Couchbase<\/span><\/a><span style=\"font-weight: 400\"> is an open source Enterprise-class MultiCloud to Edge NoSQL Database. The Couchbase functional testing framework, TestRunner has been developed in Python 2. The TestRunner git\u00a0 repository can be found at<\/span><a href=\"https:\/\/github.com\/couchbase\/testrunner\"> <span style=\"font-weight: 400\">https:\/\/github.com\/couchbase\/testrunner<\/span><\/a><span style=\"font-weight: 400\"> .\u00a0 Our goal now is to completely switch to Python 3 runtime instead of co-running with both Python 3 and Python 2.<\/span><\/p>\n<p><span style=\"font-weight: 400\">As part of the Python upgrade process, we have identified the major changes needed to successfully port to version 3. Some of the problems you&#8217;ll read about we identified during the porting process. Our aim in sharing our learnings is to help you with your own migration. You can pick the latest Python 3.x version (it depends on the pre-release, stable, security-fixes version on a specific platform, 3.7 or 3.6), which we are referring to as Python 3 throughout this blog. See more details on the release at <\/span><a href=\"https:\/\/www.python.org\/downloads\/\"><span style=\"font-weight: 400\">Python releases download<\/span><\/a><span style=\"font-weight: 400\"> and\u00a0 <\/span><span style=\"font-weight: 400\"><a href=\"https:\/\/docs.python.org\/3\">Python 3 documentation<\/a>.<\/span><\/p>\n<p>Cheat Sheet<\/p>\n<p>&nbsp;<\/p>\n<h2><span style=\"font-weight: 400\">Major Changes: Python 2 vs. Python 3<\/span><\/h2>\n<p>To get an idea of the key differences between Python 2 and Python 3, here is the summary list of code changes needed.<\/p>\n<div class=\"responsive-table\">\n<table border=\"1\">\n<tbody>\n<tr>\n<td><b>Python 2<\/b><\/td>\n<td><b>Python 3<\/b><\/td>\n<\/tr>\n<tr>\n<td><span style=\"font-weight: 400\">Text utf-8 : str<\/span><br \/>\n<span style=\"font-weight: 400\">&#8216;<\/span><span style=\"font-weight: 400\">&#8216;<\/span><\/td>\n<td><span style=\"font-weight: 400\">Text is unicode : str<\/span><br \/>\n<span style=\"font-weight: 400\">u&#8221;<\/span><\/td>\n<\/tr>\n<tr>\n<td><span style=\"font-weight: 400\">Binary is same as Text: bytes\/str<\/span><br \/>\n<span style=\"font-weight: 400\">Example:<\/span><br \/>\n<span style=\"font-weight: 400\">file.read(6) == &#8216;GIF89a&#8217;<\/span><\/td>\n<td><span style=\"font-weight: 400\">Binary data is represented as b prefix: bytes<\/span><br \/>\n<span style=\"font-weight: 400\">\u00a0b&#8221;<\/span><br \/>\n<span style=\"font-weight: 400\">Use decode() to get the string, encode() to get bytes.<\/span><span style=\"font-weight: 400\">Examples:\u00a0<\/span><br \/>\n<span style=\"font-weight: 400\">file.read(6) == b&#8217;GIF89a&#8217;<\/span><br \/>\n<span style=\"font-weight: 400\">b&#8217;hello&#8217;.decode() \u2192 &#8216;hello&#8217;<\/span><br \/>\n<span style=\"font-weight: 400\">\u2018hello\u2019.encode() \u2192 b&#8217;hello&#8217;<\/span><br \/>\n<span style=\"font-weight: 400\"><span style=\"font-weight: 400\">str(b\u2019hello\u2019) \u2192 &#8220;b&#8217;hello&#8217;<\/span><\/span>&#8220;<\/td>\n<\/tr>\n<tr>\n<td><span style=\"font-weight: 400\">Print statement<\/span><br \/>\n<span style=\"font-weight: 400\">Example: print &#8216; &#8216;<\/span><\/td>\n<td><span style=\"font-weight: 400\">Print function<\/span><br \/>\n<span style=\"font-weight: 400\">Example:print(&#8216; &#8216;)<\/span><\/td>\n<\/tr>\n<tr>\n<td><span style=\"font-weight: 400\">Integer division<\/span><br \/>\n<span style=\"font-weight: 400\">Example: 5\/2=2<\/span><\/td>\n<td><span style=\"font-weight: 400\">Floor Division. Use 2 slashes<\/span><br \/>\n<span style=\"font-weight: 400\">Example: 5\/\/2 = 2 and 5\/2=2.5<\/span><\/td>\n<\/tr>\n<tr>\n<td><span style=\"font-weight: 400\">Float division<\/span><br \/>\n<span style=\"font-weight: 400\">Example: 5\/2.0 = 2.5 or 5.0\/2 = 2.5<\/span><\/td>\n<td><span style=\"font-weight: 400\">Float Division. Use single slash<\/span><br \/>\n<span style=\"font-weight: 400\">Example: 5\/2 = 2.5<\/span><\/td>\n<\/tr>\n<tr>\n<td><span style=\"font-weight: 400\">Long type is different from int<\/span><br \/>\n<span style=\"font-weight: 400\">long\u00a0<\/span><\/td>\n<td><span style=\"font-weight: 400\">There is no long type. It is same as int<\/span><\/td>\n<\/tr>\n<tr>\n<td><span style=\"font-weight: 400\">xrange()<\/span><\/td>\n<td><span style=\"font-weight: 400\">range()<\/span><\/td>\n<\/tr>\n<tr>\n<td><span style=\"font-weight: 400\">Iteration functions had iter prefix. iterxxx()<\/span><br \/>\n<span style=\"font-weight: 400\">Example: iteritems()<\/span><\/td>\n<td><span style=\"font-weight: 400\">Dropped iter prefix. xxxx()<\/span><br \/>\n<span style=\"font-weight: 400\">Example: items()<\/span><\/td>\n<\/tr>\n<tr>\n<td><span style=\"font-weight: 400\">Lists are directly loaded (all elements loaded into memory when list is used)<\/span><br \/>\n<span style=\"font-weight: 400\">Example: for i in []\u00a0<\/span><\/td>\n<td><span style=\"font-weight: 400\">Lists are lazy loaded (when an element is accessed, then only loaded into memory)<\/span><br \/>\n<span style=\"font-weight: 400\">Example: for i in list([])\u00a0<\/span><\/td>\n<\/tr>\n<tr>\n<td><span style=\"font-weight: 400\">Dictionaries can be compared by default or against 2 dict.<\/span><br \/>\n<span style=\"font-weight: 400\">Example: sorted(dict)\u00a0<\/span><\/td>\n<td><span style=\"font-weight: 400\">Dictionaries can\u2019t be compared directly. sorted() should have key.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Example: <\/span><span style=\"font-weight: 400\">sorted(expected_result,key=(lambda x: x[bucket.name][&#8216;name&#8217;]))<\/span><span style=\"font-weight: 400\">For general dict\/list comparison, you can use below:\u00a0<\/span><br \/>\n<span style=\"font-weight: 400\">\u00a0from deepdiff import DeepDiff<\/span><br \/>\n<span style=\"font-weight: 400\">\u00a0<\/span><span style=\"font-weight: 400\">diffs = DeepDiff(actual_result[&#8216;results&#8217;], expected_result[<\/span><b>&#8216;results&#8217;<\/b><span style=\"font-weight: 400\">], <\/span><span style=\"font-weight: 400\">ignore_order<\/span><span style=\"font-weight: 400\">=<\/span><b>True<\/b><span style=\"font-weight: 400\">)<\/span><b>if <\/b><span style=\"font-weight: 400\">diffs:<\/span><br \/>\n<span style=\"font-weight: 400\">\u00a0\u00a0\u00a0<\/span><span style=\"font-weight: 400\">self<\/span><span style=\"font-weight: 400\">.assertTrue(<\/span><b>False<\/b><span style=\"font-weight: 400\">, diffs)<\/span><\/p>\n<p><span style=\"font-weight: 400\">Bytes and strings as values:<\/span><br \/>\n<span style=\"font-weight: 400\">diffs = DeepDiff(<\/span><span style=\"font-weight: 400\">set<\/span><span style=\"font-weight: 400\">(actual_indexes), <\/span><span style=\"font-weight: 400\">set<\/span><span style=\"font-weight: 400\">(indexes_names), <\/span><span style=\"font-weight: 400\">ignore_order<\/span><span style=\"font-weight: 400\">=<\/span><b>True<\/b><span style=\"font-weight: 400\">, <\/span><span style=\"font-weight: 400\">ignore_string_type_changes<\/span><span style=\"font-weight: 400\">=<\/span><b>True<\/b><span style=\"font-weight: 400\">)<\/span><\/td>\n<\/tr>\n<tr>\n<td><span style=\"font-weight: 400\">string.replace(data[i],&#8230;)<\/span><\/td>\n<td><span style=\"font-weight: 400\">data[i].replace(..)<\/span><\/td>\n<\/tr>\n<tr>\n<td><span style=\"font-weight: 400\">urllib.urlencode()<\/span><\/td>\n<td><span style=\"font-weight: 400\">New modules<\/span><\/p>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">http.client<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">urllib.request, urllib.error, urllib.parse<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">sgmllib3k<\/span><\/li>\n<\/ul>\n<p><span style=\"font-weight: 400\">Examples:\u00a0<\/span><br \/>\n<span style=\"font-weight: 400\">urllib.parse.urlencode()<\/span><\/td>\n<\/tr>\n<tr>\n<td><span style=\"font-weight: 400\">string.lowercase<\/span><\/td>\n<td><span style=\"font-weight: 400\">Attributes:<\/span><br \/>\n<span style=\"font-weight: 400\">string.ascii_lowercase<\/span><br \/>\n<span style=\"font-weight: 400\">string.ascii_uppercase<\/span><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p><span style=\"font-weight: 400\">See the <\/span><a href=\"https:\/\/github.com\/couchbaselabs\/testrunner-py3\/commits\/master\"><span style=\"font-weight: 400\">testrunner py3 commits<\/span><\/a><span style=\"font-weight: 400\">\u00a0 for changes<\/span><\/p>\n<h2><\/h2>\n<h2><span style=\"font-weight: 400\">Python 3 Setup<\/span><\/h2>\n<p><span style=\"font-weight: 400\">To setup Python 3 from scratch, run the below commands on a new host with major supported platforms.<\/span><br \/>\n<span style=\"font-weight: 400\">Later during the runtime, either use python 3 command or python in python 3 virtual env. Use either pip3 or pip3.x (pip3.6 for example) to install packages based on the installed Python 3 version.<\/span><\/p>\n<div class=\"responsive-table\">\n<table>\n<tbody>\n<tr>\n<td><b>Mac OS<\/b><br \/>\n(Example: Your laptop)<br \/>\n<span style=\"font-weight: 400\">Direct setup (pip3 automatically installed):<\/span>(https:\/\/wsvincent.com\/install-python3-mac\/)<\/p>\n<pre class=\"lang:python decode:true\">brew install python3<\/pre>\n<p><span style=\"font-weight: 400\">Virtual environment setup:<\/span><\/p>\n<pre class=\"lang:sh decode:true\">$ pip3 install virtualenv\r\n$ mkdir ~\/environments\r\n$ virtualenv -p python3 ~\/environments\r\n$ source ~\/environments\/bin\/activate\r\n(environments) jmunta-mac:~ jagadeshmunta\r\n$ python -V\r\nPython 3.7.3\r\n(environments) jmunta-mac:~ jagadeshmunta\r\n<\/pre>\n<p>Install required libraries:<\/p>\n<pre class=\"lang:sh decode:true\">$ pip3 install couchbase\r\n$ pip3 install sgmllib3k\r\n$ pip3 install paramiko\r\n$ pip3 install httplib2\r\n$ pip3 install pyyaml\r\n$ pip3 install Geohash\r\n$ pip3 install python-geohash\r\n$ pip3 install deepdiff\r\n$ pip3 install pyes\r\n\r\n<\/pre>\n<p>For now, the below modification is required to the common Python 3 http client otherwise, you would hit an error.<\/p>\n<pre class=\"lang:sh decode:true \">$ vi \/usr\/lib64\/python3.6\/http\/client.py\u00a0\u00a0 \r\nchunk to chunk.encode() in similar to the below:\r\n1078 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 chunk = f'{len(chunk):X}\\r\\n'.encode('ascii') + chunk.encode() \\<\/pre>\n<p>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td><b>CentOS\u00a0\u00a0<\/b><br \/>\n(<span style=\"font-weight: 400\">Example node: Jenkins Slave)<\/span><br \/>\nDirect setup and virtual environment:<\/p>\n<pre class=\"lang:sh decode:true\"># yum -y install https:\/\/centos7.iuscommunity.org\/ius-release.rpm\r\n# yum list available &gt; \/tmp\/available_pkgs.txt\r\n# cat \/tmp\/available_pkgs.txt\u00a0 |egrep python3\r\n# yum -y install python36u\r\n# python3.6 --version\r\n# yum -y install python36u-pip\r\n# yum -y install python36u-devel\r\n# python3.6 -V\r\n# mkdir ~\/environments\r\n# cd ~\/environments\/\r\n# python3.6 -m venv my_env\r\n# source ~\/environments\/my_env\/bin\/activate\r\n# python -V<\/pre>\n<p>Install required libraries:<\/p>\n<pre class=\"lang:sh decode:true\"># pip3.6 install requests\r\n# pip3.6 install sgmllib3k\r\n# pip3.6 install paramiko\r\n# pip3.6 install httplib2\r\n# pip3.6 install pyyaml\r\n# pip3.6 install pytz\r\n# pip3.6 install Geohash\r\n# pip3.6 install python-geohash\r\n# pip3.6 install deepdiff\r\n# pip3.6 install pyes<\/pre>\n<p>&nbsp;<\/p>\n<p><span style=\"font-weight: 400\">Perform Couchbase CSDK and Python SDK installation on new slave:<\/span><\/p>\n<pre class=\"lang:sh decode:true \"># yum -y install wget git\r\n# wget https:\/\/packages.couchbase.com\/releases\/couchbase-release\/couchbase-release-1.0-6-x86_64.rpm\r\n# rpm -iv couchbase-release-1.0-6-x86_64.rpm\r\n# yum install libcouchbase-devel libcouchbase2-bin gcc gcc-c++\r\n# pip3.6 install couchbase<\/pre>\n<p>For now, the below modification is required to the common Python 3 http client otherwise, you would hit an error.<\/p>\n<pre class=\"lang:sh decode:true\">$ vi \/usr\/lib64\/python3.6\/http\/client.py\u00a0\u00a0 \r\nchunk to chunk.encode() in similar to the below: \r\n1078 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 chunk = f'{len(chunk):X}\\r\\n'.encode('ascii') + chunk.encode() \\<\/pre>\n<p>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td><b>Ubuntu slave using for Python 3 runtime verification<\/b><br \/>\nDirect Setup:<\/p>\n<pre class=\"lang:sh decode:true \"># apt install python3-pip<\/pre>\n<p>&nbsp;<\/p>\n<p>Install the required libraries:<\/p>\n<pre class=\"lang:sh decode:true\"># pip3 install sgmllib3k\r\n# pip3 install paramiko\r\n# pip3 install httplib2\r\n# pip3 install pyyaml\r\n# pip3 install pytz (NOTE: used by xdcr tests)\r\n# pip3 install Geohash\r\n# pip3 install python-geohash\r\n# pip3 install deepdiff\r\n# pip3 install pyes<\/pre>\n<p><span style=\"font-weight: 400\">Install CSDK and Python SDK installation: (Ref:<\/span><span style=\"font-weight: 400\">\u00a0<\/span><a href=\"https:\/\/docs.couchbase.com\/c-sdk\/2.10\/start-using-sdk.html\"><span style=\"font-weight: 400\">https:\/\/docs.couchbase.com\/c-sdk\/2.10\/start-using-sdk.html )<\/span><\/a><\/p>\n<pre class=\"lang:sh decode:true\"># wget -O- https:\/\/packages.couchbase.com\/ubuntu\/couchbase.key | sudo apt-key add -\u00a0\r\n# cat \/etc\/apt\/sources.list.d\/couchbase.list\r\ndeb [ arch=amd64 ] https:\/\/packages.couchbase.com\/releases\/couchbase-server\/enterprise\/deb\/ bionic bionic\/main\r\ndeb [ arch=amd64 ] https:\/\/packages.couchbase.com\/releases\/couchbase-server\/community\/deb\/ bionic bionic\/main\r\ndeb https:\/\/packages.couchbase.com\/ubuntu bionic bionic\/main\u00a0\r\n# apt-get update\u00a0\r\n#\u00a0 apt-get install libcouchbase-dev libcouchbase2-bin build-essential\u00a0\r\n#\u00a0 pip3 install couchbase<\/pre>\n<p>For now, the below modification is required to the common Python 3 http client otherwise, you would hit an error.<\/p>\n<pre class=\"lang:sh decode:true\">$ vi \/usr\/lib64\/python3.6\/http\/client.py\u00a0\u00a0 \r\nchunk to chunk.encode() in similar to the below: \r\n1078 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 chunk = f'{len(chunk):X}\\r\\n'.encode('ascii') + chunk.encode() \\<\/pre>\n<p>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td><b>Windows<\/b><br \/>\n<span style=\"font-weight: 400\">Download and install: <\/span><a href=\"https:\/\/www.python.org\/ftp\/python\/3.7.4\/python-3.7.4.exe\"><span style=\"font-weight: 400\">https:\/\/www.python.org\/ftp\/python\/3.7.4\/python-3.7.4.exe<\/span><\/a><\/p>\n<pre class=\"lang:ps decode:true\">C:\\Python\\Python37-32&gt;python.exe -VPython 3.7.4\r\nD:\\py3porting\\testrunner&gt;set PATH=C:\\Python\\Python37-32;C:\\Python\\Python37-32\\Scripts;%PATH%\r\nD:\\py3porting\\testrunner&gt;pip3 -V\r\npip 19.0.3 from c:\\python\\python37-32\\lib\\site-packages\\pip (python 3.7)<\/pre>\n<p>Install required libraries:<\/p>\n<pre class=\"lang:ps decode:true\">pip3 install libcouchbase\r\npip3 install sgmllib3k\r\npip3 install paramiko\r\npip3 install httplib2\r\npip3 install pyyaml\r\npip3 install Geohash\r\npip3 install python-geohash\r\npip3 install deepdiff\r\npip3 install pyes<\/pre>\n<p>&nbsp;<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<h2><span style=\"font-weight: 400\">Porting Process<\/span><\/h2>\n<p>At a high level, the porting is a three step process. 1) Auto conversion 2) Manual changes 3) Runtime validation and fix<\/p>\n<p>At first, clone the original repository and have the basic automatic conversion changes. Checkin the changes as a new repository until full conversion is done. This way, the current regression cycles can go without interruption.<\/p>\n<h3><span style=\"font-weight: 400\">1. Auto conversion<\/span><\/h3>\n<p><span style=\"font-weight: 400\">There is an automated tool called <\/span><a href=\"https:\/\/docs.python.org\/2\/library\/2to3.html#\"><span style=\"font-weight: 400\">2to3<\/span><\/a> tool<span style=\"font-weight: 400\">, provided by the Python 3 team that helps in taking care of a few common patterns like print, exception, list wrapping, relative imports etc.\u00a0\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400\">You can start with a single directory in the locally cloned workspace to do double check. Later, the conversion can be done entirely on entire code so that basic porting is taken care of.<\/span><\/p>\n<p>Below are some of the sample 2to3 conversion commands on the MacOS. In the last command, note that all idioms were applied. This way, the first time conversion can take care of key changes.<\/p>\n<pre class=\"lang:sh decode:true\">(myenv) jmunta-mac:myscripts jagadeshmunta$ 2to3 . -o new -n -w .\r\nhq-mac:testrunner jagadeshmunta$ cd lib; mv lib\/couchbase_helper ..\/couchbase_helper\r\nhq-mac:testrunner jagadeshmunta$ 2to3 -f all -f buffer -f idioms -f set_literal -f ws_comma\u00a0 -n -o ~\/p3testrunner_3 -w . |tee ~\/2to3_3.txt\r\nhq-mac:testrunner jagadeshmunta$ time 2to3 -f all -f buffer -f idioms -f set_literal -f ws_comma\u00a0 -n -w . |tee ~\/2to3_4.txt\r\n$ 2to3 -f all -f buffer -f idioms -f set_literal -f ws_comma\u00a0 -n -o ~\/p3testrunner_helper -w ..\/couchbase_helper |tee ~\/2to3_helper.txt\r\ncp -R ~\/p3testrunner_helper\/* .<\/pre>\n<p>&nbsp;<\/p>\n<h3><span style=\"font-weight: 400\">2. Manual changes<\/span><\/h3>\n<p><span style=\"font-weight: 400\">The auto conversion doesn\u2019t do the complete porting. The below common problems might be experienced during the porting process than the common syntax changes done by the auto conversion 2to3 tool.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400\">Run the test class and see if there are any errors and fix appropriately, deciding whether to switch from bytes to str or str to bytes or some sort\/comparison issue where one has to fix the key name in the sorted function. This is an iterative process until all the code runtime has been validated.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Once a common pattern for sure is clear, then you can do grep and sed to replace across many class files. If you are not sure about other code until runtime, then defer until that test class is executed.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400\">There might be issues with third party libraries\/modules might have changed, those need to be searched on the web and used appropriately.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Make sure all the code path is covered by running across all supported platforms and parameters.<\/span><\/p>\n<h3>3. Runtime Validation and Fix<\/h3>\n<p><span style=\"font-weight: 400\">Once the conversion is done, then perform a lot of code runtime as Python is a dynamic language. Otherwise, the changes can break the things if you do just visual static code inspection\/changes. You can start with basic sanity tests, acceptance tests and then select full tests from a single module of tests. <\/span><\/p>\n<p><span style=\"font-weight: 400\">Once you&#8217;re comfortable, then go with all other modules one by one. Keep checking in the changes to the new repository. In addition, you need to make sure there are no regressions with ported changes from this new repository by running sanity tests on the newer builds. Also, the validation should include all the supported platforms with Python 3.<\/span><\/p>\n<p>&nbsp;<\/p>\n<h2><span style=\"font-weight: 400\">Python 3 Ported Code and Status<\/span><\/h2>\n<p><span style=\"font-weight: 400\">Below is where to find the new repository for Python 3 ported code until it is merged to the main repository. The plan is to do one cycle of porting or intermediately take the changes from the main repo and do a manual merge to this.<\/span><\/p>\n<p><a href=\"https:\/\/github.com\/couchbaselabs\/testrunner-py3\/\"><span style=\"font-weight: 400\">https:\/\/github.com\/couchbaselabs\/testrunner-py3\/<\/span><\/a><\/p>\n<p><span style=\"font-weight: 400\">(Branch: master)<\/span><\/p>\n<p><span style=\"font-weight: 400\">Many common changes were already done but not completed as there might be some other runtime issues. Fixes in common can also be regressed to the earlier fixes because of assumptions on input value type conversions. There is still some more ported code to be validated with Python 3 and the effort is still in progress.<\/span><\/p>\n<p>Now, let me show you the common issues <span style=\"font-weight: 400\">that occurred<\/span> during the runtime validation. You can use this as a reference when you hit an issue to see if you are having the similar issue. You can apply the same solution and see if it works for you. <span style=\"font-weight: 400\">And if you have any<\/span> new ideas, you can put them in the comments.<\/p>\n<h2><span style=\"font-weight: 400\">Common Runtime Problems<\/span><\/h2>\n<p><span style=\"font-weight: 400\">\u00a0<\/span><\/p>\n<h4><span style=\"font-weight: 400\">1. Problem(s): <\/span><\/h4>\n<ul>\n<li><span style=\"font-weight: 400\">You might get some of the below TypeErrors during runtime like str instead of bytes and bytes instead of str<\/span><\/li>\n<li><span style=\"font-weight: 400\">Error#1. TypeError: can&#8217;t concat str to bytes<\/span><\/li>\n<li><span style=\"font-weight: 400\">Error#2. TypeError: must be str, not bytes<\/span>\n<ul>\n<li>\n<pre class=\"lang:python decode:true\">File \"lib\/mc_bin_client.py\", line 53, in __init__&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;\r\nif msg: supermsg += \":&amp;nbsp; \" + str(msg)\r\nTypeError: must be str, not bytes\r\n\r\nFile \"lib\/mc_bin_client.py\", line 141, in _recvMsg\u00a0\u00a0\u00a0\u00a0\r\nresponse += data\r\nTypeError: must be str, not bytes<\/pre>\n<\/li>\n<\/ul>\n<\/li>\n<li><span style=\"font-weight: 400\">Error#3. TypeError: a bytes-like object is required, not &#8216;str&#8217;<\/span>\n<ul>\n<li>\n<pre class=\"lang:python decode:true\">File \"lib\/remote\/remote_util.py\", line 3038, in log_command_output&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;\r\nif \"Warning\" in line and \"hugepages\" in line:\r\nTypeError: a bytes-like object is required, not 'str'\r\n\r\nFile \"lib\/tasks\/task.py\", line 1167, in run_high_throughput_mode&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;\r\nraise Exception(rv[\"err\"])\r\nException: a bytes-like object is required, not 'str'\r\n\r\nFile \"lib\/mc_bin_client.py\", line 936, in _set_vbucket&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;\r\nself.vbucketId = (((zlib.crc32(key)) &gt;&gt; 16) &amp; 0x7fff) &amp; (self.vbucket_count - 1)\r\nTypeError: a bytes-like object is required, not 'str'\r\n\r\n\r\nFile \"lib\/mc_bin_client.py\", line 148, in _recvMsg\u00a0\u00a0\u00a0\u00a0\r\nmagic = struct.unpack(\"&gt;B\", response[0:1])[0]\r\nTypeError: a bytes-like object is required, not 'str'\r\n\r\nFile \"lib\/remote\/remote_util.py\", line 4560, in check_cmd&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;\r\nif out and command_output in out[0]:\r\nTypeError: a bytes-like object is required, not 'str'\r\n<\/pre>\n<\/li>\n<\/ul>\n<\/li>\n<li><span style=\"font-weight: 400\">Error#4. TypeError: Cannot mix str and non-str arguments<\/span>\n<ul>\n<li>\n<pre class=\"lang:python decode:true\">File \"lib\/mc_bin_client.py\", line 126, in _sendMsg&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;\r\nself.s.send(msg + extraHeader + key + val + extended_meta_data)\r\nTypeError: can't concat str to bytes\r\n\r\nFile \"\/usr\/lib64\/python3.6\/urllib\/parse.py\", line 120, in _coerce_args\u00a0\u00a0\u00a0\u00a0\r\nraise TypeError(\"Cannot mix str and non-str arguments\")\r\nTypeError: Cannot mix str and non-str arguments<\/pre>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h4><span style=\"font-weight: 400\">Solution(s):<\/span><\/h4>\n<p><span style=\"font-weight: 400\">See the types of the variables in the statement and use xxx.encode() to get the bytes or xxx.decode() to get the string or use b prefix or use str(). Sometimes, the input might not be unknown and in this case, use try x.encode() except AttributeError: pass<\/span><\/p>\n<h4><span style=\"font-weight: 400\"><br \/>\n<\/span><span style=\"font-weight: 400\">2. Problem(s): <\/span><\/h4>\n<p><span style=\"font-weight: 400\">TypeError: <\/span><span style=\"font-weight: 400\">root &#8211; ERROR &#8211; &#8212;&#8212;-&gt;installation failed: a bytes-like object is required, not &#8216;str&#8217;<\/span><\/p>\n<h4><span style=\"font-weight: 400\">Solution(s):\u00a0 <\/span><\/h4>\n<p><span style=\"font-weight: 400\">In this case, add b as prefix to the string under comparison or change the byte type to string type. Example: lib\/remote\/remote_util.py<\/span><\/p>\n<pre class=\"lang:python decode:true\">if o[0] != b\"\":\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\n   o = o[0].split(b\" \")<\/pre>\n<p><span style=\"font-weight: 400\">Surround with try-except to check the exact line causing the error (say above TypeError.)\u00a0<\/span><\/p>\n<pre class=\"lang:python decode:true \">\u00a0import traceback\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\n try:\u00a0\u00a0\r\n \r\n ..\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\n \r\n except Exception as e:\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\n   log.info(\"{}\".format(e))\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\n   traceback.print_exc()\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\n   exc_type, exc_obj, exc_tb = sys.exc_info()\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\n   fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\n   print(exc_type, fname, exc_tb.tb_lineno)<\/pre>\n<p><span style=\"font-weight: 400\">Sample output after traceback.print_exec() to see the full stack trace in similar to java.<\/span><\/p>\n<p>Fix with changes to lib\/remote\/remote_util.py as below.<\/p>\n<pre class=\"lang:python decode:true\">\u00a0\u00a0\u00a0\r\n3079 \u00a0 \u00a0 \u00a0 \u00a0 for line in output:\u00a0\u00a0\u00a0\r\n3080\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0try:\u00a0\u00a0\u00a0\r\n3081 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 line=line.decode()\u00a0\u00a0\u00a0\r\n3082 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 except AttributeError:\u00a0\u00a0\u00a0\r\n3083 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 pass<\/pre>\n<h4><\/h4>\n<h4><span style=\"font-weight: 400\">3. Problem(s):<\/span><\/h4>\n<pre class=\"lang:python decode:true\">File \"lib\/membase\/api\/rest_client.py\", line 4178, in multiscan_count_for_gsi_index_with_rest&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;\r\ncontent = content.split(\"[]\")[0]\r\nTypeError: a bytes-like object is required, not 'str'<\/pre>\n<p>&nbsp;<\/p>\n<h4><span style=\"font-weight: 400\">Solution(s): <\/span><\/h4>\n<pre class=\"lang:python decode:true \">content = content.split(b'[]')[0].decode()<\/pre>\n<p>&nbsp;<\/p>\n<h4><span style=\"font-weight: 400\">4. Problem(s): <\/span><\/h4>\n<p><span style=\"font-weight: 400\">AttributeError suite_setUp() or suite_tearDown() are missing for some testsuites.<\/span><\/p>\n<pre class=\"lang:python decode:true\">AttributeError: type object 'XDCRAdvFilterTests' has no attribute 'suite_setUp'<\/pre>\n<h4><span style=\"font-weight: 400\">Solution(s): <\/span><\/h4>\n<p><span style=\"font-weight: 400\">Add the dummy suite_setUp() and suite_tearDown() methods.\u00a0<\/span><\/p>\n<pre class=\"lang:sh decode:true \">11a12,18\r\n&gt; \r\n&gt;     def suite_setUp(self):\r\n&gt;         print(\"*** XDCRAdvFilterTests : suite_Setup() ***\")\r\n&gt; \r\n&gt;     def suite_tearDown(self):\r\n&gt;         print(\"*** XDCRAdvFilterTests : suite_tearDown() ***\")\r\n&gt;<\/pre>\n<p>&nbsp;<\/p>\n<h4><span style=\"font-weight: 400\">5. Problem(s):<\/span><\/h4>\n<pre class=\"lang:python decode:true \">File \".\/testrunner.py\", line 416, in main\u00a0\u00a0\u00a0\u00a0\r\nresult.errors = [(name, e.message)]\r\nAttributeError: 'AttributeError' object has no attribute 'message'<\/pre>\n<p>&nbsp;<\/p>\n<h4><span style=\"font-weight: 400\">Solution(s):<\/span><\/h4>\n<pre class=\"lang:python decode:true \">result.errors = [(name, str(e))]<\/pre>\n<p>&nbsp;<\/p>\n<h4><span style=\"font-weight: 400\">6. Problem(s): <\/span><\/h4>\n<p><span style=\"font-weight: 400\">AttributeError: &#8216;Transport&#8217; object has no attribute &#8216;_Thread__stop&#8217;<\/span><\/p>\n<pre class=\"lang:python decode:true\">File \".\/testrunner.py\", line 529, in main&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;\r\nt._Thread__stop()\r\nAttributeError: 'Transport' object has no attribute '_Thread__stop'\r\n\r\nFile \"pytests\/view\/viewquerytests.py\", line 45, in stop\u00a0\u00a0\u00a0\u00a0\r\nself._Thread__stop()\r\nAttributeError: 'StoppableThread' object has no attribute '_Thread__stop'\u00a0\u00a0\u00a0\u00a0\r\n\r\nself._stop()\r\nTypeError: 'Event' object is not callable\r\n<\/pre>\n<h4><span style=\"font-weight: 400\">Solution(s):<\/span><\/h4>\n<p><span style=\"font-weight: 400\">There is no direct stopping of a non-daemonic thread. But syntax-wise use t._stop(). The recommendation is to use the graceful shutdown using a global flag and check in the thread\u2019s run() to break.<\/span><\/p>\n<p><span style=\"font-weight: 400\">(<\/span><a href=\"https:\/\/stackoverflow.com\/questions\/27102881\/python-threading-self-stop-event-object-is-not-callable\"><span style=\"font-weight: 400\">https:\/\/stackoverflow.com\/questions\/27102881\/python-threading-self-stop-event-object-is-not-callable<\/span><\/a><span style=\"font-weight: 400\">)<\/span><\/p>\n<h3><\/h3>\n<h4><span style=\"font-weight: 400\">7. Problem(s): <\/span><\/h4>\n<p><span style=\"font-weight: 400\">Test expirytests.ExpiryTests.test_expired_keys was not found: module &#8216;string&#8217; has no attribute &#8216;translate&#8217;<\/span><\/p>\n<h4><span style=\"font-weight: 400\">Solution(s): <\/span><\/h4>\n<p><span style=\"font-weight: 400\">Rewrite with str static methods. There is no old way of getting all chars, so we used the earlier code and used total set.<\/span><\/p>\n<p><span style=\"font-weight: 400\">vi lib\/membase\/api\/tap.py\u00a0<\/span><\/p>\n<pre class=\"lang:python decode:true \">def buildGoodSet(goodChars=string.printable, badChar='?'):\u00a0\u00a0\u00a0\u00a0\r\n143 \u00a0 \u00a0 \"\"\"Build a translation table that turns all characters not in goodChars\u00a0\u00a0\u00a0\u00a0\r\n144 \u00a0 \u00a0 to badChar\"\"\"\u00a0\u00a0\u00a0\u00a0\r\n145 \u00a0 \u00a0 allChars = '\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&amp;\\'()*+,-.\/0123\u00a0 \u00a0 \u00a0 \u00a0 456789:;&lt;=&gt;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\\x7f\\x80\\x81\\x82\\x83\\x84\\x85\\x86\\x87\\x88\\x89\\x8a\\x8b\\x8c\\x8d\\x8e\\x8f\\x90\\x91\\x92\\x9 \u00a0 \u00a0 3\\x94\\x95\\x96\\x97\\x98\\x99\\x9a\\x9b\\x9c\\x9d\\x9e\\x9f\\xa0\\xa1\\xa2\\xa3\\xa4\\xa5\\xa6\\xa7\\xa8\\xa9\\xaa\\xab\\xac\\xad\\xae\\xaf\\xb0\\xb1\\xb2\\xb3\\xb4\\xb5\\xb6\\xb7\\xb8\\xb9\\xba\\x bb\\xbc\\xbd\\xbe\\xbf\\xc0\\xc1\\xc2\\xc3\\xc4\\xc5\\xc6\\xc7\\xc8\\xc9\\xca\\xcb\\xcc\\xcd\\xce\\xcf\\xd0\\xd1\\xd2\\xd3\\xd4\\xd5\\xd6\\xd7\\xd8\\xd9\\xda\\xdb\\xdc\\xdd\\xde\\xdf\\xe0\\xe1\\xe2\\\u00a0 \u00a0 \u00a0 \u00a0 xe3\\xe4\\xe5\\xe6\\xe7\\xe8\\xe9\\xea\\xeb\\xec\\xed\\xee\\xef\\xf0\\xf1\\xf2\\xf3\\xf4\\xf5\\xf6\\xf7\\xf8\\xf9\\xfa\\xfb\\xfc\\xfd\\xfe\\xff'\u00a0\u00a0\u00a0\u00a0\r\n146 \u00a0 \u00a0 badchars = str.maketrans(allChars, allChars, goodChars)\u00a0\u00a0\u00a0\u00a0\r\n147 \u00a0 \u00a0 badchars1=str.translate(allChars,badchars)\u00a0\u00a0\u00a0\u00a0\r\n148 \u00a0 \u00a0 rv = str.maketrans(badchars1, badChar * len(badchars1))\u00a0\u00a0\u00a0\u00a0\r\n149 \u00a0 \u00a0 return rv<\/pre>\n<p>&nbsp;<\/p>\n<h4><span style=\"font-weight: 400\">8. Problem(s): <\/span><\/h4>\n<p><span style=\"font-weight: 400\">TabError: inconsistent use of tabs and spaces in indentation<\/span><\/p>\n<pre class=\"lang:python decode:true \">File \"pytests\/security\/audittest.py\", line 396\u00a0\u00a0\u00a0\u00a0\r\nshell = RemoteMachineShellConnection(self.master)\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\n^\r\nTabError: inconsistent use of tabs and spaces in indentation<\/pre>\n<p>&nbsp;<\/p>\n<h4><span style=\"font-weight: 400\">Solution(s):<\/span><\/h4>\n<p><span style=\"font-weight: 400\">Search for tab characters and replace with space characters.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400\">For the above issue, remove tab characters.<\/span><\/p>\n<pre class=\"lang:sh decode:true \">sed -i 's\/\\t\/\u00a0 \u00a0 \u00a0 \u00a0 \/g' pytests\/security\/audittest.py<\/pre>\n<p>&nbsp;<\/p>\n<h4><span style=\"font-weight: 400\">9. Problem(s):<\/span><\/h4>\n<pre class=\"lang:python decode:true\">File \"lib\/couchbase_helper\/documentgenerator.py\", line 83, in __next__\u00a0\u00a0\u00a0\u00a0\r\nvalue = arg[seed % len(arg)]\r\nTypeError: list indices must be integers or slices, not float\r\n\r\nFile \"lib\/membase\/helper\/bucket_helper.py\", line 517, in load_some_data\u00a0\u00a0\u00a0\u00a0\r\nkeys = [\"key_%s_%d\" % (testuuid, i) for i in range(number_of_buckets)]\r\nTypeError: 'float' object cannot be interpreted as an integer\u00a0\r\n\r\nFile \"lib\/membase\/helper\/bucket_helper.py\", line 372, in verify_data\u00a0\u00a0\u00a0\u00a0\r\ntest.assertEqual(value, key, msg='values dont match')\r\nAssertionError: b'key_d918f450-5858-4430-a016-230e1f45bcf9_0' != 'key_d918f450-5858-4430-a016-230e1f45bcf9_0' : values dont match\r\n\r\nFile \"pytests\/setgettests.py\", line 90, in set_get_test\u00a0\u00a0\u00a0\u00a0\r\nself.test.fail(\"value mismatch for key {0}\".format(key))\r\nAssertionError: value mismatch for key 9fcbd36f-e34d-477b-9fc5-0a5d067dff4b\r\n\r\nFile \"pytests\/security\/auditmain.py\", line 320, in returnFieldsDef\u00a0\u00a0\u00a0\u00a0\r\nif (isinstance((particulars['mandatory_fields'][items.encode('utf-8')]), dict)):\r\nKeyError: b'bucket_name'\r\n\r\nFile \"lib\/tasks\/task.py\", line 2370, in _check_ddoc_revision\u00a0\u00a0\u00a0\u00a0\r\nnew_rev_id = self._parse_revision(meta['rev'])\r\nKeyError: 'rev'\r\n<\/pre>\n<h4><span style=\"font-weight: 400\">Solution(s):<\/span><\/h4>\n<p><span style=\"font-weight: 400\">Case sensitiveness issue. Fixed by changing from x_couchbase_meta key to X_Couchbase_Meta<\/span><\/p>\n<p>&nbsp;<\/p>\n<h4><span style=\"font-weight: 400\">10. Problem(s): <\/span><\/h4>\n<ul>\n<li><span style=\"font-weight: 400\">Error#1. TypeError: &#8216;&lt;&#8216; not supported between instances of &#8216;dict&#8217; and &#8216;dict&#8217;<\/span><\/li>\n<li><span style=\"font-weight: 400\">Error#2. TypeError: &#8216;cmp&#8217; is an invalid keyword argument for this function<\/span><\/li>\n<\/ul>\n<pre class=\"lang:python decode:true\">File \"pytests\/tuqquery\/tuq_dml.py\", line 455, in test_insert_with_select\u00a0\u00a0\u00a0\u00a0\r\nexpected_result = sorted([{bucket.name: {'name': doc['name']}} for doc in values[:num_docs]])\r\nTypeError: '&lt;' not supported between instances of 'dict' and 'dict'<\/pre>\n<h4><span style=\"font-weight: 400\">Solution(s):<\/span><\/h4>\n<pre class=\"lang:python decode:true \">expected_result = sorted(expected_result,key=(lambda x: x[bucket.name]['name']))<\/pre>\n<p><span style=\"font-weight: 400\">\u00a0\u00a0\u00a0<\/span><\/p>\n<h4><span style=\"font-weight: 400\">11. Problem(s):<\/span><\/h4>\n<pre class=\"lang:python decode:true\">File \"pytests\/tuqquery\/tuq_2i_index.py\", line 1057, in test_simple_array_index\u00a0\u00a0\u00a0\u00a0\r\nself.assertTrue(sorted(actual_result_within['results']) == sorted(expected_result['results']))\r\nTypeError: '&lt;' not supported between instances of 'dict' and 'dict'<\/pre>\n<h4><span style=\"font-weight: 400\">Solution(s):<\/span><\/h4>\n<pre class=\"lang:default decode:true \">-\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 self.assertTrue(sorted(actual_result_within['results']) == sorted(expected_result['results']))\r\n+\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 self.assertTrue(sorted(actual_result_within['results'], key=(lambda x: x['name'])) == \\\r\n+\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 sorted(expected_result['results'], key=(lambda x: x['name'])))<\/pre>\n<p>&nbsp;<\/p>\n<h4><span style=\"font-weight: 400\">12. Problem(s):<\/span><\/h4>\n<pre class=\"lang:python decode:true\">File \"pytests\/tuqquery\/tuq.py\", line 1221, in _verify_results&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;\r\nself.fail(\"Results are incorrect.Actual num %s. Expected num: %s.\\n\" % (len(actual_result), len(expected_result)))\r\nAssertionError: Results are incorrect.Actual num 0. Expected num: 72.\r\n\r\nFile \"lib\/tasks\/task.py\", line 3638, in filter_emitted_rows\u00a0\u00a0\u00a0\u00a0\r\nreverse=descending_set)\r\nTypeError: 'cmp' is an invalid keyword argument for this function<\/pre>\n<h4><span style=\"font-weight: 400\">Solution(s):<\/span><\/h4>\n<pre class=\"lang:python decode:true \">expected_rows = sorted(self.emitted_rows, key=(lambda x: (x['key'],x['id'])),reverse=descending_set)<\/pre>\n<p>&nbsp;<\/p>\n<h4><span style=\"font-weight: 400\">13. Problem(s):<\/span><\/h4>\n<pre class=\"lang:python decode:true\">\u00a0File \"lib\/tasks\/task.py\", line 3675, in &lt;listcomp&gt;\u00a0\u00a0\u00a0\u00a0\r\nexpected_rows = [row for row in expected_rows if row['key'] &gt;= start_key and row['key'] &lt;= end_key]\r\nTypeError: '&gt;=' not supported between instances of 'int' and 'NoneType'<\/pre>\n<h4><span style=\"font-weight: 400\">Solution(s): <\/span><\/h4>\n<p><span style=\"font-weight: 400\">Here, it should return int as python 3 doesn\u2019t compare automatically as in python 2.<\/span><\/p>\n<p>&nbsp;<\/p>\n<h4><span style=\"font-weight: 400\">14. Problem(s): <\/span><\/h4>\n<pre class=\"lang:python decode:true\">hasattr(items,\u2019iteritems\u2019) doesn\u2019t return true<\/pre>\n<h4><span style=\"font-weight: 400\">Solution(s):<\/span><\/h4>\n<pre class=\"lang:python decode:true\">@@ -754,7 +755,7 @@ class MemcachedClient(object):\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\n# If this is a dict, convert it to a pair generator\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\ncollection = self.collection_name(collection)\u00a0\r\n-\u00a0 \u00a0 \u00a0 \u00a0 if hasattr(items, 'iteritems'):\r\n+\u00a0 \u00a0 \u00a0 \u00a0 if hasattr(items, 'items'):\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\nitems = iter(items.items())\r\n\r\nif hasattr(items, 'items'):<\/pre>\n<p>&nbsp;<\/p>\n<h4><span style=\"font-weight: 400\">15. Problem(s):<\/span><\/h4>\n<pre class=\"lang:python decode:true \">\u00a0File \"lib\/crc32.py\", line 78, in crc32_hash\u00a0\u00a0\u00a0\u00a0\r\ncrc = (crc &gt;&gt; 8) ^ crc32tab[int((crc ^ ord(ch)) &amp; 0xff)]\r\nTypeError: ord() expected string of length 1, but int found<\/pre>\n<h4><span style=\"font-weight: 400\">Solution(s):<\/span><\/h4>\n<p><span style=\"font-weight: 400\">Converted the key to string so that ch is string instead of int with binary key. See the file.<\/span><\/p>\n<pre class=\"lang:python decode:true\">try:\u00a0\r\n  key = key.decode()\r\nexcept \r\n  AttributeError:\u00a0pass<\/pre>\n<p>&nbsp;<\/p>\n<h4><span style=\"font-weight: 400\">16. Problem(s): <\/span><\/h4>\n<p><span style=\"font-weight: 400\">TypeError: &#8216;FileNotFoundError&#8217; object is not sub-scriptable<\/span><\/p>\n<h4><span style=\"font-weight: 400\">Solution(s): <\/span><\/h4>\n<p><span style=\"font-weight: 400\">Changed in Python 3 as FileNotFoundError is not sub-scriptable and instead, use errno attribute,\u00a0 e.errno<\/span><\/p>\n<pre class=\"lang:python decode:true\">File \"lib\/remote\/remote_util.py\", line 1714, in create_directory\u00a0\u00a0\u00a0\u00a0\r\nif e[0] == 2:\r\nTypeError: 'FileNotFoundError' object is not subscriptable\r\n-\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 if e[0] == 2:\r\n+\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 if e.errno == 2:<\/pre>\n<p>&nbsp;<\/p>\n<h4><span style=\"font-weight: 400\">17. Problem(s): <\/span><\/h4>\n<pre class=\"lang:python decode:true\">Traceback (most recent call last):\u00a0\u00a0\r\nFile \"lib\/couchbase_helper\/tuq_helper.py\", line 521, in run_query_and_verify_result\u00a0\u00a0\u00a0\u00a0\r\nself._verify_results(sorted_actual_result, sorted_expected_result)\u00a0\u00a0\r\nFile \"lib\/couchbase_helper\/tuq_helper.py\", line 114, in _verify_results\u00a0\u00a0\u00a0\u00a0\r\nraise Exception(msg)\r\nException: The number of rows match but the results mismatch, please check<\/pre>\n<h4><span style=\"font-weight: 400\">Solution(s):<\/span><\/h4>\n<p><span style=\"font-weight: 400\">The nested dictionary\/list comparison was not working because of the earlier sorted function to sort completely is now not available. Use deepdiff module and DeepDiff class to do the comparison<\/span><\/p>\n<p>&nbsp;<\/p>\n<h4><span style=\"font-weight: 400\">18. Problem(s): <\/span><\/h4>\n<p><span style=\"font-weight: 400\">AttributeError: module &#8216;string&#8217; has no attribute &#8216;replace&#8217;<\/span><\/p>\n<pre class=\"lang:default decode:true\">File \"scripts\/populateIni.py\", line 52, in main\u00a0\u00a0\u00a0\u00a0\r\ndata[i] = string.replace(data[i], 'dynamic', servers[0])\r\nAttributeError: module 'string' has no attribute 'replace'<\/pre>\n<h4><span style=\"font-weight: 400\">Solution(s): <\/span><\/h4>\n<p><span style=\"font-weight: 400\">Use direct str variable to replace as shown below for fixing the issue.<\/span><\/p>\n<pre class=\"lang:python decode:true \">data[i].replace( 'dynamic', servers[0])<\/pre>\n<p>&nbsp;<\/p>\n<h4><span style=\"font-weight: 400\">19. Problem(s): <\/span><\/h4>\n<pre class=\"lang:python decode:true\">TypeError: '&gt;' not supported between instances of 'int' and 'str'<\/pre>\n<h4><span style=\"font-weight: 400\">Solution(s): <\/span><\/h4>\n<p><span style=\"font-weight: 400\">Use str or int function appropriately.<\/span><\/p>\n<pre class=\"lang:python decode:true \">\u00a0\u00a0if where_clause:\r\n+\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 where_clause = where_clause.replace('if\u00a0 t &gt; \"', 'if str(t) &gt; \"') # to fix the type error between int, str comparison<\/pre>\n<p>&nbsp;<\/p>\n<h4><span style=\"font-weight: 400\">20. Problem(s): <\/span><\/h4>\n<p><span style=\"font-weight: 400\">NameError: name &#8216;cmp&#8217; is not defined<\/span><\/p>\n<h4><span style=\"font-weight: 400\">Solution(s): <\/span><\/h4>\n<p><span style=\"font-weight: 400\">Use deepdiff module and DeepDiff class to do object comparison.<\/span><\/p>\n<p>&nbsp;<\/p>\n<h4>21. Problem(s):<\/h4>\n<pre class=\"lang:python decode:true\">\u00a0\u00a0File \"lib\/couchbase_helper\/tuq_helper.py\", line 782, in verify_indexes_redistributed\u00a0\u00a0\u00a0\u00a0\r\nif cmp(items_count_before_rebalance, items_count_after_rebalance) != 0:\r\nNameError: name 'cmp' is not defined<\/pre>\n<h4><span style=\"font-weight: 400\">Solution(s): <\/span><\/h4>\n<pre class=\"lang:python decode:true\">Use deepdiff module and DeepDiff class to do object comparison.\r\n-\u00a0 \u00a0 \u00a0 \u00a0 if cmp(index_state_before_rebalance, index_state_after_rebalance) != 0:\r\n+\u00a0 \u00a0 \u00a0 \u00a0 if DeepDiff(index_state_before_rebalance, index_sFile \"lib\/couchbase_helper\/documentgenerator.py\", line 19, in has_next\u00a0\u00a0\u00a0\u00a0\r\nreturn self.itr &lt; self.end\r\nTypeError: '&lt;' not supported between instances of 'int' and 'str'<\/pre>\n<p><span style=\"font-weight: 400\">Convert str to int as below for the above type error issue.<\/span><\/p>\n<pre class=\"lang:python decode:true\">return int(self.itr) &lt; int(self.end)<\/pre>\n<p>&#8212;-<\/p>\n<p>That&#8217;s all for now on the list of problems to watch for when you upgrade Python version 2 to Python version 3. We will post more learnings in future blog posts. In the meantime, good luck migrating!<\/p>\n<p>&nbsp;<\/p>\n<h2><span style=\"font-weight: 400\">Further readings<\/span><\/h2>\n<p>The following references were helped us. You can also read further at below reference links to get more details and improve your code porting to Python 3.<\/p>\n<ol>\n<li style=\"font-weight: 400\"><a href=\"https:\/\/www.python.org\/dev\/peps\/pep-0373\/\"><span style=\"font-weight: 400\">https:\/\/www.python.org\/dev\/peps\/pep-0373\/<\/span><\/a><\/li>\n<li style=\"font-weight: 400\"><a href=\"https:\/\/wiki.python.org\/moin\/Python2orPython3\"><span style=\"font-weight: 400\">https:\/\/wiki.python.org\/moin\/Python2orPython3<\/span><\/a><\/li>\n<li style=\"font-weight: 400\"><a href=\"https:\/\/www.toptal.com\/python\/python-3-is-it-worth-the-switch\"><span style=\"font-weight: 400\">https:\/\/www.toptal.com\/python\/python-3-is-it-worth-the-switch<\/span><\/a><\/li>\n<li style=\"font-weight: 400\"><a href=\"https:\/\/weknowinc.com\/blog\/running-multiple-python-versions-mac-osx\"><span style=\"font-weight: 400\">https:\/\/weknowinc.com\/blog\/running-multiple-python-versions-mac-osx<\/span><\/a><\/li>\n<li style=\"font-weight: 400\"><a href=\"https:\/\/docs.python.org\/3\/howto\/pyporting.html\"><span style=\"font-weight: 400\">https:\/\/docs.python.org\/3\/howto\/pyporting.html<\/span><\/a><\/li>\n<li style=\"font-weight: 400\"><a href=\"https:\/\/wsvincent.com\/install-python3-mac\/\"><span style=\"font-weight: 400\">https:\/\/wsvincent.com\/install-python3-mac\/<\/span><\/a><\/li>\n<li style=\"font-weight: 400\"><a href=\"https:\/\/python3porting.com\/pdfs\/SupportingPython3-screen-1.0-latest.pdf\"><span style=\"font-weight: 400\">https:\/\/python3porting.com\/pdfs\/SupportingPython3-screen-1.0-latest.pdf<\/span><\/a><\/li>\n<li style=\"font-weight: 400\"><a href=\"https:\/\/riptutorial.com\/Download\/python-language.pdf\"><span style=\"font-weight: 400\">https:\/\/riptutorial.com\/Download\/python-language.pdf<\/span><\/a><\/li>\n<li style=\"font-weight: 400\"><a href=\"https:\/\/docs.couchbase.com\/python-sdk\/2.5\/start-using-sdk.html\"><span style=\"font-weight: 400\">https:\/\/docs.couchbase.com\/python-sdk\/2.5\/start-using-sdk.html<\/span><\/a><\/li>\n<li style=\"font-weight: 400\"><a href=\"https:\/\/docs.couchbase.com\/c-sdk\/2.10\/start-using-sdk.html\"><span style=\"font-weight: 400\">https:\/\/docs.couchbase.com\/c-sdk\/2.10\/start-using-sdk.html<\/span><\/a><\/li>\n<li style=\"font-weight: 400\"><a href=\"https:\/\/pypi.org\/project\/deepdiff\/\"><span style=\"font-weight: 400\">https:\/\/pypi.org\/project\/deepdiff\/<\/span><\/a><\/li>\n<li style=\"font-weight: 400\"><a href=\"https:\/\/buildmedia.readthedocs.org\/media\/pdf\/portingguide\/latest\/portingguide.pdf\"><span style=\"font-weight: 400\">https:\/\/buildmedia.readthedocs.org\/media\/pdf\/portingguide\/latest\/portingguide.pdf<\/span><\/a><\/li>\n<li style=\"font-weight: 400\"><a href=\"https:\/\/ptgmedia.pearsoncmg.com\/imprint_downloads\/informit\/promotions\/python\/python2python3.pdf\"><span style=\"font-weight: 400\">https:\/\/ptgmedia.pearsoncmg.com\/imprint_downloads\/informit\/promotions\/python\/python2python3.pdf<\/span><\/a><\/li>\n<\/ol>\n<p>Hope you had a good time reading!<\/p>\n<p><strong>Disclaimer:<\/strong> Please view this as a quick reference for your Python 3 upgrade, rather than a complete guide to resolving porting issues. Our intent here is to help you at some level and give you a jump start on the porting process. Please feel free to share if you learned something new that can help us. Your positive feedback is appreciated!<\/p>\n<p>&nbsp;<\/p>\n<p>&#8212;<\/p>\n<p>Thanks to Raju Suravarjjala and Keshav Murthy for their key inputs and feedback.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction The last major Python upgrade &#8212; to version 3 &#8212; arrived in Dec. 2008, nearly 12 years ago. And yet there is a good chance that you are still working on the Python 2 product or test code. If [&hellip;]<\/p>\n","protected":false},"author":46261,"featured_media":9922,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[1815,2381,1816,9139,2389],"tags":[1725],"ppma_author":[9096],"class_list":["post-7726","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-best-practices-and-tutorials","category-community","category-couchbase-server","category-python","category-solutions","tag-nosql-database"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.8 (Yoast SEO v25.8) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Python 2 to 3 Migration: How to Update &amp; Key Differences<\/title>\n<meta name=\"description\" content=\"Learn how to update from Python 2 to 3 in this post from Couchbase. We also cover their key differences and identify common problems with migration.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.couchbase.com\/blog\/tips-and-tricks-for-upgrading-from-python-2-to-python-3\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"How to Update Python 2 to Python 3 &amp; The Differences Between Them\" \/>\n<meta property=\"og:description\" content=\"Learn how to update from Python 2 to 3 in this post from Couchbase. We also cover their key differences and identify common problems with migration.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/tips-and-tricks-for-upgrading-from-python-2-to-python-3\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2019-10-13T21:34:34+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-06-14T04:25:16+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/10\/update-python-blogbanner.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1575\" \/>\n\t<meta property=\"og:image:height\" content=\"628\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Jagadesh Munta, Principal Software Engineer, Couchbase\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Jagadesh Munta, Principal Software Engineer, Couchbase\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"11 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/tips-and-tricks-for-upgrading-from-python-2-to-python-3\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/tips-and-tricks-for-upgrading-from-python-2-to-python-3\/\"},\"author\":{\"name\":\"Jagadesh Munta, Principal Software Engineer, Couchbase\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/5efab7fca2a650b389d487e721997306\"},\"headline\":\"How to Update Python 2 to Python 3 &amp; The Differences Between Them\",\"datePublished\":\"2019-10-13T21:34:34+00:00\",\"dateModified\":\"2025-06-14T04:25:16+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/tips-and-tricks-for-upgrading-from-python-2-to-python-3\/\"},\"wordCount\":2541,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/tips-and-tricks-for-upgrading-from-python-2-to-python-3\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/10\/update-python-blogbanner.jpg\",\"keywords\":[\"NoSQL Database\"],\"articleSection\":[\"Best Practices and Tutorials\",\"Community\",\"Couchbase Server\",\"Python\",\"Solutions\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/tips-and-tricks-for-upgrading-from-python-2-to-python-3\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/tips-and-tricks-for-upgrading-from-python-2-to-python-3\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/tips-and-tricks-for-upgrading-from-python-2-to-python-3\/\",\"name\":\"Python 2 to 3 Migration: How to Update & Key Differences\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/tips-and-tricks-for-upgrading-from-python-2-to-python-3\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/tips-and-tricks-for-upgrading-from-python-2-to-python-3\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/10\/update-python-blogbanner.jpg\",\"datePublished\":\"2019-10-13T21:34:34+00:00\",\"dateModified\":\"2025-06-14T04:25:16+00:00\",\"description\":\"Learn how to update from Python 2 to 3 in this post from Couchbase. We also cover their key differences and identify common problems with migration.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/tips-and-tricks-for-upgrading-from-python-2-to-python-3\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/tips-and-tricks-for-upgrading-from-python-2-to-python-3\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/tips-and-tricks-for-upgrading-from-python-2-to-python-3\/#primaryimage\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/10\/update-python-blogbanner.jpg\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/10\/update-python-blogbanner.jpg\",\"width\":1575,\"height\":628,\"caption\":\"Developers discuss how to upgrade python.\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/tips-and-tricks-for-upgrading-from-python-2-to-python-3\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"How to Update Python 2 to Python 3 &amp; The Differences Between Them\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"name\":\"The Couchbase Blog\",\"description\":\"Couchbase, the NoSQL Database\",\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"width\":218,\"height\":34,\"caption\":\"The Couchbase Blog\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/5efab7fca2a650b389d487e721997306\",\"name\":\"Jagadesh Munta, Principal Software Engineer, Couchbase\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/2b547f1e03e58f24f78d6318913302d1\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/6d1189147482e8a4e1c0d2a3db919014c2cfe816b6d11357c3fd740f9deadd31?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/6d1189147482e8a4e1c0d2a3db919014c2cfe816b6d11357c3fd740f9deadd31?s=96&d=mm&r=g\",\"caption\":\"Jagadesh Munta, Principal Software Engineer, Couchbase\"},\"description\":\"Jagadesh Munta is a Principal Software Engineer at Couchbase Inc. USA. Prior to this, he was a veteran in Sun Microsystems and Oracle together for 19 years. Jagadesh is holding Masters in Software Engineering at San Jose State University,USA and B.Tech. Computer Science and Engineering at JNTU,India. He is an author of \\\"Software Quality and Java Automation Engineer Survival Guide\u201d to help Software developers and Quality automation engineers.\",\"url\":\"https:\/\/www.couchbase.com\/blog\/author\/jagadesh\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Python 2 to 3 Migration: How to Update & Key Differences","description":"Learn how to update from Python 2 to 3 in this post from Couchbase. We also cover their key differences and identify common problems with migration.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.couchbase.com\/blog\/tips-and-tricks-for-upgrading-from-python-2-to-python-3\/","og_locale":"en_US","og_type":"article","og_title":"How to Update Python 2 to Python 3 &amp; The Differences Between Them","og_description":"Learn how to update from Python 2 to 3 in this post from Couchbase. We also cover their key differences and identify common problems with migration.","og_url":"https:\/\/www.couchbase.com\/blog\/tips-and-tricks-for-upgrading-from-python-2-to-python-3\/","og_site_name":"The Couchbase Blog","article_published_time":"2019-10-13T21:34:34+00:00","article_modified_time":"2025-06-14T04:25:16+00:00","og_image":[{"width":1575,"height":628,"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/10\/update-python-blogbanner.jpg","type":"image\/jpeg"}],"author":"Jagadesh Munta, Principal Software Engineer, Couchbase","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Jagadesh Munta, Principal Software Engineer, Couchbase","Est. reading time":"11 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/tips-and-tricks-for-upgrading-from-python-2-to-python-3\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/tips-and-tricks-for-upgrading-from-python-2-to-python-3\/"},"author":{"name":"Jagadesh Munta, Principal Software Engineer, Couchbase","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/5efab7fca2a650b389d487e721997306"},"headline":"How to Update Python 2 to Python 3 &amp; The Differences Between Them","datePublished":"2019-10-13T21:34:34+00:00","dateModified":"2025-06-14T04:25:16+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/tips-and-tricks-for-upgrading-from-python-2-to-python-3\/"},"wordCount":2541,"commentCount":0,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/tips-and-tricks-for-upgrading-from-python-2-to-python-3\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/10\/update-python-blogbanner.jpg","keywords":["NoSQL Database"],"articleSection":["Best Practices and Tutorials","Community","Couchbase Server","Python","Solutions"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/tips-and-tricks-for-upgrading-from-python-2-to-python-3\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/tips-and-tricks-for-upgrading-from-python-2-to-python-3\/","url":"https:\/\/www.couchbase.com\/blog\/tips-and-tricks-for-upgrading-from-python-2-to-python-3\/","name":"Python 2 to 3 Migration: How to Update & Key Differences","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/tips-and-tricks-for-upgrading-from-python-2-to-python-3\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/tips-and-tricks-for-upgrading-from-python-2-to-python-3\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/10\/update-python-blogbanner.jpg","datePublished":"2019-10-13T21:34:34+00:00","dateModified":"2025-06-14T04:25:16+00:00","description":"Learn how to update from Python 2 to 3 in this post from Couchbase. We also cover their key differences and identify common problems with migration.","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/tips-and-tricks-for-upgrading-from-python-2-to-python-3\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/tips-and-tricks-for-upgrading-from-python-2-to-python-3\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/tips-and-tricks-for-upgrading-from-python-2-to-python-3\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/10\/update-python-blogbanner.jpg","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/10\/update-python-blogbanner.jpg","width":1575,"height":628,"caption":"Developers discuss how to upgrade python."},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/tips-and-tricks-for-upgrading-from-python-2-to-python-3\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"How to Update Python 2 to Python 3 &amp; The Differences Between Them"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"The Couchbase Blog","description":"Couchbase, the NoSQL Database","publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"The Couchbase Blog","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","width":218,"height":34,"caption":"The Couchbase Blog"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/5efab7fca2a650b389d487e721997306","name":"Jagadesh Munta, Principal Software Engineer, Couchbase","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/2b547f1e03e58f24f78d6318913302d1","url":"https:\/\/secure.gravatar.com\/avatar\/6d1189147482e8a4e1c0d2a3db919014c2cfe816b6d11357c3fd740f9deadd31?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/6d1189147482e8a4e1c0d2a3db919014c2cfe816b6d11357c3fd740f9deadd31?s=96&d=mm&r=g","caption":"Jagadesh Munta, Principal Software Engineer, Couchbase"},"description":"Jagadesh Munta is a Principal Software Engineer at Couchbase Inc. USA. Prior to this, he was a veteran in Sun Microsystems and Oracle together for 19 years. Jagadesh is holding Masters in Software Engineering at San Jose State University,USA and B.Tech. Computer Science and Engineering at JNTU,India. He is an author of \"Software Quality and Java Automation Engineer Survival Guide\u201d to help Software developers and Quality automation engineers.","url":"https:\/\/www.couchbase.com\/blog\/author\/jagadesh\/"}]}},"authors":[{"term_id":9096,"user_id":46261,"is_guest":0,"slug":"jagadesh","display_name":"Jagadesh Munta, Principal Software Engineer, Couchbase","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/6d1189147482e8a4e1c0d2a3db919014c2cfe816b6d11357c3fd740f9deadd31?s=96&d=mm&r=g","author_category":"","last_name":"Munta, Principal Software Engineer, Couchbase","first_name":"Jagadesh","job_title":"","user_url":"","description":"Jagadesh Munta is a Principal Software Engineer at Couchbase Inc. USA. Prior to this, he was a veteran in Sun Microsystems and Oracle together for 19 years. Jagadesh is holding Masters in Software Engineering at San Jose State University,USA and B.Tech. Computer Science and Engineering at JNTU,India. He is an author of \"Software Quality and Java Automation Engineer Survival Guide\u201d to help Software developers and Quality automation engineers."}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/7726","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/users\/46261"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/comments?post=7726"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/7726\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media\/9922"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media?parent=7726"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/categories?post=7726"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/tags?post=7726"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=7726"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}