jmespath.py icon indicating copy to clipboard operation
jmespath.py copied to clipboard

Matching against objects derived from base collection types

Open Derfies opened this issue 6 years ago • 1 comments

I would like to use this library to match against values derived like collections.MutableSequence and collections.MutableMapping. For example:

` import collections

import jmespath

class MySequence( collections.MutableSequence ):

def __init__( self, data ):
	self.data = data

def __delitem__( self, index ):
	del self.data[index]

def __getitem__( self, index ):
	return self.data[index]

def __len__( self ):
	return len( self.data )

def __setitem__( self, index, value ):
	self.data[index] = value

def insert( self, index, value ):
	self.data.insert( index, value )

data = [ {"name": "Seattle", "state": "WA"}, {"name": "New York", "state": "NY"}, {"name": "Bellevue", "state": "WA"}, {"name": "Olympia", "state": "WA"} ]

print jmespath.compile( '[0]' ).search( data ) # --> {'state': 'WA', 'name': 'Seattle'} print jmespath.compile( '[0]' ).search( MySequence( data ) ) # --> None ` It seems like this should be doable by changing all instances of isinstance( foo, list ) to isinstance( foo, collections.MutableSequence ), as this will return True for the default list type.

Derfies avatar Jun 20 '18 01:06 Derfies

I agree that this would be a great change (and while we're at it, using collections.abc.Sequence rather than MutableSequence).

For the time being, though, I've found a suitable workaround by just having my custom collection classes inherit from the python builtin as well as the collections base class. In your example:

class MySequence( collections.MutableSequence, list):
  def __init__( self, data ):
	  self.data = data
  
  def __delitem__( self, index ):
	  del self.data[index]
  
  def __getitem__( self, index ):
	  return self.data[index]
  
  def __len__( self ):
	  return len( self.data )
  
  def __setitem__( self, index, value ):
	  self.data[index] = value
  
  def insert( self, index, value ):
	  self.data.insert( index, value )

If the relevant class definitions are in code you can't modify (e.g. someone else's library), and you don't mind doing something gnarly, you can monkey-patch the collections class before the rest of your imports:

import collections.abc
class CompatibleSequence(collections.abc.MutableSequence, list):
    ...
collections.abc.MutableSequence = CompatibleSequence

import PackageThatProvidesCollectionsYouWantToNavigateWithJMESPath

Both strategies result in the print statements at the bottom of the example printing the desired output.

naclomi avatar Dec 30 '22 02:12 naclomi