views:

57

answers:

3

Hey,

I am trying to rewrite my lib written in PHP into python. It handles all sphinx requests. In the init function, I am trying to set default search and match modes, but I have run into a little problem. I get the modes from a config file.

In PHP, you need to use a constant as an input:

$this->sphinx->SetMatchMode(constant($this->conf['match_mode']));

This will convert the string from config file into a constant and everything works. The tricky part starts in python, when I try to do this:

self.sphinx.SetMatchMode(self.config['match_mode'])

I get:

AssertionError in
assert(mode in [SPH_MATCH_ALL, SPH_MATCH_ANY, SPH_MATCH_PHRASE, SPH_MATCH_BOOLEAN, SPH_MATCH_EXTENDED, SPH_MATCH_FULLSCAN, SPH_MATCH_EXTENDED2]) 

In this case, the input should be an integer, but the input is a string and I cant convert it because I get an exception - the string is SPH_MATCH_ALL.

invalid literal for int() with base 10: 'SPH_MATCH_ALL'

When I try this:

print type(self.config['match_mode']) # -- string
print type(SPH_MATCH_ALL) # -- integer
print SPH_MATCH_ALL # -- 1 
print SPH_MATCH_ANY # -- 0

So my question would be, how can I convert the string into an integer or whatever it thinks it is, so I wont get an assertion error. Of course, that I could just do some if/else statements, but I dont want that. Is there any elegant way to do this?

A: 

Write a function that converts the mode string to the corresponding integer, then use that when you call in the config:

self.sphinx.SetMatchMode(modeToInt(self.config['match_mode']))

You can hive away whatever if/else ugliness is required into the function.

Simon Hibbs
As I said under the assertion error part, I cant convert it as this raises and exception - invalid literal for int() with base 10: 'SPH_MATCH_ANY'
realshadow
Sorry, I figured that out after I posted. I've rewritten with what I hope is a more constructive answer.
Simon Hibbs
Ah, i just read your own edit with mroe info. The problem is that you have SPH_MATCH_ALL defined as a constant, but config is returning a string literal 'SPH_MATCH_ALL'. You could use a dictionary lookup using the string 'SPH_MATCH_ALL' as the key to the required integher value. Then you could write - mode_to_int[self.config['match_mode']]
Simon Hibbs
+1  A: 

I'm not familiar with sphinx, but based on you question, I would try something like this

DEFAULT = 0
mode = getattr(self.sphinx, self.config['match_mode'], DEFAULT)
self.sphinx.SetMatchMode(mode)

That's assuming that the sphinx module defines the modes in the form

SPH_MATCH_ANY = 0
SPH_MATCH_ALL = 1
# ....
lsc
+3  A: 

Python doesn't have a direct equivalent of the PHP constant() function. If the constant in question is imported from a module, the cleanest way to do it is like this:

import myconstants
num = int(getattr(myconstants, self.config['match_mode']))

Or if it's defined at global scope within the current module, you can do this:

X = 1
num = int(globals()['X'])

Either way, you're doing something slightly risky by letting the user control which objects your code deals with. It's not quite eval(), but it's a little way down that road. That's why I've included the int() conversions there - they should fail if the user configures the system with the name of something that isn't an integer. There may be more robust ways to do this - I'm not quite comfortable with it, but it's somewhere close to your PHP constant() code without a complete rewrite.

RichieHindle
Thanks, that was it! (the globals part). User has no access do this, its just that it will be used on multiple servers and not all of them have the same configurations for sphinx.
realshadow
I'd also check that `s.startswith('SPH_MATCH_')`.
tc.