Skip to content

Commit

Permalink
Factor out guts of '{topic,subscription}_name_from_path'.
Browse files Browse the repository at this point in the history
Use a passed-in regex, in spite of Zawinski's law.

Put the factored-out code in 'gcloud._helpers', because I already know
I need it in logging.

Addresses:
#1580 (comment)
#1580 (comment)
#1580 (comment).
  • Loading branch information
tseaver committed Mar 8, 2016
1 parent f9e9103 commit 40a72be
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 63 deletions.
40 changes: 39 additions & 1 deletion gcloud/_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@
import calendar
import datetime
import os
from threading import local as Local
import re
import socket
import sys
from threading import local as Local

from google.protobuf import timestamp_pb2
import six
Expand Down Expand Up @@ -388,6 +389,43 @@ def _datetime_to_pb_timestamp(when):
return timestamp_pb2.Timestamp(seconds=seconds, nanos=nanos)


def _name_from_project_path(path, project, template):
"""Validate a URI path and get the leaf object's name.
:type path: string
:param path: URI path containing the name.
:type project: string
:param project: The project associated with the request. It is
included for validation purposes.
:type template: string
:param template: Template regex describing the expected form of the path.
The regex must have two named groups, 'project' and
'name'.
:rtype: string
:returns: Name parsed from ``path``.
:raises: :class:`ValueError` if the ``path`` is ill-formed or if
the project from the ``path`` does not agree with the
``project`` passed in.
"""
if isinstance(template, str):
template = re.compile(template)

match = template.match(path)

if not match:
raise ValueError('path did not match: %s' % (template.pattern))

found_project = match.group('project')
if found_project != project:
raise ValueError('Project from client should agree with '
'project from resource.')

return match.group('name')


try:
from pytz import UTC # pylint: disable=unused-import,wrong-import-order
except ImportError:
Expand Down
37 changes: 13 additions & 24 deletions gcloud/pubsub/_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@

"""Helper functions for shared behavior."""

import re

from gcloud._helpers import _name_from_project_path


_TOPIC_PATH_TEMPLATE = re.compile(
r'projects/(?P<project>\w+)/topics/(?P<name>\w+)')


def topic_name_from_path(path, project):
"""Validate a topic URI path and get the topic name.
Expand All @@ -31,18 +39,11 @@ def topic_name_from_path(path, project):
the project from the ``path`` does not agree with the
``project`` passed in.
"""
# PATH = 'projects/%s/topics/%s' % (PROJECT, TOPIC_NAME)
path_parts = path.split('/')
if (len(path_parts) != 4 or path_parts[0] != 'projects' or
path_parts[2] != 'topics'):
raise ValueError('Expected path to be of the form '
'projects/{project}/topics/{topic_name}')
if (len(path_parts) != 4 or path_parts[0] != 'projects' or
path_parts[2] != 'topics' or path_parts[1] != project):
raise ValueError('Project from client should agree with '
'project from resource.')
return _name_from_project_path(path, project, _TOPIC_PATH_TEMPLATE)


return path_parts[3]
_SUBSCRIPTION_PATH_TEMPLATE = re.compile(
r'projects/(?P<project>\w+)/subscriptions/(?P<name>\w+)')


def subscription_name_from_path(path, project):
Expand All @@ -61,16 +62,4 @@ def subscription_name_from_path(path, project):
the project from the ``path`` does not agree with the
``project`` passed in.
"""
# PATH = 'projects/%s/subscriptions/%s' % (PROJECT, TOPIC_NAME)
path_parts = path.split('/')
if (len(path_parts) != 4 or path_parts[0] != 'projects' or
path_parts[2] != 'subscriptions'):
raise ValueError(
'Expected path to be of the form '
'projects/{project}/subscriptions/{subscription_name}')
if (len(path_parts) != 4 or path_parts[0] != 'projects' or
path_parts[2] != 'subscriptions' or path_parts[1] != project):
raise ValueError('Project from client should agree with '
'project from resource.')

return path_parts[3]
return _name_from_project_path(path, project, _SUBSCRIPTION_PATH_TEMPLATE)
40 changes: 2 additions & 38 deletions gcloud/pubsub/test__helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,7 @@ def _callFUT(self, path, project):
from gcloud.pubsub._helpers import topic_name_from_path
return topic_name_from_path(path, project)

def test_invalid_path_length(self):
PATH = 'projects/foo'
PROJECT = None
self.assertRaises(ValueError, self._callFUT, PATH, PROJECT)

def test_invalid_path_format(self):
TOPIC_NAME = 'TOPIC_NAME'
PROJECT = 'PROJECT'
PATH = 'foo/%s/bar/%s' % (PROJECT, TOPIC_NAME)
self.assertRaises(ValueError, self._callFUT, PATH, PROJECT)

def test_invalid_project(self):
TOPIC_NAME = 'TOPIC_NAME'
PROJECT1 = 'PROJECT1'
PROJECT2 = 'PROJECT2'
PATH = 'projects/%s/topics/%s' % (PROJECT1, TOPIC_NAME)
self.assertRaises(ValueError, self._callFUT, PATH, PROJECT2)

def test_valid_data(self):
def test_it(self):
TOPIC_NAME = 'TOPIC_NAME'
PROJECT = 'PROJECT'
PATH = 'projects/%s/topics/%s' % (PROJECT, TOPIC_NAME)
Expand All @@ -53,25 +35,7 @@ def _callFUT(self, path, project):
from gcloud.pubsub._helpers import subscription_name_from_path
return subscription_name_from_path(path, project)

def test_invalid_path_length(self):
PATH = 'projects/foo'
PROJECT = None
self.assertRaises(ValueError, self._callFUT, PATH, PROJECT)

def test_invalid_path_format(self):
TOPIC_NAME = 'TOPIC_NAME'
PROJECT = 'PROJECT'
PATH = 'foo/%s/bar/%s' % (PROJECT, TOPIC_NAME)
self.assertRaises(ValueError, self._callFUT, PATH, PROJECT)

def test_invalid_project(self):
TOPIC_NAME = 'TOPIC_NAME'
PROJECT1 = 'PROJECT1'
PROJECT2 = 'PROJECT2'
PATH = 'projects/%s/subscriptions/%s' % (PROJECT1, TOPIC_NAME)
self.assertRaises(ValueError, self._callFUT, PATH, PROJECT2)

def test_valid_data(self):
def test_it(self):
TOPIC_NAME = 'TOPIC_NAME'
PROJECT = 'PROJECT'
PATH = 'projects/%s/subscriptions/%s' % (PROJECT, TOPIC_NAME)
Expand Down
35 changes: 35 additions & 0 deletions gcloud/test__helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,41 @@ def test_it(self):
self.assertEqual(self._callFUT(dt_stamp), timestamp)


class Test__name_from_project_path(unittest2.TestCase):

PROJECT = 'PROJECT'
THING_NAME = 'THING_NAME'
TEMPLATE = r'projects/(?P<project>\w+)/things/(?P<name>\w+)'

def _callFUT(self, path, project, template):
from gcloud._helpers import _name_from_project_path
return _name_from_project_path(path, project, template)

def test_w_invalid_path_length(self):
PATH = 'projects/foo'
with self.assertRaises(ValueError):
self._callFUT(PATH, None, self.TEMPLATE)

def test_w_invalid_path_segments(self):
PATH = 'foo/%s/bar/%s' % (self.PROJECT, self.THING_NAME)
with self.assertRaises(ValueError):
self._callFUT(PATH, self.PROJECT, self.TEMPLATE)

def test_w_mismatched_project(self):
PROJECT1 = 'PROJECT1'
PROJECT2 = 'PROJECT2'
PATH = 'projects/%s/things/%s' % (PROJECT1, self.THING_NAME)
with self.assertRaises(ValueError):
self._callFUT(PATH, PROJECT2, self.TEMPLATE)

def test_w_valid_data_w_compiled_regex(self):
import re
template = re.compile(self.TEMPLATE)
PATH = 'projects/%s/things/%s' % (self.PROJECT, self.THING_NAME)
name = self._callFUT(PATH, self.PROJECT, template)
self.assertEqual(name, self.THING_NAME)


class _AppIdentity(object):

def __init__(self, app_id):
Expand Down

0 comments on commit 40a72be

Please sign in to comment.