maxmind / GeoIP2-python

Python code for GeoIP2 webservice client and database reader
https://geoip2.readthedocs.org/en/latest/
Apache License 2.0
1.1k stars 140 forks source link

Database Reader exceptions #115

Closed fisher85 closed 2 years ago

fisher85 commented 3 years ago

I read the documentation here: https://github.com/maxmind/GeoIP2-python#database-reader-exceptions

If the database file does not exist or is not readable, the constructor will raise a FileNotFoundError.

But if the database is not readable (access denied, disk damaged, etc.), other exceptions will be thrown. It would be more correct to write like this:

If the database file does not exist or is not readable, the constructor will raise a FileNotFoundError.

Or even more:

If the database file does not exist or is not readable, the constructor will raise a FileNotFoundError.

And I think an example like this could be given here:

from geoip2.database import Reader
from geoip2.errors import AddressNotFoundError
from maxminddb.errors import InvalidDatabaseError

def get_iso_code(db_path, ip_address) -> str:
    reader = None

    try:
        reader = Reader(db_path, locales=['en'])
    except InvalidDatabaseError as err:
        print(f'GeoIP database {db_path} is invalid or there is an internal bug in the geoip2 reader: {err}')
    except FileNotFoundError:
        print(f'GeoIP database {db_path} not found')
    except PermissionError:
        print(f'You are not allowed to read GeoIP database {db_path}')
    except OSError:
        print(f'GeoIP database {db_path} is not readable')

    if reader is None:
        return ''

    try:
        response = reader.country(ip_address)
        return response.country.iso_code or ''
    except AddressNotFoundError:
        print(f'IP address {ip_address} is not in the database')
    except InvalidDatabaseError as err:
        print(f'GeoIP database {db_path} is invalid or there is an internal bug in the geoip2 reader: {err}')        
    except ValueError:
        print(f'IP address {ip_address} is invalid')

    return ''

print(get_iso_code('/path/to/GeoLite2-Country.mmdb', '8.8.8.8'))
# US
print(get_iso_code('/path/to/corrupted.mmdb', '8.8.8.8'))
# GeoIP database /path/to/corrupted.mmdb is invalid or there is an internal bug in the geoip2 reader: 
# Error looking up 8.8.8.8. The MaxMind DB file's search tree is corrupt
print(get_iso_code('/path/to/not_found', '8.8.8.8'))
# GeoIP database /path/to/not_found not found
print(get_iso_code('/path/to/GeoLite2-Country.mmdb', '127.0.0.1'))
# IP address 127.0.0.1 is not in the database
print(get_iso_code('/path/to/GeoLite2-Country.mmdb', '999.0.0.1'))
# IP address 999.0.0.1 is invalid
oschwald commented 3 years ago

Without checking, I believe the text in the documentation is correct when using the C extension, but the pure Python code will throw whatever error that Python itself throws. Perhaps the text should just be updated to:

If the database file does not exist or is not readable, the constructor will raise an exception.

fisher85 commented 3 years ago

Yes, it will be right:

If the database file does not exist or is not readable, the constructor will raise an exception.

oschwald commented 2 years ago

This has been clarified. Thanks!