Bug 1133146: Add geolocation capabilities.

Add functions for country lookup and MaxMind DB handling.
This commit is contained in:
Paul McLanahan 2015-03-16 16:08:54 -04:00
Родитель 0e5e664caa
Коммит cb4a45710e
13 изменённых файлов: 3707 добавлений и 0 удалений

1
.gitignore поставляемый
Просмотреть файл

@ -27,6 +27,7 @@ Desktop.ini
venv
.vagrant
*.db
*.mmdb
james.ini
/media/js/test/test-results.xml
bedrock/externalfiles/files_cache

42
bedrock/base/geo.py Normal file
Просмотреть файл

@ -0,0 +1,42 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from django.conf import settings
try:
import maxminddb
except ImportError:
maxminddb = None
if maxminddb is not None:
try:
geo = maxminddb.open_database(settings.MAXMIND_DB_PATH)
except (IOError, maxminddb.InvalidDatabaseError):
geo = None
else:
geo = None
def get_country_from_ip(ip_addr):
"""Return country info for the given IP Address."""
if geo is not None:
try:
data = geo.get(ip_addr)
except ValueError:
data = None
if data:
country = data.get('country', data.get('registered_country'))
if country:
return country['iso_code'].upper()
return settings.MAXMIND_DEFAULT_COUNTRY.upper()
def get_country_from_request(request):
"""Return country info for the given request data."""
client_ip = request.META.get('HTTP_X_CLUSTER_CLIENT_IP',
request.META.get('REMOTE_ADDR'))
return get_country_from_ip(client_ip)

Просмотреть файл

@ -4,10 +4,13 @@
import os
from subprocess import call
from django.test.utils import override_settings
from mock import patch
import chkcrontab_lib as chkcrontab
from funfactory.settings_base import path
from bedrock.base import geo
from bedrock.mozorg.tests import TestCase
@ -42,3 +45,72 @@ class TestCrontabFiles(TestCase):
cronlog = chkcrontab.LogCounter()
return_value = chkcrontab.check_crontab(filename, cronlog)
self.assertEqual(return_value, 0, 'Problem with ' + filename)
@patch('bedrock.base.geo.geo')
class TestGeo(TestCase):
# real output from a real maxmind db
good_geo_data = {
u'continent': {
u'code': u'NA',
u'geoname_id': 6255149L,
u'names': {u'de': u'Nordamerika',
u'en': u'North America',
u'es': u'Norteam\xe9rica',
u'fr': u'Am\xe9rique du Nord',
u'ja': u'\u5317\u30a2\u30e1\u30ea\u30ab',
u'pt-BR': u'Am\xe9rica do Norte',
u'ru': u'\u0421\u0435\u0432\u0435\u0440\u043d\u0430\u044f '
u'\u0410\u043c\u0435\u0440\u0438\u043a\u0430',
u'zh-CN': u'\u5317\u7f8e\u6d32'}
},
u'country': {
u'geoname_id': 6252001L,
u'iso_code': u'US',
u'names': {u'de': u'USA',
u'en': u'United States',
u'es': u'Estados Unidos',
u'fr': u'\xc9tats-Unis',
u'ja': u'\u30a2\u30e1\u30ea\u30ab\u5408\u8846\u56fd',
u'pt-BR': u'Estados Unidos',
u'ru': u'\u0421\u0428\u0410',
u'zh-CN': u'\u7f8e\u56fd'}
},
u'location': {u'latitude': 38.0, u'longitude': -97.0},
u'registered_country': {
u'geoname_id': 6252001L,
u'iso_code': u'US',
u'names': {u'de': u'USA',
u'en': u'United States',
u'es': u'Estados Unidos',
u'fr': u'\xc9tats-Unis',
u'ja': u'\u30a2\u30e1\u30ea\u30ab\u5408\u8846\u56fd',
u'pt-BR': u'Estados Unidos',
u'ru': u'\u0421\u0428\u0410',
u'zh-CN': u'\u7f8e\u56fd'}
}
}
def test_get_country_by_ip(self, geo_mock):
geo_mock.get.return_value = self.good_geo_data
self.assertEqual(geo.get_country_from_ip('1.1.1.1'), 'US')
geo_mock.get.assert_called_with('1.1.1.1')
@override_settings(MAXMIND_DEFAULT_COUNTRY='XX')
def test_get_country_by_ip_default(self, geo_mock):
"""Geo failure should return default country."""
geo_mock.get.return_value = None
self.assertEqual(geo.get_country_from_ip('1.1.1.1'), 'XX')
geo_mock.get.assert_called_with('1.1.1.1')
geo_mock.reset_mock()
geo_mock.get.side_effect = ValueError
self.assertEqual(geo.get_country_from_ip('1.1.1.1'), 'XX')
geo_mock.get.assert_called_with('1.1.1.1')
@override_settings(MAXMIND_DEFAULT_COUNTRY='XX')
def test_get_country_by_ip_bad_data(self, geo_mock):
"""Bad data from geo should return default country."""
geo_mock.get.return_value = {'fred': 'flintstone'}
self.assertEqual(geo.get_country_from_ip('1.1.1.1'), 'XX')
geo_mock.get.assert_called_with('1.1.1.1')

Просмотреть файл

@ -2336,3 +2336,6 @@ FIREFOX_OS_FEEDS = (
FIREFOX_OS_FEED_LOCALES = [feed[0] for feed in FIREFOX_OS_FEEDS]
TABLEAU_DB_URL = None
MAXMIND_DB_PATH = os.getenv('MAXMIND_DB_PATH', path('GeoIP2-Country.mmdb'))
MAXMIND_DEFAULT_COUNTRY = os.getenv('MAXMIND_DEFAULT_COUNTRY', 'US')

Просмотреть файл

@ -6,3 +6,5 @@ MySQL-python==1.2.3c1
Jinja2==2.5.5
# sha256: KjyjT2OwYu6OBZyiRgrBgEDsliLwox4UM4Pw25RM6zY
lxml==2.3.3
# sha256: z7Y2FZPiv53Fe_051X6y8U4-RhzuMzrC_-2w-HP3l80
maxminddb==1.1.1

Просмотреть файл

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2008 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Просмотреть файл

@ -0,0 +1,17 @@
Metadata-Version: 1.1
Name: ipaddr
Version: 2.1.11
Summary: UNKNOWN
Home-page: http://code.google.com/p/ipaddr-py/
Author: Google
Author-email: ipaddr-py-dev@googlegroups.com
License: Apache License, Version 2.0
Description: UNKNOWN
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Classifier: Topic :: Internet
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: System :: Networking

Просмотреть файл

@ -0,0 +1,8 @@
ipaddr.py is a library for working with IP addresses, both IPv4 and IPv6.
It was developed by Google for internal use, and is now open source.
Project home page: http://code.google.com/p/ipaddr-py/
Please send contributions to ipaddr-py-dev@googlegroups.com. Code should
include unit tests and follow the Google Python style guide:
http://code.google.com/p/soc/wiki/PythonStyleGuide

Просмотреть файл

@ -0,0 +1,295 @@
#summary notes from releases
= Release Notes =
Here are the visible changes for each release.
== 2.1.11 ==
(2014-01-31)
* hostmask parsing bug fixed by pmarks (a nearly complete rewrite of the mask parsing code)
* i97, incorrectly parses some v6 addresses.
* docstring typos.
* i95, refer to the nets in the exception raised by collapse_address_list
* add license to boilerplate to test-2to3.sh
== 2.1.10 ==
(2012-01-20)
Friday night, LAUNCH LAUNCH LAUNCH!
* i84, fix iterhosts for /31's or /127's
* private method arg cleanup.
* i83, docstring issue.
* i87, new ipv4/ipv6 parser. patch from pmarks
* i90, fix copyright.
* bytes fix. patch from pmarks.
== 2.1.9 ==
(2011-02-22)
The last outstanding issues.
* fix warnings from python3.2
* fix bug in _is_shorthand_ip resulting in bad teredo addresses.
== 2.1.8 ==
(2011-02-09)
This release fixes regressions.
* Address and networks now again compare true, if the address matches.
* ipaddr works again on Python 2.4 and 2.5.
== 2.1.7 ==
(2011-01-13)
* turn teredo and sixtofour into properties as opposed to normal methods.
== 2.1.6 ==
(2011-01-13)
* typo fixes.
* fix for ipaddr_test referring to an old version of ipaddr.
* add test cases for r176 and r196.
* fix for recognizing IPv6 addresses with embedded IPv4 address not being recognized.
* additional unit tests for network comparisons and sorting.
* force hash() to long to ensure consistency
* turn v4_int_to_packed and v6_int_to_packed into public functions to aid converting between integers and network objects.
* add support for pulling teredo and 6to4 embedded addresses out of an IPv6 address.
== 2.1.5 ==
(2010-09-11)
* containment test should always return false on mixed-type tests.
== 2.1.4 ==
(2010-08-15)
* fix for issue66, more invalid IPv6 addresses will be rejected
== 2.1.3 ==
(2010-06-12)
* fix for issue61, incorrect network containment (thanks bw.default)
== 2.1.2 ==
(2010-05-31)
* Happy Memorial day.
* arithmetic for v4 and v6 address objects and ints (issue 57).
* fix address_exclude issue where excluding an address from itself puked.
* make sure addresses and networks don't compare.
* doc-string fixes (issue60)
* and masked() method to _BaseNet to return a network object with the host bits masked out (issue58)
* fix v6 subnet representation (email to ipaddr-py-dev)
== 2.1.1 ==
(2010-03-02)
* bug with list comprehension in {{{ IPv4Network._is_valid_netmask() }}}
* kill the last remaining instances of the old exceptions in the docstrings(thanks Scott Kitterman)
== 2.1.0 ==
(2010-02-13)
Easier change this time :)
* networks and addresses are unsortable by default (see https://groups.google.com/group/ipaddr-py-dev/browse_thread/thread/8fbc5166be71adbc for discussion).
* exception text cleanup.
* fixing inconsistent behavior of v4/v6 address/network comparisons.
* add IPv4Network().is_unspecified (thanks rep.dot.net)
* fix for decoding mapped addresses (thanks rlaager)
* docstring updates (thanks Scott Kitterman)
* fix errant ref to non-existent variable(s) (thanks Harry Bock)
* fix exceptions (most exceptions are subclassed from ValueError now, so this can easily be caught)
* iterator for looping through subnets (thanks Marco Giutsi)
That's mostly it. there were quite a few other minor changes, but this should cover the major bits. Usage.wiki will be updated in the coming days.
== 2.0.0 ==
First and foremost, this is a backwards incompatible change. Code written for ipaddr-1.x will likely not work stock with ipaddr-2.0. For users of the 1.x branch, I'll continue to provide support, but new-feature development has ceased. But it's not so bad, take a look.All in all, I think this new version of ipaddr is much more intuitive and easy to use.
The best way to get a feel for this code is to download it and try and out, but I've tried to list some of the more important changes below to help you out.
The major changes.
# IPvXAddress and IPvXNetwork classes.
* Individual addresses are now (IPv4|IPv6)Address objects. Network attributes that are actually addresses (eg, broadcast, network, hostmask) are now (IPv4|IPv6)Address objects. That means no more IPv4/IPv6 classes handling only networks.
{{{
In [3]: ipaddr.IPv4Network("1.1.1.0/24")
Out[3]: IPv4Network('1.1.1.0/24')
In [4]: ipaddr.IPv4Network("1.1.1.0/24").network
Out[4]: IPv4Address('1.1.1.0')
In [5]: ipaddr.IPv4Network("1.1.1.0/24").broadcast
Out[5]: IPv4Address('1.1.1.255')
}}}
* no more ext methods. To reference the stringified version of any attribute, you call str() on (similar for the numeric value with int()).
{{{
In [6]: str(ipaddr.IPv4Network("1.1.1.0/24").broadcast)
Out[6]: '1.1.1.255'
In [7]: int(ipaddr.IPv4Network("1.1.1.0/24").broadcast)
Out[7]: 16843263
In [8]: int(ipaddr.IPv4Network("1.1.1.0/24").network)
Out[8]: 16843008
In [9]: str(ipaddr.IPv4Network("1.1.1.0/24").network)
Out[9]: '1.1.1.0'
}}}
* IP() everything-constructor has been replaced by IPAddress() and IPNetwork() constructors. It seems reasonable to assume that an application programmer will know when they are dealing strictly with ip addresses vs. networks and making this separation de-clutters the code. IPNetwork still assumes a default prefixlength of 32 for IPv4 and 128 for IPv6 if none is supplied (just like IP() used to), so when in doubt, you can always use IPNetwork.
{{{
In [16]: ipaddr.IPNetwork('1.1.1.1')
Out[16]: IPv4Network('1.1.1.1/32')
In [17]: ipaddr.IPNetwork('1.1.1.1/12')
Out[17]: IPv4Network('1.1.1.1/12')
In [18]: ipaddr.IPNetwork('::1')
Out[18]: IPv6Network('::1/128')
In [19]: ipaddr.IPNetwork('::1/64')
Out[19]: IPv6Network('::1/64')
}}}
# Some other (but no less important) bug fixes/improvements:
* __ contains __ accepts strings/ints as well as (IPv4|IPv6)Address objects.
{{{
In [9]: ipaddr.IPAddress('1.1.1.1') in ipaddr.IPNetwork('1.1.1.0/24')
Out[9]: True
In [10]: '1.1.1.1' in ipaddr.IPv4Network("1.1.1.0/24")
Out[10]: True
In [11]: '1' in ipaddr.IPv4Network("0.0.0.0/0")
Out[11]: True
In [12]: 1 in ipaddr.IPv4Network("0.0.0.0/0")
Out[12]: True
}}}
* summarize_address_range. You can now get a list of all of the networks between two distinct (IPv4|IPv6)Address'es (results in potentially huge speed boosts for address collapsing)
{{{
In [14]: ipaddr.summarize_address_range(ipaddr.IPAddress('1.1.0.0'), ipaddr.IPAddress('1.1.255.255'))
Out[14]: [IPv4Network('1.1.0.0/16')]
In [15]: ipaddr.summarize_address_range(ipaddr.IPAddress('1.1.0.0'), ipaddr.IPAddress('1.1.255.254'))
Out[15]:
[IPv4Network('1.1.0.0/17'),
IPv4Network('1.1.128.0/18'),
IPv4Network('1.1.192.0/19'),
IPv4Network('1.1.224.0/20'),
IPv4Network('1.1.240.0/21'),
IPv4Network('1.1.248.0/22'),
IPv4Network('1.1.252.0/23'),
IPv4Network('1.1.254.0/24'),
IPv4Network('1.1.255.0/25'),
IPv4Network('1.1.255.128/26'),
IPv4Network('1.1.255.192/27'),
IPv4Network('1.1.255.224/28'),
IPv4Network('1.1.255.240/29'),
IPv4Network('1.1.255.248/30'),
IPv4Network('1.1.255.252/31'),
IPv4Network('1.1.255.254/32')]
}}}
* network iterators. the (IPv4|IPv6)Network classes now implement iterators to help quickly access each member of a network in sequence:
{{{
In [24]: for addr in iter(ipaddr.IPNetwork('1.1.1.1/28')): addr
....:
Out[24]: IPv4Address('1.1.1.0')
Out[24]: IPv4Address('1.1.1.1')
Out[24]: IPv4Address('1.1.1.2')
Out[24]: IPv4Address('1.1.1.3')
Out[24]: IPv4Address('1.1.1.4')
Out[24]: IPv4Address('1.1.1.5')
Out[24]: IPv4Address('1.1.1.6')
Out[24]: IPv4Address('1.1.1.7')
Out[24]: IPv4Address('1.1.1.8')
Out[24]: IPv4Address('1.1.1.9')
Out[24]: IPv4Address('1.1.1.10')
Out[24]: IPv4Address('1.1.1.11')
Out[24]: IPv4Address('1.1.1.12')
Out[24]: IPv4Address('1.1.1.13')
Out[24]: IPv4Address('1.1.1.14')
Out[24]: IPv4Address('1.1.1.15')
}}}
* additionally, an iterhosts() method has been added to allow for iterating over all of the usable addresses on a network (everything except the network and broadcast addresses)
{{{
In [26]: for addr in ipaddr.IPNetwork('1.1.1.1/28').iterhosts(): addr
....:
Out[26]: IPv4Address('1.1.1.1')
Out[26]: IPv4Address('1.1.1.2')
Out[26]: IPv4Address('1.1.1.3')
Out[26]: IPv4Address('1.1.1.4')
Out[26]: IPv4Address('1.1.1.5')
Out[26]: IPv4Address('1.1.1.6')
Out[26]: IPv4Address('1.1.1.7')
Out[26]: IPv4Address('1.1.1.8')
Out[26]: IPv4Address('1.1.1.9')
Out[26]: IPv4Address('1.1.1.10')
Out[26]: IPv4Address('1.1.1.11')
Out[26]: IPv4Address('1.1.1.12')
Out[26]: IPv4Address('1.1.1.13')
Out[26]: IPv4Address('1.1.1.14')
}}}
Thanks to the python community and everyone who's made feature suggestions or submitted patches. Please continue to send bugs/enhancements/patches to the mailing list.
== 1.1.1 ==
This release contains a single important bugfix. All users of 1.1.0 should upgrade.
* r77 A logical error caused ordering operators to behave incorrectly.
== 1.1.0 ==
`ipaddr.py` is now part of the standard library in Python 2.7 and 3.1! This release is compatible with the `ipaddr` from future versions of Python.
Special thanks to Philipp Hagemeister for making most of the improvements to this release, and to Gregory P. Smith for shepherding this into the Python standard library.
* r59 Method names are now PEP-8 compliant, instead of Google-style camel case. The old method names remain, but are deprecated; you should use the lowercase names to be compatible with Python 2.7/3.1. (pmoody)
* r63 .prefixlen is now a property. (pmoody)
* r64 Stronger validation. (Philipp Hagemeister)
* r65 1.2.3.4 is not a valid v6 address, so we can simplify the constructor. (Philipp Hagemeister)
* r66 Expand rich comparison operations and their tests, with a goal of supporting 2to3. Add a new method .networks_key(). Add a new script to run through 2to3 and make sure tests pass under Python 3 with the converted version. (Philipp Hagemeister)
* r68 New method .packed(). (Philipp Hagemeister)
* r69 Add `is_multicast`, `is_unspecified`, `is_loopback`, `is_link_local`, `is_site_local`, and `is_private` for IPv6. Make more methods into properties. Improved documentation and tests for `is_*` properties for IPv4 and IPv6. Rename `networks_key()` to `_get_networks_key()`.
* r71 Fix off-by-one bug (issue 15). (gpsmith)
== 1.0.2 ==
* r52 Force the return value in testHexRepresentation to uppercase to workaround Python version. (smart)
* r51 Fix testHexRepresentation(). Hex representations of longs are uppercase. (smart)
* r50 Remove trailing whitespace and update docstrings. (smart)
* r44. this makes the spacing and docstrings pep8 compliant. (pmoody)
* r43. When processing the IPv4 mapped address 16 bits at a time, the components are stored in the reverse order. Updated the test to use a non-symmetric IPv4 address, which exhibited the bug. (smart)
* r40. implment __int__ and __hex__. will need to be updated for py3k (to use __index__) (pmoody)
* r38 A cleanup from issue 9 : Make exception messages consistent for IP(''), IPv4(''), IPv6('') (smart)
* r37 Fix for issue 9 : ipaddr.IP('') should raise ValueError (mshields)
== 1.0.1 ==
* str() now produces lowercase for IPv6 addresses, to match inet_pton(3). (http://codereview.appspot.com/7678)
* repr() now produces strings that can be pasted back into the interpreter.

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,36 @@
#!/usr/bin/python
#
# Copyright 2008 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from distutils.core import setup
import ipaddr
setup(name='ipaddr',
maintainer='Google',
maintainer_email='ipaddr-py-dev@googlegroups.com',
version=ipaddr.__version__,
url='http://code.google.com/p/ipaddr-py/',
license='Apache License, Version 2.0',
classifiers=[
'Development Status :: 5 - Production/Stable',
'Intended Audience :: Developers',
'License :: OSI Approved :: Apache Software License',
'Operating System :: OS Independent',
'Topic :: Internet',
'Topic :: Software Development :: Libraries',
'Topic :: System :: Networking'],
py_modules=['ipaddr'])

Просмотреть файл

@ -5,6 +5,7 @@ packages/python-memcached
packages/pytz
packages/PyYAML/lib
packages/futures
packages/ipaddr
src/basket-client
src/bleach
src/chkcrontab