Use email.utils.formataddr/parseaddr to generate/parse user IDs
authorW. Trevor King <wking@drexel.edu>
Sun, 7 Feb 2010 18:37:37 +0000 (13:37 -0500)
committerW. Trevor King <wking@drexel.edu>
Sun, 7 Feb 2010 18:37:37 +0000 (13:37 -0500)
libbe/ui/util/user.py

index 98f16a6d66da8a24c69d4443687054415d3d84f5..460a1dd19a8b67b47def08dd35383c1bf007445c 100644 (file)
 # with this program; if not, write to the Free Software Foundation, Inc.,
 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
-"""
-Tools for getting, setting, creating, and parsing the user's id.  For
-example,
-  'John Doe <jdoe@example.com>'
-Note that the Arch VCS backend *enforces* ids with this format.
+"""Tools for getting, setting, creating, and parsing the user's ID.
+
+IDs will look like 'John Doe <jdoe@example.com>'.  Note that the
+:mod:`libbe.storage.vcs.arch <Arch VCS backend>` *enforces* IDs with
+this format.
+
+Do not confuse the user IDs discussed in this module, which refer to
+humans, with the "user IDs" discussed in :mod:`libbe.util.id`, which
+are human-readable tags refering to objects.
 """
 
+try:
+    from email.utils import formataddr, parseaddr
+except ImportErrror: # adjust to old python < 2.5
+    from email.Utils import formataddr, parseaddr
 import os
 import re
 from socket import gethostname
@@ -29,6 +37,8 @@ import libbe
 import libbe.storage.util.config
 
 def get_fallback_username():
+    """Return a username extracted from environmental variables.
+    """
     name = None
     for env in ["LOGNAME", "USERNAME"]:
         if os.environ.has_key(env):
@@ -38,52 +48,69 @@ def get_fallback_username():
     return name
 
 def get_fallback_email():
+    """Return an email address extracted from environmental variables.
+    """
     hostname = gethostname()
     name = get_fallback_username()
     return "%s@%s" % (name, hostname)
 
 def create_user_id(name, email=None):
-    """
+    """Create a user ID string from given `name` and `email` strings.
+
+    Examples
+    --------
+
     >>> create_user_id("John Doe", "jdoe@example.com")
     'John Doe <jdoe@example.com>'
     >>> create_user_id("John Doe")
     'John Doe'
+
+    See Also
+    --------
+    parse_user_id : inverse
     """
     assert len(name) > 0
     if email == None or len(email) == 0:
         return name
     else:
-        return "%s <%s>" % (name, email)
+        return formataddr((name, email))
 
 def parse_user_id(value):
-    """
+    """Parse a user ID string into `name` and `email` strings.
+
+    Examples
+    --------
+
     >>> parse_user_id("John Doe <jdoe@example.com>")
     ('John Doe', 'jdoe@example.com')
     >>> parse_user_id("John Doe")
     ('John Doe', None)
-    >>> try:
-    ...     parse_user_id("John Doe <jdoe@example.com><what?>")
-    ... except AssertionError:
-    ...     print "Invalid match"
-    Invalid match
+    >>> parse_user_id("John Doe <jdoe@example.com><what?>")
+    ('John Doe', 'jdoe@example.com')
+    See Also
+    --------
+    create_user_id : inverse
     """
-    emailexp = re.compile("(.*) <([^>]*)>(.*)")
-    match = emailexp.search(value)
-    if match == None:
-        email = None
-        name = value
-    else:
-        assert len(match.groups()) == 3
-        assert match.groups()[2] == "", match.groups()
-        email = match.groups()[1]
-        name = match.groups()[0]
-    assert name != None
-    assert len(name) > 0
-    return (name, email)
+    if '<' not in value:
+        return (value, None)
+    return parseaddr(value)
 
 def get_user_id(storage=None):
-    """
-    Sometimes the storage will also keep track of the user id (e.g. most VCSs).
+    """Return a user ID, checking a list of possible sources.
+
+    The source order is:
+
+    1. Global BE configuration.
+    2. `storage.get_user_id`, if that function is defined.
+    3. :func:`get_fallback_username` and :func:`get_fallback_email`.
+
+    Notes
+    -----
+    Sometimes the storage will keep track of the user ID (e.g. most
+    VCSs, see :meth:`libbe.storage.vcs.base.VCS.get_user_id`).  If so,
+    we prefer that ID to the fallback, since the user has likely
+    configured it directly.
     """
     user = libbe.storage.util.config.get_val('user')
     if user != None:
@@ -98,6 +125,10 @@ def get_user_id(storage=None):
     return user
 
 def set_user_id(user_id):
-    """
+    """Set the user ID in a user's BE configuration.
+
+    See Also
+    --------
+    libbe.storage.util.config.set_val
     """
     user = libbe.storage.util.config.set_val('user', user_id)