/atom/url.py
Python | 139 lines | 102 code | 10 blank | 27 comment | 10 complexity | 8da1a83bd79ea061a97deba4de4afa3d MD5 | raw file
1#!/usr/bin/python 2# 3# Copyright (C) 2008 Google Inc. 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17 18__author__ = 'api.jscudder (Jeff Scudder)' 19 20 21import urlparse 22import urllib 23 24 25DEFAULT_PROTOCOL = 'http' 26DEFAULT_PORT = 80 27 28 29def parse_url(url_string): 30 """Creates a Url object which corresponds to the URL string. 31 32 This method can accept partial URLs, but it will leave missing 33 members of the Url unset. 34 """ 35 parts = urlparse.urlparse(url_string) 36 url = Url() 37 if parts[0]: 38 url.protocol = parts[0] 39 if parts[1]: 40 host_parts = parts[1].split(':') 41 if host_parts[0]: 42 url.host = host_parts[0] 43 if len(host_parts) > 1: 44 url.port = host_parts[1] 45 if parts[2]: 46 url.path = parts[2] 47 if parts[4]: 48 param_pairs = parts[4].split('&') 49 for pair in param_pairs: 50 pair_parts = pair.split('=') 51 if len(pair_parts) > 1: 52 url.params[urllib.unquote_plus(pair_parts[0])] = ( 53 urllib.unquote_plus(pair_parts[1])) 54 elif len(pair_parts) == 1: 55 url.params[urllib.unquote_plus(pair_parts[0])] = None 56 return url 57 58class Url(object): 59 """Represents a URL and implements comparison logic. 60 61 URL strings which are not identical can still be equivalent, so this object 62 provides a better interface for comparing and manipulating URLs than 63 strings. URL parameters are represented as a dictionary of strings, and 64 defaults are used for the protocol (http) and port (80) if not provided. 65 """ 66 def __init__(self, protocol=None, host=None, port=None, path=None, 67 params=None): 68 self.protocol = protocol 69 self.host = host 70 self.port = port 71 self.path = path 72 self.params = params or {} 73 74 def to_string(self): 75 url_parts = ['', '', '', '', '', ''] 76 if self.protocol: 77 url_parts[0] = self.protocol 78 if self.host: 79 if self.port: 80 url_parts[1] = ':'.join((self.host, str(self.port))) 81 else: 82 url_parts[1] = self.host 83 if self.path: 84 url_parts[2] = self.path 85 if self.params: 86 url_parts[4] = self.get_param_string() 87 return urlparse.urlunparse(url_parts) 88 89 def get_param_string(self): 90 param_pairs = [] 91 for key, value in self.params.iteritems(): 92 param_pairs.append('='.join((urllib.quote_plus(key), 93 urllib.quote_plus(str(value))))) 94 return '&'.join(param_pairs) 95 96 def get_request_uri(self): 97 """Returns the path with the parameters escaped and appended.""" 98 param_string = self.get_param_string() 99 if param_string: 100 return '?'.join([self.path, param_string]) 101 else: 102 return self.path 103 104 def __cmp__(self, other): 105 if not isinstance(other, Url): 106 return cmp(self.to_string(), str(other)) 107 difference = 0 108 # Compare the protocol 109 if self.protocol and other.protocol: 110 difference = cmp(self.protocol, other.protocol) 111 elif self.protocol and not other.protocol: 112 difference = cmp(self.protocol, DEFAULT_PROTOCOL) 113 elif not self.protocol and other.protocol: 114 difference = cmp(DEFAULT_PROTOCOL, other.protocol) 115 if difference != 0: 116 return difference 117 # Compare the host 118 difference = cmp(self.host, other.host) 119 if difference != 0: 120 return difference 121 # Compare the port 122 if self.port and other.port: 123 difference = cmp(self.port, other.port) 124 elif self.port and not other.port: 125 difference = cmp(self.port, DEFAULT_PORT) 126 elif not self.port and other.port: 127 difference = cmp(DEFAULT_PORT, other.port) 128 if difference != 0: 129 return difference 130 # Compare the path 131 difference = cmp(self.path, other.path) 132 if difference != 0: 133 return difference 134 # Compare the parameters 135 return cmp(self.params, other.params) 136 137 def __str__(self): 138 return self.to_string() 139