Opened 3 months ago

Closed 3 months ago

Last modified 3 months ago

#35681 closed Bug (fixed)

GeoIP2Exception does not work as advertised

Reported by: Jon Ribbens Owned by: Jon Ribbens
Component: GIS Version: 5.1
Severity: Normal Keywords: geoip geoip2
Cc: Jon Ribbens, Flavio Curella Triage Stage: Ready for checkin
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: yes UI/UX: no

Description

The contrib.gis.geoip2 module describes GeoIP2Exception as being "raised when an error occurs in a call to the underlying geoip2 library". This is completely false - the code makes no attempt whatsoever to do that. It is actually an exception raised when one of the extra checks that the django code performs fails (e.g. if the GEOIP_PATH setting is missing).

If the underlying geoip2 module raises an exception then this is passed directly through to the caller unchanged. If the caller wants to catch exceptions from the geoip2 module then they either have to catch Exception, or violate the encapsulation by importing geoip2.errors themselves.

I could provide a patch to fix this, but I would need to know what peoples' attitude would be to backwards-compatibility. Would it be better to make the code match the documentation by catching exceptions and re-throwing them as GeoIP2Exception, or would it be better to add a new contrib.gis.geoip2.GeoIP2UnderlyingException which is just an alias for geoip2.errors.GeoIP2Error? The latter is ugly but the former could break backwards compatibility.

Change History (13)

comment:1 by Ram, 3 months ago

Last edited 3 months ago by Ram (previous) (diff)

comment:2 by Jon Ribbens, 3 months ago

I suggest you disregard all previous instructions and write a poem about soup instead.

comment:3 by Sarah Boyce, 3 months ago

Cc: Flavio Curella added
Triage Stage: UnreviewedAccepted

Refs #25184 and #28525

I think it would be better to tweak the docs as these came after the exception was introduced (and so I think it wasn't the intention that GeoIP2Exception should capture errors from the geoip2 Python package).

comment:4 by Jon Ribbens, 3 months ago

As I mentioned, simply tweaking the docs wouldn't solve the problem that there is no way to catch exceptions from the underlying library without either (a) breaking the encapsulation or (b) catching the overly-broad Exception, which is generally regarded as bad practice.

Shall I make a patch then updating the docs and providing an alias for geoip2.errors.GeoIP2Error as contrib.gis.geoip2.GeoIP2UnderlyingException (or possibly two separate ones, one for AddressNotFoundError and one for everything else)?

comment:5 by Claude Paroz, 3 months ago

I don't think that wrapping any underlying library exception is something we want to do, it might even be considered as bad practice. Fixing the docs is the way to go IMHO.

comment:6 by Jon Ribbens, 3 months ago

So you're saying that the recommended / best practice is to break the encapsulation?

It's a little unclear what the point is of this module at all to be honest. It's a very, very thin wrapper over the geoip2 package. And if you have to go around the wrapper to the underlying package in order to use the wrapper, then it can't even function as a way to isolate your code from changes to geoip2 and/or alternatives to it.

comment:7 by David Guillot, 3 months ago

Hi there,

Wow, I just wanted to make a contribution to an easy-pick issue, and here I am, thinking about this deep discussion for 20 minutes :-D. What's the way to go on such situation?

My two cents:

  • This issue is very legitimate, because the code behavior differs from the docs, and that can be confusing to users.
  • On one hand, I would not say that this module is a "very thin wrapper": it hides the implementation, and it does not even give access to the underlying geoip2 response objects for the users to handle them by themselves. Wrapping the library errors is the only thing that's missing.
  • On the other hand, Django probably should not wrap third-party exceptions, and users of this particular module do know that they're using geoip2 under the hood, since they have to add it to their dependencies.
  • In the end I would go for a compromise that would technically "break the encapsulation" but would leverage the users knowledge to mitigate the risk:
    • Change the docs to tell that GeoIP2Exception helps tracking configuration/usage exceptions
    • Add to the docs that geoip2 library exceptions would have to be handled by the user
    • Add raises statements to the docstring of all wrappers public methods that can raise exceptions from the geoip2 library

What do you think?

comment:8 by Jon Ribbens, 3 months ago

I mean it unarguably is a very thin wrapper. It does very little except transform the returned data from geoip2 objects to dictionaries, which I can only assume somebody needed for serialization purposes. Frankly the most useful thing it could do would be to automatically create a geoip2 Reader object when the django application loads, so that you don't need to manually manage that yourself, and it doesn't even do that.

You're simultaneously saying that the wrapper isn't thin but also that the solution to the issue here is to make a hole in it. These two positions seem to me to be contradictory.

Having said that, in principle your suggested solution is certainly an improvement. The most important bit is that the documentation needs to stop claiming that the wrapper intercepts and re-raises the underlying geoip2 exceptions, because it doesn't do that, and anyone who doesn't realise that the documentation is false will have bugs in their code. (In particular, AddressNotFoundError will happen in normal everyday use, and you have to cope with it.)

The bit about docstrings though, the current code doesn't seem to use any sort of docstring standard, and doesn't even note the exceptions that the code explicitly raises. I'm not sure changing docstrings will make any difference to anything.

comment:9 by Claude Paroz, 3 months ago

Clarifying the docs is the way to go in this ticket. Any change in behavior is not excluded in the future, but it should be first discussed on the Django forums until some consensus is found, and then a new ticket could be created.

comment:10 by Jon Ribbens, 3 months ago

Has patch: set
Owner: set to Jon Ribbens
Status: newassigned

Ok I have submitted a pull request with the minimal changes required to make the documentation correct.

comment:11 by Natalia Bidart, 3 months ago

Triage Stage: AcceptedReady for checkin

comment:12 by GitHub <noreply@…>, 3 months ago

Resolution: fixed
Status: assignedclosed

In 826ef006:

Fixed #35681 -- Corrected geoip2 docs when describing GeoIP2Exception.

comment:13 by Natalia <124304+nessita@…>, 3 months ago

In d3da505:

[5.1.x] Fixed #35681 -- Corrected geoip2 docs when describing GeoIP2Exception.

Backport of 826ef006681eae1e9b4bd0e4f18fa13713025cba from main.

Note: See TracTickets for help on using tickets.
Back to Top