-1

I create a lib which can be imported and used as is, and there is also a start script, which creates a single instance of the main class for use within the script:

# read config, init stuff, and then create an instance

r = RepoClient(config)

Now, the start script accepts a 'command' argument, and as of now, it must be invoke like:

repo config.json -c 'r.ls()'

i.e. the 'r' variable must be used.

I would like to be able to drop the 'r' variable. For that, the start script, somehow, needs the ls function. I can do it by putting the following in the script, after the r instance is created:

ls = r.ls

etc. for all the commands the RepoClient class supports.

Is there anything automatic? The code below doesn't work, of course, but you get the idea:

from r import *

What I can think of is annotating methods with a custom @command annotation, iterating over all the methods and checking for it and if found, setting it as a script global, but hopefully the batteries do support something like this already ;d

EDIT: for now, the command passed as the last argument is run the following way:

exec(sys.argv[2])
wujek
  • 10,112
  • 12
  • 52
  • 88
  • why not: ```def ls(*args, **kargs): return r.ls(*args, **kargs)```? – Alleo May 09 '16 at 19:21
  • Because I have to write all that code. And it is exactly the same as `ls = r.ls` (at least I think so, I'm not a Python pro). The `r` instance has quite a few commands similar to `ls`, and I would have to perform such an assignment for each one. Then, if I add a new command/method, I have to remember to add it to the script globals as well - error prone stuff, which should be automized. – wujek May 09 '16 at 19:23
  • Do you really need the command string you pass to your script to be the same as what names are looked up the module namespace? I think you could make it so `ls()` just looks the names up in the instance namespace, rather than copying the instance namespace into the module namespace. – BrenBarn May 09 '16 at 19:26
  • @wujek ah, ok. I believe that http://stackoverflow.com/questions/7268643/package-specific-import-hooks-in-python can be helpful – Alleo May 09 '16 at 19:26
  • It's hard to understand what you're trying to *achieve*, out of context; I suspect an [XY problem](http://meta.stackexchange.com/q/66377/248731). – jonrsharpe May 09 '16 at 19:27
  • @BrenBarn How can I do that? Just to be clear, `ls` is a method of `RepoClient`, as is `mkdir`, `find`, `cd` etc. The script invocation could be: `repo config.json 'r.find("test/bla")`, `ls` is just a basic example. – wujek May 09 '16 at 19:29
  • I think you want argparse subcommands. See here: http://stackoverflow.com/questions/8368110/python-argparse-subcommand-subcommand – aghast May 09 '16 at 19:31
  • @jonrsharpe I think the question is pretty clear: I'm asking how to 'copy' all methods from an instance to the global namespace of the script r is defined in, so that I can omit the `r.` part. I can do this in other languages, like for example Groovy, and the result is a nice DSL. – wujek May 09 '16 at 19:32
  • @wujek then use Groovy! Without an explanation of what you are actually trying to do, it's hard to make sensible suggestions. – jonrsharpe May 09 '16 at 19:33
  • @jonrsharpe Sorry, but what is not clear? I want to be able to pass the command `ls()` to the script instead of `r.ls()`, i.e. I somehow want to get rid of the `r`. I know I can manually copy the functions to the globals in the script; I know I can use argparse etc I' asking wthether Python supports something like `from r import *` to just copy all the methods to the global scope, like is possible for modules. 'Use Groovy' is not a solution as it has to be Python, period. – wujek May 09 '16 at 19:36
  • @wujek: You'd need to show *how* your start script is taking that command string and running it. – BrenBarn May 09 '16 at 19:38
  • *"I' asking wthether [sic] Python supports something like `from r import *` to just copy all the methods to the global scope"* - then the answer is no, you can't import the methods out of an instance. – jonrsharpe May 09 '16 at 19:39
  • @BrenBarn Done in an edit (it's just an exec() call). – wujek May 09 '16 at 19:41
  • @jonrsharpe Yes, I know that this syntax does't work. Is there anything else I could try, or is my idea of iterating over the methods and just copying them into the global space the way to do it? Just for information: in Groovy I would implement the `def getProperty(...)` method, which is invoked for any missing property of the instance it is defined in (scripts are Script instances), and it could look it up in the `r` instance. Does Python have something along these lines? – wujek May 09 '16 at 19:43

1 Answers1

1

No, there is no way to do that "automatically". However, you don't actually need to copy the items into the global namespace. You can pass a namespace to exec to use. You could give your RepoClient a __getitem__ method, allowing it to act as a namespace. Here's a simple example:

class Foo(object):
    def blah(self):
        print("Blah!")

    def __getitem__(self, attr):
        return getattr(self, attr)

f = Foo()

exec('blah()', globals(), f)

It outputs Blah!.

BrenBarn
  • 242,874
  • 37
  • 412
  • 384
  • This is good. I can even define the `__getitem__` method in the script and add it to the Foo class by `Foo.__getitem__ = lambda self, name: getattr(self, name)` and it still works. – wujek May 09 '16 at 19:55