@@ -29,8 +29,9 @@ class Subscription(object):
2929 :type name: string
3030 :param name: the name of the subscription
3131
32- :type topic: :class:`gcloud.pubsub.topic.Topic`
33- :param topic: the topic to which the subscription belongs..
32+ :type topic: :class:`gcloud.pubsub.topic.Topic` or ``NoneType``
33+ :param topic: the topic to which the subscription belongs; if ``None``,
34+ the subscription's topic has been deleted.
3435
3536 :type ack_deadline: int
3637 :param ack_deadline: the deadline (in seconds) by which messages pulled
@@ -39,10 +40,32 @@ class Subscription(object):
3940 :type push_endpoint: string
4041 :param push_endpoint: URL to which messages will be pushed by the back-end.
4142 If not set, the application must pull messages.
43+
44+ :type client: :class:`gcloud.pubsub.client.Client` or ``NoneType``
45+ :param client: the client to use. If not passed, falls back to the
46+ ``client`` stored on the topic.
4247 """
43- def __init__ (self , name , topic , ack_deadline = None , push_endpoint = None ):
48+
49+ _DELETED_TOPIC_PATH = '_deleted-topic_'
50+ """Value of ``projects.subscriptions.topic`` when topic has been deleted.
51+
52+ See:
53+ https://cloud.google.com/pubsub/reference/rest/v1/projects.subscriptions#Subscription.FIELDS.topic
54+ """
55+
56+ def __init__ (self , name , topic = None , ack_deadline = None , push_endpoint = None ,
57+ client = None ):
58+
59+ if client is None and topic is None :
60+ raise TypeError ("Pass only one of 'topic' or 'client'." )
61+
62+ if client is not None and topic is not None :
63+ raise TypeError ("Pass only one of 'topic' or 'client'." )
64+
4465 self .name = name
4566 self .topic = topic
67+ self ._client = client or topic ._client
68+ self ._project = self ._client .project
4669 self .ack_deadline = ack_deadline
4770 self .push_endpoint = push_endpoint
4871
@@ -67,23 +90,33 @@ def from_api_repr(cls, resource, client, topics=None):
6790 if topics is None :
6891 topics = {}
6992 topic_path = resource ['topic' ]
70- topic = topics .get (topic_path )
71- if topic is None :
72- # NOTE: This duplicates behavior from Topic.from_api_repr to avoid
73- # an import cycle.
74- topic_name = topic_name_from_path (topic_path , client .project )
75- topic = topics [topic_path ] = client .topic (topic_name )
93+ if topic_path == cls ._DELETED_TOPIC_PATH :
94+ topic = None
95+ else :
96+ topic = topics .get (topic_path )
97+ if topic is None :
98+ # NOTE: This duplicates behavior from Topic.from_api_repr to
99+ # avoid an import cycle.
100+ topic_name = topic_name_from_path (topic_path , client .project )
101+ topic = topics [topic_path ] = client .topic (topic_name )
76102 _ , _ , _ , name = resource ['name' ].split ('/' )
77103 ack_deadline = resource .get ('ackDeadlineSeconds' )
78104 push_config = resource .get ('pushConfig' , {})
79105 push_endpoint = push_config .get ('pushEndpoint' )
106+ if topic is None :
107+ return cls (name , ack_deadline = ack_deadline ,
108+ push_endpoint = push_endpoint , client = client )
80109 return cls (name , topic , ack_deadline , push_endpoint )
81110
111+ @property
112+ def project (self ):
113+ """Project bound to the subscription."""
114+ return self ._client .project
115+
82116 @property
83117 def path (self ):
84118 """URL path for the subscription's APIs"""
85- project = self .topic .project
86- return '/projects/%s/subscriptions/%s' % (project , self .name )
119+ return '/projects/%s/subscriptions/%s' % (self .project , self .name )
87120
88121 def _require_client (self , client ):
89122 """Check client or verify over-ride.
@@ -97,7 +130,7 @@ def _require_client(self, client):
97130 :returns: The client passed in or the currently bound client.
98131 """
99132 if client is None :
100- client = self .topic . _client
133+ client = self ._client
101134 return client
102135
103136 def create (self , client = None ):
0 commit comments