Repository: bear/python-twitter

Issue:
calc_expected_status_length does not work
calc_expected_status_length is broken in two ways right now. 

1. URL_REGEXP only recognizes URLs at the start of a string, which is correct for is_url, but for calc_expected_status_length, all URLs should be detected, not just URLs at the start of the tweet. There should be a different URL_REGEXP for calc_expected_status_length without the start-of-string makers.
2. The URL regex has multiple groups, so findall returns a list of tuples, not strings. If there are matches, replaced_chars = len(''.join(match)) crashes, it should be replaced_chars = len(''.join(map(lambda x: x[0], match))) instead

Discussion:

Patch:
diff --git a/twitter/__init__.py b/twitter/__init__.py
index 87bb718..0534776 100644
--- a/twitter/__init__.py
+++ b/twitter/__init__.py
@@ -23,7 +23,7 @@ __author__       = 'The Python-Twitter Developers'
 __email__        = 'python-twitter@googlegroups.com'
 __copyright__    = 'Copyright (c) 2007-2016 The Python-Twitter Developers'
 __license__      = 'Apache License 2.0'
-__version__      = '3.2'
+__version__      = '3.2.1'
 __url__          = 'https://github.com/bear/python-twitter'
 __download_url__ = 'https://pypi.python.org/pypi/python-twitter'
 __description__  = 'A Python wrapper around the Twitter API'
diff --git a/twitter/twitter_utils.py b/twitter/twitter_utils.py
index 081d1ed..0b2af5b 100644
--- a/twitter/twitter_utils.py
+++ b/twitter/twitter_utils.py
@@ -161,12 +161,13 @@ def calc_expected_status_length(status, short_url_length=23):
         Expected length of the status message as an integer.
 
     """
-    replaced_chars = 0
-    status_length = len(status)
-    match = re.findall(URL_REGEXP, status)
-    if len(match) >= 1:
-        replaced_chars = len(''.join(match))
-    status_length = status_length - replaced_chars + (short_url_length * len(match))
+    status_length = 0
+    for word in re.split(r'\s', status):
+        if is_url(word):
+            status_length += short_url_length
+        else:
+            status_length += len(word)
+    status_length += len(re.findall(r'\s', status))
     return status_length
 
 


Test patch:
diff --git a/tests/test_twitter_utils.py b/tests/test_twitter_utils.py
index 3ca619f..b021e34 100644
--- a/tests/test_twitter_utils.py
+++ b/tests/test_twitter_utils.py
@@ -5,6 +5,7 @@ import unittest
 import twitter
 
 from twitter.twitter_utils import (
+    calc_expected_status_length,
     parse_media_file
 )
 
@@ -58,3 +59,18 @@ class ApiTest(unittest.TestCase):
         self.assertRaises(
             twitter.TwitterError,
             lambda: twitter.twitter_utils.enf_type('test', int, 'hi'))
+
+    def test_calc_expected_status_length(self):
+        status = 'hi a tweet there'
+        len_status = calc_expected_status_length(status)
+        self.assertEqual(len_status, 16)
+
+    def test_calc_expected_status_length_with_url(self):
+        status = 'hi a tweet there example.com'
+        len_status = calc_expected_status_length(status)
+        self.assertEqual(len_status, 40)
+
+    def test_calc_expected_status_length_with_url_and_extra_spaces(self):
+        status = 'hi a tweet          there               example.com'
+        len_status = calc_expected_status_length(status)
+        self.assertEqual(len_status, 63)