codekingpro/portable-devtools
114k
1# -*- coding: utf-8 -*-2import collections3import platform4import sys5 6 7def user_agent(name, version, extras=None):8 """Return an internet-friendly user_agent string.9 10 The majority of this code has been wilfully stolen from the equivalent11 function in Requests.12 13 :param name: The intended name of the user-agent, e.g. "python-requests".14 :param version: The version of the user-agent, e.g. "0.0.1".15 :param extras: List of two-item tuples that are added to the user-agent16 string.17 :returns: Formatted user-agent string18 :rtype: str19 """20 if extras is None:21 extras = []22 23 return UserAgentBuilder(24 name, version25 ).include_extras(26 extras27 ).include_implementation(28 ).include_system().build()29 30 31class UserAgentBuilder(object):32 """Class to provide a greater level of control than :func:`user_agent`.33 34 This is used by :func:`user_agent` to build its User-Agent string.35 36 .. code-block:: python37 38 user_agent_str = UserAgentBuilder(39 name='requests-toolbelt',40 version='17.4.0',41 ).include_implementation(42 ).include_system(43 ).include_extras([44 ('requests', '2.14.2'),45 ('urllib3', '1.21.2'),46 ]).build()47 48 """49 50 format_string = '%s/%s'51 52 def __init__(self, name, version):53 """Initialize our builder with the name and version of our user agent.54 55 :param str name:56 Name of our user-agent.57 :param str version:58 The version string for user-agent.59 """60 self._pieces = collections.deque([(name, version)])61 62 def build(self):63 """Finalize the User-Agent string.64 65 :returns:66 Formatted User-Agent string.67 :rtype:68 str69 """70 return " ".join([self.format_string % piece for piece in self._pieces])71 72 def include_extras(self, extras):73 """Include extra portions of the User-Agent.74 75 :param list extras:76 list of tuples of extra-name and extra-version77 """78 if any(len(extra) != 2 for extra in extras):79 raise ValueError('Extras should be a sequence of two item tuples.')80 81 self._pieces.extend(extras)82 return self83 84 def include_implementation(self):85 """Append the implementation string to the user-agent string.86 87 This adds the the information that you're using CPython 2.7.13 to the88 User-Agent.89 """90 self._pieces.append(_implementation_tuple())91 return self92 93 def include_system(self):94 """Append the information about the Operating System."""95 self._pieces.append(_platform_tuple())96 return self97 98 99def _implementation_tuple():100 """Return the tuple of interpreter name and version.101 102 Returns a string that provides both the name and the version of the Python103 implementation currently running. For example, on CPython 2.7.5 it will104 return "CPython/2.7.5".105 106 This function works best on CPython and PyPy: in particular, it probably107 doesn't work for Jython or IronPython. Future investigation should be done108 to work out the correct shape of the code for those platforms.109 """110 implementation = platform.python_implementation()111 112 if implementation == 'CPython':113 implementation_version = platform.python_version()114 elif implementation == 'PyPy':115 implementation_version = '%s.%s.%s' % (sys.pypy_version_info.major,116 sys.pypy_version_info.minor,117 sys.pypy_version_info.micro)118 if sys.pypy_version_info.releaselevel != 'final':119 implementation_version = ''.join([120 implementation_version, sys.pypy_version_info.releaselevel121 ])122 elif implementation == 'Jython':123 implementation_version = platform.python_version() # Complete Guess124 elif implementation == 'IronPython':125 implementation_version = platform.python_version() # Complete Guess126 else:127 implementation_version = 'Unknown'128 129 return (implementation, implementation_version)130 131 132def _implementation_string():133 return "%s/%s" % _implementation_tuple()134 135 136def _platform_tuple():137 try:138 p_system = platform.system()139 p_release = platform.release()140 except IOError:141 p_system = 'Unknown'142 p_release = 'Unknown'143 return (p_system, p_release)144 