diff --git a/cylc/flow/exceptions.py b/cylc/flow/exceptions.py
index 06c5bfcb15a..2a05dfb85ee 100644
--- a/cylc/flow/exceptions.py
+++ b/cylc/flow/exceptions.py
@@ -167,3 +167,8 @@ class CylcMissingContextPointError(CyclingError):
class CylcMissingFinalCyclePointError(CyclingError):
"""An error denoting a missing (but required) final cycle point."""
+
+
+class PlatformLookupError(CylcConfigError):
+ """Unable to determine the correct job platform from the information
+ given"""
diff --git a/cylc/flow/platform_lookup.py b/cylc/flow/platform_lookup.py
new file mode 100644
index 00000000000..268904e03ce
--- /dev/null
+++ b/cylc/flow/platform_lookup.py
@@ -0,0 +1,98 @@
+# THIS FILE IS PART OF THE CYLC SUITE ENGINE.
+# Copyright (C) 2008-2019 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 .
+#
+# Tests for the platform lookup.
+
+import re
+from cylc.flow.exceptions import PlatformLookupError
+
+
+def forward_lookup(platforms, job_platform):
+ """
+ Find out which job platform to use given a list of possible platforms and
+ a task platform string.
+
+ Verifies selected platform is present in global.rc file and returns it,
+ raises error if platfrom is not in global.rc or returns 'localhost' if
+ no platform is initally selected.
+
+ Args:
+ job_platform (str):
+ platform item from config [runtime][TASK]platform
+ platforms (dictionary):
+ list of possible platforms defined by global.rc
+
+ Returns:
+ platform (str):
+ string representing a platform from the global config.
+
+ Example:
+ >>> platforms = {
+ ... 'suite server platform': None,
+ ... 'desktop[0-9][0-9]|laptop[0-9][0-9]': None,
+ ... 'sugar': {
+ ... 'login hosts': 'localhost',
+ ... 'batch system': 'slurm'
+ ... },
+ ... 'hpc': {
+ ... 'login hosts': ['hpc1', 'hpc2'],
+ ... 'batch system': 'pbs'
+ ... },
+ ... 'hpc1-bg': {
+ ... 'login hosts': 'hpc1',
+ ... 'batch system': 'background'
+ ... },
+ ... 'hpc2-bg': {
+ ... 'login hosts': 'hpc2',
+ ... 'batch system': 'background'
+ ... }
+ ... }
+ >>> job_platform = 'desktop22'
+ >>> forward_lookup(platforms, job_platform)
+ 'desktop22'
+ """
+ if job_platform is None:
+ return 'localhost'
+ for platform in reversed(list(platforms)):
+ if re.fullmatch(platform, job_platform):
+ return job_platform
+
+ raise PlatformLookupError(
+ f"No matching platform \"{job_platform}\" found")
+
+
+def reverse_lookup(task_job, task_remote, platforms):
+ """
+ Find out which job platform to use given a list of possible platforms
+ and the task dictionary with cylc 7 definitions in it.
+
+ Args:
+ task_job (dict):
+ Suite config [runtime][TASK][job] section
+ task_remote (dict):
+ Suite config [runtime][TASK][remote] section
+ platforms (dict):
+ Dictionary containing platfrom definitions.
+
+ Returns:
+ platfrom (str):
+ string representing a platform from the global config.
+
+ Examples:
+ Tim - write some doctests here...
+
+ """
+ raise NotImplementedError
diff --git a/cylc/flow/tests/test_platform_lookup.py b/cylc/flow/tests/test_platform_lookup.py
new file mode 100644
index 00000000000..064c3cceef7
--- /dev/null
+++ b/cylc/flow/tests/test_platform_lookup.py
@@ -0,0 +1,87 @@
+# THIS FILE IS PART OF THE CYLC SUITE ENGINE.
+# Copyright (C) 2008-2019 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 .
+#
+# Tests for the platform lookup.
+
+import pytest
+from cylc.flow.platform_lookup import forward_lookup, reverse_lookup
+from cylc.flow.exceptions import PlatformLookupError
+
+PLATFORMS_STANDARD = {
+ 'suite server platform': None,
+ 'desktop[0-9][0-9]|laptop[0-9][0-9]': None,
+ 'sugar': {
+ 'login hosts': 'localhost',
+ 'batch system': 'slurm'
+ },
+ 'hpc': {
+ 'login hosts': ['hpc1', 'hpc2'],
+ 'batch system': 'pbs'
+ },
+ 'hpc1-bg': {
+ 'login hosts': 'hpc1',
+ 'batch system': 'background'
+ },
+ 'hpc2-bg': {
+ 'login hosts': 'hpc2',
+ 'batch system': 'background'
+ }
+}
+
+PLATFORMS_NO_UNIQUE = {
+ 'sugar': {
+ 'login hosts': 'localhost',
+ 'batch system': 'slurm'
+ },
+ 'pepper': {
+ 'login hosts': ['hpc1', 'hpc2'],
+ 'batch system': 'slurm'
+ },
+
+}
+
+PLATFORMS_WITH_RE = {
+ 'hpc.*': {'login hosts': 'hpc1', 'batch system': 'background'},
+ 'h.*': {'login hosts': 'hpc3'},
+ r'vld\d{2,3}': None,
+ 'nu.*': {'batch system': 'slurm'}
+}
+
+
+@pytest.mark.parametrize(
+ "PLATFORMS, platform, expected",
+ [(PLATFORMS_WITH_RE, 'nutmeg', 'nutmeg'),
+ (PLATFORMS_WITH_RE, 'vld798', 'vld798'),
+ (PLATFORMS_WITH_RE, 'vld56', 'vld56'),
+ (PLATFORMS_NO_UNIQUE, 'sugar', 'sugar'),
+ (PLATFORMS_STANDARD, None, 'localhost'),
+ (PLATFORMS_STANDARD, 'laptop22', 'laptop22'),
+ (PLATFORMS_STANDARD, 'hpc1-bg', 'hpc1-bg'),
+ (PLATFORMS_WITH_RE, 'hpc2', 'hpc2')
+ ]
+)
+def test_basic(PLATFORMS, platform, expected):
+ assert forward_lookup(PLATFORMS, platform) == expected
+
+
+def test_platform_not_there():
+ with pytest.raises(PlatformLookupError):
+ forward_lookup(PLATFORMS_STANDARD, 'moooo')
+
+
+def test_similar_but_not_exact_match():
+ with pytest.raises(PlatformLookupError):
+ forward_lookup(PLATFORMS_WITH_RE, 'vld1')