<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body dir="auto"><div>I'm still reading this and need to play with your examples. But, I think this is EXACTLY what I needed.</div><div><br></div><div>Thank you!!!!<br><br>G</div><div><br>On Feb 12, 2013, at 6:41 PM, Jake Alheid <<a href="mailto:shakefu@gmail.com">shakefu@gmail.com</a>> wrote:<br><br></div><blockquote type="cite"><div>If you want 3rd parties to be able to register runners, then entry points is a good way to go. However, since your example looks like you have control over all the files, you might want to look at runpy (<a href="http://docs.python.org/2/library/runpy.html#runpy.run_module">http://docs.python.org/2/library/runpy.html#runpy.run_module</a>) to import your runner's module dictionary, which can then be called. Something like:<div>
<br></div><div><font face="courier new, monospace">def get_runner(name):</font></div><div><font face="courier new, monospace"> return runpy.run_module('baypiggies.' + name)</font></div><div><font face="courier new, monospace"><br>
</font></div><div><font face="courier new, monospace">get_runner('fruit')['chew']()</font></div><div><div><br></div><div>The documentation is really terrible for setuptools... I can't remember what I originally read that helped me grok what was going.<br>
<div><br></div><div>If you really want to use entry points for this, you want to define it in your setup.py, and do something like:</div><div><br></div><div><font face="courier new, monospace">entry_points = {</font></div>
<div><font face="courier new, monospace"> 'baypiggies':[</font></div><div><font face="courier new, monospace"> 'fruit = baypiggies.fruit',</font></div><div><font face="courier new, monospace"> 'meta = baypiggies.meat',</font></div>
<div><font face="courier new, monospace"> 'mock = baypiggies.mock',</font></div><div><font face="courier new, monospace"> ],</font></div><div><font face="courier new, monospace">},</font></div><div><br>
</div>
<div>This just registers those namespaces (modules in this case) with setuptools/pkg_resources for later consumption. You consume using iter_entry_points:</div><div><br></div><div><font face="courier new, monospace">def get_runner_module(name):</font></div>
<div><font face="courier new, monospace"> """ Return a module for `name`. """</font></div><div><span style="font-family:'courier new',monospace"> # This looks for the first entry point with `name` in the 'baypiggies'</span></div>
<div><font face="courier new, monospace"> for entry in pkg_resources.iter_entry_points('baypiggies', name):</font></div><div><font face="courier new, monospace"> # Return the loaded module or object, or raise ImportError</font></div>
<div><span style="font-family:'courier new',monospace"> return entry.load()</span></div><div><br></div><div>If you don't want the module in sys.modules, use runpy instead, and replace the last line with:</div>
<div><br></div><div><font face="courier new, monospace"> # Return the module's namespace dictionary</font></div><div><font face="courier new, monospace"> return runpy.run_module(entry.module_name)</font></div>
<div><div><div><br></div><div>Of course, using entry_points will also allow third party packages to register with your runner using the 'baypiggies' entry point. You could allow for that, and get a list of all registered names, like:</div>
<div><br></div><div><font face="courier new, monospace">def get_registered_names():</font></div><div><font face="courier new, monospace"> names = []</font></div><div><font face="courier new, monospace"> for entry in pkg_resources.iter_entry_points('baypiggies'):</font></div>
<div><span style="font-family:'courier new',monospace"> names.append(<a href="http://entry.name">entry.name</a>)</span></div><div><font face="courier new, monospace"> return names</font></div><div><br></div>
<div>Hope this helps!</div><div>--</div>Jake Alheid<br><div><a href="http://about.me/jake" target="_blank">http://about.me/jake</a></div></div>
<br><br><div class="gmail_quote">On Tue, Feb 12, 2013 at 5:00 PM, Glen Jarvis <span dir="ltr"><<a href="mailto:glen@glenjarvis.com" target="_blank">glen@glenjarvis.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
I have a directory like this:<div><br><div>baypiggies<br><div><div> - __init__.py</div><div> - fruit.py</div><div> - meat.py</div><div> - mock.py</div><div> - runner.py</div><div><br></div><div>My runner.py is the main entry point and it is used to dynamically chose which of these other files to import.</div>
<div><br></div><div><div># pylint: disable=C0103,R0904</div><div><br></div><div>"""A sample dynamically loaded example with endpoints</div><div><br></div><div>./runner.py --backend=fruit</div><div>"""</div>
<div><br></div><div>from optparse import OptionParser</div><div><br></div><div><br></div><div>entry_points = {</div><div> 'fruit': dict(</div><div> thump = ('fruit', 'thump'),</div><div>
eat = ('fruit', 'eat'),</div>
<div> chew = ('fruit', 'chew'),</div><div> ),</div><div> 'meat': dict(</div><div> thump = ('meat', 'thump'),</div><div> eat = ('meat', 'eat'),</div>
<div> chew = ('meat', 'chew'),</div><div> ),</div><div> 'mock': dict(</div><div> thump = ('mock', 'thump'),</div><div> eat = ('mock', 'eat'),</div>
<div> chew = ('mock', 'chew'),</div><div> ),</div><div> 'custom1': dict(</div><div> thump = ('myns.mypkg.mymodule', 'thump'),</div><div> eat = ('myns.mypkg.mymodule', 'eat'),</div>
<div> chew = ('myns.mypkg.mymodule', 'chew'),</div><div> ),</div><div>}</div><div><br></div></div><div><div>def import_entry_points(entries):</div><div><br></div><div> """Dynamically import the functions for the specified backend</div>
<div><br></div><div> entry_points is a global dictionary whos keys correspond to each</div><div> of the different types of backends that we can support. The variable</div><div> options.backend specifies which of the backends that will be used</div>
<div> during this program run.</div><div><br></div><div> The value of entry_points (for options.backend) is another</div><div> dictionary which map the functions needed to the modules from where</div><div> we will import these modules. We only want to import the backend</div>
<div> modules that will be used (and not have unnecessary dependencies).</div><div><br></div><div> This module will replace the values in this inner dictionary with</div><div> the imported functions. This way, the functions are imported and</div>
<div> available when needed.</div><div> """</div><div><br></div><div> for entry in entries:</div><div> module, name = entries[entry]</div><div> _temp = __import__(module, globals(), locals(), [name], 0)</div>
<div> entries[entry] = getattr(_temp, entry)</div><div><br></div><div><br></div><div>def run(backend="mock"):</div><div> print "Running, backend: ", backend</div><div> import_entry_points(entry_points[backend])</div>
<div><br></div><div> import pprint</div><div> pprint.pprint(entry_points)</div><div><br></div><div> print "THUMPING..."</div><div> entry_points[backend]["thump"]()</div><div><br></div><div>
print "EATING..."</div><div> entry_points[backend]["eat"]()</div><div><br></div><div> print "CHEWING..."</div><div> # Chew five times</div><div> entry_points[backend]["chew"](5)</div>
<div><br></div><div>if __name__ == "__main__":</div><div> parser = OptionParser()</div><div> parser.add_option("-b", "--backend", dest="backend",</div><div> default="mock",</div>
<div> help="Choose which backend to run.")</div><div><br></div><div> (options, args) = parser.parse_args()</div><div> run(options.backend)</div></div><div><br></div><div><br></div><div>
<br></div><div>Now, as you can see, the backends are loaded dynamically depending upon the command line options (let's only import what we need).</div><div><br></div><div><div>prompt> python runner.py </div><div>Running, backend: mock</div>
<div>{'custom1': {'chew': ('myns.mypkg.mymodule', 'chew'),</div><div> 'eat': ('myns.mypkg.mymodule', 'eat'),</div><div> 'thump': ('myns.mypkg.mymodule', 'thump')},</div>
<div> 'fruit': {'chew': ('fruit', 'chew'),</div><div> 'eat': ('fruit', 'eat'),</div><div> 'thump': ('fruit', 'thump')},</div>
<div> 'meat': {'chew': ('meat', 'chew'),</div><div> 'eat': ('meat', 'eat'),</div><div> 'thump': ('meat', 'thump')},</div><div>
'mock': {'chew': <function chew at 0x10c3e1aa0>,</div><div> 'eat': <function eat at 0x10c3e1a28>,</div><div> 'thump': <function thump at 0x10c3e19b0>}}</div>
<div>THUMPING...</div><div>Pretend to thump</div><div>EATING...</div><div>Pretend to eat</div><div>CHEWING...</div><div>Prentend to chew</div></div><div><br></div><div><br></div><div>And, totally new/different backend if I choose the option:</div>
<div><br></div><div><br></div><div><div>Running, backend: fruit</div><div>{'custom1': {'chew': ('myns.mypkg.mymodule', 'chew'),</div><div> 'eat': ('myns.mypkg.mymodule', 'eat'),</div>
<div> 'thump': ('myns.mypkg.mymodule', 'thump')},</div><div> 'fruit': {'chew': <function chew at 0x103a11aa0>,</div><div> 'eat': <function eat at 0x103a11a28>,</div>
<div> 'thump': <function thump at 0x103a119b0>},</div><div> 'meat': {'chew': ('meat', 'chew'),</div><div> 'eat': ('meat', 'eat'),</div>
<div> 'thump': ('meat', 'thump')},</div><div> 'mock': {'chew': ('mock', 'chew'),</div><div> 'eat': ('mock', 'eat'),</div><div>
'thump': ('mock', 'thump')}}</div><div>THUMPING...</div><div>Thumping fruit...</div><div>EATING...</div><div>Eating fruit.. very healthy....</div><div>CHEWING...</div><div>Fruit chew 0</div>
<div>Fruit chew 1</div><div>Fruit chew 2</div><div>Fruit chew 3</div><div>Fruit chew 4</div></div><div><br></div><div><br></div><div><br></div><div>Here are examples of my backends:</div><div><br></div><div><br></div>
<div><br></div><div><br></div><div><div>"""An empty mock (Currently not implemented)"""</div><div><br></div><div><br></div><div>def thump():</div><div><br></div><div> print "Pretend to thump"</div>
<div><br></div><div><br></div><div>def eat():</div><div><br></div><div> print "Pretend to eat"</div><div><br></div><div><br></div><div>def chew(number_of_times):</div><div><br></div><div> print "Prentend to chew"</div>
</div><div><br></div><div><br></div><div><br></div><div><br></div><div>Here's the mock one (by default):</div><div><div><br></div><div><br></div><div>def thump():</div><div><br></div><div> print "Pretend to thump"</div>
<div><br></div><div><br></div><div>def eat():</div><div><br></div><div> print "Pretend to eat"</div><div><br></div><div><br></div><div>def chew(number_of_times):</div><div><br></div><div> print "Prentend to chew"</div>
</div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div>So, I'm supposed to be using entry points from the setuptools library (instead of the above). But, I've googled and get stuck. I just don't see how to use it (and use it without doing a setup each time).:</div>
<div><br></div><div><a href="http://stackoverflow.com/questions/774824/explain-python-entry-points/9615473#9615473" target="_blank">http://stackoverflow.com/questions/774824/explain-python-entry-points/9615473#9615473</a></div>
<div><br></div>
<div>Can someone help me by example? I'm confused... </div><div><br></div><div><br></div><div>Cheers,</div><div><br></div><div><br></div><div>Glen</div><div>--</div>
<p>"Pursue, keep up with, circle round and round your life as a dog does his master's chase. Do what you love. Know your own bone; gnaw at it, bury it, unearth it, and gnaw it still."</p>
<p>--Henry David Thoreau</p>
</div></div></div>
<br>_______________________________________________<br>
Baypiggies mailing list<br>
<a href="mailto:Baypiggies@python.org">Baypiggies@python.org</a><br>
To change your subscription options or unsubscribe:<br>
<a href="http://mail.python.org/mailman/listinfo/baypiggies" target="_blank">http://mail.python.org/mailman/listinfo/baypiggies</a><br></blockquote></div><br></div></div></div>
</div></blockquote></body></html>