converted case-study-porting-chardet-to-python-3 to HTML

This commit is contained in:
Mark Pilgrim
2009-01-25 15:24:09 -05:00
parent 3d725f7474
commit e44b5ee3fe
4 changed files with 1038 additions and 337 deletions
+701
View File
@@ -0,0 +1,701 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Case study: porting chardet to Python 3 - Dive into Python 3</title>
<link rel="stylesheet" type="text/css" href="dip3.css">
</head>
<body>
<h1>Case study: porting chardet to Python 3</h1>
<ul class="toc">
<li><a href="#running2to3">Running <code class="filename">2to3</code></a></li>
<li><a href="#falseisinvalidsyntax"><code>False</code> is invalid syntax</a></li>
<li><a href="#namefileisnotdefined">Name '<var>file</var>' is not defined</a></li>
<li><a href="#cantconvertbytesobject">Can't convert '<code>bytes</code>' object to <code>str</code> implicitly</a></li>
</ul>
<section id="running2to3">
<h2>Running <code class="filename">2to3</code></h2>
<p>We're going to migrate the <code class="filename">chardet</code> module from Python 2 to Python 3. Python 3 comes with a utility script to help with this, called <code class="filename">2to3</code>. <code class="filename">2to3</code> takes your actual Python 2 source code as input, and auto-converts as much as it can to Python 3. [FIXME reference 2to3 chapter once it's done]</p>
<p>The <code class="filename">chardet</code> library is split across several different files, all in the same directory. The <code class="filename">2to3</code> script makes it easy to convert multiple files at once: just pass a directory as a command line argument, and <code class="filename">2to3</code> will convert each of the files in turn.</p>
<pre class="screen"><samp class="prompt">C:\home\chardet></samp><kbd>python c:\Python30\Tools\Scripts\2to3.py -w chardet\</kbd>
<samp>RefactoringTool: Skipping implicit fixer: buffer
RefactoringTool: Skipping implicit fixer: idioms
RefactoringTool: Skipping implicit fixer: set_literal
RefactoringTool: Skipping implicit fixer: ws_comma
--- chardet\__init__.py (original)
+++ chardet\__init__.py (refactored)
@@ -18,7 +18,7 @@
__version__ = "1.0.1"
def detect(aBuf):
- import universaldetector
+ from . import universaldetector
u = universaldetector.UniversalDetector()
u.reset()
u.feed(aBuf)
--- chardet\big5prober.py (original)
+++ chardet\big5prober.py (refactored)
@@ -25,10 +25,10 @@
# 02110-1301 USA
######################### END LICENSE BLOCK #########################
-from mbcharsetprober import MultiByteCharSetProber
-from codingstatemachine import CodingStateMachine
-from chardistribution import Big5DistributionAnalysis
-from mbcssm import Big5SMModel
+from .mbcharsetprober import MultiByteCharSetProber
+from .codingstatemachine import CodingStateMachine
+from .chardistribution import Big5DistributionAnalysis
+from .mbcssm import Big5SMModel
class Big5Prober(MultiByteCharSetProber):
def __init__(self):
--- chardet\chardistribution.py (original)
+++ chardet\chardistribution.py (refactored)
@@ -25,12 +25,12 @@
# 02110-1301 USA
######################### END LICENSE BLOCK #########################
-import constants
-from euctwfreq import EUCTWCharToFreqOrder, EUCTW_TABLE_SIZE, EUCTW_TYPICAL_DISTRIBUTION_RATIO
-from euckrfreq import EUCKRCharToFreqOrder, EUCKR_TABLE_SIZE, EUCKR_TYPICAL_DISTRIBUTION_RATIO
-from gb2312freq import GB2312CharToFreqOrder, GB2312_TABLE_SIZE, GB2312_TYPICAL_DISTRIBUTION_RATIO
-from big5freq import Big5CharToFreqOrder, BIG5_TABLE_SIZE, BIG5_TYPICAL_DISTRIBUTION_RATIO
-from jisfreq import JISCharToFreqOrder, JIS_TABLE_SIZE, JIS_TYPICAL_DISTRIBUTION_RATIO
+from . import constants
+from .euctwfreq import EUCTWCharToFreqOrder, EUCTW_TABLE_SIZE, EUCTW_TYPICAL_DISTRIBUTION_RATIO
+from .euckrfreq import EUCKRCharToFreqOrder, EUCKR_TABLE_SIZE, EUCKR_TYPICAL_DISTRIBUTION_RATIO
+from .gb2312freq import GB2312CharToFreqOrder, GB2312_TABLE_SIZE, GB2312_TYPICAL_DISTRIBUTION_RATIO
+from .big5freq import Big5CharToFreqOrder, BIG5_TABLE_SIZE, BIG5_TYPICAL_DISTRIBUTION_RATIO
+from .jisfreq import JISCharToFreqOrder, JIS_TABLE_SIZE, JIS_TYPICAL_DISTRIBUTION_RATIO
ENOUGH_DATA_THRESHOLD = 1024
SURE_YES = 0.99
--- chardet\charsetgroupprober.py (original)
+++ chardet\charsetgroupprober.py (refactored)
@@ -26,7 +26,7 @@
######################### END LICENSE BLOCK #########################
import constants, sys
-from charsetprober import CharSetProber
+from .charsetprober import CharSetProber
class CharSetGroupProber(CharSetProber):
def __init__(self):
--- chardet\codingstatemachine.py (original)
+++ chardet\codingstatemachine.py (refactored)
@@ -25,7 +25,7 @@
# 02110-1301 USA
######################### END LICENSE BLOCK #########################
-from constants import eStart, eError, eItsMe
+from .constants import eStart, eError, eItsMe
class CodingStateMachine:
def __init__(self, sm):
--- chardet\constants.py (original)
+++ chardet\constants.py (refactored)
@@ -38,10 +38,10 @@
SHORTCUT_THRESHOLD = 0.95
-import __builtin__
+import builtins
if not hasattr(__builtin__, 'False'):
False = 0
True = 1
else:
- False = __builtin__.False
- True = __builtin__.True
+ False = builtins.False
+ True = builtins.True
--- chardet\escprober.py (original)
+++ chardet\escprober.py (refactored)
@@ -26,9 +26,9 @@
######################### END LICENSE BLOCK #########################
import constants, sys
-from escsm import HZSMModel, ISO2022CNSMModel, ISO2022JPSMModel, ISO2022KRSMModel
-from charsetprober import CharSetProber
-from codingstatemachine import CodingStateMachine
+from .escsm import HZSMModel, ISO2022CNSMModel, ISO2022JPSMModel, ISO2022KRSMModel
+from .charsetprober import CharSetProber
+from .codingstatemachine import CodingStateMachine
class EscCharSetProber(CharSetProber):
def __init__(self):
--- chardet\escsm.py (original)
+++ chardet\escsm.py (refactored)
@@ -25,7 +25,7 @@
# 02110-1301 USA
######################### END LICENSE BLOCK #########################
-from constants import eStart, eError, eItsMe
+from .constants import eStart, eError, eItsMe
HZ_cls = ( \
1,0,0,0,0,0,0,0, # 00 - 07
--- chardet\eucjpprober.py (original)
+++ chardet\eucjpprober.py (refactored)
@@ -26,12 +26,12 @@
######################### END LICENSE BLOCK #########################
import constants, sys
-from constants import eStart, eError, eItsMe
-from mbcharsetprober import MultiByteCharSetProber
-from codingstatemachine import CodingStateMachine
-from chardistribution import EUCJPDistributionAnalysis
-from jpcntx import EUCJPContextAnalysis
-from mbcssm import EUCJPSMModel
+from .constants import eStart, eError, eItsMe
+from .mbcharsetprober import MultiByteCharSetProber
+from .codingstatemachine import CodingStateMachine
+from .chardistribution import EUCJPDistributionAnalysis
+from .jpcntx import EUCJPContextAnalysis
+from .mbcssm import EUCJPSMModel
class EUCJPProber(MultiByteCharSetProber):
def __init__(self):
--- chardet\euckrprober.py (original)
+++ chardet\euckrprober.py (refactored)
@@ -25,10 +25,10 @@
# 02110-1301 USA
######################### END LICENSE BLOCK #########################
-from mbcharsetprober import MultiByteCharSetProber
-from codingstatemachine import CodingStateMachine
-from chardistribution import EUCKRDistributionAnalysis
-from mbcssm import EUCKRSMModel
+from .mbcharsetprober import MultiByteCharSetProber
+from .codingstatemachine import CodingStateMachine
+from .chardistribution import EUCKRDistributionAnalysis
+from .mbcssm import EUCKRSMModel
class EUCKRProber(MultiByteCharSetProber):
def __init__(self):
--- chardet\euctwprober.py (original)
+++ chardet\euctwprober.py (refactored)
@@ -25,10 +25,10 @@
# 02110-1301 USA
######################### END LICENSE BLOCK #########################
-from mbcharsetprober import MultiByteCharSetProber
-from codingstatemachine import CodingStateMachine
-from chardistribution import EUCTWDistributionAnalysis
-from mbcssm import EUCTWSMModel
+from .mbcharsetprober import MultiByteCharSetProber
+from .codingstatemachine import CodingStateMachine
+from .chardistribution import EUCTWDistributionAnalysis
+from .mbcssm import EUCTWSMModel
class EUCTWProber(MultiByteCharSetProber):
def __init__(self):
--- chardet\gb2312prober.py (original)
+++ chardet\gb2312prober.py (refactored)
@@ -25,10 +25,10 @@
# 02110-1301 USA
######################### END LICENSE BLOCK #########################
-from mbcharsetprober import MultiByteCharSetProber
-from codingstatemachine import CodingStateMachine
-from chardistribution import GB2312DistributionAnalysis
-from mbcssm import GB2312SMModel
+from .mbcharsetprober import MultiByteCharSetProber
+from .codingstatemachine import CodingStateMachine
+from .chardistribution import GB2312DistributionAnalysis
+from .mbcssm import GB2312SMModel
class GB2312Prober(MultiByteCharSetProber):
def __init__(self):
--- chardet\hebrewprober.py (original)
+++ chardet\hebrewprober.py (refactored)
@@ -25,8 +25,8 @@
# 02110-1301 USA
######################### END LICENSE BLOCK #########################
-from charsetprober import CharSetProber
-import constants
+from .charsetprober import CharSetProber
+from . import constants
# This prober doesn't actually recognize a language or a charset.
# It is a helper prober for the use of the Hebrew model probers
--- chardet\jpcntx.py (original)
+++ chardet\jpcntx.py (refactored)
@@ -25,7 +25,7 @@
# 02110-1301 USA
######################### END LICENSE BLOCK #########################
-import constants
+from . import constants
NUM_OF_CATEGORY = 6
DONT_KNOW = -1
--- chardet\langbulgarianmodel.py (original)
+++ chardet\langbulgarianmodel.py (refactored)
@@ -25,7 +25,7 @@
# 02110-1301 USA
######################### END LICENSE BLOCK #########################
-import constants
+from . import constants
# 255: Control characters that usually does not exist in any text
# 254: Carriage/Return
--- chardet\langcyrillicmodel.py (original)
+++ chardet\langcyrillicmodel.py (refactored)
@@ -25,7 +25,7 @@
# 02110-1301 USA
######################### END LICENSE BLOCK #########################
-import constants
+from . import constants
# KOI8-R language model
# Character Mapping Table:
--- chardet\langgreekmodel.py (original)
+++ chardet\langgreekmodel.py (refactored)
@@ -25,7 +25,7 @@
# 02110-1301 USA
######################### END LICENSE BLOCK #########################
-import constants
+from . import constants
# 255: Control characters that usually does not exist in any text
# 254: Carriage/Return
--- chardet\langhebrewmodel.py (original)
+++ chardet\langhebrewmodel.py (refactored)
@@ -27,7 +27,7 @@
# 02110-1301 USA
######################### END LICENSE BLOCK #########################
-import constants
+from . import constants
# 255: Control characters that usually does not exist in any text
# 254: Carriage/Return
--- chardet\langhungarianmodel.py (original)
+++ chardet\langhungarianmodel.py (refactored)
@@ -25,7 +25,7 @@
# 02110-1301 USA
######################### END LICENSE BLOCK #########################
-import constants
+from . import constants
# 255: Control characters that usually does not exist in any text
# 254: Carriage/Return
--- chardet\langthaimodel.py (original)
+++ chardet\langthaimodel.py (refactored)
@@ -25,7 +25,7 @@
# 02110-1301 USA
######################### END LICENSE BLOCK #########################
-import constants
+from . import constants
# 255: Control characters that usually does not exist in any text
# 254: Carriage/Return
--- chardet\latin1prober.py (original)
+++ chardet\latin1prober.py (refactored)
@@ -26,8 +26,8 @@
# 02110-1301 USA
######################### END LICENSE BLOCK #########################
-from charsetprober import CharSetProber
-import constants
+from .charsetprober import CharSetProber
+from . import constants
import operator
FREQ_CAT_NUM = 4
--- chardet\mbcharsetprober.py (original)
+++ chardet\mbcharsetprober.py (refactored)
@@ -28,8 +28,8 @@
######################### END LICENSE BLOCK #########################
import constants, sys
-from constants import eStart, eError, eItsMe
-from charsetprober import CharSetProber
+from .constants import eStart, eError, eItsMe
+from .charsetprober import CharSetProber
class MultiByteCharSetProber(CharSetProber):
def __init__(self):
--- chardet\mbcsgroupprober.py (original)
+++ chardet\mbcsgroupprober.py (refactored)
@@ -27,14 +27,14 @@
# 02110-1301 USA
######################### END LICENSE BLOCK #########################
-from charsetgroupprober import CharSetGroupProber
-from utf8prober import UTF8Prober
-from sjisprober import SJISProber
-from eucjpprober import EUCJPProber
-from gb2312prober import GB2312Prober
-from euckrprober import EUCKRProber
-from big5prober import Big5Prober
-from euctwprober import EUCTWProber
+from .charsetgroupprober import CharSetGroupProber
+from .utf8prober import UTF8Prober
+from .sjisprober import SJISProber
+from .eucjpprober import EUCJPProber
+from .gb2312prober import GB2312Prober
+from .euckrprober import EUCKRProber
+from .big5prober import Big5Prober
+from .euctwprober import EUCTWProber
class MBCSGroupProber(CharSetGroupProber):
def __init__(self):
--- chardet\mbcssm.py (original)
+++ chardet\mbcssm.py (refactored)
@@ -25,7 +25,7 @@
# 02110-1301 USA
######################### END LICENSE BLOCK #########################
-from constants import eStart, eError, eItsMe
+from .constants import eStart, eError, eItsMe
# BIG5
--- chardet\sbcharsetprober.py (original)
+++ chardet\sbcharsetprober.py (refactored)
@@ -27,7 +27,7 @@
######################### END LICENSE BLOCK #########################
import constants, sys
-from charsetprober import CharSetProber
+from .charsetprober import CharSetProber
SAMPLE_SIZE = 64
SB_ENOUGH_REL_THRESHOLD = 1024
--- chardet\sbcsgroupprober.py (original)
+++ chardet\sbcsgroupprober.py (refactored)
@@ -27,15 +27,15 @@
######################### END LICENSE BLOCK #########################
import constants, sys
-from charsetgroupprober import CharSetGroupProber
-from sbcharsetprober import SingleByteCharSetProber
-from langcyrillicmodel import Win1251CyrillicModel, Koi8rModel, Latin5CyrillicModel, MacCyrillicModel, Ibm866Model, Ibm855Model
-from langgreekmodel import Latin7GreekModel, Win1253GreekModel
-from langbulgarianmodel import Latin5BulgarianModel, Win1251BulgarianModel
-from langhungarianmodel import Latin2HungarianModel, Win1250HungarianModel
-from langthaimodel import TIS620ThaiModel
-from langhebrewmodel import Win1255HebrewModel
-from hebrewprober import HebrewProber
+from .charsetgroupprober import CharSetGroupProber
+from .sbcharsetprober import SingleByteCharSetProber
+from .langcyrillicmodel import Win1251CyrillicModel, Koi8rModel, Latin5CyrillicModel, MacCyrillicModel, Ibm866Model, Ibm855Model
+from .langgreekmodel import Latin7GreekModel, Win1253GreekModel
+from .langbulgarianmodel import Latin5BulgarianModel, Win1251BulgarianModel
+from .langhungarianmodel import Latin2HungarianModel, Win1250HungarianModel
+from .langthaimodel import TIS620ThaiModel
+from .langhebrewmodel import Win1255HebrewModel
+from .hebrewprober import HebrewProber
class SBCSGroupProber(CharSetGroupProber):
def __init__(self):
--- chardet\sjisprober.py (original)
+++ chardet\sjisprober.py (refactored)
@@ -25,13 +25,13 @@
# 02110-1301 USA
######################### END LICENSE BLOCK #########################
-from mbcharsetprober import MultiByteCharSetProber
-from codingstatemachine import CodingStateMachine
-from chardistribution import SJISDistributionAnalysis
-from jpcntx import SJISContextAnalysis
-from mbcssm import SJISSMModel
+from .mbcharsetprober import MultiByteCharSetProber
+from .codingstatemachine import CodingStateMachine
+from .chardistribution import SJISDistributionAnalysis
+from .jpcntx import SJISContextAnalysis
+from .mbcssm import SJISSMModel
import constants, sys
-from constants import eStart, eError, eItsMe
+from .constants import eStart, eError, eItsMe
class SJISProber(MultiByteCharSetProber):
def __init__(self):
--- chardet\universaldetector.py (original)
+++ chardet\universaldetector.py (refactored)
@@ -27,10 +27,10 @@
######################### END LICENSE BLOCK #########################
import constants, sys
-from latin1prober import Latin1Prober # windows-1252
-from mbcsgroupprober import MBCSGroupProber # multi-byte character sets
-from sbcsgroupprober import SBCSGroupProber # single-byte character sets
-from escprober import EscCharSetProber # ISO-2122, etc.
+from .latin1prober import Latin1Prober # windows-1252
+from .mbcsgroupprober import MBCSGroupProber # multi-byte character sets
+from .sbcsgroupprober import SBCSGroupProber # single-byte character sets
+from .escprober import EscCharSetProber # ISO-2122, etc.
import re
MINIMUM_THRESHOLD = 0.20
--- chardet\utf8prober.py (original)
+++ chardet\utf8prober.py (refactored)
@@ -26,10 +26,10 @@
######################### END LICENSE BLOCK #########################
import constants, sys
-from constants import eStart, eError, eItsMe
-from charsetprober import CharSetProber
-from codingstatemachine import CodingStateMachine
-from mbcssm import UTF8SMModel
+from .constants import eStart, eError, eItsMe
+from .charsetprober import CharSetProber
+from .codingstatemachine import CodingStateMachine
+from .mbcssm import UTF8SMModel
ONE_CHAR_PROB = 0.5
RefactoringTool: Files that were modified:
RefactoringTool: chardet\__init__.py
RefactoringTool: chardet\big5prober.py
RefactoringTool: chardet\chardistribution.py
RefactoringTool: chardet\charsetgroupprober.py
RefactoringTool: chardet\codingstatemachine.py
RefactoringTool: chardet\constants.py
RefactoringTool: chardet\escprober.py
RefactoringTool: chardet\escsm.py
RefactoringTool: chardet\eucjpprober.py
RefactoringTool: chardet\euckrprober.py
RefactoringTool: chardet\euctwprober.py
RefactoringTool: chardet\gb2312prober.py
RefactoringTool: chardet\hebrewprober.py
RefactoringTool: chardet\jpcntx.py
RefactoringTool: chardet\langbulgarianmodel.py
RefactoringTool: chardet\langcyrillicmodel.py
RefactoringTool: chardet\langgreekmodel.py
RefactoringTool: chardet\langhebrewmodel.py
RefactoringTool: chardet\langhungarianmodel.py
RefactoringTool: chardet\langthaimodel.py
RefactoringTool: chardet\latin1prober.py
RefactoringTool: chardet\mbcharsetprober.py
RefactoringTool: chardet\mbcsgroupprober.py
RefactoringTool: chardet\mbcssm.py
RefactoringTool: chardet\sbcharsetprober.py
RefactoringTool: chardet\sbcsgroupprober.py
RefactoringTool: chardet\sjisprober.py
RefactoringTool: chardet\universaldetector.py
RefactoringTool: chardet\utf8prober.py</samp></pre>
<p>Now run the <code class="filename">2to3</code> script on the testing harness, <code class="filename">test.py</code>.</p>
<pre class="screen"><samp class="prompt">C:\home\chardet></samp><kbd>python c:\Python30\Tools\Scripts\2to3.py -w test.py</kbd>
<samp>RefactoringTool: Skipping implicit fixer: buffer
RefactoringTool: Skipping implicit fixer: idioms
RefactoringTool: Skipping implicit fixer: set_literal
RefactoringTool: Skipping implicit fixer: ws_comma
--- test.py (original)
+++ test.py (refactored)
@@ -4,7 +4,7 @@
count = 0
u = UniversalDetector()
for f in glob.glob(sys.argv[1]):
- print f.ljust(60),
+ print(f.ljust(60), end=' ')
u.reset()
for line in file(f, 'rb'):
u.feed(line)
@@ -12,8 +12,8 @@
u.close()
result = u.result
if result['encoding']:
- print result['encoding'], 'with confidence', result['confidence']
+ print(result['encoding'], 'with confidence', result['confidence'])
else:
- print '******** no result'
+ print('******** no result')
count += 1
-print count, 'tests'
+print(count, 'tests')
RefactoringTool: Files that were modified:
RefactoringTool: test.py</samp></pre>
<p>Well, that wasn't so hard. Just a few imports and print statements to convert. Time to run the new version. Do you think it'll work?</p>
</section>
<section id="falseisinvalidsyntax">
<h2><code>False</code> is invalid syntax</h2>
<p>Now for the real test: running the test harness against the test suite. Since the test suite is designed to cover all the possible code paths, it's a good way to test our ported code to make sure there aren't any bugs lurking anywhere.</p>
<pre class="screen"><samp class="prompt">C:\home\chardet></samp><kbd>python test.py tests\*\*</kbd>
<samp class="traceback">Traceback (most recent call last):
File "test.py", line 1, in &lt;module>
from chardet.universaldetector import UniversalDetector
File "C:\home\chardet\chardet\universaldetector.py", line 51
self.done = constants.False
^
SyntaxError: invalid syntax</samp></pre>
<p>Hmm, a small snag. In Python 3, <code>False</code> is a reserved word, so you can't use it as a variable name. Let's look at <code class="filename">constants.py</code> to see where it's defined. Here's the original version from <code class="filename">constants.py</code>, before the <code class="filename">2to3</code> script changed it:</p>
<pre><code>import __builtin__
if not hasattr(__builtin__, 'False'):
False = 0
True = 1
else:
False = __builtin__.False
True = __builtin__.True</code></pre>
<p>This piece of code is designed to allow this library to run under older versions of Python 2. Prior to Python 2.3 [FIXME-LINK], Python had no built-in <code>Boolean</code> type. This code detects the absence of the built-in constants <code>True</code> and <code>False</code>, and defines them if necessary.</p>
<p>However, Python 3 will always have a <code>Boolean</code> type, so this entire code snippet is unnecessary. The simplest solution is to replace all instances of "<code>constants.True</code>" and "<code>constants.False</code>" with "<code>True</code>" and "<code>False</code>", respectively, then delete this dead code from <code class="filename">constants.py</code>.</p>
<p>So this line in <code class="filename">universaldetector.py</code>:</p>
<pre><code>self.done = constants.False</code></pre>
<p>Becomes</p>
<pre><code>self.done = False</code></pre>
<p>Ah, wasn't that satisfying? The code is shorter and more readable already.</p>
</section>
<section id="nomodulenamedconstants">
<h2>No module named <code class="filename">constants</code></h2>
<p>Time to run test.py again and see how far it gets.</p>
<pre class="screen"><samp class="prompt">C:\home\chardet></samp><kbd>python test.py tests\*\*</kbd>
<samp class="traceback">Traceback (most recent call last):
File "test.py", line 1, in &lt;module>
from chardet.universaldetector import UniversalDetector
File "C:\home\chardet\chardet\universaldetector.py", line 29, in &lt;module>
import constants, sys
ImportError: No module named constants</samp></pre>
<p>What's that you say? No module named <code class="filename">constants</code>? Of course there's a module named <code class="filename">constants</code>. ... Oh wait, no there isn't. Remember when the <code class="filename">2to3</code> script fixed up all those import statements? This library has a lot of relative imports -- that is, modules that import other modules within the library. In Python 3, all import statements are absolute by default [FIXME-LINK PEP 0328]. To do relative imports, you need to do something like this instead:</p>
<pre><code>from . import constants</code></pre>
<p>But wait. Wasn't the <code class="filename">2to3</code> script supposed to take care of these for you? Well, it did, but this particular import statement combines two different types of imports into one line: a relative import of the <code class="filename">constants</code> module within the library, and an absolute import of the <code class="filename">sys</code> module that is pre-installed in the Python standard library. In Python 2, you could combine these into one import statement. In Python 3, you can't, and the <code class="filename">2to3</code> script is not smart enough to split the import statement into two.</p>
<p>The solution is to split the import statement manually. So this two-in-one import:</p>
<pre><code>import constants, sys</code></pre>
<p>Needs to become two separate imports:</p>
<pre><code>from . import constants
import sys</code></pre>
<p>There are variations of this problem scattered throughout the <code class="filename">chardet</code> library. In some places it's "<code>import constants, sys</code>"; in other places, it's "<code>import constants, re</code>". The fix is the same: manually split the import statement into two lines, one for the relative import, the other for the absolute import.</p>
<p>Onward!</p>
</section>
<section id="namefileisnotdefined">
<h2>Name '<var>file</var>' is not defined</h2>
<pre class="screen"><samp class="prompt">C:\home\chardet></samp><kbd>python test.py tests\*\*</kbd>
<samp>tests\ascii\howto.diveintomark.org.xml</samp>
<samp class="traceback">Traceback (most recent call last):
File "test.py", line 9, in &lt;module>
for line in file(f, 'rb'):
NameError: name 'file' is not defined</samp></pre>
<p>This one surprised me, because I've been using this idiom as long as I can remember. In Python 2, the global <var>file()</var> function was an alias for <var>open()</var>, which was the standard way of opening files for reading. In Python 3, the entire system for reading and writing files has been refactored into the <code class="filename">io</code> module. [FIXME-LINK PEP 3116] I'll cover the new I/O module in more detail in Chapter FIXME, but for now, the important bit is that the global <var>file()</var> function no longer exists. However, the <var>open()</var> function does still exist. (Technically, it's an alias for <var>io.open()</var>, but never mind that right now.)</p>
<p>Thus, the simplest solution to the problem of the missing <var>file()</var> is to call <var>open()</var> instead:</p>
<pre><code>for line in open(f, 'rb'):</code></pre>
<p>And that's all I have to say about that.</p>
</section>
<section id="cantuseastringpattern">
<h2>Can't use a string pattern on a bytes-like object</h2>
<p>FIXME intro</p>
<pre class="screen"><samp class="prompt">C:\home\chardet></samp><kbd>python test.py tests\*\*</kbd>
<samp>tests\ascii\howto.diveintomark.org.xml</samp>
<samp class="traceback">Traceback (most recent call last):
File "test.py", line 10, in &lt;module>
u.feed(line)
File "C:\home\chardet\chardet\universaldetector.py", line 98, in feed
if self._highBitDetector.search(aBuf):
TypeError: can't use a string pattern on a bytes-like object</samp></pre>
<p>Now things are starting to get interesting. And by "interesting," I mean "confusing as all hell."</p>
<p>First, let's see what <var>self._highBitDetector</var> is. It's defined in the <var>__init__</var> method of the <var>UniversalDetector</var> class:</p>
<pre><code>class UniversalDetector:
def __init__(self):
self._highBitDetector = re.compile(r'[\x80-\xFF]')</code></pre>
<p>This pre-compiles a regular expression designed to find non-ASCII characters in the range 128-255 (0x80-0xFF). Wait, that's not quite right; I need to be more precise with my terminology. This pattern is designed to find non-ASCII <em>bytes</em> in the range 128-255.</p>
<p>And therein lies the problem.</p>
<p>In Python 2, a string was an array of bytes whose character encoding was tracked separately. If you wanted Python 2 to keep track of the character encoding, you had to use a Unicode string (<code>u''</code>) instead. But in Python 3, a string is always what Python 2 called a Unicode string -- that is, an array of Unicode characters (of possibly varying byte lengths). Since this regular expression is defined by a string pattern, it can only be used to search a string -- again, an array of characters. But what we're searching is not a string, it's a byte array. Looking at the traceback, this error occurred in <code class="filename">universaldetector.py</code>:</p>
<pre><code>def feed(self, aBuf):
.
.
.
if self._mInputState == ePureAscii:
if self._highBitDetector.search(aBuf):</code></pre>
<p>And what is <var>aBuf</var>? Let's backtrack further to a place that calls <var>UniversalDetector.feed()</var>. One place that calls it is the test harness, <code class="filename">test.py</code>.</p>
<pre><code>u = UniversalDetector()
.
.
.
for line in open(f, 'rb'):
u.feed(line)</code></pre>
<p>And here we find our answer: in the <var>UniversalDetector.feed()</var> method, <var>aBuf</var> is a line read from a file on disk. Look carefully at the parameters used to open the file: <code>'rb'</code>. <code>'r'</code> is for "read"; OK, big deal, we're reading the file. Ah, but <code>'b'</code> is for "bytes." Without the <code>'b'</code> flag, this <code>for</code> loop would read the file, line by line, and convert each line into a string -- an array of Unicode characters -- according to the system default character encoding. (You could override the system encoding with another parameter to <var>open()</var>, but never mind that for now.) But with the <code>'b'</code> flag, this <code>for</code> loop reads the file, line by line, and stores each line exactly as it appears in the file, as an array of bytes. That byte array gets passed to <var>UniversalDetector.feed()</var>, and eventually gets passed to the pre-compiled regular expression, <var>self._highBitDetector</var>, to search for high-bit... characters. But we don't have characters; we have bytes. Oops.</p>
<p>What we need this regular expression to search is not an array of characters, but an array of bytes.</p>
<p>Once you realize that, the solution is not difficult. Regular expressions defined with strings can search strings. Regular expressions defined with byte arrays can search byte arrays. To define a byte array pattern, we simply change the type of the argument we use to define the regular expression to a byte array. So instead of this:</p>
<pre><code>self._highBitDetector = re.compile(r'[\x80-\xFF]')</code></pre>
<p>We now have this:</p>
<pre><code>self._highBitDetector = re.compile(b'[\x80-\xFF]')</code></pre>
<p>There is one other case of this same problem, on the very next line:</p>
<pre><code>self._escDetector = re.compile(r'(\033|~{)')</code></pre>
<p>Again, this is going to be used to search a byte array (the same <var>aBuf</var> variable, in fact), so the regular expression pattern needs to be defined as a byte array:</p>
<pre><code>self._escDetector = re.compile(b'(\033|~{)')</code></pre>
</section>
<section id="cantconvertbytesobject">
<h2>Can't convert '<code>bytes</code>' object to <code>str</code> implicitly</h2>
<p>Curiouser and curiouser...</p>
<pre class="screen"><samp class="prompt">C:\home\chardet></samp><kbd>python test.py tests\*\*</kbd>
<samp>tests\ascii\howto.diveintomark.org.xml</samp>
<samp class="traceback">Traceback (most recent call last):
File "test.py", line 10, in &lt;module>
u.feed(line)
File "C:\home\chardet\chardet\universaldetector.py", line 100, in feed
elif (self._mInputState == ePureAscii) and self._escDetector.search(self._mLastChar + aBuf):
TypeError: Can't convert 'bytes' object to str implicitly</samp></pre>
</section>
</body>
</html>
+82 -82
View File
@@ -346,7 +346,7 @@ several months behind in updating their ActivePython installer when new version
<samp class="computeroutput">PythonWin 2.2.2 (#37, Nov 26 2002, 10:24:37) [MSC 32 bit (Intel)] on win32. <samp class="computeroutput">PythonWin 2.2.2 (#37, Nov 26 2002, 10:24:37) [MSC 32 bit (Intel)] on win32.
Portions Copyright 1994-2001 Mark Hammond (mhammond@skippinet.com.au) - Portions Copyright 1994-2001 Mark Hammond (mhammond@skippinet.com.au) -
see 'Help/About PythonWin' for further copyright information.</samp> see 'Help/About PythonWin' for further copyright information.</samp>
<samp> class="prompt">>>> </samp> <samp class="prompt">>>> </samp>
</pre></div> </pre></div>
<div class="procedure"> <div class="procedure">
<h3 class="title">Procedure 1.2. Option 2: Installing Python from <a href="http://www.python.org/" title="Python language home page">Python.org</a></h3> <h3 class="title">Procedure 1.2. Option 2: Installing Python from <a href="http://www.python.org/" title="Python language home page">Python.org</a></h3>
@@ -383,7 +383,7 @@ Type "copyright", "credits" or "license()" for more information.
**************************************************************** ****************************************************************
IDLE 1.0</samp> IDLE 1.0</samp>
<samp> class="prompt">>>> </samp> <samp class="prompt">>>> </samp>
</pre></div> </pre></div>
</div> </div>
<div class="section"> <div class="section">
@@ -418,7 +418,7 @@ Welcome to Darwin!
<samp class="computeroutput">Python 2.2 (#1, 07/14/02, 23:25:09) <samp class="computeroutput">Python 2.2 (#1, 07/14/02, 23:25:09)
[GCC Apple cpp-precomp 6.14] on darwin [GCC Apple cpp-precomp 6.14] on darwin
Type "help", "copyright", "credits", or "license" for more information.</samp> Type "help", "copyright", "credits", or "license" for more information.</samp>
<samp> class="prompt">>>> </samp>[press Ctrl+D to get back to the command prompt] <samp class="prompt">>>> </samp>[press Ctrl+D to get back to the command prompt]
<samp class="prompt">[localhost:~] you% </samp> <samp class="prompt">[localhost:~] you% </samp>
</pre></div> </pre></div>
<div class="procedure"> <div class="procedure">
@@ -458,7 +458,7 @@ Window->Python Interactive (<kbd class="shortcut">Cmd-0</kbd>). The opening win
[GCC 3.1 20020420 (prerelease)] [GCC 3.1 20020420 (prerelease)]
Type "copyright", "credits" or "license" for more information. Type "copyright", "credits" or "license" for more information.
MacPython IDE 1.0.1</samp> MacPython IDE 1.0.1</samp>
<samp> class="prompt">>>> </samp> <samp class="prompt">>>> </samp>
</pre></div> </pre></div>
<p>Note that once you install the latest version, the pre-installed version is still present. If you are running scripts from <p>Note that once you install the latest version, the pre-installed version is still present. If you are running scripts from
the command line, you need to be aware which version of Python you are using.</p> the command line, you need to be aware which version of Python you are using.</p>
@@ -467,12 +467,12 @@ the command line, you need to be aware which version of Python you are using.</p
<samp class="computeroutput">Python 2.2 (#1, 07/14/02, 23:25:09) <samp class="computeroutput">Python 2.2 (#1, 07/14/02, 23:25:09)
[GCC Apple cpp-precomp 6.14] on darwin [GCC Apple cpp-precomp 6.14] on darwin
Type "help", "copyright", "credits", or "license" for more information.</samp> Type "help", "copyright", "credits", or "license" for more information.</samp>
<samp> class="prompt">>>> </samp>[press Ctrl+D to get back to the command prompt] <samp class="prompt">>>> </samp>[press Ctrl+D to get back to the command prompt]
<samp class="prompt">[localhost:~] you% </samp>/usr/local/bin/python <samp class="prompt">[localhost:~] you% </samp>/usr/local/bin/python
<samp class="computeroutput">Python 2.3 (#2, Jul 30 2003, 11:45:28) <samp class="computeroutput">Python 2.3 (#2, Jul 30 2003, 11:45:28)
[GCC 3.1 20020420 (prerelease)] on darwin [GCC 3.1 20020420 (prerelease)] on darwin
Type "help", "copyright", "credits", or "license" for more information.</samp> Type "help", "copyright", "credits", or "license" for more information.</samp>
<samp> class="prompt">>>> </samp>[press Ctrl+D to get back to the command prompt] <samp class="prompt">>>> </samp>[press Ctrl+D to get back to the command prompt]
<samp class="prompt">[localhost:~] you% </samp> <samp class="prompt">[localhost:~] you% </samp>
</pre></div> </pre></div>
</div> </div>
@@ -512,7 +512,7 @@ Window->Python Interactive (<kbd class="shortcut">Cmd-0</kbd>). You'll see a sc
[GCC 3.1 20020420 (prerelease)] [GCC 3.1 20020420 (prerelease)]
Type "copyright", "credits" or "license" for more information. Type "copyright", "credits" or "license" for more information.
MacPython IDE 1.0.1</samp> MacPython IDE 1.0.1</samp>
<samp> class="prompt">>>> </samp> <samp class="prompt">>>> </samp>
</pre></div> </pre></div>
</div> </div>
<div class="section"> <div class="section">
@@ -529,19 +529,19 @@ Connecting to python.org[194.109.137.226]:80... connected.
HTTP request sent, awaiting response... 200 OK HTTP request sent, awaiting response... 200 OK
Length: 7,495,111 [application/octet-stream] Length: 7,495,111 [application/octet-stream]
...</samp> ...</samp>
<samp> class="prompt">[root@localhost root]# </samp>rpm -Uvh python2.3-2.3-5pydotorg.i386.rpm <samp class="prompt">[root@localhost root]# </samp>rpm -Uvh python2.3-2.3-5pydotorg.i386.rpm
<samp class="computeroutput">Preparing... ########################################### [100%] <samp class="computeroutput">Preparing... ########################################### [100%]
1:python2.3 ########################################### [100%]</samp> 1:python2.3 ########################################### [100%]</samp>
<samp> class="prompt">[root@localhost root]# </samp>python <img id="install.unix.1.1" src="images/callouts/1.png" alt="1" border="0" width="12" height="12"> <samp class="prompt">[root@localhost root]# </samp>python <img id="install.unix.1.1" src="images/callouts/1.png" alt="1" border="0" width="12" height="12">
<samp class="computeroutput">Python 2.2.2 (#1, Feb 24 2003, 19:13:11) <samp class="computeroutput">Python 2.2.2 (#1, Feb 24 2003, 19:13:11)
[GCC 3.2.2 20030222 (Red Hat Linux 3.2.2-4)] on linux2 [GCC 3.2.2 20030222 (Red Hat Linux 3.2.2-4)] on linux2
Type "help", "copyright", "credits", or "license" for more information.</samp> Type "help", "copyright", "credits", or "license" for more information.</samp>
<samp> class="prompt">>>> </samp>[press Ctrl+D to exit] <samp class="prompt">>>> </samp>[press Ctrl+D to exit]
<samp class="prompt">[root@localhost root]# </samp>python2.3 <img id="install.unix.1.2" src="images/callouts/2.png" alt="2" border="0" width="12" height="12"> <samp class="prompt">[root@localhost root]# </samp>python2.3 <img id="install.unix.1.2" src="images/callouts/2.png" alt="2" border="0" width="12" height="12">
<samp class="computeroutput">Python 2.3 (#1, Sep 12 2003, 10:53:56) <samp class="computeroutput">Python 2.3 (#1, Sep 12 2003, 10:53:56)
[GCC 3.2.2 20030222 (Red Hat Linux 3.2.2-5)] on linux2 [GCC 3.2.2 20030222 (Red Hat Linux 3.2.2-5)] on linux2
Type "help", "copyright", "credits", or "license" for more information.</samp> Type "help", "copyright", "credits", or "license" for more information.</samp>
<samp> class="prompt">>>> </samp>[press Ctrl+D to exit] <samp class="prompt">>>> </samp>[press Ctrl+D to exit]
<samp class="prompt">[root@localhost root]# </samp>which python2.3 <img id="install.unix.1.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12"> <samp class="prompt">[root@localhost root]# </samp>which python2.3 <img id="install.unix.1.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12">
/usr/bin/python2.3 /usr/bin/python2.3
</pre><div class="calloutlist"> </pre><div class="calloutlist">
@@ -586,7 +586,7 @@ The following NEW packages will be installed:
0 upgraded, 2 newly installed, 0 to remove and 3 not upgraded. 0 upgraded, 2 newly installed, 0 to remove and 3 not upgraded.
Need to get 0B/2880kB of archives. Need to get 0B/2880kB of archives.
After unpacking 9351kB of additional disk space will be used.</samp> After unpacking 9351kB of additional disk space will be used.</samp>
<samp> class="prompt">Do you want to continue? [Y/n] </samp>Y <samp class="prompt">Do you want to continue? [Y/n] </samp>Y
<samp class="computeroutput">Selecting previously deselected package python2.3. <samp class="computeroutput">Selecting previously deselected package python2.3.
(Reading database ... 22848 files and directories currently installed.) (Reading database ... 22848 files and directories currently installed.)
Unpacking python2.3 (from .../python2.3_2.3.1-1_i386.deb) ... Unpacking python2.3 (from .../python2.3_2.3.1-1_i386.deb) ...
@@ -596,13 +596,13 @@ Setting up python (2.3.1-1) ...
Setting up python2.3 (2.3.1-1) ... Setting up python2.3 (2.3.1-1) ...
Compiling python modules in /usr/lib/python2.3 ... Compiling python modules in /usr/lib/python2.3 ...
Compiling optimized python modules in /usr/lib/python2.3 ...</samp> Compiling optimized python modules in /usr/lib/python2.3 ...</samp>
<samp> class="prompt">localhost:~# </samp>exit <samp class="prompt">localhost:~# </samp>exit
logout logout
<samp class="prompt">localhost:~$ </samp>python <samp class="prompt">localhost:~$ </samp>python
<samp class="computeroutput">Python 2.3.1 (#2, Sep 24 2003, 11:39:14) <samp class="computeroutput">Python 2.3.1 (#2, Sep 24 2003, 11:39:14)
[GCC 3.3.2 20030908 (Debian prerelease)] on linux2 [GCC 3.3.2 20030908 (Debian prerelease)] on linux2
Type "help", "copyright", "credits" or "license" for more information.</samp> Type "help", "copyright", "credits" or "license" for more information.</samp>
<samp> class="prompt">>>> </samp>[press Ctrl+D to exit] <samp class="prompt">>>> </samp>[press Ctrl+D to exit]
</pre></div> </pre></div>
</div> </div>
<div class="section"> <div class="section">
@@ -617,14 +617,14 @@ Connecting to www.python.org[194.109.137.226]:80... connected.
HTTP request sent, awaiting response... 200 OK HTTP request sent, awaiting response... 200 OK
Length: 8,436,880 [application/x-tar] Length: 8,436,880 [application/x-tar]
...</samp> ...</samp>
<samp> class="prompt">localhost:~# </samp>tar xfz Python-2.3.tgz <samp class="prompt">localhost:~# </samp>tar xfz Python-2.3.tgz
<samp class="prompt">localhost:~# </samp>cd Python-2.3 <samp class="prompt">localhost:~# </samp>cd Python-2.3
<samp class="prompt">localhost:~/Python-2.3# </samp>./configure <samp class="prompt">localhost:~/Python-2.3# </samp>./configure
<samp class="computeroutput">checking MACHDEP... linux2 <samp class="computeroutput">checking MACHDEP... linux2
checking EXTRAPLATDIR... checking EXTRAPLATDIR...
checking for --without-gcc... no checking for --without-gcc... no
...</samp> ...</samp>
<samp> class="prompt">localhost:~/Python-2.3# </samp>make <samp class="prompt">localhost:~/Python-2.3# </samp>make
<samp class="computeroutput">gcc -pthread -c -fno-strict-aliasing -DNDEBUG -g -O3 -Wall -Wstrict-prototypes <samp class="computeroutput">gcc -pthread -c -fno-strict-aliasing -DNDEBUG -g -O3 -Wall -Wstrict-prototypes
-I. -I./Include -DPy_BUILD_CORE -o Modules/python.o Modules/python.c -I. -I./Include -DPy_BUILD_CORE -o Modules/python.o Modules/python.c
gcc -pthread -c -fno-strict-aliasing -DNDEBUG -g -O3 -Wall -Wstrict-prototypes gcc -pthread -c -fno-strict-aliasing -DNDEBUG -g -O3 -Wall -Wstrict-prototypes
@@ -632,10 +632,10 @@ gcc -pthread -c -fno-strict-aliasing -DNDEBUG -g -O3 -Wall -Wstrict-prototypes
gcc -pthread -c -fno-strict-aliasing -DNDEBUG -g -O3 -Wall -Wstrict-prototypes gcc -pthread -c -fno-strict-aliasing -DNDEBUG -g -O3 -Wall -Wstrict-prototypes
-I. -I./Include -DPy_BUILD_CORE -o Parser/grammar1.o Parser/grammar1.c -I. -I./Include -DPy_BUILD_CORE -o Parser/grammar1.o Parser/grammar1.c
...</samp> ...</samp>
<samp> class="prompt">localhost:~/Python-2.3# </samp>make install <samp class="prompt">localhost:~/Python-2.3# </samp>make install
<samp class="computeroutput">/usr/bin/install -c python /usr/local/bin/python2.3 <samp class="computeroutput">/usr/bin/install -c python /usr/local/bin/python2.3
...</samp> ...</samp>
<samp> class="prompt">localhost:~/Python-2.3# </samp>exit <samp class="prompt">localhost:~/Python-2.3# </samp>exit
logout logout
<samp class="prompt">localhost:~$ </samp>which python <samp class="prompt">localhost:~$ </samp>which python
/usr/local/bin/python /usr/local/bin/python
@@ -643,7 +643,7 @@ logout
<samp class="computeroutput">Python 2.3.1 (#2, Sep 24 2003, 11:39:14) <samp class="computeroutput">Python 2.3.1 (#2, Sep 24 2003, 11:39:14)
[GCC 3.3.2 20030908 (Debian prerelease)] on linux2 [GCC 3.3.2 20030908 (Debian prerelease)] on linux2
Type "help", "copyright", "credits" or "license" for more information.</samp> Type "help", "copyright", "credits" or "license" for more information.</samp>
<samp> class="prompt">>>> </samp>[press Ctrl+D to get back to the command prompt] <samp class="prompt">>>> </samp>[press Ctrl+D to get back to the command prompt]
<samp class="prompt">localhost:~$ </samp> <samp class="prompt">localhost:~$ </samp>
</pre></div> </pre></div>
</div> </div>
@@ -892,7 +892,7 @@ Returns string.</span></pre><div class="calloutlist">
<samp class="computeroutput">['', '/usr/local/lib/python2.2', '/usr/local/lib/python2.2/plat-linux2', <samp class="computeroutput">['', '/usr/local/lib/python2.2', '/usr/local/lib/python2.2/plat-linux2',
'/usr/local/lib/python2.2/lib-dynload', '/usr/local/lib/python2.2/site-packages', '/usr/local/lib/python2.2/lib-dynload', '/usr/local/lib/python2.2/site-packages',
'/usr/local/lib/python2.2/site-packages/PIL', '/usr/local/lib/python2.2/site-packages/piddle']</samp> '/usr/local/lib/python2.2/site-packages/PIL', '/usr/local/lib/python2.2/site-packages/piddle']</samp>
<samp> class="prompt">>>> </samp>sys <img id="odbchelper.objects.2.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>sys <img id="odbchelper.objects.2.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12">
&lt;module 'sys' (built-in)> &lt;module 'sys' (built-in)>
<samp class="prompt">>>> </samp>sys.path.append('/my/new/path') <img id="odbchelper.objects.2.4" src="images/callouts/4.png" alt="4" border="0" width="12" height="12"></pre><div class="calloutlist"> <samp class="prompt">>>> </samp>sys.path.append('/my/new/path') <img id="odbchelper.objects.2.4" src="images/callouts/4.png" alt="4" border="0" width="12" height="12"></pre><div class="calloutlist">
<table border="0" summary="Callout list"> <table border="0" summary="Callout list">
@@ -1227,7 +1227,7 @@ KeyError: mpilgrim</span></pre><div class="calloutlist">
<div class="example"><h3 id="odbchelper.dict.del" class="title">Example 3.5. Deleting Items from a Dictionary</h3><pre class="screen"><samp class="prompt">>>> </samp>d <div class="example"><h3 id="odbchelper.dict.del" class="title">Example 3.5. Deleting Items from a Dictionary</h3><pre class="screen"><samp class="prompt">>>> </samp>d
<samp class="computeroutput">{'server': 'mpilgrim', 'uid': 'sa', 'database': 'master', <samp class="computeroutput">{'server': 'mpilgrim', 'uid': 'sa', 'database': 'master',
42: 'douglas', 'retrycount': 3}</samp> 42: 'douglas', 'retrycount': 3}</samp>
<samp> class="prompt">>>> </samp>del d[42] <img id="odbchelper.dict.4.1" src="images/callouts/1.png" alt="1" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>del d[42] <img id="odbchelper.dict.4.1" src="images/callouts/1.png" alt="1" border="0" width="12" height="12">
<samp class="prompt">>>> </samp>d <samp class="prompt">>>> </samp>d
{'server': 'mpilgrim', 'uid': 'sa', 'database': 'master', 'retrycount': 3} {'server': 'mpilgrim', 'uid': 'sa', 'database': 'master', 'retrycount': 3}
<samp class="prompt">>>> </samp>d.clear() <img id="odbchelper.dict.4.2" src="images/callouts/2.png" alt="2" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>d.clear() <img id="odbchelper.dict.4.2" src="images/callouts/2.png" alt="2" border="0" width="12" height="12">
@@ -1504,7 +1504,7 @@ KeyError: mpilgrim</span></pre><div class="calloutlist">
<samp class="traceback">Traceback (innermost last): <samp class="traceback">Traceback (innermost last):
File "&lt;interactive input>", line 1, in ? File "&lt;interactive input>", line 1, in ?
ValueError: list.index(x): x not in list</samp> ValueError: list.index(x): x not in list</samp>
<samp> class="prompt">>>> </samp>"c" in li <img id="odbchelper.list.6.4" src="images/callouts/4.png" alt="4" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>"c" in li <img id="odbchelper.list.6.4" src="images/callouts/4.png" alt="4" border="0" width="12" height="12">
False</pre><div class="calloutlist"> False</pre><div class="calloutlist">
<table border="0" summary="Callout list"> <table border="0" summary="Callout list">
<tr> <tr>
@@ -1573,7 +1573,7 @@ False</pre><div class="calloutlist">
<samp class="traceback">Traceback (innermost last): <samp class="traceback">Traceback (innermost last):
File "&lt;interactive input>", line 1, in ? File "&lt;interactive input>", line 1, in ?
ValueError: list.remove(x): x not in list</samp> ValueError: list.remove(x): x not in list</samp>
<samp> class="prompt">>>> </samp>li.pop() <img id="odbchelper.list.7.4" src="images/callouts/4.png" alt="4" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>li.pop() <img id="odbchelper.list.7.4" src="images/callouts/4.png" alt="4" border="0" width="12" height="12">
'elements' 'elements'
<samp class="prompt">>>> </samp>li <samp class="prompt">>>> </samp>li
['a', 'b', 'mpilgrim', 'example', 'new', 'two']</pre><div class="calloutlist"> ['a', 'b', 'mpilgrim', 'example', 'new', 'two']</pre><div class="calloutlist">
@@ -1705,15 +1705,15 @@ ValueError: list.remove(x): x not in list</samp>
<samp class="traceback">Traceback (innermost last): <samp class="traceback">Traceback (innermost last):
File "&lt;interactive input>", line 1, in ? File "&lt;interactive input>", line 1, in ?
AttributeError: 'tuple' object has no attribute 'append'</samp> AttributeError: 'tuple' object has no attribute 'append'</samp>
<samp> class="prompt">>>> </samp>t.remove("z") <img id="odbchelper.tuple.2.2" src="images/callouts/2.png" alt="2" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>t.remove("z") <img id="odbchelper.tuple.2.2" src="images/callouts/2.png" alt="2" border="0" width="12" height="12">
<samp class="traceback">Traceback (innermost last): <samp class="traceback">Traceback (innermost last):
File "&lt;interactive input>", line 1, in ? File "&lt;interactive input>", line 1, in ?
AttributeError: 'tuple' object has no attribute 'remove'</samp> AttributeError: 'tuple' object has no attribute 'remove'</samp>
<samp> class="prompt">>>> </samp>t.index("example") <img id="odbchelper.tuple.2.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>t.index("example") <img id="odbchelper.tuple.2.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12">
<samp class="traceback">Traceback (innermost last): <samp class="traceback">Traceback (innermost last):
File "&lt;interactive input>", line 1, in ? File "&lt;interactive input>", line 1, in ?
AttributeError: 'tuple' object has no attribute 'index'</samp> AttributeError: 'tuple' object has no attribute 'index'</samp>
<samp> class="prompt">>>> </samp>"z" in t <img id="odbchelper.tuple.2.4" src="images/callouts/4.png" alt="4" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>"z" in t <img id="odbchelper.tuple.2.4" src="images/callouts/4.png" alt="4" border="0" width="12" height="12">
True</pre><div class="calloutlist"> True</pre><div class="calloutlist">
<table border="0" summary="Callout list"> <table border="0" summary="Callout list">
<tr> <tr>
@@ -1809,7 +1809,7 @@ a matter of style.</p>
<samp class="traceback">Traceback (innermost last): <samp class="traceback">Traceback (innermost last):
File "&lt;interactive input>", line 1, in ? File "&lt;interactive input>", line 1, in ?
NameError: There is no variable named 'x'</samp> NameError: There is no variable named 'x'</samp>
<samp> class="prompt">>>> </samp>x = 1 <samp class="prompt">>>> </samp>x = 1
<samp class="prompt">>>> </samp>x <samp class="prompt">>>> </samp>x
1</pre></div> 1</pre></div>
<p>You will thank Python for this one day.</p> <p>You will thank Python for this one day.</p>
@@ -2487,7 +2487,7 @@ True</pre><div class="calloutlist">
<samp class="prompt">>>> </samp>dir(li) <img id="apihelper.builtin.3.1" src="images/callouts/1.png" alt="1" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>dir(li) <img id="apihelper.builtin.3.1" src="images/callouts/1.png" alt="1" border="0" width="12" height="12">
<samp class="computeroutput">['append', 'count', 'extend', 'index', 'insert', <samp class="computeroutput">['append', 'count', 'extend', 'index', 'insert',
'pop', 'remove', 'reverse', 'sort']</samp> 'pop', 'remove', 'reverse', 'sort']</samp>
<samp> class="prompt">>>> </samp>d = {} <samp class="prompt">>>> </samp>d = {}
<samp class="prompt">>>> </samp>dir(d) <img id="apihelper.builtin.3.2" src="images/callouts/2.png" alt="2" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>dir(d) <img id="apihelper.builtin.3.2" src="images/callouts/2.png" alt="2" border="0" width="12" height="12">
['clear', 'copy', 'get', 'has_key', 'items', 'keys', 'setdefault', 'update', 'values'] ['clear', 'copy', 'get', 'has_key', 'items', 'keys', 'setdefault', 'update', 'values']
<samp class="prompt">>>> </samp>import odbchelper <samp class="prompt">>>> </samp>import odbchelper
@@ -3035,7 +3035,7 @@ a <code class="literal">lambda</code> function; if you need something more compl
<samp class="prompt">>>> </samp>print s <samp class="prompt">>>> </samp>print s
<samp class="computeroutput">this is <samp class="computeroutput">this is
a test</samp> a test</samp>
<samp> class="prompt">>>> </samp>print s.split() <img id="apihelper.split.1.2" src="images/callouts/2.png" alt="2" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>print s.split() <img id="apihelper.split.1.2" src="images/callouts/2.png" alt="2" border="0" width="12" height="12">
['this', 'is', 'a', 'test'] ['this', 'is', 'a', 'test']
<samp class="prompt">>>> </samp>print " ".join(s.split()) <img id="apihelper.split.1.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>print " ".join(s.split()) <img id="apihelper.split.1.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12">
'this is a test'</pre><div class="calloutlist"> 'this is a test'</pre><div class="calloutlist">
@@ -3450,7 +3450,7 @@ can import individual items or use <code class="literal">from <i class="replacea
<samp class="traceback">Traceback (innermost last): <samp class="traceback">Traceback (innermost last):
File "&lt;interactive input>", line 1, in ? File "&lt;interactive input>", line 1, in ?
NameError: There is no variable named 'FunctionType'</samp> NameError: There is no variable named 'FunctionType'</samp>
<samp> class="prompt">>>> </samp>from types import FunctionType <img id="fileinfo.import.1.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>from types import FunctionType <img id="fileinfo.import.1.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12">
<samp class="prompt">>>> </samp>FunctionType <img id="fileinfo.import.1.4" src="images/callouts/4.png" alt="4" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>FunctionType <img id="fileinfo.import.1.4" src="images/callouts/4.png" alt="4" border="0" width="12" height="12">
&lt;type 'function'></pre><div class="calloutlist"> &lt;type 'function'></pre><div class="calloutlist">
<table border="0" summary="Callout list"> <table border="0" summary="Callout list">
@@ -4077,7 +4077,7 @@ provide a way to map non-method-calling syntax into method calls.</p>
<samp class="computeroutput">{'album': 'Rave Mix', 'artist': '***DJ MARY-JANE***', 'genre': 31, <samp class="computeroutput">{'album': 'Rave Mix', 'artist': '***DJ MARY-JANE***', 'genre': 31,
'title': 'KAIRO****THE BEST GOA', 'name': '/music/_singles/kairo.mp3', 'title': 'KAIRO****THE BEST GOA', 'name': '/music/_singles/kairo.mp3',
'year': '2000', 'comment': 'http://mp3.com/DJMARYJANE'}</samp> 'year': '2000', 'comment': 'http://mp3.com/DJMARYJANE'}</samp>
<samp> class="prompt">>>> </samp>mp3file["name"] = "/music/_singles/sidewinder.mp3" <img id="fileinfo.specialmethods.4.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>mp3file["name"] = "/music/_singles/sidewinder.mp3" <img id="fileinfo.specialmethods.4.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12">
<samp class="prompt">>>> </samp>mp3file <samp class="prompt">>>> </samp>mp3file
<samp class="computeroutput">{'album': '', 'artist': 'The Cynic Project', 'genre': 18, 'title': 'Sidewinder', <samp class="computeroutput">{'album': '', 'artist': 'The Cynic Project', 'genre': 18, 'title': 'Sidewinder',
'name': '/music/_singles/sidewinder.mp3', 'year': '2000', 'name': '/music/_singles/sidewinder.mp3', 'year': '2000',
@@ -4206,7 +4206,7 @@ class MP3FileInfo(FileInfo):
'year': (93, 97, &lt;function stripnulls at 0260C8D4>), 'year': (93, 97, &lt;function stripnulls at 0260C8D4>),
'comment': (97, 126, &lt;function stripnulls at 0260C8D4>), 'comment': (97, 126, &lt;function stripnulls at 0260C8D4>),
'album': (63, 93, &lt;function stripnulls at 0260C8D4>)}</samp> 'album': (63, 93, &lt;function stripnulls at 0260C8D4>)}</samp>
<samp> class="prompt">>>> </samp>m = fileinfo.MP3FileInfo() <img id="fileinfo.classattributes.1.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>m = fileinfo.MP3FileInfo() <img id="fileinfo.classattributes.1.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12">
<samp class="prompt">>>> </samp>m.tagDataMap <samp class="prompt">>>> </samp>m.tagDataMap
<samp class="computeroutput">{'title': (3, 33, &lt;function stripnulls at 0260C8D4>), <samp class="computeroutput">{'title': (3, 33, &lt;function stripnulls at 0260C8D4>),
'genre': (127, 128, &lt;built-in function ord>), 'genre': (127, 128, &lt;built-in function ord>),
@@ -4421,7 +4421,7 @@ a line of code may raise an exception, you should handle the exception using a <
<samp class="traceback">Traceback (innermost last): <samp class="traceback">Traceback (innermost last):
File "&lt;interactive input>", line 1, in ? File "&lt;interactive input>", line 1, in ?
IOError: [Errno 2] No such file or directory: '/notthere'</samp> IOError: [Errno 2] No such file or directory: '/notthere'</samp>
<samp> class="prompt">>>> </samp>try: <samp class="prompt">>>> </samp>try:
<samp class="prompt">... </samp>fsock = open("/notthere") <img id="fileinfo.exceptions.1.2" src="images/callouts/2.png" alt="2" border="0" width="12" height="12"> <samp class="prompt">... </samp>fsock = open("/notthere") <img id="fileinfo.exceptions.1.2" src="images/callouts/2.png" alt="2" border="0" width="12" height="12">
<samp class="prompt">... </samp>except IOError: <img id="fileinfo.exceptions.1.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12"> <samp class="prompt">... </samp>except IOError: <img id="fileinfo.exceptions.1.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12">
<samp class="prompt">... </samp>print "The file does not exist, exiting gracefully" <samp class="prompt">... </samp>print "The file does not exist, exiting gracefully"
@@ -4597,7 +4597,7 @@ exceptions, errors occur immediately, and you can handle them in a standard way
<samp class="prompt">>>> </samp>tagData <samp class="prompt">>>> </samp>tagData
<samp class="computeroutput">'TAGKAIRO****THE BEST GOA ***DJ MARY-JANE*** <samp class="computeroutput">'TAGKAIRO****THE BEST GOA ***DJ MARY-JANE***
Rave Mix 2000http://mp3.com/DJMARYJANE \037'</samp> Rave Mix 2000http://mp3.com/DJMARYJANE \037'</samp>
<samp> class="prompt">>>> </samp>f.tell() <img id="fileinfo.files.2.5" src="images/callouts/5.png" alt="5" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>f.tell() <img id="fileinfo.files.2.5" src="images/callouts/5.png" alt="5" border="0" width="12" height="12">
7543037</pre><div class="calloutlist"> 7543037</pre><div class="calloutlist">
<table border="0" summary="Callout list"> <table border="0" summary="Callout list">
<tr> <tr>
@@ -4657,15 +4657,15 @@ True
<samp class="traceback">Traceback (innermost last): <samp class="traceback">Traceback (innermost last):
File "&lt;interactive input>", line 1, in ? File "&lt;interactive input>", line 1, in ?
ValueError: I/O operation on closed file</samp> ValueError: I/O operation on closed file</samp>
<samp> class="prompt">>>> </samp>f.tell() <samp class="prompt">>>> </samp>f.tell()
<samp class="traceback">Traceback (innermost last): <samp class="traceback">Traceback (innermost last):
File "&lt;interactive input>", line 1, in ? File "&lt;interactive input>", line 1, in ?
ValueError: I/O operation on closed file</samp> ValueError: I/O operation on closed file</samp>
<samp> class="prompt">>>> </samp>f.read() <samp class="prompt">>>> </samp>f.read()
<samp class="traceback">Traceback (innermost last): <samp class="traceback">Traceback (innermost last):
File "&lt;interactive input>", line 1, in ? File "&lt;interactive input>", line 1, in ?
ValueError: I/O operation on closed file</samp> ValueError: I/O operation on closed file</samp>
<samp> class="prompt">>>> </samp>f.close() <img id="fileinfo.files.3.5" src="images/callouts/5.png" alt="5" border="0" width="12" height="12"></pre><div class="calloutlist"> <samp class="prompt">>>> </samp>f.close() <img id="fileinfo.files.3.5" src="images/callouts/5.png" alt="5" border="0" width="12" height="12"></pre><div class="calloutlist">
<table border="0" summary="Callout list"> <table border="0" summary="Callout list">
<tr> <tr>
<td width="12" valign="top" align="left"><a href="#fileinfo.files.3.1"><img src="images/callouts/1.png" alt="1" border="0" width="12" height="12"></a> <td width="12" valign="top" align="left"><a href="#fileinfo.files.3.1"><img src="images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
@@ -4849,7 +4849,7 @@ or other iteratable entities. But in Python, a <code class="literal">for</code>
<samp class="computeroutput">a <samp class="computeroutput">a
b b
e</samp> e</samp>
<samp> class="prompt">>>> </samp>print "\n".join(li) <img id="fileinfo.for.1.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>print "\n".join(li) <img id="fileinfo.for.1.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12">
<samp class="computeroutput">a <samp class="computeroutput">a
b b
e</span></pre><div class="calloutlist"> e</span></pre><div class="calloutlist">
@@ -4884,7 +4884,7 @@ e</span></pre><div class="calloutlist">
2 2
3 3
4</samp> 4</samp>
<samp> class="prompt">>>> </samp>li = ['a', 'b', 'c', 'd', 'e'] <samp class="prompt">>>> </samp>li = ['a', 'b', 'c', 'd', 'e']
<samp class="prompt">>>> </samp>for i in range(len(li)): <img id="fileinfo.for.3.2" src="images/callouts/2.png" alt="2" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>for i in range(len(li)): <img id="fileinfo.for.3.2" src="images/callouts/2.png" alt="2" border="0" width="12" height="12">
<samp class="prompt">... </samp>print li[i] <samp class="prompt">... </samp>print li[i]
<samp class="computeroutput">a <samp class="computeroutput">a
@@ -4921,7 +4921,7 @@ COMPUTERNAME=MPILGRIM
USERNAME=mpilgrim USERNAME=mpilgrim
[...snip...]</samp> [...snip...]</samp>
<samp> class="prompt">>>> </samp>print "\n".join(["%s=%s" % (k, v) <samp class="prompt">>>> </samp>print "\n".join(["%s=%s" % (k, v)
<samp class="prompt">... </samp>for k, v in os.environ.items()]) <img id="fileinfo.for.2.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12"> <samp class="prompt">... </samp>for k, v in os.environ.items()]) <img id="fileinfo.for.2.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12">
<samp class="computeroutput">USERPROFILE=C:\Documents and Settings\mpilgrim <samp class="computeroutput">USERPROFILE=C:\Documents and Settings\mpilgrim
OS=Windows_NT OS=Windows_NT
@@ -5044,7 +5044,7 @@ site
signal signal
UserDict UserDict
stat</samp> stat</samp>
<samp> class="prompt">>>> </samp>fileinfo <samp class="prompt">>>> </samp>fileinfo
&lt;module 'fileinfo' from 'fileinfo.pyc'> &lt;module 'fileinfo' from 'fileinfo.pyc'>
<samp class="prompt">>>> </samp>sys.modules["fileinfo"] <img id="fileinfo.modules.1.4" src="images/callouts/2.png" alt="2" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>sys.modules["fileinfo"] <img id="fileinfo.modules.1.4" src="images/callouts/2.png" alt="2" border="0" width="12" height="12">
&lt;module 'fileinfo' from 'fileinfo.pyc'></pre><div class="calloutlist"> &lt;module 'fileinfo' from 'fileinfo.pyc'></pre><div class="calloutlist">
@@ -5228,18 +5228,18 @@ stat</samp>
<samp class="computeroutput">['a_time_long_forgotten_con.mp3', 'hellraiser.mp3', <samp class="computeroutput">['a_time_long_forgotten_con.mp3', 'hellraiser.mp3',
'kairo.mp3', 'long_way_home1.mp3', 'sidewinder.mp3', 'kairo.mp3', 'long_way_home1.mp3', 'sidewinder.mp3',
'spinning.mp3']</samp> 'spinning.mp3']</samp>
<samp> class="prompt">>>> </samp>dirname = "c:\\" <samp class="prompt">>>> </samp>dirname = "c:\\"
<samp class="prompt">>>> </samp>os.listdir(dirname) <img id="fileinfo.os.3.2" src="images/callouts/2.png" alt="2" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>os.listdir(dirname) <img id="fileinfo.os.3.2" src="images/callouts/2.png" alt="2" border="0" width="12" height="12">
<samp class="computeroutput">['AUTOEXEC.BAT', 'boot.ini', 'CONFIG.SYS', 'cygwin', <samp class="computeroutput">['AUTOEXEC.BAT', 'boot.ini', 'CONFIG.SYS', 'cygwin',
'docbook', 'Documents and Settings', 'Incoming', 'Inetpub', 'IO.SYS', 'docbook', 'Documents and Settings', 'Incoming', 'Inetpub', 'IO.SYS',
'MSDOS.SYS', 'Music', 'NTDETECT.COM', 'ntldr', 'pagefile.sys', 'MSDOS.SYS', 'Music', 'NTDETECT.COM', 'ntldr', 'pagefile.sys',
'Program Files', 'Python20', 'RECYCLER', 'Program Files', 'Python20', 'RECYCLER',
'System Volume Information', 'TEMP', 'WINNT']</samp> 'System Volume Information', 'TEMP', 'WINNT']</samp>
<samp> class="prompt">>>> </samp>[f for f in os.listdir(dirname) <samp class="prompt">>>> </samp>[f for f in os.listdir(dirname)
<samp class="prompt">... </samp>if os.path.isfile(os.path.join(dirname, f))] <img id="fileinfo.os.3.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12"> <samp class="prompt">... </samp>if os.path.isfile(os.path.join(dirname, f))] <img id="fileinfo.os.3.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12">
<samp class="computeroutput">['AUTOEXEC.BAT', 'boot.ini', 'CONFIG.SYS', 'IO.SYS', 'MSDOS.SYS', <samp class="computeroutput">['AUTOEXEC.BAT', 'boot.ini', 'CONFIG.SYS', 'IO.SYS', 'MSDOS.SYS',
'NTDETECT.COM', 'ntldr', 'pagefile.sys']</samp> 'NTDETECT.COM', 'ntldr', 'pagefile.sys']</samp>
<samp> class="prompt">>>> </samp>[f for f in os.listdir(dirname) <samp class="prompt">>>> </samp>[f for f in os.listdir(dirname)
<samp class="prompt">... </samp>if os.path.isdir(os.path.join(dirname, f))] <img id="fileinfo.os.3.4" src="images/callouts/4.png" alt="4" border="0" width="12" height="12"> <samp class="prompt">... </samp>if os.path.isdir(os.path.join(dirname, f))] <img id="fileinfo.os.3.4" src="images/callouts/4.png" alt="4" border="0" width="12" height="12">
<samp class="computeroutput">['cygwin', 'docbook', 'Documents and Settings', 'Incoming', <samp class="computeroutput">['cygwin', 'docbook', 'Documents and Settings', 'Incoming',
'Inetpub', 'Music', 'Program Files', 'Python20', 'RECYCLER', 'Inetpub', 'Music', 'Program Files', 'Python20', 'RECYCLER',
@@ -5331,7 +5331,7 @@ may already be familiar with from working on the command line.</p>
<samp class="computeroutput">['a_time_long_forgotten_con.mp3', 'hellraiser.mp3', <samp class="computeroutput">['a_time_long_forgotten_con.mp3', 'hellraiser.mp3',
'kairo.mp3', 'long_way_home1.mp3', 'sidewinder.mp3', 'kairo.mp3', 'long_way_home1.mp3', 'sidewinder.mp3',
'spinning.mp3']</samp> 'spinning.mp3']</samp>
<samp> class="prompt">>>> </samp>import glob <samp class="prompt">>>> </samp>import glob
<samp class="prompt">>>> </samp>glob.glob('c:\\music\\_singles\\*.mp3') <img id="fileinfo.os.4.2" src="images/callouts/2.png" alt="2" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>glob.glob('c:\\music\\_singles\\*.mp3') <img id="fileinfo.os.4.2" src="images/callouts/2.png" alt="2" border="0" width="12" height="12">
<samp class="computeroutput">['c:\\music\\_singles\\a_time_long_forgotten_con.mp3', <samp class="computeroutput">['c:\\music\\_singles\\a_time_long_forgotten_con.mp3',
'c:\\music\\_singles\\hellraiser.mp3', 'c:\\music\\_singles\\hellraiser.mp3',
@@ -5339,10 +5339,10 @@ may already be familiar with from working on the command line.</p>
'c:\\music\\_singles\\long_way_home1.mp3', 'c:\\music\\_singles\\long_way_home1.mp3',
'c:\\music\\_singles\\sidewinder.mp3', 'c:\\music\\_singles\\sidewinder.mp3',
'c:\\music\\_singles\\spinning.mp3']</samp> 'c:\\music\\_singles\\spinning.mp3']</samp>
<samp> class="prompt">>>> </samp>glob.glob('c:\\music\\_singles\\s*.mp3') <img id="fileinfo.os.4.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>glob.glob('c:\\music\\_singles\\s*.mp3') <img id="fileinfo.os.4.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12">
<samp class="computeroutput">['c:\\music\\_singles\\sidewinder.mp3', <samp class="computeroutput">['c:\\music\\_singles\\sidewinder.mp3',
'c:\\music\\_singles\\spinning.mp3']</samp> 'c:\\music\\_singles\\spinning.mp3']</samp>
<samp> class="prompt">>>> </samp>glob.glob('c:\\music\\*\\*.mp3')<img id="fileinfo.os.4.4" src="images/callouts/4.png" alt="4" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>glob.glob('c:\\music\\*\\*.mp3')<img id="fileinfo.os.4.4" src="images/callouts/4.png" alt="4" border="0" width="12" height="12">
</pre><div class="calloutlist"> </pre><div class="calloutlist">
<table border="0" summary="Callout list"> <table border="0" summary="Callout list">
<tr> <tr>
@@ -6100,7 +6100,7 @@ it a verbose regular expression. This example shows how.</p>
# or 5-8 (V, followed by 0 to 3 I's) # or 5-8 (V, followed by 0 to 3 I's)
$ # end of string $ # end of string
"""</kbd> """</kbd>
<samp> class="prompt">>>> </samp>re.search(pattern, 'M', re.VERBOSE) <img id="re.verbose.1.1" src="images/callouts/1.png" alt="1" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>re.search(pattern, 'M', re.VERBOSE) <img id="re.verbose.1.1" src="images/callouts/1.png" alt="1" border="0" width="12" height="12">
&lt;_sre.SRE_Match object at 0x008EEB48> &lt;_sre.SRE_Match object at 0x008EEB48>
<samp class="prompt">>>> </samp>re.search(pattern, 'MCMLXXXIX', re.VERBOSE) <img id="re.verbose.1.2" src="images/callouts/2.png" alt="2" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>re.search(pattern, 'MCMLXXXIX', re.VERBOSE) <img id="re.verbose.1.2" src="images/callouts/2.png" alt="2" border="0" width="12" height="12">
&lt;_sre.SRE_Match object at 0x008EEB48> &lt;_sre.SRE_Match object at 0x008EEB48>
@@ -6440,7 +6440,7 @@ you made.</p>
(\d*) # extension is optional and can be any number of digits (\d*) # extension is optional and can be any number of digits
$ # end of string $ # end of string
''', re.VERBOSE)</kbd> ''', re.VERBOSE)</kbd>
<samp> class="prompt">>>> </samp>phonePattern.search('work 1-(800) 555.1212 #1234').groups() <img id="re.phone.7.1" src="images/callouts/1.png" alt="1" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>phonePattern.search('work 1-(800) 555.1212 #1234').groups() <img id="re.phone.7.1" src="images/callouts/1.png" alt="1" border="0" width="12" height="12">
('800', '555', '1212', '1234') ('800', '555', '1212', '1234')
<samp class="prompt">>>> </samp>phonePattern.search('800-555-1212') <img id="re.phone.7.2" src="images/callouts/2.png" alt="2" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>phonePattern.search('800-555-1212') <img id="re.phone.7.2" src="images/callouts/2.png" alt="2" border="0" width="12" height="12">
('800', '555', '1212', '') ('800', '555', '1212', '')
@@ -8366,21 +8366,21 @@ package architecture. It's one of the many things Python is good at, so take ad
<samp class="prompt">>>> </samp>grammarNode.childNodes<img id="kgp.parse.4.1" src="images/callouts/1.png" alt="1" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>grammarNode.childNodes<img id="kgp.parse.4.1" src="images/callouts/1.png" alt="1" border="0" width="12" height="12">
<samp class="computeroutput">[&lt;DOM Text node "\n">, &lt;DOM Element: ref at 17533332>, \ <samp class="computeroutput">[&lt;DOM Text node "\n">, &lt;DOM Element: ref at 17533332>, \
&lt;DOM Text node "\n">, &lt;DOM Element: ref at 17549660>, &lt;DOM Text node "\n">]</samp> &lt;DOM Text node "\n">, &lt;DOM Element: ref at 17549660>, &lt;DOM Text node "\n">]</samp>
<samp> class="prompt">>>> </samp>print grammarNode.firstChild.toxml() <img id="kgp.parse.4.2" src="images/callouts/2.png" alt="2" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>print grammarNode.firstChild.toxml() <img id="kgp.parse.4.2" src="images/callouts/2.png" alt="2" border="0" width="12" height="12">
<samp class="computeroutput"> <samp class="computeroutput">
</samp> </samp>
<samp> class="prompt">>>> </samp>print grammarNode.childNodes[1].toxml() <img id="kgp.parse.4.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>print grammarNode.childNodes[1].toxml() <img id="kgp.parse.4.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12">
<samp class="computeroutput">&lt;ref id="bit"> <samp class="computeroutput">&lt;ref id="bit">
&lt;p>0&lt;/p> &lt;p>0&lt;/p>
&lt;p>1&lt;/p> &lt;p>1&lt;/p>
&lt;/ref></samp> &lt;/ref></samp>
<samp> class="prompt">>>> </samp>print grammarNode.childNodes[3].toxml() <img id="kgp.parse.4.4" src="images/callouts/4.png" alt="4" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>print grammarNode.childNodes[3].toxml() <img id="kgp.parse.4.4" src="images/callouts/4.png" alt="4" border="0" width="12" height="12">
<samp class="computeroutput">&lt;ref id="byte"> <samp class="computeroutput">&lt;ref id="byte">
&lt;p>&lt;xref id="bit"/>&lt;xref id="bit"/>&lt;xref id="bit"/>&lt;xref id="bit"/>\ &lt;p>&lt;xref id="bit"/>&lt;xref id="bit"/>&lt;xref id="bit"/>&lt;xref id="bit"/>\
&lt;xref id="bit"/>&lt;xref id="bit"/>&lt;xref id="bit"/>&lt;xref id="bit"/>&lt;/p> &lt;xref id="bit"/>&lt;xref id="bit"/>&lt;xref id="bit"/>&lt;xref id="bit"/>&lt;/p>
&lt;/ref></samp> &lt;/ref></samp>
<samp> class="prompt">>>> </samp>print grammarNode.lastChild.toxml() <img id="kgp.parse.4.5" src="images/callouts/5.png" alt="5" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>print grammarNode.lastChild.toxml() <img id="kgp.parse.4.5" src="images/callouts/5.png" alt="5" border="0" width="12" height="12">
<samp class="computeroutput"> <samp class="computeroutput">
</span></pre><div class="calloutlist"> </span></pre><div class="calloutlist">
@@ -8428,7 +8428,7 @@ package architecture. It's one of the many things Python is good at, so take ad
<samp class="computeroutput">[&lt;DOM Text node "\n">, &lt;DOM Text node " ">, &lt;DOM Element: p at 19315844>, \ <samp class="computeroutput">[&lt;DOM Text node "\n">, &lt;DOM Text node " ">, &lt;DOM Element: p at 19315844>, \
&lt;DOM Text node "\n">, &lt;DOM Text node " ">, \ &lt;DOM Text node "\n">, &lt;DOM Text node " ">, \
&lt;DOM Element: p at 19462036>, &lt;DOM Text node "\n">]</samp> &lt;DOM Element: p at 19462036>, &lt;DOM Text node "\n">]</samp>
<samp> class="prompt">>>> </samp>pNode = refNode.childNodes[2] <samp class="prompt">>>> </samp>pNode = refNode.childNodes[2]
<samp class="prompt">>>> </samp>pNode <samp class="prompt">>>> </samp>pNode
&lt;DOM Element: p at 19315844> &lt;DOM Element: p at 19315844>
<samp class="prompt">>>> </samp>print pNode.toxml() <img id="kgp.parse.5.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>print pNode.toxml() <img id="kgp.parse.5.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12">
@@ -8525,7 +8525,7 @@ Dive in</pre><div class="calloutlist">
<samp class="traceback">Traceback (innermost last): <samp class="traceback">Traceback (innermost last):
File "&lt;interactive input>", line 1, in ? File "&lt;interactive input>", line 1, in ?
UnicodeError: ASCII encoding error: ordinal not in range(128)</samp> UnicodeError: ASCII encoding error: ordinal not in range(128)</samp>
<samp> class="prompt">>>> </samp>print s.encode('latin-1') <img id="kgp.unicode.2.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>print s.encode('latin-1') <img id="kgp.unicode.2.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12">
La Pe&ntilde;a</pre><div class="calloutlist"> La Pe&ntilde;a</pre><div class="calloutlist">
<table border="0" summary="Callout list"> <table border="0" summary="Callout list">
<tr> <tr>
@@ -8639,7 +8639,7 @@ u'\u041f\u0440\u0435\u0434\u0438\u0441\u043b\u043e\u0432\u0438\u0435'
<samp class="traceback">Traceback (innermost last): <samp class="traceback">Traceback (innermost last):
File "&lt;interactive input>", line 1, in ? File "&lt;interactive input>", line 1, in ?
UnicodeError: ASCII encoding error: ordinal not in range(128)</samp> UnicodeError: ASCII encoding error: ordinal not in range(128)</samp>
<samp> class="prompt">>>> </samp>convertedtitle = title.encode('koi8-r') <img id="kgp.unicode.6.4" src="images/callouts/4.png" alt="4" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>convertedtitle = title.encode('koi8-r') <img id="kgp.unicode.6.4" src="images/callouts/4.png" alt="4" border="0" width="12" height="12">
<samp class="prompt">>>> </samp>convertedtitle <samp class="prompt">>>> </samp>convertedtitle
'\xf0\xd2\xc5\xc4\xc9\xd3\xcc\xcf\xd7\xc9\xc5' '\xf0\xd2\xc5\xc4\xc9\xd3\xcc\xcf\xd7\xc9\xc5'
<samp class="prompt">>>> </samp>print convertedtitle <img id="kgp.unicode.6.5" src="images/callouts/5.png" alt="5" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>print convertedtitle <img id="kgp.unicode.6.5" src="images/callouts/5.png" alt="5" border="0" width="12" height="12">
@@ -8724,7 +8724,7 @@ in Python. If your <acronym>XML</acronym> documents are all 7-bit <acronym>ASCI
&lt;p>0&lt;/p> &lt;p>0&lt;/p>
&lt;p>1&lt;/p> &lt;p>1&lt;/p>
&lt;/ref></samp> &lt;/ref></samp>
<samp> class="prompt">>>> </samp>print reflist[1].toxml() <samp class="prompt">>>> </samp>print reflist[1].toxml()
<samp class="computeroutput">&lt;ref id="byte"> <samp class="computeroutput">&lt;ref id="byte">
&lt;p>&lt;xref id="bit"/>&lt;xref id="bit"/>&lt;xref id="bit"/>&lt;xref id="bit"/>\ &lt;p>&lt;xref id="bit"/>&lt;xref id="bit"/>&lt;xref id="bit"/>&lt;xref id="bit"/>\
&lt;xref id="bit"/>&lt;xref id="bit"/>&lt;xref id="bit"/>&lt;xref id="bit"/>&lt;/p> &lt;xref id="bit"/>&lt;xref id="bit"/>&lt;xref id="bit"/>&lt;xref id="bit"/>&lt;/p>
@@ -8747,7 +8747,7 @@ in Python. If your <acronym>XML</acronym> documents are all 7-bit <acronym>ASCI
&lt;p>0&lt;/p> &lt;p>0&lt;/p>
&lt;p>1&lt;/p> &lt;p>1&lt;/p>
&lt;/ref></samp> &lt;/ref></samp>
<samp> class="prompt">>>> </samp>plist = firstref.getElementsByTagName("p") <img id="kgp.search.2.2" src="images/callouts/2.png" alt="2" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>plist = firstref.getElementsByTagName("p") <img id="kgp.search.2.2" src="images/callouts/2.png" alt="2" border="0" width="12" height="12">
<samp class="prompt">>>> </samp>plist <samp class="prompt">>>> </samp>plist
[&lt;DOM Element: p at 136140116>, &lt;DOM Element: p at 136142172>] [&lt;DOM Element: p at 136140116>, &lt;DOM Element: p at 136142172>]
<samp class="prompt">>>> </samp>print plist[0].toxml() <img id="kgp.search.2.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>print plist[0].toxml() <img id="kgp.search.2.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12">
@@ -8832,7 +8832,7 @@ in Python. If your <acronym>XML</acronym> documents are all 7-bit <acronym>ASCI
&lt;p>0&lt;/p> &lt;p>0&lt;/p>
&lt;p>1&lt;/p> &lt;p>1&lt;/p>
&lt;/ref></samp> &lt;/ref></samp>
<samp> class="prompt">>>> </samp>bitref.attributes <img id="kgp.attributes.1.1" src="images/callouts/1.png" alt="1" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>bitref.attributes <img id="kgp.attributes.1.1" src="images/callouts/1.png" alt="1" border="0" width="12" height="12">
&lt;xml.dom.minidom.NamedNodeMap instance at 0x81e0c9c> &lt;xml.dom.minidom.NamedNodeMap instance at 0x81e0c9c>
<samp class="prompt">>>> </samp>bitref.attributes.keys() <img id="kgp.attributes.1.2" src="images/callouts/2.png" alt="2" border="0" width="12" height="12"> <img id="kgp.attributes.1.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>bitref.attributes.keys() <img id="kgp.attributes.1.2" src="images/callouts/2.png" alt="2" border="0" width="12" height="12"> <img id="kgp.attributes.1.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12">
[u'id'] [u'id']
@@ -9213,7 +9213,7 @@ with a window-based Python <acronym>IDE</acronym>, <code class="literal">stdout<
<samp class="computeroutput">Dive in <samp class="computeroutput">Dive in
Dive in Dive in
Dive in</samp> Dive in</samp>
<samp> class="prompt">>>> </samp>import sys <samp class="prompt">>>> </samp>import sys
<samp class="prompt">>>> </samp>for i in range(3): <samp class="prompt">>>> </samp>for i in range(3):
<samp class="prompt">... </samp>sys.stdout.write('Dive in') <img id="kgp.stdio.1.2" src="images/callouts/2.png" alt="2" border="0" width="12" height="12"> <samp class="prompt">... </samp>sys.stdout.write('Dive in') <img id="kgp.stdio.1.2" src="images/callouts/2.png" alt="2" border="0" width="12" height="12">
Dive inDive inDive in Dive inDive inDive in
@@ -9385,7 +9385,7 @@ one program's output to the next program's input.</p>
&lt;xref id="bit"/>&lt;xref id="bit"/>&lt;xref id="bit"/>&lt;xref id="bit"/>&lt;/p> &lt;xref id="bit"/>&lt;xref id="bit"/>&lt;xref id="bit"/>&lt;xref id="bit"/>&lt;/p>
&lt;/ref> &lt;/ref>
&lt;/grammar></samp> &lt;/grammar></samp>
<samp> class="prompt">[you@localhost kgp]$ </samp>cat binary.xml | python kgp.py -g - <img id="kgp.stdio.4.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12"> <img id="kgp.stdio.4.4" src="images/callouts/4.png" alt="4" border="0" width="12" height="12"> <samp class="prompt">[you@localhost kgp]$ </samp>cat binary.xml | python kgp.py -g - <img id="kgp.stdio.4.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12"> <img id="kgp.stdio.4.4" src="images/callouts/4.png" alt="4" border="0" width="12" height="12">
10110001</pre><div class="calloutlist"> 10110001</pre><div class="calloutlist">
<table border="0" summary="Callout list"> <table border="0" summary="Callout list">
<tr> <tr>
@@ -9681,10 +9681,10 @@ argecho.py
<samp class="computeroutput">argecho.py <samp class="computeroutput">argecho.py
abc abc
def</samp> def</samp>
<samp> class="prompt">[you@localhost py]$ </samp>python argecho.py --help <img id="kgp.commandline.1.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12"> <samp class="prompt">[you@localhost py]$ </samp>python argecho.py --help <img id="kgp.commandline.1.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12">
<samp class="computeroutput">argecho.py <samp class="computeroutput">argecho.py
--help</samp> --help</samp>
<samp> class="prompt">[you@localhost py]$ </samp>python argecho.py -m kant.xml <img id="kgp.commandline.1.4" src="images/callouts/4.png" alt="4" border="0" width="12" height="12"> <samp class="prompt">[you@localhost py]$ </samp>python argecho.py -m kant.xml <img id="kgp.commandline.1.4" src="images/callouts/4.png" alt="4" border="0" width="12" height="12">
<samp class="computeroutput">argecho.py <samp class="computeroutput">argecho.py
-m -m
kant.xml</span></pre><div class="calloutlist"> kant.xml</span></pre><div class="calloutlist">
@@ -10414,7 +10414,7 @@ turn it off by setting <code class="literal">httplib.HTTPConnection.debuglevel =
'content-length': '15955', 'content-length': '15955',
'accept-ranges': 'bytes', 'accept-ranges': 'bytes',
'connection': 'close'}</samp> 'connection': 'close'}</samp>
<samp> class="prompt">>>> </samp>request.add_header('If-Modified-Since', <samp class="prompt">>>> </samp>request.add_header('If-Modified-Since',
<samp class="prompt">... </samp>firstdatastream.headers.get('Last-Modified')) <img id="oa.etags.1.2" src="images/callouts/2.png" alt="2" border="0" width="12" height="12"> <samp class="prompt">... </samp>firstdatastream.headers.get('Last-Modified')) <img id="oa.etags.1.2" src="images/callouts/2.png" alt="2" border="0" width="12" height="12">
<samp class="prompt">>>> </samp>seconddatastream = opener.open(request) <img id="oa.etags.1.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>seconddatastream = opener.open(request) <img id="oa.etags.1.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12">
<samp class="traceback">Traceback (most recent call last): <samp class="traceback">Traceback (most recent call last):
@@ -10556,7 +10556,7 @@ class DefaultErrorHandler(urllib2.HTTPDefaultErrorHandler): <img id="oa.etags
&lt;title mode="escaped">dive into mark&lt;/title> &lt;title mode="escaped">dive into mark&lt;/title>
&lt;link rel="alternate" type="text/html" href="http://diveintomark.org/"/> &lt;link rel="alternate" type="text/html" href="http://diveintomark.org/"/>
&lt;-- rest of feed omitted for brevity --></samp> &lt;-- rest of feed omitted for brevity --></samp>
<samp> class="prompt">>>> </samp>request.add_header('If-None-Match', <samp class="prompt">>>> </samp>request.add_header('If-None-Match',
<samp class="prompt">... </samp>firstdatastream.headers.get('ETag')) <img id="oa.etags.4.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12"> <samp class="prompt">... </samp>firstdatastream.headers.get('ETag')) <img id="oa.etags.4.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12">
<samp class="prompt">>>> </samp>seconddatastream = opener.open(request) <samp class="prompt">>>> </samp>seconddatastream = opener.open(request)
<samp class="prompt">>>> </samp>seconddatastream.status <img id="oa.etags.4.4" src="images/callouts/4.png" alt="4" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>seconddatastream.status <img id="oa.etags.4.4" src="images/callouts/4.png" alt="4" border="0" width="12" height="12">
@@ -10646,7 +10646,7 @@ header: Accept-Ranges: bytes
header: Content-Length: 15955 header: Content-Length: 15955
header: Connection: close header: Connection: close
header: Content-Type: application/atom+xml</samp> header: Content-Type: application/atom+xml</samp>
<samp> class="prompt">>>> </samp>f.url <img id="oa.redirect.1.5" src="images/callouts/6.png" alt="6" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>f.url <img id="oa.redirect.1.5" src="images/callouts/6.png" alt="6" border="0" width="12" height="12">
'http://diveintomark.org/xml/atom.xml' 'http://diveintomark.org/xml/atom.xml'
<samp class="prompt">>>> </samp>f.headers.dict <samp class="prompt">>>> </samp>f.headers.dict
<samp class="computeroutput">{'content-length': '15955', <samp class="computeroutput">{'content-length': '15955',
@@ -10657,7 +10657,7 @@ header: Content-Type: application/atom+xml</samp>
'etag': '"e842a-3e53-55d97640"', 'etag': '"e842a-3e53-55d97640"',
'date': 'Thu, 15 Apr 2004 22:06:25 GMT', 'date': 'Thu, 15 Apr 2004 22:06:25 GMT',
'content-type': 'application/atom+xml'}</samp> 'content-type': 'application/atom+xml'}</samp>
<samp> class="prompt">>>> </samp>f.status <samp class="prompt">>>> </samp>f.status
<samp class="traceback">Traceback (most recent call last): <samp class="traceback">Traceback (most recent call last):
File "&lt;stdin>", line 1, in ? File "&lt;stdin>", line 1, in ?
AttributeError: addinfourl instance has no attribute 'status'</span> AttributeError: addinfourl instance has no attribute 'status'</span>
@@ -10786,7 +10786,7 @@ header: Content-Length: 15955
header: Connection: close header: Connection: close
header: Content-Type: application/atom+xml header: Content-Type: application/atom+xml
</samp> </samp>
<samp> class="prompt">>>> </samp>f.status <img id="oa.redirect.3.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>f.status <img id="oa.redirect.3.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12">
301 301
<samp class="prompt">>>> </samp>f.url <samp class="prompt">>>> </samp>f.url
'http://diveintomark.org/xml/atom.xml' 'http://diveintomark.org/xml/atom.xml'
@@ -10848,7 +10848,7 @@ header: Accept-Ranges: bytes
header: Content-Length: 15955 header: Content-Length: 15955
header: Connection: close header: Connection: close
header: Content-Type: application/atom+xml</samp> header: Content-Type: application/atom+xml</samp>
<samp> class="prompt">>>> </samp>f.status <img id="oa.redirect.4.4" src="images/callouts/4.png" alt="4" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>f.status <img id="oa.redirect.4.4" src="images/callouts/4.png" alt="4" border="0" width="12" height="12">
302 302
<samp class="prompt">>>> </samp>f.url <samp class="prompt">>>> </samp>f.url
http://diveintomark.org/xml/atom.xml http://diveintomark.org/xml/atom.xml
@@ -10963,7 +10963,7 @@ header: Content-Type: application/atom+xml</span>
&lt;title mode="escaped">dive into mark&lt;/title> &lt;title mode="escaped">dive into mark&lt;/title>
&lt;link rel="alternate" type="text/html" href="http://diveintomark.org/"/> &lt;link rel="alternate" type="text/html" href="http://diveintomark.org/"/>
&lt;-- rest of feed omitted for brevity --></samp> &lt;-- rest of feed omitted for brevity --></samp>
<samp> class="prompt">>>> </samp>len(data) <samp class="prompt">>>> </samp>len(data)
15955 15955
</pre><div class="calloutlist"> </pre><div class="calloutlist">
<table border="0" summary="Callout list"> <table border="0" summary="Callout list">
@@ -11186,7 +11186,7 @@ def fetch(source, etag=None, last_modified=None, agent=USER_AGENT):
'data': '&lt;?xml version="1.0" encoding="iso-8859-1"?> 'data': '&lt;?xml version="1.0" encoding="iso-8859-1"?>
&lt;feed version="0.3" &lt;feed version="0.3"
&lt;-- rest of data omitted for brevity -->'}</samp> &lt;-- rest of data omitted for brevity -->'}</samp>
<samp> class="prompt">>>> </samp>if params['status'] == 301:<img id="oa.alltogether.3.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>if params['status'] == 301:<img id="oa.alltogether.3.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12">
<samp class="prompt">... </samp>url = params['url'] <samp class="prompt">... </samp>url = params['url']
<samp class="prompt">>>> </samp>newparams = openanything.fetch( <samp class="prompt">>>> </samp>newparams = openanything.fetch(
<samp class="prompt">... </samp>url, params['etag'], params['lastmodified'], useragent) <img id="oa.alltogether.3.4" src="images/callouts/4.png" alt="4" border="0" width="12" height="12"> <samp class="prompt">... </samp>url, params['etag'], params['lastmodified'], useragent) <img id="oa.alltogether.3.4" src="images/callouts/4.png" alt="4" border="0" width="12" height="12">
@@ -11526,7 +11526,7 @@ region.</p>
&lt;/SOAP-ENV:Envelope> &lt;/SOAP-ENV:Envelope>
************************************************************************ ************************************************************************
</samp> </samp>
<samp> class="prompt">>>> </samp>temperature <samp class="prompt">>>> </samp>temperature
80.0 80.0
</pre><div class="calloutlist"> </pre><div class="calloutlist">
<table border="0" summary="Callout list"> <table border="0" summary="Callout list">
@@ -11784,7 +11784,7 @@ u'return'
&lt;/SOAP-ENV:Envelope> &lt;/SOAP-ENV:Envelope>
************************************************************************ ************************************************************************
</samp> </samp>
<samp> class="prompt">>>> </samp>temperature <samp class="prompt">>>> </samp>temperature
66.0 66.0
</pre><div class="calloutlist"> </pre><div class="calloutlist">
<table border="0" summary="Callout list"> <table border="0" summary="Callout list">
@@ -11949,7 +11949,7 @@ and you can access it programmatically too.</p>
{'fullViewableName': {'fullViewableName':
'Top/Arts/Literature/World_Literature/American/19th_Century/Twain,_Mark', 'Top/Arts/Literature/World_Literature/American/19th_Century/Twain,_Mark',
'specialEncoding': ''}]</samp> 'specialEncoding': ''}]</samp>
<samp> class="prompt">>>> </samp>results.directoryCategories[0].fullViewableName <samp class="prompt">>>> </samp>results.directoryCategories[0].fullViewableName
'Top/Arts/Literature/World_Literature/American/19th_Century/Twain,_Mark' 'Top/Arts/Literature/World_Literature/American/19th_Century/Twain,_Mark'
</pre><div class="calloutlist"> </pre><div class="calloutlist">
<table border="0" summary="Callout list"> <table border="0" summary="Callout list">
@@ -13295,7 +13295,7 @@ def fromRoman(s):
File "roman3.py", line 27, in toRoman File "roman3.py", line 27, in toRoman
raise OutOfRangeError, "number out of range (must be 1..3999)" raise OutOfRangeError, "number out of range (must be 1..3999)"
OutOfRangeError: number out of range (must be 1..3999)</samp> OutOfRangeError: number out of range (must be 1..3999)</samp>
<samp> class="prompt">>>> </samp>roman3.toRoman(1.5) <samp class="prompt">>>> </samp>roman3.toRoman(1.5)
<samp class="traceback">Traceback (most recent call last): <samp class="traceback">Traceback (most recent call last):
File "&lt;interactive input>", line 1, in ? File "&lt;interactive input>", line 1, in ?
File "roman3.py", line 29, in toRoman File "roman3.py", line 29, in toRoman
@@ -14828,11 +14828,11 @@ print 'full path =', os.path.abspath(pathname) <img id="regression.path.1.3" src
<samp class="computeroutput">sys.argv[0] = /home/you/diveintopython3/common/py/fullpath.py <samp class="computeroutput">sys.argv[0] = /home/you/diveintopython3/common/py/fullpath.py
path = /home/you/diveintopython3/common/py path = /home/you/diveintopython3/common/py
full path = /home/you/diveintopython3/common/py</samp> full path = /home/you/diveintopython3/common/py</samp>
<samp> class="prompt">[you@localhost diveintopython3]$ </samp>python common/py/fullpath.py <img id="regression.path.3.2" src="images/callouts/2.png" alt="2" border="0" width="12" height="12"> <samp class="prompt">[you@localhost diveintopython3]$ </samp>python common/py/fullpath.py <img id="regression.path.3.2" src="images/callouts/2.png" alt="2" border="0" width="12" height="12">
<samp class="computeroutput">sys.argv[0] = common/py/fullpath.py <samp class="computeroutput">sys.argv[0] = common/py/fullpath.py
path = common/py path = common/py
full path = /home/you/diveintopython3/common/py</samp> full path = /home/you/diveintopython3/common/py</samp>
<samp> class="prompt">[you@localhost diveintopython3]$ </samp>cd common/py <samp class="prompt">[you@localhost diveintopython3]$ </samp>cd common/py
<samp class="prompt">[you@localhost py]$ </samp>python fullpath.py <img id="regression.path.3.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12"> <samp class="prompt">[you@localhost py]$ </samp>python fullpath.py <img id="regression.path.3.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12">
<samp class="computeroutput">sys.argv[0] = fullpath.py <samp class="computeroutput">sys.argv[0] = fullpath.py
path = path =
@@ -15164,7 +15164,7 @@ to doesn't need to match the module name, either. You could import a series of
&lt;module 'os' from 'c:\Python22\lib\os.pyc'>, &lt;module 'os' from 'c:\Python22\lib\os.pyc'>,
&lt;module 're' from 'c:\Python22\lib\re.pyc'>, &lt;module 're' from 'c:\Python22\lib\re.pyc'>,
&lt;module 'unittest' from 'c:\Python22\lib\unittest.pyc'>]</samp> &lt;module 'unittest' from 'c:\Python22\lib\unittest.pyc'>]</samp>
<samp> class="prompt">>>> </samp>modules[0].version <img id="regression.import.3.4" src="images/callouts/4.png" alt="4" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>modules[0].version <img id="regression.import.3.4" src="images/callouts/4.png" alt="4" border="0" width="12" height="12">
'2.2.2 (#37, Nov 26 2002, 10:24:37) [MSC 32 bit (Intel)]' '2.2.2 (#37, Nov 26 2002, 10:24:37) [MSC 32 bit (Intel)]'
<samp class="prompt">>>> </samp>import sys <samp class="prompt">>>> </samp>import sys
<samp class="prompt">>>> </samp>sys.version <samp class="prompt">>>> </samp>sys.version
@@ -15318,7 +15318,7 @@ return unittest.TestSuite(map(load, modules))
&lt;module 'odbchelpertest' from 'odbchelpertest.py'>, &lt;module 'odbchelpertest' from 'odbchelpertest.py'>,
&lt;module 'pluraltest' from 'pluraltest.py'>, &lt;module 'pluraltest' from 'pluraltest.py'>,
&lt;module 'romantest' from 'romantest.py'>]</samp> &lt;module 'romantest' from 'romantest.py'>]</samp>
<samp> class="prompt">>>> </samp>modules[-1] <img id="regression.alltogether.4.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>modules[-1] <img id="regression.alltogether.4.3" src="images/callouts/3.png" alt="3" border="0" width="12" height="12">
&lt;module 'romantest' from 'romantest.py'> &lt;module 'romantest' from 'romantest.py'>
</pre><div class="calloutlist"> </pre><div class="calloutlist">
<table border="0" summary="Callout list"> <table border="0" summary="Callout list">
@@ -15356,7 +15356,7 @@ return unittest.TestSuite(map(load, modules))
... ...
] ]
]</samp> ]</samp>
<samp> class="prompt">>>> </samp>unittest.TestSuite(map(load, modules)) <img id="regression.alltogether.5.2" src="images/callouts/2.png" alt="2" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>unittest.TestSuite(map(load, modules)) <img id="regression.alltogether.5.2" src="images/callouts/2.png" alt="2" border="0" width="12" height="12">
</pre><div class="calloutlist"> </pre><div class="calloutlist">
<table border="0" summary="Callout list"> <table border="0" summary="Callout list">
<tr> <tr>
@@ -16023,10 +16023,10 @@ def plural(noun, language='en'):
<samp class="prompt">>>> </samp>counter.next() <img id="plural.stage6.2.4" src="images/callouts/4.png" alt="4" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>counter.next() <img id="plural.stage6.2.4" src="images/callouts/4.png" alt="4" border="0" width="12" height="12">
<samp class="computeroutput">entering make_counter <samp class="computeroutput">entering make_counter
2</samp> 2</samp>
<samp> class="prompt">>>> </samp>counter.next() <img id="plural.stage6.2.5" src="images/callouts/5.png" alt="5" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>counter.next() <img id="plural.stage6.2.5" src="images/callouts/5.png" alt="5" border="0" width="12" height="12">
<samp class="computeroutput">incrementing x <samp class="computeroutput">incrementing x
3</samp> 3</samp>
<samp> class="prompt">>>> </samp>counter.next() <img id="plural.stage6.2.6" src="images/callouts/6.png" alt="6" border="0" width="12" height="12"> <samp class="prompt">>>> </samp>counter.next() <img id="plural.stage6.2.6" src="images/callouts/6.png" alt="6" border="0" width="12" height="12">
<samp class="computeroutput">incrementing x <samp class="computeroutput">incrementing x
4</span> 4</span>
</pre><div class="calloutlist"> </pre><div class="calloutlist">
+8 -8
View File
@@ -1,5 +1,4 @@
/*dive into minimalism(c)2008 Mark Pilgrim,MIT-licensed*/ html{background:#fff;color:#000}
html{background:white;color:black}
body{font:normal medium 'Gill Sans','Gill Sans MT','Ikarius ADF',Candara,Jara,sans-serif;margin:1.75em auto;width:40em;line-height:1.75;word-spacing:0.1em} body{font:normal medium 'Gill Sans','Gill Sans MT','Ikarius ADF',Candara,Jara,sans-serif;margin:1.75em auto;width:40em;line-height:1.75;word-spacing:0.1em}
a{background:transparent;text-decoration:none;border-bottom:1px dotted} a{background:transparent;text-decoration:none;border-bottom:1px dotted}
a:hover{border-bottom:1px solid} a:hover{border-bottom:1px solid}
@@ -9,21 +8,22 @@ h1 a,h2 a,h3 a,#nav a{color:inherit !important}
abbr,.p{border:0;letter-spacing:0.1em;text-transform:lowercase;font-variant:small-caps} abbr,.p{border:0;letter-spacing:0.1em;text-transform:lowercase;font-variant:small-caps}
h1,h2,h3,p,ul,ol,#nav{margin:1.75em 0} h1,h2,h3,p,ul,ol,#nav{margin:1.75em 0}
h1,h2,h3{font-size:medium} h1,h2,h3{font-size:medium}
h1{background:papayawhip;color:black;width:100%;margin:0} h1{background:papayawhip;color:#000;width:100%;margin:0}
h2{margin-left:1.75em} #index h2{margin-left:1.75em}
h3{margin-left:3.5em} #index h3{margin-left:3.5em}
pre,tt{white-space:pre-wrap;font-size:medium;line-height:2.154} pre,tt{white-space:pre-wrap;font-size:medium;line-height:2.154}
cite{font-style:normal} cite{font-style:normal}
img{border:0} img{border:0}
.framed{border:1px solid} .framed{border:1px solid}
blockquote{font-size:small;line-height:2.154;margin:2.154em 0;padding:0} pre,blockquote{line-height:2.154;margin:2.154em 0;padding:0 0 0 2.154em;border-left:1px dotted}
blockquote{font-style:oblique;border-left:1px dotted;margin-left:2.154em;padding-left:2.154em} blockquote{font-size:small;font-style:oblique;margin-left:2.154em}
blockquote p{margin:2.154em 0} blockquote p{margin:2.154em 0}
.f,.c{text-align:center;clear:both} .f,.c{text-align:center;clear:both}
article + p:first-letter{float:left;color:gainsboro;padding:0.11em 4px 0 0;font:normal 4em/0.68 serif} section h2 + p:first-letter{float:left;background:transparent;color:gainsboro;padding:0.11em 4px 0 0;font:normal 4em/0.68 serif}
#arc{width:100%,border-collapse:collapse} #arc{width:100%,border-collapse:collapse}
#arc th,#arc td{list-style:none;margin:0;padding:0} #arc th,#arc td{list-style:none;margin:0;padding:0}
#arc th{padding:0 1.75em 0 0;text-align:right;vertical-align:baseline} #arc th{padding:0 1.75em 0 0;text-align:right;vertical-align:baseline}
figure{display:block;text-align:center;margin:1.75em 0} figure{display:block;text-align:center;margin:1.75em 0}
figure img{display:block;margin:0 auto} figure img{display:block;margin:0 auto}
section,article,footer{display:block} section,article,footer{display:block}
var{font-family:monospace;font-style:normal}
+247 -247
View File
@@ -8,7 +8,7 @@
<meta name="keywords" content="Python, Python 3, Dive Into Python 3, tutorial, programming, documentation, book, free"> <meta name="keywords" content="Python, Python 3, Dive Into Python 3, tutorial, programming, documentation, book, free">
<meta name="description" content="Python 3 from novice to pro"> <meta name="description" content="Python 3 from novice to pro">
</head> </head>
<body> <body id="index">
<p><cite>Dive into Python 3</cite> will cover Python 3 and its differences from Python 2. Compared to the original <cite><a href="http://diveintopython.org/">Dive into Python</a></cite>, it will be about 50% revised and 50% new material.</p> <p><cite>Dive into Python 3</cite> will cover Python 3 and its differences from Python 2. Compared to the original <cite><a href="http://diveintopython.org/">Dive into Python</a></cite>, it will be about 50% revised and 50% new material.</p>
<p>I will publish drafts online as I go. The final book will be published on paper by Apress. The book will remain online under the <a rel="license" href="http://creativecommons.org/licenses/by/3.0/">CC-BY-3.0</a> license.</p> <p>I will publish drafts online as I go. The final book will be published on paper by Apress. The book will remain online under the <a rel="license" href="http://creativecommons.org/licenses/by/3.0/">CC-BY-3.0</a> license.</p>
<p>Below is the draft table of contents. There is no text yet.</p> <p>Below is the draft table of contents. There is no text yet.</p>
@@ -17,72 +17,72 @@
<section> <section>
<h1>Installing Python</h1> <h1>Installing Python</h1>
<article> <section>
<h2>Python on Windows</h2> <h2>Python on Windows</h2>
</article> </section>
<article> <section>
<h2>Python on Mac OS X</h2> <h2>Python on Mac OS X</h2>
</article> </section>
<article> <section>
<h2>Python on Linux</h2> <h2>Python on Linux</h2>
</article> </section>
<article> <section>
<h2>Python from source</h2> <h2>Python from source</h2>
</article> </section>
<article> <section>
<h2>The interactive shell</h2> <h2>The interactive shell</h2>
</article> </section>
<article> <section>
<h2>Summary</h2> <h2>Summary</h2>
</article> </section>
</section> </section>
<section> <section>
<h1>Your first Python program</h1> <h1>Your first Python program</h1>
<article> <section>
<h2>Diving in</h2> <h2>Diving in</h2>
</article> </section>
<article> <section>
<h2>Declaring functions</h2> <h2>Declaring functions</h2>
<h3>How Python's datatypes compare to other programming languages</h3> <h3>How Python's datatypes compare to other programming languages</h3>
</article> </section>
<article> <section>
<h2>Documenting functions</h2> <h2>Documenting functions</h2>
</article> </section>
<article> <section>
<h2>Everything is an object</h2> <h2>Everything is an object</h2>
<h3>The import search path</h3> <h3>The import search path</h3>
<h3>What's an object?</h3> <h3>What's an object?</h3>
</article> </section>
<article> <section>
<h2>Indenting code</h2> <h2>Indenting code</h2>
</article> </section>
<article> <section>
<h2>Testing modules</h2> <h2>Testing modules</h2>
</article> </section>
<article> <section>
<h2>Summary</h2> <h2>Summary</h2>
</article> </section>
</section> </section>
<section> <section>
<h1>Native Python datatypes</h1> <h1>Native Python datatypes</h1>
<article> <section>
<h2>Lists</h2> <h2>Lists</h2>
<h3>Differences from Python 2</h3> <h3>Differences from Python 2</h3>
<h3>Creating new a list</h3> <h3>Creating new a list</h3>
@@ -92,9 +92,9 @@
<h3>List operators</h3> <h3>List operators</h3>
<h3>Looping through a list (list comprehensions)</h3> <h3>Looping through a list (list comprehensions)</h3>
<h3>Tuples</h3> <h3>Tuples</h3>
</article> </section>
<article> <section>
<h2>Dictionaries</h2> <h2>Dictionaries</h2>
<h3>Differences from Python 2</h3> <h3>Differences from Python 2</h3>
<h3>Creating a new dictionary</h3> <h3>Creating a new dictionary</h3>
@@ -102,9 +102,9 @@
<h3>Deleting items from a dictionary</h3> <h3>Deleting items from a dictionary</h3>
<h3>Looping through a dictionary (dictionary comprehensions)</h3> <h3>Looping through a dictionary (dictionary comprehensions)</h3>
<h3>Dictionary views</h3> <h3>Dictionary views</h3>
</article> </section>
<article> <section>
<h2>Sets</h2> <h2>Sets</h2>
<h3>Differences from Python 2</h3> <h3>Differences from Python 2</h3>
<h3>Creating a new set</h3> <h3>Creating a new set</h3>
@@ -112,9 +112,9 @@
<h3>Deleting elements from a set</h3> <h3>Deleting elements from a set</h3>
<h3>Common set operations: union, intersection, and difference</h3> <h3>Common set operations: union, intersection, and difference</h3>
<h3>Frozen sets</h3> <h3>Frozen sets</h3>
</article> </section>
<article> <section>
<h2>Numbers</h2> <h2>Numbers</h2>
<h3>Differences from Python 2</h3> <h3>Differences from Python 2</h3>
<h3>Integers</h3> <h3>Integers</h3>
@@ -122,527 +122,527 @@
<h3>Floating point numbers</h3> <h3>Floating point numbers</h3>
<h3>Complex numbers</h3> <h3>Complex numbers</h3>
<h3>Common numerical operations</h3> <h3>Common numerical operations</h3>
</article> </section>
</section> </section>
<section> <section>
<h1>Strings</h1> <h1>Strings</h1>
<article> <section>
<h2>There ain't no such thing as "plain text"</h2> <h2>There ain't no such thing as "plain text"</h2>
<h3>A brief history of character encoding</h3> <h3>A brief history of character encoding</h3>
<h3>What's a character?</h3> <h3>What's a character?</h3>
<h3>How strings are stored in memory</h3> <h3>How strings are stored in memory</h3>
<h3>Converting between different character encodings</h3> <h3>Converting between different character encodings</h3>
</article> </section>
<article> <section>
<h2>Differences from Python 2</h2> <h2>Differences from Python 2</h2>
</article> </section>
<article> <section>
<h2>Formatting strings</h2> <h2>Formatting strings</h2>
</article> </section>
<article> <section>
<h2>What's my string?</h2> <h2>What's my string?</h2>
</article> </section>
<article> <section>
<h2>Lists and strings</h2> <h2>Lists and strings</h2>
</article> </section>
<article> <section>
<h2>Historical note on the string module</h2> <h2>Historical note on the string module</h2>
</article> </section>
<article> <section>
<h2>Byte streams</h2> <h2>Byte streams</h2>
</article> </section>
<article> <section>
<h2>Summary</h2> <h2>Summary</h2>
</article> </section>
</section> </section>
<section> <section>
<h1>The power of introspection</h1> <h1>The power of introspection</h1>
<article> <section>
<h2>Diving in</h2> <h2>Diving in</h2>
</article> </section>
<article> <section>
<h2>Using optional and named arguments</h2> <h2>Using optional and named arguments</h2>
<h3>Keyword-only arguments</h3> <h3>Keyword-only arguments</h3>
</article> </section>
<article> <section>
<h2>Using type, str, dir, and other built-in functions</h2> <h2>Using type, str, dir, and other built-in functions</h2>
<h3>The type function</h3> <h3>The type function</h3>
<h3>The str function</h3> <h3>The str function</h3>
<h3>Built-in functions</h3> <h3>Built-in functions</h3>
</article> </section>
<article> <section>
<h2>Getting object references with getattr</h2> <h2>Getting object references with getattr</h2>
<h3>getattr with modules</h3> <h3>getattr with modules</h3>
<h3>getattr as a dispatcher</h3> <h3>getattr as a dispatcher</h3>
</article> </section>
<article> <section>
<h2>Filtering lists</h2> <h2>Filtering lists</h2>
</article> </section>
<article> <section>
<h2>The peculiar nature of and and or</h2> <h2>The peculiar nature of and and or</h2>
<h3>Using the and-or trick</h3> <h3>Using the and-or trick</h3>
</article> </section>
<article> <section>
<h2>Using lambda functions</h2> <h2>Using lambda functions</h2>
<h3>Real-world lambda functions</h3> <h3>Real-world lambda functions</h3>
</article> </section>
<article> <section>
<h2>Putting it all together</h2> <h2>Putting it all together</h2>
</article> </section>
<article> <section>
<h2>Summary</h2> <h2>Summary</h2>
</article> </section>
</section> </section>
<section> <section>
<h1>Objects and object-orientation</h1> <h1>Objects and object-orientation</h1>
<article> <section>
<h2>...major changes afoot...</h2> <h2>...major changes afoot...</h2>
</article> </section>
</section> </section>
<section> <section>
<h1>Exceptions</h1> <h1>Exceptions</h1>
<article> <section>
<h2>...</h2> <h2>...</h2>
</article> </section>
</section> </section>
<section> <section>
<h1>Files</h1> <h1>Files</h1>
<article> <section>
<h2>File objects</h2> <h2>File objects</h2>
</article> </section>
<article> <section>
<h2>Reading files</h2> <h2>Reading files</h2>
</article> </section>
<article> <section>
<h2>Close your files... or don't</h2> <h2>Close your files... or don't</h2>
</article> </section>
<article> <section>
<h2>Handling I/O errors</h2> <h2>Handling I/O errors</h2>
</article> </section>
<article> <section>
<h2>Writing to files</h2> <h2>Writing to files</h2>
</article> </section>
</section> </section>
<section> <section>
<h1>Regular expressions</h1> <h1>Regular expressions</h1>
<article> <section>
<h2>Diving in</h2> <h2>Diving in</h2>
</article> </section>
<article> <section>
<h2>Case study: street addresses</h2> <h2>Case study: street addresses</h2>
</article> </section>
<article> <section>
<h2>Case study: Roman numerals</h2> <h2>Case study: Roman numerals</h2>
<h3>Checking for thousands</h3> <h3>Checking for thousands</h3>
<h3>Checking for hundreds</h3> <h3>Checking for hundreds</h3>
</article> </section>
<article> <section>
<h2>Using the {n,m} syntax</h2> <h2>Using the {n,m} syntax</h2>
<h3>Checking for tens and ones</h3> <h3>Checking for tens and ones</h3>
</article> </section>
<article> <section>
<h2>Verbose regular expressions</h2> <h2>Verbose regular expressions</h2>
</article> </section>
<article> <section>
<h2>Case study: parsing phone numbers</h2> <h2>Case study: parsing phone numbers</h2>
</article> </section>
<article> <section>
<h2>Summary</h2> <h2>Summary</h2>
</article> </section>
</section> </section>
<section> <section>
<h1>HTML processing</h1> <h1>HTML processing</h1>
<article> <section>
<h2>Diving in</h2> <h2>Diving in</h2>
</article> </section>
<article> <section>
<h2>html5lib</h2> <h2>html5lib</h2>
<h3>Installing html5lib</h3> <h3>Installing html5lib</h3>
<h3>Using html5lib</h3> <h3>Using html5lib</h3>
</article> </section>
<article> <section>
<h2>Extracting data from HTML documents</h2> <h2>Extracting data from HTML documents</h2>
</article> </section>
<article> <section>
<h2>Building HTML documents</h2> <h2>Building HTML documents</h2>
</article> </section>
<article> <section>
<h2>Putting it all together</h2> <h2>Putting it all together</h2>
</article> </section>
<article> <section>
<h2>Summary</h2> <h2>Summary</h2>
</article> </section>
</section> </section>
<section> <section>
<h1>XML Processing</h1> <h1>XML Processing</h1>
<article> <section>
<h2>...major changes afoot...</h2> <h2>...major changes afoot...</h2>
</article> </section>
</section> </section>
<section> <section>
<h1><del>Scripts and streams</del></h1> <h1><del>Scripts and streams</del></h1>
<article> <section>
<h2>...will be folded into other chapters...</h2> <h2>...will be folded into other chapters...</h2>
</article> </section>
</section> </section>
<section> <section>
<h1>HTTP web services</h1> <h1>HTTP web services</h1>
<article> <section>
<h2>Diving in</h2> <h2>Diving in</h2>
</article> </section>
<article> <section>
<h2>How not to fetch data over HTTP</h2> <h2>How not to fetch data over HTTP</h2>
</article> </section>
<article> <section>
<h2>Features of HTTP</h2> <h2>Features of HTTP</h2>
<h3>User-Agent</h3> <h3>User-Agent</h3>
<h3>Redirects</h3> <h3>Redirects</h3>
<h3>Last-Modified/If-Modified-Since</h3> <h3>Last-Modified/If-Modified-Since</h3>
<h3>ETag-If-None-Match</h3> <h3>ETag-If-None-Match</h3>
<h3>Compression</h3> <h3>Compression</h3>
</article> </section>
<article> <section>
<h2>Differences from Python 2</h2> <h2>Differences from Python 2</h2>
</article> </section>
<article> <section>
<h2>httplib2 (note: needs port)</h2> <h2>httplib2 (note: needs port)</h2>
<h3>Installing httplib2</h3> <h3>Installing httplib2</h3>
<h3>Why httplib2 is better than http.client</h3> <h3>Why httplib2 is better than http.client</h3>
</article> </section>
<article> <section>
<h2>Debugging HTTP web services</h2> <h2>Debugging HTTP web services</h2>
</article> </section>
<article> <section>
<h2>Setting the User-Agent</h2> <h2>Setting the User-Agent</h2>
</article> </section>
<article> <section>
<h2>Handling Last-Modified and ETag</h2> <h2>Handling Last-Modified and ETag</h2>
</article> </section>
<article> <section>
<h2>Handling redirects</h2> <h2>Handling redirects</h2>
</article> </section>
<article> <section>
<h2>Handling compressed data</h2> <h2>Handling compressed data</h2>
</article> </section>
<article> <section>
<h2>Putting it all together</h2> <h2>Putting it all together</h2>
</article> </section>
<article> <section>
<h2>Summary</h2> <h2>Summary</h2>
</article> </section>
</section> </section>
<section> <section>
<h1><del>SOAP web services</del></h1> <h1><del>SOAP web services</del></h1>
<article> <section>
<h2>...no one will miss you...</h2> <h2>...no one will miss you...</h2>
</article> </section>
</section> </section>
<section> <section>
<h1>Unit testing</h1> <h1>Unit testing</h1>
<article> <section>
<h2>Introduction to Roman numerals</h2> <h2>Introduction to Roman numerals</h2>
</article> </section>
<article> <section>
<h2>Diving in</h2> <h2>Diving in</h2>
</article> </section>
<article> <section>
<h2>Introducing romantest.py</h2> <h2>Introducing romantest.py</h2>
</article> </section>
<article> <section>
<h2>Testing for success</h2> <h2>Testing for success</h2>
</article> </section>
<article> <section>
<h2>Testing for failure</h2> <h2>Testing for failure</h2>
</article> </section>
<article> <section>
<h2>Testing for sanity</h2> <h2>Testing for sanity</h2>
</article> </section>
</section> </section>
<section> <section>
<h1>Test-first programming</h1> <h1>Test-first programming</h1>
<article> <section>
<h2>roman.py, stage 1</h2> <h2>roman.py, stage 1</h2>
</article> </section>
<article> <section>
<h2>roman.py, stage 2</h2> <h2>roman.py, stage 2</h2>
</article> </section>
<article> <section>
<h2>roman.py, stage 3</h2> <h2>roman.py, stage 3</h2>
</article> </section>
<article> <section>
<h2>roman.py, stage 4</h2> <h2>roman.py, stage 4</h2>
</article> </section>
<article> <section>
<h2>roman.py, stage 5</h2> <h2>roman.py, stage 5</h2>
</article> </section>
</section> </section>
<section> <section>
<h1>Refactoring your code</h1> <h1>Refactoring your code</h1>
<article> <section>
<h2>Handling bugs</h2> <h2>Handling bugs</h2>
</article> </section>
<article> <section>
<h2>Handling changing requirements</h2> <h2>Handling changing requirements</h2>
</article> </section>
<article> <section>
<h2>The art of refactoring</h2> <h2>The art of refactoring</h2>
</article> </section>
<article> <section>
<h2>Postscript</h2> <h2>Postscript</h2>
</article> </section>
<article> <section>
<h2>Summary</h2> <h2>Summary</h2>
</article> </section>
</section> </section>
<section> <section>
<h1><del>Functional programming</del></h1> <h1><del>Functional programming</del></h1>
<article> <section>
<h2>...bits and pieces will be folded into other chapters...</h2> <h2>...bits and pieces will be folded into other chapters...</h2>
</article> </section>
</section> </section>
<section> <section>
<h1>Dynamic functions</h1> <h1>Dynamic functions</h1>
<article> <section>
<h2>Diving in</h2> <h2>Diving in</h2>
</article> </section>
<article> <section>
<h2>plural.py, stage 1</h2> <h2>plural.py, stage 1</h2>
</article> </section>
<article> <section>
<h2>plural.py, stage 2</h2> <h2>plural.py, stage 2</h2>
</article> </section>
<article> <section>
<h2>plural.py, stage 3</h2> <h2>plural.py, stage 3</h2>
</article> </section>
<article> <section>
<h2>plural.py, stage 4</h2> <h2>plural.py, stage 4</h2>
</article> </section>
<article> <section>
<h2>plural.py, stage 5</h2> <h2>plural.py, stage 5</h2>
</article> </section>
<article> <section>
<h2>plural.py, stage 6</h2> <h2>plural.py, stage 6</h2>
</article> </section>
<article> <section>
<h2>Summary</h2> <h2>Summary</h2>
</article> </section>
</section> </section>
<section> <section>
<h1>Metaclasses</h1> <h1>Metaclasses</h1>
<article> <section>
<h2>...once I figure out WTF metaclasses are...</h2> <h2>...once I figure out WTF metaclasses are...</h2>
</article> </section>
</section> </section>
<section> <section>
<h1>Performance tuning</h1> <h1>Performance tuning</h1>
<article> <section>
<h2>Diving in</h2> <h2>Diving in</h2>
</article> </section>
<article> <section>
<h2>Using the timeit module</h2> <h2>Using the timeit module</h2>
</article> </section>
<article> <section>
<h2>Optimizing regular expressions</h2> <h2>Optimizing regular expressions</h2>
</article> </section>
<article> <section>
<h2>Optimizing dictionary lookups</h2> <h2>Optimizing dictionary lookups</h2>
</article> </section>
<article> <section>
<h2>Optimizing list operations</h2> <h2>Optimizing list operations</h2>
</article> </section>
<article> <section>
<h2>Optimizing string manipulation</h2> <h2>Optimizing string manipulation</h2>
</article> </section>
<article> <section>
<h2>Summary</h2> <h2>Summary</h2>
</article> </section>
</section> </section>
<section> <section>
<h1>Migrating old code to Python 3</h1> <h1>Migrating old code to Python 3</h1>
<article> <section>
<h2>Diving in</h2> <h2>Diving in</h2>
</article> </section>
<article> <section>
<h2>The 2to3 migration tool</h2> <h2>The 2to3 migration tool</h2>
</article> </section>
<article> <section>
<h2>Things the 2to3 tools won't catch</h2> <h2>Things the 2to3 tools won't catch</h2>
</article> </section>
<article> <section>
<h2>Case study: feedparser</h2> <h2>Case study: feedparser</h2>
<h3>Just shoot me</h3> <h3>Just shoot me</h3>
</article> </section>
<article> <section>
<h2>Summary</h2> <h2>Summary</h2>
</article> </section>
</section> </section>
<section> <section>
<h1>Creating graphics with the Python Imaging Library</h1> <h1>Creating graphics with the Python Imaging Library</h1>
<article> <section>
<h2>...if it gets ported...</h2> <h2>...if it gets ported...</h2>
</article> </section>
</section> </section>
<section> <section>
<h1>Packaging Python libraries</h1> <h1>Packaging Python libraries</h1>
<article> <section>
<h2>A brief history of packaging (and why it's harder than you think)</h2> <h2>A brief history of packaging (and why it's harder than you think)</h2>
</article> </section>
<article> <section>
<h2>setuptools</h2> <h2>setuptools</h2>
</article> </section>
<article> <section>
<h2>distutils</h2> <h2>distutils</h2>
</article> </section>
<article> <section>
<h2>Eggs</h2> <h2>Eggs</h2>
</article> </section>
<article> <section>
<h2>pip</h2> <h2>pip</h2>
</article> </section>
<article> <section>
<h2>Platform-specific packaging</h2> <h2>Platform-specific packaging</h2>
<h3>Packaging by Linux distributions</h3> <h3>Packaging by Linux distributions</h3>
<h3>Py2exe</h3> <h3>Py2exe</h3>
<h3>Psyco</h3> <h3>Psyco</h3>
</article> </section>
</section> </section>
@@ -650,41 +650,41 @@
<h1>Where to go from here</h1> <h1>Where to go from here</h1>
<p>Tentative because most of these have not been ported to Python 3 yet.</p> <p>Tentative because most of these have not been ported to Python 3 yet.</p>
<article> <section>
<h2>WSGI</h2> <h2>WSGI</h2>
</article> </section>
<article> <section>
<h2>Django</h2> <h2>Django</h2>
</article> </section>
<article> <section>
<h2>Pylons</h2> <h2>Pylons</h2>
</article> </section>
<article> <section>
<h2>TurboGears</h2> <h2>TurboGears</h2>
</article> </section>
<article> <section>
<h2>AppEngine</h2> <h2>AppEngine</h2>
</article> </section>
<article> <section>
<h2>IronPython</h2> <h2>IronPython</h2>
</article> </section>
<article> <section>
<h2>Jython</h2> <h2>Jython</h2>
</article> </section>
<article> <section>
<h2>PyPy</h2> <h2>PyPy</h2>
</article> </section>
<article> <section>
<h2>Stackless Python</h2> <h2>Stackless Python</h2>
</article> </section>
</section> </section>