-
Notifications
You must be signed in to change notification settings - Fork 18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add gui workflow arg #370
Add gui workflow arg #370
Conversation
cylc/uiserver/scripts/gui.py
Outdated
# workflow_id, _, _ = parse_id( | ||
# arg, constraint='workflows', infer_latest_runs=True) | ||
|
||
# The following line needs to be replaced with the line above in | ||
# order to interpret the workflow_id. This, causes problems with | ||
# the ServerApp Event loop. | ||
|
||
workflow_id = arg |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PR now interprets workflow_ID given on the command line. e.g. cylc gui workflow_name
will resolve correctly to give cylc gui workflow_name/run4
.
Codecov Report
@@ Coverage Diff @@
## master #370 +/- ##
==========================================
- Coverage 79.89% 79.83% -0.07%
==========================================
Files 12 12
Lines 1159 1210 +51
Branches 219 225 +6
==========================================
+ Hits 926 966 +40
- Misses 196 206 +10
- Partials 37 38 +1
Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, works great
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, tested as working, just a couple of small questions.
I have picked this up and am running with in an attempt to get it over the line and responded to most of the comments. I have 2 questions:
|
Thanks @wxtim - as noted on Element chat, no need to bust a gut if short of time to get this in the release (next release is OK).
I haven't had a chance to look today, sorry.
Personally I think options should come before args (otherwise, logically, it sort-of looks like |
The CLI docs are coming from Jupyter Server, options are configured "traits", these double as both CLI options and configurations. E.G. the CylcUIServer adds a trait called This issue is effectively about extending the Jupyter Server CLI. If the modifications are light we can bodge them in, but if we want greater control over the CLI appearance they we would need to create our own argument parser here, parse the args, then reformat #!psudopython
def get_option_parser():
...
return parser
@cli_function
def main(..., workflow_id):
...
cylc_opts, jps_opts = parser.parse_known_args()
if not gui_running or cylc_opts.new:
argv = ['cylc', 'uiserver', *jps_opts]
# do Mel's URL magic
return CylcUIServer.launch_instance(argv)
else:
browser.open(get_gui_url()) |
I may or may not come back to this. Probably not a priority for me. |
f0ffeef
to
47e8724
Compare
Change of implementation: Originally we were creating and maintaining our own PID file, to establish if an instance of the gui was running. It turns our Jupyter Server creates two files containing the information that we require. These, by default, are housed in
The json file contains info such as url, port number, version of jpserver, token etc... In this PR, I have changed where this file is created (by setting an environment variable "JUPYTER_RUNTIME_DIR"). Now it can be found in If a gui is started without the |
I will update the logic to consider no-browser option. |
if arg.startswith('-'): | ||
continue | ||
try: | ||
loop = asyncio.new_event_loop() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should only need one loop here. Suggest doing something like this:
def main(*argv):
... = asyncio.run(parse_args())
async def parse_args():
...
for arg in jp_server_opts:
...
workflow_id, *_ = await parse_id_async(...)
cylc/uiserver/scripts/gui.py
Outdated
print( | ||
f"Workflow '{arg}' does not exist. Opening gui at dashboard.", | ||
file=sys.stderr) | ||
break |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might as well error here, other Cylc commands would fail with a no such workflow type error (saves the need for the redirect to dashboard thing).
cylc/uiserver/scripts/gui.py
Outdated
pid_match = re.search(r"jpserver-(\d+)-open.html", file) | ||
if pid_match is not None: | ||
pid = pid_match[1] | ||
if pid_exists(int(pid)): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Spanner to throw into the works, the process might not be running on this server.
Does Jupyter Server have a mechanism for checking if a server is still running?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will have a look and report back, I had forgotten that case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, Jupyter Server does have a command for checking if a server is running. I don't think this is of use to us though 😢
The command is jupyter server list
- this checks for the existence of pid file (remember this doesn't get cleaned up if the server shuts down unexpectedly)
- it then does a
os.kill(pid, 0)
to check the process is running - it defaults to process running in the case of
PermissionError(1, 'Operation not permitted')
, which I am meeting regularly as I have a load of stale files. - the result is that it is claiming to have servers running when they are not.
If the process is running on a different server, maybe we can use the info in the pid file to pick the host out?
The info stored in the file is:
{
"base_url": "/",
"hostname": "localhost",
"password": false,
"pid": 11111,
"port": 8888,
"root_dir": "/net/home/../username",
"secure": true,
"sock": "",
"token": "blah blah some big long token here",
"url": "https://localhost:8888/",
"version": "1.18.1"
}
bedfb19
to
cd9796c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't seem to detect a gui launched via JupyterHub, likely my fault, can't remember?
cylc/uiserver/app.py
Outdated
@@ -104,6 +105,9 @@ | |||
from cylc.uiserver.websockets.tornado import TornadoSubscriptionServer | |||
from cylc.uiserver.workflows_mgr import WorkflowsManager | |||
|
|||
RUNTIME_PATH = Path("~/.cylc/uiserver").expanduser() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is already defined as USER_CONF_ROOT
.
Looking into this now, perhaps due to the env variable maybe. Update: Discussed at team meeting, needs some thought. Decision made that this PR should go in first and deal with this as a separate issue - raised: #382 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tested, all working as expected.
One outstanding comment here - https://github.com/cylc/cylc-uiserver/pull/370/files/cd9796c448fc626d4eb877abb22ef1542d31656a#r952333283
Agree, Jupyter Hub is a different problem (wasn't thinking straight, that needs to be configured at the site-level).
Cheers!
I tested after rebasing this onto master. Suggest maybe rebase-squashing to see the tests pass with latest UIS code. |
Remove empty subcommands Change log
658c7e6
to
3c882ee
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Partial review
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aside from my suggestions, I have tested out and happy it's working
cylc/uiserver/app.py
Outdated
examples = ''' | ||
cylc gui # start the cylc GUI | ||
cylc gui # Start the Cylc GUI (At the dashboard page) | ||
cylc gui [workflow] # Start the Cylc GUI (at the workflow page), | ||
cylc gui --new [workflow] # Start the Cylc GUI (at the workflow page), with a | ||
new instance. By default, if there is an existing | ||
gui instance, Cylc will use that. | ||
|
||
''' # type: ignore[assignment] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"if there is an existing instance, Cylc will use that" applies more to the non --new
case, right?
I would also use dedent
to tidy this up (from textwrap import dedent
):
examples = dedent('''
cylc gui # Start the Cylc GUI (at the dashboard page).
cylc gui [workflow] # Start the Cylc GUI (at the workflow page). If
there is an existing GUI instance, Cylc will
use that.
cylc gui --new [workflow] # Start a new instance of the Cylc GUI (at the
workflow page).
''') # type: ignore[assignment]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll change the wording. The formatting is dealt with through traitlets and they indent and dedent it with yield indent(dedent(self.examples.strip()))
. An additional dedent as suggested is having no effect for me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From my testing the dedent
is needed to avoid it being like this:
examples = '''
cylc gui # ...
cylc gui [workflow] # ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Incidentally, the If there is an existing GUI instance, Cylc will use that.
is required for both the cylc gui
and the cylc gui [workflow]
options. I actually think it is neater leaving it as it is, since it conveys the same information without repetition, what do you think?
Co-authored-by: Oliver Sanders <[email protected]> Add --new option for gui Review Feedback RD
3c882ee
to
3806387
Compare
cylc/uiserver/scripts/gui.py
Outdated
|
||
|
||
def main(*argv): | ||
init_log() | ||
return CylcUIServer.launch_instance(argv or None) | ||
new_gui = CLI_OPT_NEW in argv |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not used because it is redefined in next line
new_gui = CLI_OPT_NEW in argv |
This adds functionality for opening the gui at a specific workflow when running
cylc gui <workflow_name>
These changes close #239 and #240
This PR also restricts the number of gui instances to one, by searching for pid file created by jupyter server.
CONTRIBUTING.md
and added my name as a Code Contributor.setup.cfg
. No dependency changes.