Skip to content

feat: allow to add a command dynamically#608

Merged
KazuCocoa merged 11 commits intoappium:masterfrom
KazuCocoa:add-command
Jun 6, 2021
Merged

feat: allow to add a command dynamically#608
KazuCocoa merged 11 commits intoappium:masterfrom
KazuCocoa:add-command

Conversation

@KazuCocoa
Copy link
Copy Markdown
Member

Appium 2.0 will allow custom drivers/plugins add their own endpoint.
Then, we want to allow clients to add custom commands for them.

In Ruby, I've added like https://github.com/appium/ruby_lib_core/blob/b9f015d7dea14964a0733f2385ebcff68da1e18e/test/unit/android/webdriver/w3c/commands_test.rb#L31-L98 as an experimental method. (The method was already used internally, so as Ruby client, it was just exposed the method as a public method.)

In Python, I've added two methods. add_command and execute_custom_command.

add_command adds the pair of HTTP method and a path in self.command_executor._commands.
execute_custom_command calls a method from self.command_executor._commands as self.execute.
We want to hide self.execute and self.command_executor since they are for internal usage so far. They may change by updating selenium library, for instance.

# add commands
driver.add_command(method='POST', url='session/$sessionId/path/to/custom/url', name='test_command')

def do_command():
    # some logic for arguments
    return_value = driver.execute_custom_command('test_command', arguments)
    # dom some process for the return value
    return result

driver.custom_my_command = do_command
...
result = driver.custom_my_command()  # just call it
...

I considered decoration way, but so far, this exposing two methods as public methods are simpler I think.

What do you think?
Your thought is welcome such as better naming etc.

@KazuCocoa KazuCocoa changed the title feat: allow to add command dynamically feat: allow to add a command dynamically Jun 5, 2021
raise ValueError("{} is already defined".format(name))

if not isinstance(method, CommandMethod):
raise ValueError("'{}' is invalid. Valid method is in '{}'.".format(method, CommandMethod.__name__))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...should be one of ...

Copy link
Copy Markdown
Contributor

@mykola-mokhnach mykola-mokhnach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to mention this feature in the driver documentation somewhere

@KazuCocoa KazuCocoa merged commit b4c15e2 into appium:master Jun 6, 2021
@KazuCocoa KazuCocoa deleted the add-command branch June 6, 2021 21:22
@jlipps
Copy link
Copy Markdown
Member

jlipps commented Jun 7, 2021

this is fantastic @KazuCocoa! one question: so let's say I wanted to create a client sidecar module for people using my custom driver. I could instruct my users to do something like this:

from appium import webdriver
from mydriver_client import update_driver

driver = webdriver.Remote(...)
update_driver(driver)
result = driver.my_custom_command(args)

or, if I wanted to wrap the entire lib, I could do:

from mydriver_client import webdriver
driver = webdriver.Remote(...)
result = driver.my_custom_command(args)

as the client extension library author I could easily provide both interfaces. The latter interface is more concise, but the former interface could be used if there are multiple client extensions that need to be applied to the driver.

i guess one other thought I have: is there any reason for us to standardize the extension interface to make it easy for extension authors and users? so we could do something like this from an end user perspective:

from appium import webdriver
import client_ext1
import client_ext2

driver = webdriver.Remote(..., extensions=[client_ext1, client_ext2])
driver.custom_command_from_ext1()
driver.custom_command_from_ext2()

so that our appium client code knows how to extract command information from the 3rd party client extensions.

what do you think @KazuCocoa @mykola-mokhnach?

@KazuCocoa
Copy link
Copy Markdown
Member Author

ah, seems good idea > extensions=[client_ext1, client_ext2]
Let me try it out

@jlipps
Copy link
Copy Markdown
Member

jlipps commented Jun 7, 2021

Yeah this way all client extensions can have a simple template to follow. For example we could publish the find_by_image commands a built-in extension module that people could just copy

from appium import webdriver
from appium.extensions import images

driver = webdriver.Remote(..., extensions=[images])

this mirrors the fact that the image functionality is a plugin now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants