{"id":13593777,"url":"https://github.com/maxmind/GeoIP2-python","last_synced_at":"2025-04-09T05:32:15.234Z","repository":{"id":7914913,"uuid":"9299325","full_name":"maxmind/GeoIP2-python","owner":"maxmind","description":"Python code for GeoIP2 webservice client and database reader","archived":false,"fork":false,"pushed_at":"2025-03-21T19:00:43.000Z","size":684,"stargazers_count":1141,"open_issues_count":6,"forks_count":142,"subscribers_count":52,"default_branch":"main","last_synced_at":"2025-04-08T23:14:06.287Z","etag":null,"topics":["geoip","geoip2","maxmind","mmdb"],"latest_commit_sha":null,"homepage":"https://geoip2.readthedocs.org/en/latest/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/maxmind.png","metadata":{"files":{"readme":"README.rst","changelog":"HISTORY.rst","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2013-04-08T15:07:28.000Z","updated_at":"2025-04-05T01:26:34.000Z","dependencies_parsed_at":"2024-01-21T07:26:55.836Z","dependency_job_id":"1f09202c-240b-4e6c-b684-54126ff4b32a","html_url":"https://github.com/maxmind/GeoIP2-python","commit_stats":{"total_commits":456,"total_committers":21,"mean_commits":"21.714285714285715","dds":0.1271929824561403,"last_synced_commit":"884dfc3bc6464c393644a0c86ac1cb3c846eccaa"},"previous_names":[],"tags_count":43,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxmind%2FGeoIP2-python","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxmind%2FGeoIP2-python/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxmind%2FGeoIP2-python/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxmind%2FGeoIP2-python/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/maxmind","download_url":"https://codeload.github.com/maxmind/GeoIP2-python/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247986891,"owners_count":21028890,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["geoip","geoip2","maxmind","mmdb"],"created_at":"2024-08-01T16:01:24.393Z","updated_at":"2025-04-09T05:32:15.224Z","avatar_url":"https://github.com/maxmind.png","language":"Python","readme":"=========================\nMaxMind GeoIP2 Python API\n=========================\n\nDescription\n-----------\n\nThis package provides an API for the GeoIP2 and GeoLite2 `web services\n\u003chttps://dev.maxmind.com/geoip/docs/web-services?lang=en\u003e`_ and `databases\n\u003chttps://dev.maxmind.com/geoip/docs/databases?lang=en\u003e`_.\n\nInstallation\n------------\n\nTo install the ``geoip2`` module, type:\n\n.. code-block:: bash\n\n    $ pip install geoip2\n\nIf you are not able to install from PyPI, you may also use ``pip`` from the\nsource directory:\n\n.. code-block:: bash\n\n    $ python -m pip install .\n\nDatabase Reader Extension\n^^^^^^^^^^^^^^^^^^^^^^^^^\n\nIf you wish to use the C extension for the database reader, you must first\ninstall the `libmaxminddb C API \u003chttps://github.com/maxmind/libmaxminddb\u003e`_.\nPlease `see the instructions distributed with it\n\u003chttps://github.com/maxmind/libmaxminddb/blob/main/README.md\u003e`_.\n\nIP Geolocation Usage\n--------------------\n\nIP geolocation is inherently imprecise. Locations are often near the center of\nthe population. Any location provided by a GeoIP2 database or web service\nshould not be used to identify a particular address or household.\n\nWeb Service Usage\n-----------------\n\nTo use this API, you first construct either a ``geoip2.webservice.Client`` or\n``geoip2.webservice.AsyncClient``, passing your MaxMind ``account_id`` and\n``license_key`` to the constructor. To use the GeoLite2 web service instead of\nthe GeoIP2 web service, set the optional ``host`` keyword argument to\n``geolite.info``. To use the Sandbox GeoIP2 web service instead of the\nproduction GeoIP2 web service, set the optional ``host`` keyword argument to\n``sandbox.maxmind.com``.\n\nAfter doing this, you may call the method corresponding to request type\n(e.g., ``city`` or ``country``), passing it the IP address you want to look up.\n\nIf the request succeeds, the method call will return a model class for the\nendpoint you called. This model in turn contains multiple record classes,\neach of which represents part of the data returned by the web service.\n\nIf the request fails, the client class throws an exception.\n\nSync Web Service Example\n------------------------\n\n.. code-block:: pycon\n\n    \u003e\u003e\u003e import geoip2.webservice\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e # This creates a Client object that can be reused across requests.\n    \u003e\u003e\u003e # Replace \"42\" with your account ID and \"license_key\" with your license\n    \u003e\u003e\u003e # key. Set the \"host\" keyword argument to \"geolite.info\" to use the\n    \u003e\u003e\u003e # GeoLite2 web service instead of the GeoIP2 web service. Set the\n    \u003e\u003e\u003e # \"host\" keyword argument to \"sandbox.maxmind.com\" to use the Sandbox\n    \u003e\u003e\u003e # GeoIP2 web service instead of the production GeoIP2 web service.\n    \u003e\u003e\u003e with geoip2.webservice.Client(42, 'license_key') as client:\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e     # Replace \"city\" with the method corresponding to the web service\n    \u003e\u003e\u003e     # that you are using, i.e., \"country\", \"city\", or \"insights\". Please\n    \u003e\u003e\u003e     # note that Insights is not supported by the GeoLite2 web service.\n    \u003e\u003e\u003e     response = client.city('203.0.113.0')\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e     response.country.iso_code\n    'US'\n    \u003e\u003e\u003e     response.country.name\n    'United States'\n    \u003e\u003e\u003e     response.country.names['zh-CN']\n    u'美国'\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e     response.subdivisions.most_specific.name\n    'Minnesota'\n    \u003e\u003e\u003e     response.subdivisions.most_specific.iso_code\n    'MN'\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e     response.city.name\n    'Minneapolis'\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e     response.postal.code\n    '55455'\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e     response.location.latitude\n    44.9733\n    \u003e\u003e\u003e     response.location.longitude\n    -93.2323\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e     response.traits.network\n    IPv4Network('203.0.113.0/32')\n\nAsync Web Service Example\n-------------------------\n\n.. code-block:: pycon\n\n    \u003e\u003e\u003e import asyncio\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e import geoip2.webservice\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e async def main():\n    \u003e\u003e\u003e     # This creates an AsyncClient object that can be reused across\n    \u003e\u003e\u003e     # requests on the running event loop. If you are using multiple event\n    \u003e\u003e\u003e     # loops, you must ensure the object is not used on another loop.\n    \u003e\u003e\u003e     #\n    \u003e\u003e\u003e     # Replace \"42\" with your account ID and \"license_key\" with your license\n    \u003e\u003e\u003e     # key. Set the \"host\" keyword argument to \"geolite.info\" to use the\n    \u003e\u003e\u003e     # GeoLite2 web service instead of the GeoIP2 web service. Set the\n    \u003e\u003e\u003e     # \"host\" keyword argument to \"sandbox.maxmind.com\" to use the Sandbox\n    \u003e\u003e\u003e     # GeoIP2 web service instead of the production GeoIP2 web service.\n    \u003e\u003e\u003e     async with geoip2.webservice.AsyncClient(42, 'license_key') as client:\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e         # Replace \"city\" with the method corresponding to the web service\n    \u003e\u003e\u003e         # that you are using, i.e., \"country\", \"city\", or \"insights\". Please\n    \u003e\u003e\u003e         # note that Insights is not supported by the GeoLite2 web service.\n    \u003e\u003e\u003e         response = await client.city('203.0.113.0')\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e         response.country.iso_code\n    'US'\n    \u003e\u003e\u003e         response.country.name\n    'United States'\n    \u003e\u003e\u003e         response.country.names['zh-CN']\n    u'美国'\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e         response.subdivisions.most_specific.name\n    'Minnesota'\n    \u003e\u003e\u003e         response.subdivisions.most_specific.iso_code\n    'MN'\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e         response.city.name\n    'Minneapolis'\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e         response.postal.code\n    '55455'\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e         response.location.latitude\n    44.9733\n    \u003e\u003e\u003e         response.location.longitude\n    -93.2323\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e         response.traits.network\n    IPv4Network('203.0.113.0/32')\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e asyncio.run(main())\n\nWeb Service Client Exceptions\n-----------------------------\n\nFor details on the possible errors returned by the web service itself, see\nhttps://dev.maxmind.com/geoip/docs/web-services?lang=en for the GeoIP2 web\nservice docs.\n\nIf the web service returns an explicit error document, this is thrown as a\n``AddressNotFoundError``, ``AuthenticationError``, ``InvalidRequestError``, or\n``OutOfQueriesError`` as appropriate. These all subclass ``GeoIP2Error``.\n\nIf some other sort of error occurs, this is thrown as an ``HTTPError``. This\nis thrown when some sort of unanticipated error occurs, such as the web\nservice returning a 500 or an invalid error document. If the web service\nreturns any status code besides 200, 4xx, or 5xx, this also becomes an\n``HTTPError``.\n\nFinally, if the web service returns a 200 but the body is invalid, the client\nthrows a ``GeoIP2Error``.\n\nDatabase Usage\n--------------\n\nTo use the database API, you first construct a ``geoip2.database.Reader`` using\nthe path to the file as the first argument. After doing this, you may call the\nmethod corresponding to database type (e.g., ``city`` or ``country``), passing it\nthe IP address you want to look up.\n\nIf the lookup succeeds, the method call will return a model class for the\ndatabase method you called. This model in turn contains multiple record classes,\neach of which represents part of the data for the record.\n\nIf the request fails, the reader class throws an exception.\n\nDatabase Example\n----------------\n\nCity Database\n^^^^^^^^^^^^^\n\n.. code-block:: pycon\n\n    \u003e\u003e\u003e import geoip2.database\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e # This creates a Reader object. You should use the same object\n    \u003e\u003e\u003e # across multiple requests as creation of it is expensive.\n    \u003e\u003e\u003e with geoip2.database.Reader('/path/to/GeoLite2-City.mmdb') as reader:\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e     # Replace \"city\" with the method corresponding to the database\n    \u003e\u003e\u003e     # that you are using, e.g., \"country\".\n    \u003e\u003e\u003e     response = reader.city('203.0.113.0')\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e     response.country.iso_code\n    'US'\n    \u003e\u003e\u003e     response.country.name\n    'United States'\n    \u003e\u003e\u003e     response.country.names['zh-CN']\n    u'美国'\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e     response.subdivisions.most_specific.name\n    'Minnesota'\n    \u003e\u003e\u003e     response.subdivisions.most_specific.iso_code\n    'MN'\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e     response.city.name\n    'Minneapolis'\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e     response.postal.code\n    '55455'\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e     response.location.latitude\n    44.9733\n    \u003e\u003e\u003e     response.location.longitude\n    -93.2323\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e     response.traits.network\n    IPv4Network('203.0.113.0/24')\n\nAnonymous IP Database\n^^^^^^^^^^^^^^^^^^^^^\n\n.. code-block:: pycon\n\n    \u003e\u003e\u003e import geoip2.database\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e # This creates a Reader object. You should use the same object\n    \u003e\u003e\u003e # across multiple requests as creation of it is expensive.\n    \u003e\u003e\u003e with geoip2.database.Reader('/path/to/GeoIP2-Anonymous-IP.mmdb') as reader:\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e     response = reader.anonymous_ip('203.0.113.0')\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e     response.is_anonymous\n    True\n    \u003e\u003e\u003e     response.is_anonymous_vpn\n    False\n    \u003e\u003e\u003e     response.is_hosting_provider\n    False\n    \u003e\u003e\u003e     response.is_public_proxy\n    False\n    \u003e\u003e\u003e     response.is_residential_proxy\n    False\n    \u003e\u003e\u003e     response.is_tor_exit_node\n    True\n    \u003e\u003e\u003e     response.ip_address\n    '203.0.113.0'\n    \u003e\u003e\u003e     response.network\n    IPv4Network('203.0.113.0/24')\n\nASN Database\n^^^^^^^^^^^^\n\n.. code-block:: pycon\n\n    \u003e\u003e\u003e import geoip2.database\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e # This creates a Reader object. You should use the same object\n    \u003e\u003e\u003e # across multiple requests as creation of it is expensive.\n    \u003e\u003e\u003e with geoip2.database.Reader('/path/to/GeoLite2-ASN.mmdb') as reader:\n    \u003e\u003e\u003e     response = reader.asn('203.0.113.0')\n    \u003e\u003e\u003e     response.autonomous_system_number\n    1221\n    \u003e\u003e\u003e     response.autonomous_system_organization\n    'Telstra Pty Ltd'\n    \u003e\u003e\u003e     response.ip_address\n    '203.0.113.0'\n    \u003e\u003e\u003e     response.network\n    IPv4Network('203.0.113.0/24')\n\nConnection-Type Database\n^^^^^^^^^^^^^^^^^^^^^^^^\n\n.. code-block:: pycon\n\n    \u003e\u003e\u003e import geoip2.database\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e # This creates a Reader object. You should use the same object\n    \u003e\u003e\u003e # across multiple requests as creation of it is expensive.\n    \u003e\u003e\u003e with geoip2.database.Reader('/path/to/GeoIP2-Connection-Type.mmdb') as reader:\n    \u003e\u003e\u003e     response = reader.connection_type('203.0.113.0')\n    \u003e\u003e\u003e     response.connection_type\n    'Corporate'\n    \u003e\u003e\u003e     response.ip_address\n    '203.0.113.0'\n    \u003e\u003e\u003e     response.network\n    IPv4Network('203.0.113.0/24')\n\n\nDomain Database\n^^^^^^^^^^^^^^^\n\n.. code-block:: pycon\n\n    \u003e\u003e\u003e import geoip2.database\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e # This creates a Reader object. You should use the same object\n    \u003e\u003e\u003e # across multiple requests as creation of it is expensive.\n    \u003e\u003e\u003e with geoip2.database.Reader('/path/to/GeoIP2-Domain.mmdb') as reader:\n    \u003e\u003e\u003e     response = reader.domain('203.0.113.0')\n    \u003e\u003e\u003e     response.domain\n    'umn.edu'\n    \u003e\u003e\u003e     response.ip_address\n    '203.0.113.0'\n\nEnterprise Database\n^^^^^^^^^^^^^^^^^^^\n\n.. code-block:: pycon\n\n    \u003e\u003e\u003e import geoip2.database\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e # This creates a Reader object. You should use the same object\n    \u003e\u003e\u003e # across multiple requests as creation of it is expensive.\n    \u003e\u003e\u003e with geoip2.database.Reader('/path/to/GeoIP2-Enterprise.mmdb') as reader:\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e     # Use the .enterprise method to do a lookup in the Enterprise database\n    \u003e\u003e\u003e     response = reader.enterprise('203.0.113.0')\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e     response.country.confidence\n    99\n    \u003e\u003e\u003e     response.country.iso_code\n    'US'\n    \u003e\u003e\u003e     response.country.name\n    'United States'\n    \u003e\u003e\u003e     response.country.names['zh-CN']\n    u'美国'\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e     response.subdivisions.most_specific.name\n    'Minnesota'\n    \u003e\u003e\u003e     response.subdivisions.most_specific.iso_code\n    'MN'\n    \u003e\u003e\u003e     response.subdivisions.most_specific.confidence\n    77\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e     response.city.name\n    'Minneapolis'\n    \u003e\u003e\u003e     response.country.confidence\n    11\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e     response.postal.code\n    '55455'\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e     response.location.accuracy_radius\n    50\n    \u003e\u003e\u003e     response.location.latitude\n    44.9733\n    \u003e\u003e\u003e     response.location.longitude\n    -93.2323\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e     response.traits.network\n    IPv4Network('203.0.113.0/24')\n\n\nISP Database\n^^^^^^^^^^^^\n\n.. code-block:: pycon\n\n    \u003e\u003e\u003e import geoip2.database\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e # This creates a Reader object. You should use the same object\n    \u003e\u003e\u003e # across multiple requests as creation of it is expensive.\n    \u003e\u003e\u003e with geoip2.database.Reader('/path/to/GeoIP2-ISP.mmdb') as reader:\n    \u003e\u003e\u003e     response = reader.isp('203.0.113.0')\n    \u003e\u003e\u003e     response.autonomous_system_number\n    1221\n    \u003e\u003e\u003e     response.autonomous_system_organization\n    'Telstra Pty Ltd'\n    \u003e\u003e\u003e     response.isp\n    'Telstra Internet'\n    \u003e\u003e\u003e     response.organization\n    'Telstra Internet'\n    \u003e\u003e\u003e     response.ip_address\n    '203.0.113.0'\n    \u003e\u003e\u003e     response.network\n    IPv4Network('203.0.113.0/24')\n\nDatabase Reader Exceptions\n--------------------------\n\nIf the database file does not exist or is not readable, the constructor will\nraise a ``FileNotFoundError`` or a ``PermissionError``. If the IP address passed\nto a method is invalid, a ``ValueError`` will be raised. If the file is invalid\nor there is a bug in the reader, a ``maxminddb.InvalidDatabaseError`` will be\nraised with a description of the problem. If an IP address is not in the\ndatabase, a ``AddressNotFoundError`` will be raised.\n\n``AddressNotFoundError`` references the largest subnet where no address would be\nfound. This can be used to efficiently enumerate entire subnets:\n\n.. code-block:: python\n\n    import geoip2.database\n    import geoip2.errors\n    import ipaddress\n\n    # This creates a Reader object. You should use the same object\n    # across multiple requests as creation of it is expensive.\n    with geoip2.database.Reader('/path/to/GeoLite2-ASN.mmdb') as reader:\n        network = ipaddress.ip_network(\"192.128.0.0/15\")\n\n        ip_address = network[0]\n        while ip_address in network:\n            try:\n                response = reader.asn(ip_address)\n                response_network = response.network\n            except geoip2.errors.AddressNotFoundError as e:\n                response = None\n                response_network = e.network\n            print(f\"{response_network}: {response!r}\")\n            ip_address = response_network[-1] + 1  # move to next subnet\n\nValues to use for Database or Dictionary Keys\n---------------------------------------------\n\n**We strongly discourage you from using a value from any ``names`` property as\na key in a database or dictionaries.**\n\nThese names may change between releases. Instead we recommend using one of the\nfollowing:\n\n* ``geoip2.records.City`` - ``city.geoname_id``\n* ``geoip2.records.Continent`` - ``continent.code`` or ``continent.geoname_id``\n* ``geoip2.records.Country`` and ``geoip2.records.RepresentedCountry`` - ``country.iso_code`` or ``country.geoname_id``\n* ``geoip2.records.subdivision`` - ``subdivision.iso_code`` or ``subdivision.geoname_id``\n\nWhat data is returned?\n----------------------\n\nWhile many of the models contain the same basic records, the attributes which\ncan be populated vary between web service endpoints or databases. In\naddition, while a model may offer a particular piece of data, MaxMind does not\nalways have every piece of data for any given IP address.\n\nBecause of these factors, it is possible for any request to return a record\nwhere some or all of the attributes are unpopulated.\n\nThe only piece of data which is always returned is the ``ip_address``\nattribute in the ``geoip2.records.Traits`` record.\n\nIntegration with GeoNames\n-------------------------\n\n`GeoNames \u003chttps://www.geonames.org/\u003e`_ offers web services and downloadable\ndatabases with data on geographical features around the world, including\npopulated places. They offer both free and paid premium data. Each feature is\nuniquely identified by a ``geoname_id``, which is an integer.\n\nMany of the records returned by the GeoIP web services and databases include a\n``geoname_id`` field. This is the ID of a geographical feature (city, region,\ncountry, etc.) in the GeoNames database.\n\nSome of the data that MaxMind provides is also sourced from GeoNames. We\nsource things like place names, ISO codes, and other similar data from the\nGeoNames premium data set.\n\nReporting Data Problems\n-----------------------\n\nIf the problem you find is that an IP address is incorrectly mapped, please\n`submit your correction to MaxMind \u003chttps://www.maxmind.com/en/correction\u003e`_.\n\nIf you find some other sort of mistake, like an incorrect spelling, please\ncheck the `GeoNames site \u003chttps://www.geonames.org/\u003e`_ first. Once you've\nsearched for a place and found it on the GeoNames map view, there are a\nnumber of links you can use to correct data (\"move\", \"edit\", \"alternate\nnames\", etc.). Once the correction is part of the GeoNames data set, it\nwill be automatically incorporated into future MaxMind releases.\n\nIf you are a paying MaxMind customer and you're not sure where to submit a\ncorrection, please `contact MaxMind support\n\u003chttps://www.maxmind.com/en/support\u003e`_ for help.\n\nRequirements\n------------\n\nPython 3.9 or greater is required. Older versions are not supported.\n\nThe Requests HTTP library is also required. See\n\u003chttps://pypi.org/project/requests/\u003e for details.\n\nVersioning\n----------\n\nThe GeoIP2 Python API uses `Semantic Versioning \u003chttps://semver.org/\u003e`_.\n\nSupport\n-------\n\nPlease report all issues with this code using the `GitHub issue tracker\n\u003chttps://github.com/maxmind/GeoIP2-python/issues\u003e`_\n\nIf you are having an issue with a MaxMind service that is not specific to the\nclient API, please contact `MaxMind support\n\u003chttps://www.maxmind.com/en/support\u003e`_ for assistance.\n","funding_links":[],"categories":["资源列表","Python"],"sub_categories":["地理位置"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaxmind%2FGeoIP2-python","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmaxmind%2FGeoIP2-python","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaxmind%2FGeoIP2-python/lists"}