Help me pick an API design (OO vs functional)


M

Michael Herrmann

Hello everyone,

my name is Michael, I'm the lead developer of a Python GUI automation library for Windows called Automa: http://www.getautoma.com. We want to add somefeatures to our library but are unsure how to best expose them via our API.. It would be extremely helpful for us if you could let us know which API design feels "right" to you.

Our API already offers very simple commands for automating the GUI of a Windows computer. For example:

from automa.api import *
start("Notepad")
write("Hello World!")
press(CTRL + 's')
write("test.txt", into="File name")
click("Save")
click("Close")

When you execute this script, Automa starts Notepad and simulates key strokes, mouse movements and clicks to perform the required commands. At the moment, each action is performed in the currently active window.

We do not (yet) have a functionality that allows you to explicitly switch to a specific window. Such a functionality would for instance make it possible to open two Notepad windows using the start(...) command, and copy text between them.

One API design would be to have our start(...) function return a "Window" (say) object, whose methods allow you to do the same operations as the global functions write(...), press(...), click(...) etc., but in the respective window. In this design, the example of operating two Notepad windows could be written as

notepad_1 = start("Notepad")
notepad_2 = start("Notepad")
notepad_1.write("Hello World!")
notepad_1.press(CTRL + 'a', CTRL + 'c')
notepad_2.press(CTRL + 'v')

The problem with this design is that it effectively duplicates our API: We want to keep our "global" functions because they are so easy to read. If weadd methods to a new "Window" class that do more or less the same, we feelthat we are violating Python's principle that "There should be one - and preferably only one - obvious way to do it."

An alternative design would be to make the window switching an explicit action. One way of doing this would be to add a new global function, say "switch_to" or "activate", that takes a single parameter that identifies the window to be switched to. We could still have start(...) return a Window object, that could then be passed to our function:

notepad_1 = start("Notepad")
notepad_2 = start("Notepad")
switch_to(notepad_1)
write("Hello World!")
press(CTRL + 'a', CTRL + 'c')
switch_to(notepad_2)
press(CTRL + 'v')

Maybe our Window objects could also be used as context managers:

notepad_1 = start("Notepad")
notepad_2 = start("Notepad")
with notepad_1:
write("Hello World!")
press(CTRL + 'a', CTRL + 'c')
with notepad_2:
press(CTRL + 'v')

As a final idea, switching could also be done as a method of the Window class:

notepad_1 = start("Notepad")
notepad_2 = start("Notepad")
notepad_1.activate()
write("Hello World!")
press(CTRL + 'a', CTRL + 'c')
notepad_2.activate()
press(CTRL + 'v')

It would be extremely helpful for us if you could let me know which way of using the API you would prefer. If you opt for an explicit version, how would you call the respective method? "activate" / "switch_to" / "focus" or something else?

Thank you so much!

Best wishes,
Michael
 
Ad

Advertisements

K

Kwpolska

notepad_1 = start("Notepad")
notepad_2 = start("Notepad")
notepad_1.write("Hello World!")
notepad_1.press(CTRL + 'a', CTRL + 'c')
notepad_2.press(CTRL + 'v')

Explicit is better than implicit. Changing windows should be explicit
and not implified by your library.
notepad_1 = start("Notepad")
notepad_2 = start("Notepad")
switch_to(notepad_1)
write("Hello World!")
press(CTRL + 'a', CTRL + 'c')
switch_to(notepad_2)
press(CTRL + 'v')

Much better.
notepad_1 = start("Notepad")
notepad_2 = start("Notepad")
with notepad_1:
write("Hello World!")
press(CTRL + 'a', CTRL + 'c')
with notepad_2:
press(CTRL + 'v')

That’s ugly, and don’t forget that your users aren’t Pythonistas most
of the time.
notepad_1 = start("Notepad")
notepad_2 = start("Notepad")
notepad_1.activate()
write("Hello World!")
press(CTRL + 'a', CTRL + 'c')
notepad_2.activate()
press(CTRL + 'v')

That is nice and makes sense, because a global function feels wrong,
at least for me.
It would be extremely helpful for us if you could let me know which way of using the API you would prefer. If you opt for an explicit version, how would you call the respective method? "activate" / "switch_to" / "focus" or something else?

Window().focus() is the best IMO.

PS. do you plan a version for non-Windows OSes? Also, €99 is too expensive.
 
M

Michael Herrmann

Hi Kwpolska,

thanks for your reply (as last time I posted here!).

...


That’s ugly, and don’t forget that your users aren’t Pythonistas most
of the time.

I kind of like the context manager solution because the indentation makes it very obvious what happens in which window. You are right about our targetgroup though. Also, the "with" is not as explicit as it probably should be..
...
PS. do you plan a version for non-Windows OSes? Also, €99 is too expensive.

We'd of course love to support other platforms but don't currently have theresources to do this. We actually just wrote a blog entry about this and some related questions: http://www.getautoma.com/blog/automa-faq If we have something wrong, do let us know in the comments over there!

It's very hard work building such an automation tool and also we have to live off something. Unfortunately, we can't make the price any lower.

P.S.: First-time bottom-posting!
 
M

Michael Herrmann

Hi Kwpolska,

thanks for your reply (as last time I posted here!).

...


That’s ugly, and don’t forget that your users aren’t Pythonistas most
of the time.

I kind of like the context manager solution because the indentation makes it very obvious what happens in which window. You are right about our targetgroup though. Also, the "with" is not as explicit as it probably should be..
...
PS. do you plan a version for non-Windows OSes? Also, €99 is too expensive.

We'd of course love to support other platforms but don't currently have theresources to do this. We actually just wrote a blog entry about this and some related questions: http://www.getautoma.com/blog/automa-faq If we have something wrong, do let us know in the comments over there!

It's very hard work building such an automation tool and also we have to live off something. Unfortunately, we can't make the price any lower.

P.S.: First-time bottom-posting!
 
C

Chris Angelico

I kind of like the context manager solution because the indentation makesit very obvious what happens in which window. You are right about our target group though. Also, the "with" is not as explicit as it probably should be.

What happens at the __exit__ of the context manager? What happens if
context managers are nested? I'd be inclined to the simpler option of
an explicit switch (since focus doesn't really "stack" and it'd feel
weird for focus to *sometimes* switch away when you're done working
with one window), though the context manager syntax does have its
advantages too.
We'd of course love to support other platforms but don't currently have the resources to do this. We actually just wrote a blog entry about this andsome related questions: http://www.getautoma.com/blog/automa-faq If we have something wrong, do let us know in the comments over there!

Make the API clean enough and someone else might well write a Linux
equivalent. Then it'll be as simple as a try/import/except/import at
the top and multiple platforms will work.
P.S.: First-time bottom-posting!

Congrats! Feels good, doesn't it :)

ChrisA
 
E

Ethan Furman

Hello everyone,

my name is Michael, I'm the lead developer of a Python GUI automation library for Windows called Automa: http://www.getautoma.com. We want to add some features to our library but are unsure how to best expose them via our API. It would be extremely helpful for us if you could let us know which API design feels "right" to you.

Our API already offers very simple commands for automating the GUI of a Windows computer. For example:

from automa.api import *
start("Notepad")
write("Hello World!")
press(CTRL + 's')
write("test.txt", into="File name")
click("Save")
click("Close")

When you execute this script, Automa starts Notepad and simulates key strokes, mouse movements and clicks to perform the required commands. At the moment, each action is performed in the currently active window.

We do not (yet) have a functionality that allows you to explicitly switch to a specific window. Such a functionality would for instance make it possible to open two Notepad windows using the start(...) command, and copy text between them.

One API design would be to have our start(...) function return a "Window" (say) object, whose methods allow you to do the same operations as the global functions write(...), press(...), click(...) etc., but in the respective window. In this design, the example of operating two Notepad windows could be written as

notepad_1 = start("Notepad")
notepad_2 = start("Notepad")
notepad_1.write("Hello World!")
notepad_1.press(CTRL + 'a', CTRL + 'c')
notepad_2.press(CTRL + 'v')

This is the way to go. Just move your global functions into the Window object (or whatever you call it), break
backwards compatibility (major version number change, perhaps?), and call it good.

It makes much more sense to call methods of several different objects (which is explicit -- you always know which object
is being used) than having a magic function that changes the object in the background (plus you now have to search
backwards for the last magic invocation to know -- and what if a called function changes it?).
 
Ad

Advertisements

M

Mitya Sirenef

Hello everyone,

my name is Michael, I'm the lead developer of a Python GUI automation library for Windows called Automa: http://www.getautoma.com. We want to add some features to our library but are unsure how to best expose them via our API. It would be extremely helpful for us if you could let us know which API design feels "right" to you.

Our API already offers very simple commands for automating the GUI of a Windows computer. For example:

from automa.api import *
start("Notepad")
write("Hello World!")
press(CTRL + 's')
write("test.txt", into="File name")
click("Save")
click("Close")

When you execute this script, Automa starts Notepad and simulates key strokes, mouse movements and clicks to perform the required commands. At the moment, each action is performed in the currently active window.

We do not (yet) have a functionality that allows you to explicitly switch to a specific window. Such a functionality would for instance make it possible to open two Notepad windows using the start(...) command, and copy text between them.

One API design would be to have our start(...) function return a "Window" (say) object, whose methods allow you to do the same operations as the global functions write(...), press(...), click(...) etc., but in the respective window. In this design, the example of operating two Notepad windows could be written as

notepad_1 = start("Notepad")
notepad_2 = start("Notepad")
notepad_1.write("Hello World!")
notepad_1.press(CTRL + 'a', CTRL + 'c')
notepad_2.press(CTRL + 'v')

The problem with this design is that it effectively duplicates our API: We want to keep our "global" functions because they are so easy to read. If we add methods to a new "Window" class that do more or less the same, we feel that we are violating Python's principle that "There should be one - and preferably only one - obvious way to do it."

An alternative design would be to make the window switching an explicit action. One way of doing this would be to add a new global function, say "switch_to" or "activate", that takes a single parameter that identifies the window to be switched to. We could still have start(...) return a Window object, that could then be passed to our function:

notepad_1 = start("Notepad")
notepad_2 = start("Notepad")
switch_to(notepad_1)
write("Hello World!")
press(CTRL + 'a', CTRL + 'c')
switch_to(notepad_2)
press(CTRL + 'v')

Maybe our Window objects could also be used as context managers:

notepad_1 = start("Notepad")
notepad_2 = start("Notepad")
with notepad_1:
write("Hello World!")
press(CTRL + 'a', CTRL + 'c')
with notepad_2:
press(CTRL + 'v')

As a final idea, switching could also be done as a method of the Window class:

notepad_1 = start("Notepad")
notepad_2 = start("Notepad")
notepad_1.activate()
write("Hello World!")
press(CTRL + 'a', CTRL + 'c')
notepad_2.activate()
press(CTRL + 'v')

It would be extremely helpful for us if you could let me know which way of using the API you would prefer. If you opt for an explicit version, how would you call the respective method? "activate" / "switch_to" / "focus" or something else?

Thank you so much!

Best wishes,
Michael


I think I would prefer context managers. I don't think it's a big
problem for
win users because this behaviour would be one of the first things documented
in the start guide and would be all over example scripts, so a new user
missing
or forgetting it is not a realistic scenario.

The advantages are that it's explicit, blocks are indented and it's
impossible to
miss which window is the action applied to, and at the same time actions are
short and easy to type and read.

-m
 
M

Michael Herrmann

...

What happens at the __exit__ of the context manager? What happens if
context managers are nested? I'd be inclined to the simpler option of
an explicit switch (since focus doesn't really "stack" and it'd feel
weird for focus to *sometimes* switch away when you're done working
with one window), though the context manager syntax does have its
advantages too.

You are right, an __exit__ for a window doesn't really make sense and neither does stacking. There's also the problem that the focus window may change- for instance when closing it. What happens if you're still inside the "with ..." then? At first glance, I think the context manager solution looks nice syntactically, but maybe it isn't the way to go here.
...



Make the API clean enough and someone else might well write a Linux
equivalent. Then it'll be as simple as a try/import/except/import at
the top and multiple platforms will work.

Yes, that's a good point. A clean API is very important to us (hence my posting here).

Thanks for your answer!
Michael
 
M

Michael Herrmann

On 03/25/2013 12:29 PM, Michael Herrmann wrote:
...

This is the way to go. Just move your global functions into the Window object (or whatever you call it), break
backwards compatibility (major version number change, perhaps?), and callit good.

It makes much more sense to call methods of several different objects (which is explicit -- you always know which object
is being used) than having a magic function that changes the object in the background (plus you now have to search
backwards for the last magic invocation to know -- and what if a called function changes it?).

Your points are valid and I cannot really say anything against them. The problem with moving all global functions into the Window object is that this adds a lot of syntactic baggage that isn't needed in 90% of the cases. We really prefer the simplicity of

start("Notepad")
write("Hello World!")
press(CTRL + 's')
write("test.txt", into="File name")
click("Save")
press(ALT + F4)

over

notepad = start("Notepad")
notepad.write("Hello World!")
notepad.press(CTRL + 's')
notepad.write("test.txt", into="File name")
notepad.click("Save")
notepad.press(ALT + F4).

Also, there's a problem here: The "Save" dialogue that opens in the above script is technically a different window so in theory you would have to introduce a new object to distinguish between the original window that lets youedit your text document from the "Save" window. This is very tedious and error-prone. You are right, though, that we have to do some logic in the background to remember the last window.

In light of this, could you live with something along the lines of design #4?

notepad_1 = start("Notepad")
notepad_2 = start("Notepad")
notepad_1.focus()
write("Hello World!")
press(CTRL + 'a', CTRL + 'c')
notepad_2.focus()
press(CTRL + 'v')

Thanks,
Michael
 
M

Michael Herrmann

...

I think I would prefer context managers. I don't think it's a big
problem for
win users because this behaviour would be one of the first things documented
in the start guide and would be all over example scripts, so a new user
missing
or forgetting it is not a realistic scenario.

The advantages are that it's explicit, blocks are indented and it's
impossible to
miss which window is the action applied to, and at the same time actions are
short and easy to type and read.

Thank you for your reply. What do you think of Chris Angelico's points?
He said:
What happens at the __exit__ of the context manager? What happens if
context managers are nested? I'd be inclined to the simpler option of
an explicit switch (since focus doesn't really "stack" and it'd feel
weird for focus to *sometimes* switch away when you're done working
with one window), though the context manager syntax does have its
advantages too.

What I am most afraid of: that the window that's currently the context "disappears":
notepad = start("Notepad")
with notepad:
press(ALT + TAB)
write("Am I in Notepad now?")

What do you think of designs #3 and #4?

notepad_1 = start("Notepad")
notepad_2 = start("Notepad")
switch_to(notepad_1)
write("Hello World!")
press(CTRL + 'a', CTRL + 'c')
switch_to(notepad_2)
press(CTRL + 'v')

notepad_1 = start("Notepad")
notepad_2 = start("Notepad")
notepad_1.activate()
write("Hello World!")
press(CTRL + 'a', CTRL + 'c')
notepad_2.activate()
press(CTRL + 'v')

I somehow prefer "activate" over "focus" as in my feeling, you'd normally say that you focus *on* something, so it should be called "focus_on" or "give_focus[_to]". Can you say, in everyday English, that you "focus a window"?I'm not a native speaker so maybe my feeling is misguided.

Thanks,
Michael
 
D

Dave Angel

Your points are valid and I cannot really say anything against them. The problem with moving all global functions into the Window object is that this adds a lot of syntactic baggage that isn't needed in 90% of the cases. We really prefer the simplicity of

start("Notepad")
write("Hello World!")
press(CTRL + 's')
write("test.txt", into="File name")
click("Save")
press(ALT + F4)

over

notepad = start("Notepad")
notepad.write("Hello World!")
notepad.press(CTRL + 's')
notepad.write("test.txt", into="File name")
notepad.click("Save")
notepad.press(ALT + F4).

Also, there's a problem here: The "Save" dialogue that opens in the above script is technically a different window so in theory you would have to introduce a new object to distinguish between the original window that lets you edit your text document from the "Save" window. This is very tedious and error-prone. You are right, though, that we have to do some logic in the background to remember the last window.

In light of this, could you live with something along the lines of design #4?

notepad_1 = start("Notepad")
notepad_2 = start("Notepad")
notepad_1.focus()
write("Hello World!")
press(CTRL + 'a', CTRL + 'c')
notepad_2.focus()
press(CTRL + 'v')

Thanks,
Michael

Seems to me that the official interface should all be methods. However,
you could have a new object which always represents the "focus" window.
Then the USER could define trivial functions:

def write(*args):
focused.write(*args)

Somewhere in this thread you mention that save() creates a new window,
so a method-oriented approach would require that the user get that
window object, and call its methods rather than the original window's.
I say that's a very good thing, since the things you send may very well
have very different meanings to the save dialog than they do in the
original one.

Another concern I'd have is what happens if the user changes focus with
his mouse? Does that change the meaning you had for focus() in the
above exchange? Do you want your press() method to apply to a different
window when the user changes to that window?
 
Ad

Advertisements

C

Chris Angelico

You are right, an __exit__ for a window doesn't really make sense and neither does stacking. There's also the problem that the focus window may change - for instance when closing it. What happens if you're still inside the "with ..." then? At first glance, I think the context manager solution looks nice syntactically, but maybe it isn't the way to go here.

Fundamental point: As I understand the API, it doesn't *actually* tie
to a window. You don't locate the Notepad window and send it keys -
you switch focus to Notepad and then send keys to the whole system. Is
this correct? I'm basing my understanding on this paragraph from your
original post:
We do not (yet) have a functionality that allows you to explicitly switchto a
specific window. Such a functionality would for instance make it possibleto
open two Notepad windows using the start(...) command, and copy text
between them.

If so, then all of the method-based options are effectively lying,
because they imply a binding that's not there. The actual sequence of
actions includes imperatives of "switch to some other window", so I
think that's what the API should reflect. Otherwise, there's risk that
something will get horribly horribly confused between the programmer's
brain and the end result (which could happen on either side of your
code).

But if you can unambiguously identify a running instance of something
and switch to it, then a method on the object that start() returns
would be absolutely correct. So I'd be looking at either your second
or fourth options from the original post.

ChrisA
 
C

Chris Angelico

What do you think of designs #3 and #4?

notepad_1 = start("Notepad")
notepad_2 = start("Notepad")
switch_to(notepad_1)
write("Hello World!")
press(CTRL + 'a', CTRL + 'c')
switch_to(notepad_2)
press(CTRL + 'v')

notepad_1 = start("Notepad")
notepad_2 = start("Notepad")
notepad_1.activate()
write("Hello World!")
press(CTRL + 'a', CTRL + 'c')
notepad_2.activate()
press(CTRL + 'v')

Ehh, I referred to these as options 2 and 4. Got lost in the indexing
somewhere. These are the same two I meant, though - these are the
options I think are the most plausible.

(Hindsight being 20/20, it'd have been awesome if the original
snippets had had identifiers next to them. Oh well, no matter.)

ChrisA
 
M

Michael Herrmann

----- Original Message -----

So is the example above. This is the best solution in my opinion.

Thanks for your reply. What do you mean by "So is the example above" though?
I think you're having the same issue that some other APIs, let's say matplotlib for example. They try to accommodate scientists (matlab) and programmers(python) by having a double API style.

One looks like

legend()
title()
plot()
save()

the other looks like

fig = figure()
fig.add_legend()
fig.title()
fig.plot()
fig.save()

The problem is, when searching for example on the net, you'll end up witha mix of both, it can become a nightmare.

Interesting point. I'll google a little about matplotlib.
I definitely prefer the later, for the reasons that have already been given to you in this thread and by the fact that with the correct (I)python shell, you can create your window object and get auto-completion on its methods just by hitting <tab>, very helpful when introspecting objects. Can be achieved of course in any python shell with function like dir() ; my point being that OOO design keeps things in their place, see the zen of python "Namespaces are one honking great idea -- let's do more of those!"

Doesn't the IPython do auto-completion for "global" functions?

Thanks,
Michael (www.getautoma.com)
 
M

Michael Herrmann

----- Original Message -----

So is the example above. This is the best solution in my opinion.

Thanks for your reply. What do you mean by "So is the example above" though?
I think you're having the same issue that some other APIs, let's say matplotlib for example. They try to accommodate scientists (matlab) and programmers(python) by having a double API style.

One looks like

legend()
title()
plot()
save()

the other looks like

fig = figure()
fig.add_legend()
fig.title()
fig.plot()
fig.save()

The problem is, when searching for example on the net, you'll end up witha mix of both, it can become a nightmare.

Interesting point. I'll google a little about matplotlib.
I definitely prefer the later, for the reasons that have already been given to you in this thread and by the fact that with the correct (I)python shell, you can create your window object and get auto-completion on its methods just by hitting <tab>, very helpful when introspecting objects. Can be achieved of course in any python shell with function like dir() ; my point being that OOO design keeps things in their place, see the zen of python "Namespaces are one honking great idea -- let's do more of those!"

Doesn't the IPython do auto-completion for "global" functions?

Thanks,
Michael (www.getautoma.com)
 
C

Chris Angelico

Doesn't the IPython do auto-completion for "global" functions?

Even if it does, it'll be polluted with every other global. Methods
don't have that problem. On the flip side, since presumably this is
(will be) a module, anyone who wants autocomplete of its top-level
functions can simply "import module" instead of "from module import
*", which will do the same namespacing.

ChrisA
 
Ad

Advertisements

M

Michael Herrmann

...
Seems to me that the official interface should all be methods. However,
you could have a new object which always represents the "focus" window.
Then the USER could define trivial functions:

def write(*args):
focused.write(*args)

It's an interesting idea. But why not give this write(...) to them in the first place? Am I the only one who appreciates the simplicity of

start("Notepad")
write("Hello World!")
press(CTRL + 's')
write("test.txt", into="File name")
click("Save")
press(ALT + F4)

over

notepad = start("Notepad")
notepad.write("Hello World!")
notepad.press(CTRL + 's')
notepad.write("test.txt", into="File name")
notepad.click("Save")
notepad.press(ALT + F4)?
Somewhere in this thread you mention that save() creates a new window,
so a method-oriented approach would require that the user get that
window object, and call its methods rather than the original window's.
I say that's a very good thing, since the things you send may very well
have very different meanings to the save dialog than they do in the
original one.

save() is not a function, but I assume you mean the action that opens the "Save" dialogue (I think that'd be `press(CTRL + 's')`). You are right that it's nice for it to be explicit. However, in 95% of cases, the window you want the next action to be performed in is the window that is currently active. I appreciate the explicitness, but to force it on the user for only 5% of cases seems a bit much.
Another concern I'd have is what happens if the user changes focus with
his mouse? Does that change the meaning you had for focus() in the
above exchange? Do you want your press() method to apply to a different
window when the user changes to that window?

No. Internally, we remember which window is the currently active window. Ifyou just run a script without user-intervention, this will be the respective foreground window. If some other window is in the foreground - which most typically happens when the user is interactively entering commands one after the other, so the foreground window is the console window, we do switchto the window that's supposed to be the active one. It may sound like black magic, but it works very well in practice, and really is not too ambiguous. When you read a script like

start("Notepad")
write("Hello World")
press(CTRL + 's')
write("test.txt", into="File name")
click("Save")
click("Close")

I hold that you intuitively know what's going on, without even thinking about window switching.

Best,
Michael
www.getautoma.com
 
M

Michael Herrmann

...
Fundamental point: As I understand the API, it doesn't *actually* tie
to a window. You don't locate the Notepad window and send it keys -
you switch focus to Notepad and then send keys to the whole system. Is
this correct? I'm basing my understanding on this paragraph from your
original post:


If so, then all of the method-based options are effectively lying,
because they imply a binding that's not there. The actual sequence of
actions includes imperatives of "switch to some other window", so I
think that's what the API should reflect. Otherwise, there's risk that
something will get horribly horribly confused between the programmer's
brain and the end result (which could happen on either side of your
code).

As I just wrote in my reply to Dave, internally we know very well which window an action is to be performed in. This window is the window that'd be inthe foreground after the previous action, if nothing interferes with the system while the script is being executed. A common exception is when you enter commands in the interactive interpreter: say you write

The Notepad window opens, but for you to enter the next command, you have to switch back to the interpreter window. If you do that, and enter

then we remember that you were previously working with the Notepad window and activate this window before performing the key strokes to type "Hello World".
But if you can unambiguously identify a running instance of something
and switch to it, then a method on the object that start() returns
would be absolutely correct. So I'd be looking at either your second
or fourth options from the original post.

Those are also my favorites at the moment :)

Michael
www.getautoma.com
 
M

Michael Herrmann

...
Fundamental point: As I understand the API, it doesn't *actually* tie
to a window. You don't locate the Notepad window and send it keys -
you switch focus to Notepad and then send keys to the whole system. Is
this correct? I'm basing my understanding on this paragraph from your
original post:


If so, then all of the method-based options are effectively lying,
because they imply a binding that's not there. The actual sequence of
actions includes imperatives of "switch to some other window", so I
think that's what the API should reflect. Otherwise, there's risk that
something will get horribly horribly confused between the programmer's
brain and the end result (which could happen on either side of your
code).

As I just wrote in my reply to Dave, internally we know very well which window an action is to be performed in. This window is the window that'd be inthe foreground after the previous action, if nothing interferes with the system while the script is being executed. A common exception is when you enter commands in the interactive interpreter: say you write

The Notepad window opens, but for you to enter the next command, you have to switch back to the interpreter window. If you do that, and enter

then we remember that you were previously working with the Notepad window and activate this window before performing the key strokes to type "Hello World".
But if you can unambiguously identify a running instance of something
and switch to it, then a method on the object that start() returns
would be absolutely correct. So I'd be looking at either your second
or fourth options from the original post.

Those are also my favorites at the moment :)

Michael
www.getautoma.com
 
Ad

Advertisements

M

Michael Herrmann

On Tue, Mar 26, 2013 at 8:38 PM, Michael Herrmann




Ehh, I referred to these as options 2 and 4. Got lost in the indexing
somewhere. These are the same two I meant, though - these are the
options I think are the most plausible.

(Hindsight being 20/20, it'd have been awesome if the original
snippets had had identifiers next to them. Oh well, no matter.)

True, and the indexing mistake was my fault... Here goes:

Design #1:
notepad_1 = start("Notepad")
notepad_2 = start("Notepad")
notepad_1.write("Hello World!")
notepad_1.press(CTRL + 'a', CTRL + 'c')
notepad_2.press(CTRL + 'v')

Design #2:
notepad_1 = start("Notepad")
notepad_2 = start("Notepad")
switch_to(notepad_1)
write("Hello World!")
press(CTRL + 'a', CTRL + 'c')
switch_to(notepad_2)
press(CTRL + 'v')

Design #3:
notepad_1 = start("Notepad")
notepad_2 = start("Notepad")
with notepad_1:
write("Hello World!")
press(CTRL + 'a', CTRL + 'c')
with notepad_2:
press(CTRL + 'v')

Design #4:
notepad_1 = start("Notepad")
notepad_2 = start("Notepad")
notepad_1.activate()
write("Hello World!")
press(CTRL + 'a', CTRL + 'c')
notepad_2.activate()
press(CTRL + 'v')

Michael
www.getautoma.com
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top