Skip to content

Commit

Permalink
[soc2009/http-wsgi-improvements] Merged up to 11009 from trunk.
Browse files Browse the repository at this point in the history
  • Loading branch information
ccahoon committed Jun 16, 2009
1 parent 3d4f9ec commit c435676
Show file tree
Hide file tree
Showing 17 changed files with 303 additions and 115 deletions.
2 changes: 1 addition & 1 deletion django/contrib/contenttypes/generic.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ def get_default_prefix(cls):
def get_queryset(self): def get_queryset(self):
# Avoid a circular import. # Avoid a circular import.
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
if self.instance is None: if self.instance is None or self.instance.pk is None:
return self.model._default_manager.none() return self.model._default_manager.none()
return self.model._default_manager.filter(**{ return self.model._default_manager.filter(**{
self.ct_field.name: ContentType.objects.get_for_model(self.instance), self.ct_field.name: ContentType.objects.get_for_model(self.instance),
Expand Down
2 changes: 1 addition & 1 deletion django/contrib/gis/gdal/libgdal.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
lib_names = None lib_names = None
elif os.name == 'nt': elif os.name == 'nt':
# Windows NT shared library # Windows NT shared library
lib_names = ['gdal15'] lib_names = ['gdal16', 'gdal15']
elif os.name == 'posix': elif os.name == 'posix':
# *NIX library names. # *NIX library names.
lib_names = ['gdal', 'GDAL', 'gdal1.6.0', 'gdal1.5.0', 'gdal1.4.0'] lib_names = ['gdal', 'GDAL', 'gdal1.6.0', 'gdal1.5.0', 'gdal1.4.0']
Expand Down
7 changes: 3 additions & 4 deletions django/contrib/gis/tests/test_geoip.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -84,16 +84,15 @@ def test04_city(self):
self.assertEqual('USA', d['country_code3']) self.assertEqual('USA', d['country_code3'])
self.assertEqual('Houston', d['city']) self.assertEqual('Houston', d['city'])
self.assertEqual('TX', d['region']) self.assertEqual('TX', d['region'])
self.assertEqual('77002', d['postal_code'])
self.assertEqual(713, d['area_code']) self.assertEqual(713, d['area_code'])
geom = g.geos(query) geom = g.geos(query)
self.failIf(not isinstance(geom, GEOSGeometry)) self.failIf(not isinstance(geom, GEOSGeometry))
lon, lat = (-95.366996765, 29.752300262) lon, lat = (-95.4152, 29.7755)
lat_lon = g.lat_lon(query) lat_lon = g.lat_lon(query)
lat_lon = (lat_lon[1], lat_lon[0]) lat_lon = (lat_lon[1], lat_lon[0])
for tup in (geom.tuple, g.coords(query), g.lon_lat(query), lat_lon): for tup in (geom.tuple, g.coords(query), g.lon_lat(query), lat_lon):
self.assertAlmostEqual(lon, tup[0], 9) self.assertAlmostEqual(lon, tup[0], 4)
self.assertAlmostEqual(lat, tup[1], 9) self.assertAlmostEqual(lat, tup[1], 4)


def suite(): def suite():
s = unittest.TestSuite() s = unittest.TestSuite()
Expand Down
87 changes: 52 additions & 35 deletions django/contrib/gis/utils/geoip.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
GeoIP(R) is a registered trademark of MaxMind, LLC of Boston, Massachusetts. GeoIP(R) is a registered trademark of MaxMind, LLC of Boston, Massachusetts.
For IP-based geolocation, this module requires the GeoLite Country and City For IP-based geolocation, this module requires the GeoLite Country and City
datasets, in binary format (CSV will not work!). The datasets may be datasets, in binary format (CSV will not work!). The datasets may be
downloaded from MaxMind at http://www.maxmind.com/download/geoip/database/. downloaded from MaxMind at http://www.maxmind.com/download/geoip/database/.
Grab GeoIP.dat.gz and GeoLiteCity.dat.gz, and unzip them in the directory Grab GeoIP.dat.gz and GeoLiteCity.dat.gz, and unzip them in the directory
corresponding to settings.GEOIP_PATH. See the GeoIP docstring and examples corresponding to settings.GEOIP_PATH. See the GeoIP docstring and examples
Expand Down Expand Up @@ -34,7 +34,7 @@
>>> g.lat_lon('salon.com') >>> g.lat_lon('salon.com')
(37.789798736572266, -122.39420318603516) (37.789798736572266, -122.39420318603516)
>>> g.lon_lat('uh.edu') >>> g.lon_lat('uh.edu')
(-95.415199279785156, 29.77549934387207) (-95.415199279785156, 29.77549934387207)
>>> g.geos('24.124.1.80').wkt >>> g.geos('24.124.1.80').wkt
'POINT (-95.2087020874023438 39.0392990112304688)' 'POINT (-95.2087020874023438 39.0392990112304688)'
""" """
Expand All @@ -45,7 +45,7 @@
if not settings.configured: settings.configure() if not settings.configured: settings.configure()


# Creating the settings dictionary with any settings, if needed. # Creating the settings dictionary with any settings, if needed.
GEOIP_SETTINGS = dict((key, getattr(settings, key)) GEOIP_SETTINGS = dict((key, getattr(settings, key))
for key in ('GEOIP_PATH', 'GEOIP_LIBRARY_PATH', 'GEOIP_COUNTRY', 'GEOIP_CITY') for key in ('GEOIP_PATH', 'GEOIP_LIBRARY_PATH', 'GEOIP_COUNTRY', 'GEOIP_CITY')
if hasattr(settings, key)) if hasattr(settings, key))
lib_path = GEOIP_SETTINGS.get('GEOIP_LIBRARY_PATH', None) lib_path = GEOIP_SETTINGS.get('GEOIP_LIBRARY_PATH', None)
Expand Down Expand Up @@ -83,8 +83,17 @@ class GeoIPRecord(Structure):
('postal_code', c_char_p), ('postal_code', c_char_p),
('latitude', c_float), ('latitude', c_float),
('longitude', c_float), ('longitude', c_float),
# TODO: In 1.4.6 this changed from `int dma_code;` to
# `union {int metro_code; int dma_code;};`. Change
# to a `ctypes.Union` in to accomodate in future when
# pre-1.4.6 versions are no longer distributed.
('dma_code', c_int), ('dma_code', c_int),
('area_code', c_int), ('area_code', c_int),
# TODO: The following structure fields were added in 1.4.3 --
# uncomment these fields when sure previous versions are no
# longer distributed by package maintainers.
#('charset', c_int),
#('continent_code', c_char_p),
] ]
class GeoIPTag(Structure): pass class GeoIPTag(Structure): pass


Expand All @@ -99,9 +108,12 @@ def record_output(func):
rec_by_addr = record_output(lgeoip.GeoIP_record_by_addr) rec_by_addr = record_output(lgeoip.GeoIP_record_by_addr)
rec_by_name = record_output(lgeoip.GeoIP_record_by_name) rec_by_name = record_output(lgeoip.GeoIP_record_by_name)


# For opening up GeoIP databases. # For opening & closing GeoIP database files.
geoip_open = lgeoip.GeoIP_open geoip_open = lgeoip.GeoIP_open
geoip_open.restype = DBTYPE geoip_open.restype = DBTYPE
geoip_close = lgeoip.GeoIP_delete
geoip_close.argtypes = [DBTYPE]
geoip_close.restype = None


# String output routines. # String output routines.
def string_output(func): def string_output(func):
Expand Down Expand Up @@ -136,6 +148,12 @@ class GeoIP(object):
GEOIP_CHECK_CACHE = 2 GEOIP_CHECK_CACHE = 2
GEOIP_INDEX_CACHE = 4 GEOIP_INDEX_CACHE = 4
cache_options = dict((opt, None) for opt in (0, 1, 2, 4)) cache_options = dict((opt, None) for opt in (0, 1, 2, 4))
_city_file = ''
_country_file = ''

# Initially, pointers to GeoIP file references are NULL.
_city = None
_country = None


def __init__(self, path=None, cache=0, country=None, city=None): def __init__(self, path=None, cache=0, country=None, city=None):
""" """
Expand Down Expand Up @@ -174,43 +192,42 @@ def __init__(self, path=None, cache=0, country=None, city=None):
if not isinstance(path, basestring): if not isinstance(path, basestring):
raise TypeError('Invalid path type: %s' % type(path).__name__) raise TypeError('Invalid path type: %s' % type(path).__name__)


cntry_ptr, city_ptr = (None, None)
if os.path.isdir(path): if os.path.isdir(path):
# Getting the country and city files using the settings # Constructing the GeoIP database filenames using the settings
# dictionary. If no settings are provided, default names # dictionary. If the database files for the GeoLite country
# are assigned. # and/or city datasets exist, then try and open them.
country = os.path.join(path, country or GEOIP_SETTINGS.get('GEOIP_COUNTRY', 'GeoIP.dat')) country_db = os.path.join(path, country or GEOIP_SETTINGS.get('GEOIP_COUNTRY', 'GeoIP.dat'))
city = os.path.join(path, city or GEOIP_SETTINGS.get('GEOIP_CITY', 'GeoLiteCity.dat')) if os.path.isfile(country_db):
self._country = geoip_open(country_db, cache)
self._country_file = country_db

city_db = os.path.join(path, city or GEOIP_SETTINGS.get('GEOIP_CITY', 'GeoLiteCity.dat'))
if os.path.isfile(city_db):
self._city = geoip_open(city_db, cache)
self._city_file = city_db
elif os.path.isfile(path): elif os.path.isfile(path):
# Otherwise, some detective work will be needed to figure # Otherwise, some detective work will be needed to figure
# out whether the given database path is for the GeoIP country # out whether the given database path is for the GeoIP country
# or city databases. # or city databases.
ptr = geoip_open(path, cache) ptr = geoip_open(path, cache)
info = geoip_dbinfo(ptr) info = geoip_dbinfo(ptr)
if lite_regex.match(info): if lite_regex.match(info):
# GeoLite City database. # GeoLite City database detected.
city, city_ptr = path, ptr self._city = ptr
self._city_file = path
elif free_regex.match(info): elif free_regex.match(info):
# GeoIP Country database. # GeoIP Country database detected.
country, cntry_ptr = path, ptr self._country = ptr
self._country_file = path
else: else:
raise GeoIPException('Unable to recognize database edition: %s' % info) raise GeoIPException('Unable to recognize database edition: %s' % info)
else: else:
raise GeoIPException('GeoIP path must be a valid file or directory.') raise GeoIPException('GeoIP path must be a valid file or directory.')


# `_init_db` does the dirty work. def __del__(self):
self._init_db(country, cache, '_country', cntry_ptr) # Cleaning any GeoIP file handles lying around.
self._init_db(city, cache, '_city', city_ptr) if self._country: geoip_close(self._country)

if self._city: geoip_close(self._city)
def _init_db(self, db_file, cache, attname, ptr=None):
"Helper routine for setting GeoIP ctypes database properties."
if ptr:
# Pointer already retrieved.
pass
elif os.path.isfile(db_file or ''):
ptr = geoip_open(db_file, cache)
setattr(self, attname, ptr)
setattr(self, '%s_file' % attname, db_file)


def _check_query(self, query, country=False, city=False, city_or_country=False): def _check_query(self, query, country=False, city=False, city_or_country=False):
"Helper routine for checking the query and database availability." "Helper routine for checking the query and database availability."
Expand All @@ -219,11 +236,11 @@ def _check_query(self, query, country=False, city=False, city_or_country=False):
raise TypeError('GeoIP query must be a string, not type %s' % type(query).__name__) raise TypeError('GeoIP query must be a string, not type %s' % type(query).__name__)


# Extra checks for the existence of country and city databases. # Extra checks for the existence of country and city databases.
if city_or_country and self._country is None and self._city is None: if city_or_country and not (self._country or self._city):
raise GeoIPException('Invalid GeoIP country and city data files.') raise GeoIPException('Invalid GeoIP country and city data files.')
elif country and self._country is None: elif country and not self._country:
raise GeoIPException('Invalid GeoIP country data file: %s' % self._country_file) raise GeoIPException('Invalid GeoIP country data file: %s' % self._country_file)
elif city and self._city is None: elif city and not self._city:
raise GeoIPException('Invalid GeoIP city data file: %s' % self._city_file) raise GeoIPException('Invalid GeoIP city data file: %s' % self._city_file)


def city(self, query): def city(self, query):
Expand All @@ -247,7 +264,7 @@ def city(self, query):
return dict((tup[0], getattr(record, tup[0])) for tup in record._fields_) return dict((tup[0], getattr(record, tup[0])) for tup in record._fields_)
else: else:
return None return None

def country_code(self, query): def country_code(self, query):
"Returns the country code for the given IP Address or FQDN." "Returns the country code for the given IP Address or FQDN."
self._check_query(query, city_or_country=True) self._check_query(query, city_or_country=True)
Expand All @@ -268,12 +285,12 @@ def country_name(self, query):


def country(self, query): def country(self, query):
""" """
Returns a dictonary with with the country code and name when given an Returns a dictonary with with the country code and name when given an
IP address or a Fully Qualified Domain Name (FQDN). For example, both IP address or a Fully Qualified Domain Name (FQDN). For example, both
'24.124.1.80' and 'djangoproject.com' are valid parameters. '24.124.1.80' and 'djangoproject.com' are valid parameters.
""" """
# Returning the country code and name # Returning the country code and name
return {'country_code' : self.country_code(query), return {'country_code' : self.country_code(query),
'country_name' : self.country_name(query), 'country_name' : self.country_name(query),
} }


Expand Down Expand Up @@ -318,7 +335,7 @@ def city_info(self):
ci = geoip_dbinfo(self._city) ci = geoip_dbinfo(self._city)
return ci return ci
city_info = property(city_info) city_info = property(city_info)

def info(self): def info(self):
"Returns information about all GeoIP databases in use." "Returns information about all GeoIP databases in use."
return 'Country:\n\t%s\nCity:\n\t%s' % (self.country_info, self.city_info) return 'Country:\n\t%s\nCity:\n\t%s' % (self.country_info, self.city_info)
Expand Down
87 changes: 64 additions & 23 deletions django/core/mail.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ class EmailMessage(object):
A container for email information. A container for email information.
""" """
content_subtype = 'plain' content_subtype = 'plain'
multipart_subtype = 'mixed' mixed_subtype = 'mixed'
encoding = None # None => use settings default encoding = None # None => use settings default


def __init__(self, subject='', body='', from_email=None, to=None, bcc=None, def __init__(self, subject='', body='', from_email=None, to=None, bcc=None,
Expand Down Expand Up @@ -234,16 +234,7 @@ def message(self):
encoding = self.encoding or settings.DEFAULT_CHARSET encoding = self.encoding or settings.DEFAULT_CHARSET
msg = SafeMIMEText(smart_str(self.body, settings.DEFAULT_CHARSET), msg = SafeMIMEText(smart_str(self.body, settings.DEFAULT_CHARSET),
self.content_subtype, encoding) self.content_subtype, encoding)
if self.attachments: msg = self._create_message(msg)
body_msg = msg
msg = SafeMIMEMultipart(_subtype=self.multipart_subtype)
if self.body:
msg.attach(body_msg)
for attachment in self.attachments:
if isinstance(attachment, MIMEBase):
msg.attach(attachment)
else:
msg.attach(self._create_attachment(*attachment))
msg['Subject'] = self.subject msg['Subject'] = self.subject
msg['From'] = self.extra_headers.pop('From', self.from_email) msg['From'] = self.extra_headers.pop('From', self.from_email)
msg['To'] = ', '.join(self.to) msg['To'] = ', '.join(self.to)
Expand Down Expand Up @@ -277,8 +268,7 @@ def send(self, fail_silently=False):
def attach(self, filename=None, content=None, mimetype=None): def attach(self, filename=None, content=None, mimetype=None):
""" """
Attaches a file with the given filename and content. The filename can Attaches a file with the given filename and content. The filename can
be omitted (useful for multipart/alternative messages) and the mimetype be omitted and the mimetype is guessed, if not provided.
is guessed, if not provided.
If the first parameter is a MIMEBase subclass it is inserted directly If the first parameter is a MIMEBase subclass it is inserted directly
into the resulting message attachments. into the resulting message attachments.
Expand All @@ -296,15 +286,26 @@ def attach_file(self, path, mimetype=None):
content = open(path, 'rb').read() content = open(path, 'rb').read()
self.attach(filename, content, mimetype) self.attach(filename, content, mimetype)


def _create_attachment(self, filename, content, mimetype=None): def _create_message(self, msg):
return self._create_attachments(msg)

def _create_attachments(self, msg):
if self.attachments:
body_msg = msg
msg = SafeMIMEMultipart(_subtype=self.mixed_subtype)
if self.body:
msg.attach(body_msg)
for attachment in self.attachments:
if isinstance(attachment, MIMEBase):
msg.attach(attachment)
else:
msg.attach(self._create_attachment(*attachment))
return msg

def _create_mime_attachment(self, content, mimetype):
""" """
Converts the filename, content, mimetype triple into a MIME attachment Converts the content, mimetype pair into a MIME attachment object.
object.
""" """
if mimetype is None:
mimetype, _ = mimetypes.guess_type(filename)
if mimetype is None:
mimetype = DEFAULT_ATTACHMENT_MIME_TYPE
basetype, subtype = mimetype.split('/', 1) basetype, subtype = mimetype.split('/', 1)
if basetype == 'text': if basetype == 'text':
attachment = SafeMIMEText(smart_str(content, attachment = SafeMIMEText(smart_str(content,
Expand All @@ -314,6 +315,18 @@ def _create_attachment(self, filename, content, mimetype=None):
attachment = MIMEBase(basetype, subtype) attachment = MIMEBase(basetype, subtype)
attachment.set_payload(content) attachment.set_payload(content)
Encoders.encode_base64(attachment) Encoders.encode_base64(attachment)
return attachment

def _create_attachment(self, filename, content, mimetype=None):
"""
Converts the filename, content, mimetype triple into a MIME attachment
object.
"""
if mimetype is None:
mimetype, _ = mimetypes.guess_type(filename)
if mimetype is None:
mimetype = DEFAULT_ATTACHMENT_MIME_TYPE
attachment = self._create_mime_attachment(content, mimetype)
if filename: if filename:
attachment.add_header('Content-Disposition', 'attachment', attachment.add_header('Content-Disposition', 'attachment',
filename=filename) filename=filename)
Expand All @@ -325,11 +338,39 @@ class EmailMultiAlternatives(EmailMessage):
messages. For example, including text and HTML versions of the text is messages. For example, including text and HTML versions of the text is
made easier. made easier.
""" """
multipart_subtype = 'alternative' alternative_subtype = 'alternative'


def attach_alternative(self, content, mimetype=None): def __init__(self, subject='', body='', from_email=None, to=None, bcc=None,
connection=None, attachments=None, headers=None, alternatives=None):
"""
Initialize a single email message (which can be sent to multiple
recipients).
All strings used to create the message can be unicode strings (or UTF-8
bytestrings). The SafeMIMEText class will handle any necessary encoding
conversions.
"""
super(EmailMultiAlternatives, self).__init__(subject, body, from_email, to, bcc, connection, attachments, headers)
self.alternatives=alternatives or []

def attach_alternative(self, content, mimetype):
"""Attach an alternative content representation.""" """Attach an alternative content representation."""
self.attach(content=content, mimetype=mimetype) assert content is not None
assert mimetype is not None
self.alternatives.append((content, mimetype))

def _create_message(self, msg):
return self._create_attachments(self._create_alternatives(msg))

def _create_alternatives(self, msg):
if self.alternatives:
body_msg = msg
msg = SafeMIMEMultipart(_subtype=self.alternative_subtype)
if self.body:
msg.attach(body_msg)
for alternative in self.alternatives:
msg.attach(self._create_mime_attachment(*alternative))
return msg


def send_mail(subject, message, from_email, recipient_list, def send_mail(subject, message, from_email, recipient_list,
fail_silently=False, auth_user=None, auth_password=None): fail_silently=False, auth_user=None, auth_password=None):
Expand Down
2 changes: 1 addition & 1 deletion django/core/management/commands/dumpdata.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def handle(self, *app_labels, **options):
model_list = get_models(app) model_list = get_models(app)


for model in model_list: for model in model_list:
objects.extend(model.objects.all()) objects.extend(model._default_manager.all())


try: try:
return serializers.serialize(format, objects, indent=indent) return serializers.serialize(format, objects, indent=indent)
Expand Down
7 changes: 5 additions & 2 deletions django/db/backends/creation.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -26,8 +26,11 @@ def __init__(self, connection):
self.connection = connection self.connection = connection


def _digest(self, *args): def _digest(self, *args):
"Generate a 32 bit digest of a set of arguments that can be used to shorten identifying names" """
return '%x' % (abs(hash(args)) % (1<<32)) Generates a 32-bit digest of a set of arguments that can be used to
shorten identifying names.
"""
return '%x' % (abs(hash(args)) % 4294967296L) # 2**32


def sql_create_model(self, model, style, known_models=set()): def sql_create_model(self, model, style, known_models=set()):
""" """
Expand Down
Loading

0 comments on commit c435676

Please sign in to comment.