Skip to content

Commit

Permalink
scan: use non-blocking io to read the contact file
Browse files Browse the repository at this point in the history
  • Loading branch information
oliver-sanders committed Aug 4, 2020
1 parent 29ed5a3 commit 7ddc90e
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 12 deletions.
4 changes: 2 additions & 2 deletions cylc/flow/network/scan_nt.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
ContactFileFields,
SuiteFiles,
get_suite_title,
load_contact_file
load_contact_file_async
)


Expand Down Expand Up @@ -169,7 +169,7 @@ async def contact_info(flow):
"""
flow.update(
load_contact_file(flow['name'], path=flow['path'])
await load_contact_file_async(flow['name'], run_dir=flow['path'])
)
return flow

Expand Down
43 changes: 33 additions & 10 deletions cylc/flow/suite_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,23 @@

# Note: Some modules are NOT imported in the header. Expensive modules are only
# imported on demand.
from functools import lru_cache
from pathlib import Path
import os
import re
import shutil
import stat
import zmq.auth

import aiofiles

from cylc.flow import LOG
from cylc.flow.cfgspec.glbl_cfg import glbl_cfg
from cylc.flow.exceptions import SuiteServiceFileError
from cylc.flow.pathutil import get_remote_suite_run_dir, get_suite_run_dir
import cylc.flow.flags
from cylc.flow.pathutil import get_suite_run_dir
from cylc.flow.hostuserutil import (
get_host, get_user, is_remote, is_remote_host, is_remote_user)
get_user,
is_remote_host,
is_remote_user
)
from cylc.flow.unicode_rules import SuiteNameValidator

from enum import Enum
Expand Down Expand Up @@ -375,13 +378,10 @@ def get_suite_srv_dir(reg, suite_owner=None):
return os.path.join(run_d, SuiteFiles.Service.DIRNAME)


def load_contact_file(reg, path=None, owner=None, host=None):
def load_contact_file(reg, owner=None, host=None):
"""Load contact file. Return data as key=value dict."""
file_base = SuiteFiles.Service.CONTACT
if path:
path = path / SuiteFiles.Service.DIRNAME
else:
path = get_suite_srv_dir(reg)
path = get_suite_srv_dir(reg)
file_content = _load_local_item(file_base, path)
if file_content:
data = {}
Expand All @@ -393,6 +393,29 @@ def load_contact_file(reg, path=None, owner=None, host=None):
raise SuiteServiceFileError("Couldn't load contact file")


async def load_contact_file_async(reg, run_dir=None):
if not run_dir:
path = Path(
get_suite_srv_dir(reg),
SuiteFiles.Service.CONTACT
)
else:
path = Path(
run_dir,
SuiteFiles.Service.DIRNAME,
SuiteFiles.Service.CONTACT
)
try:
async with aiofiles.open(path, mode='r') as cont:
data = {}
async for line in cont:
key, value = [item.strip() for item in line.split("=", 1)]
data[key] = value
return data
except IOError:
raise SuiteServiceFileError("Couldn't load contact file")


def parse_suite_arg(options, arg):
"""From CLI arg "SUITE", return suite name and suite.rc path.
Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ def find_version(*file_paths):


install_requires = [
'aiofiles==0.5.*',
'ansimarkup>=1.0.0',
'colorama>=0.4,<=1',
'click>=7.0',
Expand Down
46 changes: 46 additions & 0 deletions tests/integration/test_suite_files.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# THIS FILE IS PART OF THE CYLC SUITE ENGINE.
# Copyright (C) NIWA & British Crown (Met Office) & Contributors.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import pytest

from cylc.flow.suite_files import (
ContactFileFields as CFF,
load_contact_file,
load_contact_file_async
)


@pytest.fixture(scope='module')
async def myflow(mod_flow, mod_scheduler, mod_run, mod_one_conf):
reg = mod_flow(mod_one_conf)
schd = mod_scheduler(reg)
async with mod_run(schd):
yield schd


def test_load_contact_file(myflow):
cont = load_contact_file(myflow.suite)
assert cont[CFF.HOST] == myflow.host


@pytest.mark.asyncio
async def test_load_contact_file_async(myflow):
cont = await load_contact_file_async(myflow.suite)
assert cont[CFF.HOST] == myflow.host

# compare the async interface to the sync interface
cont2 = load_contact_file(myflow.suite)
assert cont == cont2

0 comments on commit 7ddc90e

Please sign in to comment.