Evaluation of class returns false

Rachel W

I have written this class:

class DSMCalc(object):
    def __init__(self, footprint):
        if footprint.__class__.__base__.__module__ is not 'shapely.geometry.base':
            raise TypeError('footprint input geometry is not a shapely geometry based object')
        self.footprint = footprint

As best as I can tell I need to do the whole business of __class__.__base__.__module__ because I am trying to be inclusive of all shapely objects (shapely.geometry.polygon.Polygon and shapely.geometry.multipolygon.MultiPolygon, for example) and that combination of attributes was I found that seemed like it would work, since all the objects that I want to include output shapely.geometry.base.

When I run the code, however, I get a TypeError even when putting in a valid shapely.geometry.polygon.Polygon object. I have tried the above code with shapely.geometry.base both as a string and a module. How can this be?

Some example objects to reproduce the error:

valid_geojson_polygon_feature = {
'properties': {"name":"test"},
'type': 'Feature',
'geometry': {
    'coordinates': [[(-122.4103173469268, 37.78337247419125), (-122.41042064203376, 37.7833590750075),
                     (-122.41046641056752, 37.78360478527359), (-122.41047393562782, 37.783644775039576),
                     (-122.4103759761863, 37.78365638609612), (-122.4103173469268, 37.78337247419125)]],
    'type': 'Polygon'}}

from shapely.geometry import shape as get_shape
valid_shapely_polygon_feature = get_shape(valid_geojson_polygon_feature['geometry'])
print(valid_shapely_polygon_feature.__class__.__base__.__module__)
DSMCalc(valid_shapely_polygon_feature)
ShadowRanger

You can't rely on is working with string literals. Even when it works, it's an implementation detail of CPython, and in this case, even CPython's implementation doesn't support it, because CPython only automatically interns string literals that fit the rules for identifiers (that is, variable names). Your string contains .s, which means it's not automatically interned. You can see this easily at the interactive prompt:

>>> x = 'shapely.geometry.base'  # Not a legal variable name
>>> y = 'shapely.geometry.base'
>>> x is y
False
>>> x = 'abc123'  # Legal variable name
>>> y = 'abc123'
>>> x is y
True

Basically, change your test to != 'shapely.geometry.base', and if you need more details, read up on the difference between is and ==.

I'll note that your test is flawed in other ways. Right now, you require the immediate parent to be defined in shapely.geometry.base. But if you subclass a valid class, the child will be invalid (because the __base__ will refer to the subclass from the other module, not ultimate base class in shapely.geometry.base). A better solution is proper isinstance checking based on known good base classes, e.g.:

# Top of file
from shapely.geometry.base import BaseGeometry, GeometrySequence

# Test code (passing a tuple of legal bases classes is allowed)
if not isinstance(footprint, (BaseGeometry, GeometrySequence)):
    raise TypeError('footprint input geometry is not a shapely geometry based object')

which, on top of being more explicit about what you want (explicitly enumerating legal base classes), and allowing indirect subclasses of the classes in question rather than only direct subclasses of a handful of base classes from that module, avoids allowing spurious types like CAP_STYLE and JOIN_STYLE (which, while defined in shapely.geometry.base, appear to exist largely as simple enum-like classes of constants, not actual geometry related things, and are likely not types you'd want to allow).

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related