[Python-checkins] cpython (merge default -> default): merge heads

giampaolo.rodola python-checkins at python.org
Fri Apr 26 15:24:56 CEST 2013


http://hg.python.org/cpython/rev/1a9c9861e56a
changeset:   83523:1a9c9861e56a
parent:      83522:8f7bdfe81b76
parent:      83521:58b0e301b78a
user:        Giampaolo Rodola' <g.rodola at gmail.com>
date:        Fri Apr 26 15:24:42 2013 +0200
summary:
  merge heads

files:
  Lib/keyword.py           |  22 +++++----
  Lib/test/test_keyword.py |  58 ++++++++++++++-------------
  Lib/test/test_urllib2.py |  24 +++++++++++
  Lib/urllib/request.py    |  27 +++++++++---
  Misc/ACKS                |   1 +
  Misc/NEWS                |   6 ++
  6 files changed, 93 insertions(+), 45 deletions(-)


diff --git a/Lib/keyword.py b/Lib/keyword.py
--- a/Lib/keyword.py
+++ b/Lib/keyword.py
@@ -60,6 +60,12 @@
     if len(args) > 1: optfile = args[1]
     else: optfile = "Lib/keyword.py"
 
+    # load the output skeleton from the target, taking care to preserve its
+    # newline convention.
+    with open(optfile, newline='') as fp:
+        format = fp.readlines()
+    nl = format[0][len(format[0].strip()):] if format else '\n'
+
     # scan the source file for keywords
     with open(iptfile) as fp:
         strprog = re.compile('"([^"]+)"')
@@ -68,25 +74,21 @@
             if '{1, "' in line:
                 match = strprog.search(line)
                 if match:
-                    lines.append("        '" + match.group(1) + "',\n")
+                    lines.append("        '" + match.group(1) + "'," + nl)
     lines.sort()
 
-    # load the output skeleton from the target
-    with open(optfile) as fp:
-        format = fp.readlines()
-
-    # insert the lines of keywords
+    # insert the lines of keywords into the skeleton
     try:
-        start = format.index("#--start keywords--\n") + 1
-        end = format.index("#--end keywords--\n")
+        start = format.index("#--start keywords--" + nl) + 1
+        end = format.index("#--end keywords--" + nl)
         format[start:end] = lines
     except ValueError:
         sys.stderr.write("target does not contain format markers\n")
         sys.exit(1)
 
     # write the output file
-    with open(optfile, 'w') as fp:
-        fp.write(''.join(format))
+    with open(optfile, 'w', newline='') as fp:
+        fp.writelines(format)
 
 if __name__ == "__main__":
     main()
diff --git a/Lib/test/test_keyword.py b/Lib/test/test_keyword.py
--- a/Lib/test/test_keyword.py
+++ b/Lib/test/test_keyword.py
@@ -9,7 +9,8 @@
 import textwrap
 
 KEYWORD_FILE             = support.findfile('keyword.py')
-GRAMMAR_FILE             = os.path.join('..', '..', 'Python', 'graminit.c')
+GRAMMAR_FILE             = os.path.join(os.path.split(__file__)[0],
+                                        '..', '..', 'Python', 'graminit.c')
 TEST_PY_FILE             = 'keyword_test.py'
 GRAMMAR_TEST_FILE        = 'graminit_test.c'
 PY_FILE_WITHOUT_KEYWORDS = 'minimal_keyword.py'
@@ -30,7 +31,7 @@
     # preserved for backward compatibility.
     def test_changing_the_kwlist_does_not_affect_iskeyword(self):
         oldlist = keyword.kwlist
-        self.addCleanup(lambda: setattr(keyword, 'kwlist', oldlist))
+        self.addCleanup(setattr, keyword, 'kwlist', oldlist)
         keyword.kwlist = ['its', 'all', 'eggs', 'beans', 'and', 'a', 'slice']
         self.assertFalse(keyword.iskeyword('eggs'))
 
@@ -38,11 +39,12 @@
 class TestKeywordGeneration(unittest.TestCase):
 
     def _copy_file_without_generated_keywords(self, source_file, dest_file):
-        with open(source_file) as fp:
+        with open(source_file, 'rb') as fp:
             lines = fp.readlines()
-        with open(dest_file, 'w') as fp:
-            fp.writelines(lines[:lines.index("#--start keywords--\n") + 1])
-            fp.writelines(lines[lines.index("#--end keywords--\n"):])
+        nl = lines[0][len(lines[0].strip()):]
+        with open(dest_file, 'wb') as fp:
+            fp.writelines(lines[:lines.index(b"#--start keywords--" + nl) + 1])
+            fp.writelines(lines[lines.index(b"#--end keywords--" + nl):])
 
     def _generate_keywords(self, grammar_file, target_keyword_py_file):
         proc = subprocess.Popen([sys.executable,
@@ -56,15 +58,15 @@
                      'test only works from source build directory')
     def test_real_grammar_and_keyword_file(self):
         self._copy_file_without_generated_keywords(KEYWORD_FILE, TEST_PY_FILE)
-        self.addCleanup(lambda: support.unlink(TEST_PY_FILE))
+        self.addCleanup(support.unlink, TEST_PY_FILE)
         self.assertFalse(filecmp.cmp(KEYWORD_FILE, TEST_PY_FILE))
-        self.assertEqual(0, self._generate_keywords(GRAMMAR_FILE,
-                                                    TEST_PY_FILE)[0])
+        self.assertEqual((0, b''), self._generate_keywords(GRAMMAR_FILE,
+                                                           TEST_PY_FILE))
         self.assertTrue(filecmp.cmp(KEYWORD_FILE, TEST_PY_FILE))
 
     def test_grammar(self):
         self._copy_file_without_generated_keywords(KEYWORD_FILE, TEST_PY_FILE)
-        self.addCleanup(lambda: support.unlink(TEST_PY_FILE))
+        self.addCleanup(support.unlink, TEST_PY_FILE)
         with open(GRAMMAR_TEST_FILE, 'w') as fp:
             # Some of these are probably implementation accidents.
             fp.writelines(textwrap.dedent("""\
@@ -86,40 +88,40 @@
                     {1, 'no good'}
                     {283, 0},
                     {1,  "too many spaces"}"""))
-        self.addCleanup(lambda: support.unlink(GRAMMAR_TEST_FILE))
+        self.addCleanup(support.unlink, GRAMMAR_TEST_FILE)
         self._generate_keywords(GRAMMAR_TEST_FILE, TEST_PY_FILE)
         expected = [
-            "        'This one is tab indented',\n",
-            "        'also legal',\n",
-            "        'continue',\n",
-            "        'crazy but legal',\n",
-            "        'jello',\n",
-            "        'lemon',\n",
-            "        'tomato',\n",
-            "        'turnip',\n",
-            "        'wigii',\n",
+            "        'This one is tab indented',",
+            "        'also legal',",
+            "        'continue',",
+            "        'crazy but legal',",
+            "        'jello',",
+            "        'lemon',",
+            "        'tomato',",
+            "        'turnip',",
+            "        'wigii',",
             ]
         with open(TEST_PY_FILE) as fp:
-            lines = fp.readlines()
-        start = lines.index("#--start keywords--\n") + 1
-        end = lines.index("#--end keywords--\n")
+            lines = fp.read().splitlines()
+        start = lines.index("#--start keywords--") + 1
+        end = lines.index("#--end keywords--")
         actual = lines[start:end]
         self.assertEqual(actual, expected)
 
     def test_empty_grammar_results_in_no_keywords(self):
         self._copy_file_without_generated_keywords(KEYWORD_FILE,
                                                    PY_FILE_WITHOUT_KEYWORDS)
-        self.addCleanup(lambda: support.unlink(PY_FILE_WITHOUT_KEYWORDS))
+        self.addCleanup(support.unlink, PY_FILE_WITHOUT_KEYWORDS)
         shutil.copyfile(KEYWORD_FILE, TEST_PY_FILE)
-        self.addCleanup(lambda: support.unlink(TEST_PY_FILE))
-        self.assertEqual(0, self._generate_keywords(os.devnull,
-                                                    TEST_PY_FILE)[0])
+        self.addCleanup(support.unlink, TEST_PY_FILE)
+        self.assertEqual((0, b''), self._generate_keywords(os.devnull,
+                                                           TEST_PY_FILE))
         self.assertTrue(filecmp.cmp(TEST_PY_FILE, PY_FILE_WITHOUT_KEYWORDS))
 
     def test_keywords_py_without_markers_produces_error(self):
         rc, stderr = self._generate_keywords(os.devnull, os.devnull)
         self.assertNotEqual(rc, 0)
-        self.assertEqual(stderr, b'target does not contain format markers\n')
+        self.assertRegex(stderr, b'does not contain format markers')
 
     def test_missing_grammar_file_produces_error(self):
         rc, stderr = self._generate_keywords(NONEXISTENT_FILE, KEYWORD_FILE)
diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py
--- a/Lib/test/test_urllib2.py
+++ b/Lib/test/test_urllib2.py
@@ -904,6 +904,30 @@
             p_ds_req = h.do_request_(ds_req)
             self.assertEqual(p_ds_req.unredirected_hdrs["Host"],"example.com")
 
+    def test_full_url_setter(self):
+        # Checks to ensure that components are set correctly after setting the
+        # full_url of a Request object
+
+        urls = [
+            'http://example.com?foo=bar#baz',
+            'http://example.com?foo=bar&spam=eggs#bash',
+            'http://example.com',
+        ]
+
+        # testing a reusable request instance, but the url parameter is
+        # required, so just use a dummy one to instantiate
+        r = Request('http://example.com')
+        for url in urls:
+            r.full_url = url
+            self.assertEqual(r.get_full_url(), url)
+
+    def test_full_url_deleter(self):
+        r = Request('http://www.example.com')
+        del r.full_url
+        self.assertIsNone(r.full_url)
+        self.assertIsNone(r.fragment)
+        self.assertEqual(r.selector, '')
+
     def test_fixpath_in_weirdurls(self):
         # Issue4493: urllib2 to supply '/' when to urls where path does not
         # start with'/'
diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py
--- a/Lib/urllib/request.py
+++ b/Lib/urllib/request.py
@@ -259,9 +259,7 @@
     def __init__(self, url, data=None, headers={},
                  origin_req_host=None, unverifiable=False,
                  method=None):
-        # unwrap('<URL:type://host/path>') --> 'type://host/path'
-        self.full_url = unwrap(url)
-        self.full_url, self.fragment = splittag(self.full_url)
+        self.full_url = url
         self.headers = {}
         self.unredirected_hdrs = {}
         self._data = None
@@ -274,8 +272,24 @@
         self.origin_req_host = origin_req_host
         self.unverifiable = unverifiable
         self.method = method
+
+    @property
+    def full_url(self):
+        return self._full_url
+
+    @full_url.setter
+    def full_url(self, url):
+        # unwrap('<URL:type://host/path>') --> 'type://host/path'
+        self._full_url = unwrap(url)
+        self._full_url, self.fragment = splittag(self._full_url)
         self._parse()
 
+    @full_url.deleter
+    def full_url(self):
+        self._full_url = None
+        self.fragment = None
+        self.selector = ''
+
     @property
     def data(self):
         return self._data
@@ -295,7 +309,7 @@
         self.data = None
 
     def _parse(self):
-        self.type, rest = splittype(self.full_url)
+        self.type, rest = splittype(self._full_url)
         if self.type is None:
             raise ValueError("unknown url type: %r" % self.full_url)
         self.host, self.selector = splithost(rest)
@@ -313,9 +327,8 @@
 
     def get_full_url(self):
         if self.fragment:
-            return '%s#%s' % (self.full_url, self.fragment)
-        else:
-            return self.full_url
+            return '{}#{}'.format(self.full_url, self.fragment)
+        return self.full_url
 
     def set_proxy(self, host, type):
         if self.type == 'https' and not self._tunnel_host:
diff --git a/Misc/ACKS b/Misc/ACKS
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -153,6 +153,7 @@
 Sven Brauch
 Erik Bray
 Brian Brazil
+Demian Brecht
 Dave Brennan
 Tom Bridgman
 Anthony Briggs
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -49,6 +49,12 @@
 Library
 -------
 
+- Issue #17830: When keyword.py is used to update a keyword file, it now
+  preserves the line endings of the original file.
+
+- Issue #17272: Making the urllib.request's Request.full_url a descriptor.
+  Fixes bugs with assignment to full_url. Patch by Demian Brecht.
+
 - Issue #17353: Plistlib emitted empty data tags with deeply nested datastructures
 
 - Issue #11714: Use 'with' statements to assure a Semaphore releases a

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list