Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit d5d402d

Browse filesBrowse files
ryanmatsJon Wayne Parrott
authored andcommitted
App Engine Cloud Storage Client Sample (GoogleCloudPlatform#793)
* Added AppEngine Storage Client sample, renamed subfolders * Fixed code review issues * Updated storage api-client code to upload/delete objects - now testing works * Changed BUCKET_NAME back to <your-bucket-name> * Fixed code review issues
1 parent 5861d19 commit d5d402d
Copy full SHA for d5d402d

File tree

Expand file treeCollapse file tree

12 files changed

+233
-1
lines changed
Filter options
Expand file treeCollapse file tree

12 files changed

+233
-1
lines changed

‎appengine/standard/storage/main.py renamed to ‎appengine/standard/storage/api-client/main.py

Copy file name to clipboardExpand all lines: appengine/standard/storage/api-client/main.py
+22-1Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@
2323
"""
2424

2525
import json
26+
import StringIO
2627

2728
from googleapiclient import discovery
29+
from googleapiclient import http
2830
from oauth2client.client import GoogleCredentials
2931
import webapp2
3032

@@ -37,14 +39,33 @@
3739

3840

3941
class MainPage(webapp2.RequestHandler):
42+
def upload_object(self, bucket, file_object):
43+
body = {
44+
'name': 'storage-api-client-sample-file.txt',
45+
}
46+
req = storage.objects().insert(
47+
bucket=bucket, body=body, media_body=http.MediaIoBaseUpload(
48+
file_object, 'application/octet-stream'))
49+
resp = req.execute()
50+
return resp
51+
52+
def delete_object(self, bucket, filename):
53+
req = storage.objects().delete(bucket=bucket, object=filename)
54+
resp = req.execute()
55+
return resp
56+
4057
def get(self):
41-
response = storage.objects().list(bucket=BUCKET_NAME).execute()
58+
string_io_file = StringIO.StringIO('Hello World!')
59+
self.upload_object(BUCKET_NAME, string_io_file)
4260

61+
response = storage.objects().list(bucket=BUCKET_NAME).execute()
4362
self.response.write(
4463
'<h3>Objects.list raw response:</h3>'
4564
'<pre>{}</pre>'.format(
4665
json.dumps(response, sort_keys=True, indent=2)))
4766

67+
self.delete_object(BUCKET_NAME, 'storage-api-client-sample-file.txt')
68+
4869

4970
app = webapp2.WSGIApplication([
5071
('/', MainPage)

‎appengine/standard/storage/appengine-client/__init__.py

Copy file name to clipboardExpand all lines: appengine/standard/storage/appengine-client/__init__.py
Whitespace-only changes.
+12Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
runtime: python27
2+
api_version: 1
3+
threadsafe: yes
4+
5+
env_variables:
6+
7+
handlers:
8+
- url: /blobstore.*
9+
script: blobstore.app
10+
11+
- url: /.*
12+
script: main.app
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from google.appengine.ext import vendor
2+
3+
# Add any libraries installed in the "lib" folder.
4+
vendor.add('lib')
+167Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
#!/usr/bin/env python
2+
3+
# Copyright 2017 Google Inc.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
# [START sample]
18+
"""A sample app that uses GCS client to operate on bucket and file."""
19+
20+
# [START imports]
21+
import os
22+
23+
import cloudstorage
24+
from google.appengine.api import app_identity
25+
26+
import webapp2
27+
28+
# [END imports]
29+
30+
# [START retries]
31+
cloudstorage.set_default_retry_params(
32+
cloudstorage.RetryParams(
33+
initial_delay=0.2, max_delay=5.0, backoff_factor=2, max_retry_period=15
34+
))
35+
# [END retries]
36+
37+
38+
class MainPage(webapp2.RequestHandler):
39+
"""Main page for GCS demo application."""
40+
41+
# [START get_default_bucket]
42+
def get(self):
43+
bucket_name = os.environ.get(
44+
'BUCKET_NAME', app_identity.get_default_gcs_bucket_name())
45+
46+
self.response.headers['Content-Type'] = 'text/plain'
47+
self.response.write(
48+
'Demo GCS Application running from Version: {}\n'.format(
49+
os.environ['CURRENT_VERSION_ID']))
50+
self.response.write('Using bucket name: \n\n'.format(bucket_name))
51+
# [END get_default_bucket]
52+
53+
bucket = '/' + bucket_name
54+
filename = bucket + '/demo-testfile'
55+
self.tmp_filenames_to_clean_up = []
56+
57+
self.create_file(filename)
58+
self.response.write('\n\n')
59+
60+
self.read_file(filename)
61+
self.response.write('\n\n')
62+
63+
self.stat_file(filename)
64+
self.response.write('\n\n')
65+
66+
self.create_files_for_list_bucket(bucket)
67+
self.response.write('\n\n')
68+
69+
self.list_bucket(bucket)
70+
self.response.write('\n\n')
71+
72+
self.list_bucket_directory_mode(bucket)
73+
self.response.write('\n\n')
74+
75+
self.delete_files()
76+
self.response.write('\n\nThe demo ran successfully!\n')
77+
78+
# [START write]
79+
def create_file(self, filename):
80+
"""Create a file."""
81+
82+
self.response.write('Creating file {}\n'.format(filename))
83+
84+
# The retry_params specified in the open call will override the default
85+
# retry params for this particular file handle.
86+
write_retry_params = cloudstorage.RetryParams(backoff_factor=1.1)
87+
with cloudstorage.open(
88+
filename, 'w', content_type='text/plain', options={
89+
'x-goog-meta-foo': 'foo', 'x-goog-meta-bar': 'bar'},
90+
retry_params=write_retry_params) as cloudstorage_file:
91+
cloudstorage_file.write('abcde\n')
92+
cloudstorage_file.write('f'*1024*4 + '\n')
93+
self.tmp_filenames_to_clean_up.append(filename)
94+
# [END write]
95+
96+
# [START read]
97+
def read_file(self, filename):
98+
self.response.write(
99+
'Abbreviated file content (first line and last 1K):\n')
100+
101+
with cloudstorage.open(filename) as cloudstorage_file:
102+
self.response.write(cloudstorage_file.readline())
103+
cloudstorage_file.seek(-1024, os.SEEK_END)
104+
self.response.write(cloudstorage_file.read())
105+
# [END read]
106+
107+
def stat_file(self, filename):
108+
self.response.write('File stat:\n')
109+
110+
stat = cloudstorage.stat(filename)
111+
self.response.write(repr(stat))
112+
113+
def create_files_for_list_bucket(self, bucket):
114+
self.response.write('Creating more files for listbucket...\n')
115+
filenames = [bucket + n for n in [
116+
'/foo1', '/foo2', '/bar', '/bar/1', '/bar/2', '/boo/']]
117+
for f in filenames:
118+
self.create_file(f)
119+
120+
# [START list_bucket]
121+
def list_bucket(self, bucket):
122+
"""Create several files and paginate through them."""
123+
124+
self.response.write('Listbucket result:\n')
125+
126+
# Production apps should set page_size to a practical value.
127+
page_size = 1
128+
stats = cloudstorage.listbucket(bucket + '/foo', max_keys=page_size)
129+
while True:
130+
count = 0
131+
for stat in stats:
132+
count += 1
133+
self.response.write(repr(stat))
134+
self.response.write('\n')
135+
136+
if count != page_size or count == 0:
137+
break
138+
stats = cloudstorage.listbucket(
139+
bucket + '/foo', max_keys=page_size, marker=stat.filename)
140+
# [END list_bucket]
141+
142+
def list_bucket_directory_mode(self, bucket):
143+
self.response.write('Listbucket directory mode result:\n')
144+
for stat in cloudstorage.listbucket(bucket + '/b', delimiter='/'):
145+
self.response.write(stat)
146+
self.response.write('\n')
147+
if stat.is_dir:
148+
for subdir_file in cloudstorage.listbucket(
149+
stat.filename, delimiter='/'):
150+
self.response.write(' {}'.format(subdir_file))
151+
self.response.write('\n')
152+
153+
# [START delete_files]
154+
def delete_files(self):
155+
self.response.write('Deleting files...\n')
156+
for filename in self.tmp_filenames_to_clean_up:
157+
self.response.write('Deleting file {}\n'.format(filename))
158+
try:
159+
cloudstorage.delete(filename)
160+
except cloudstorage.NotFoundError:
161+
pass
162+
# [END delete_files]
163+
164+
165+
app = webapp2.WSGIApplication(
166+
[('/', MainPage)], debug=True)
167+
# [END sample]
+27Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Copyright 2017 Google Inc. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import webtest
16+
17+
import main
18+
19+
20+
def test_get(testbed, cloud_config):
21+
main.BUCKET_NAME = cloud_config.project
22+
app = webtest.TestApp(main.app)
23+
24+
response = app.get('/')
25+
26+
assert response.status_int == 200
27+
assert 'The demo ran successfully!' in response.body
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
GoogleAppEngineCloudStorageClient==1.9.22.1

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.