def process_image(self, image_contents_id): session = Client().session() contents = session.query(ImageContents).\ filter(ImageContents.image_contents_id == image_contents_id).\ one() image = session.query(Image).\ filter(Image.image_id == contents.image_id).\ one() truck = ImageTruck( contents.contents, contents.content_type, image.source_url) truck.filename = image.filename metadata = ImageMetadata.image_metadata(truck.contents) truck.contents = ReorientImage.reorient_image(truck.contents) def after_upload(size): redis.publish(REDIS_CHANNEL, json.dumps({ 'task_id': self.request.id, 'suffix': size, })) ResizeImage.make_resizes(image, truck, after_upload) print "uploading original image" truck.upload() redis.publish(REDIS_CHANNEL, json.dumps({ 'task_id': self.request.id, 'suffix': '', })) delay(queued_tasks, Invalidate(), image.image_id) for attr, value in metadata.iteritems(): setattr(image, attr, value) session.add(image) session.delete(contents)
def add(request_format): tag_names = request.form['tags'].split(' ') url = request.form['url'] if url: print 'fetching from remote url' truck = ImageTruck.new_from_url(url) elif request.files['file']: image = request.files['file'] truck = ImageTruck.new_from_stream(image.stream, image.mimetype) else: abort(400) metadata = ImageMetadata.image_metadata(truck.contents) print 'potentially reorienting' truck.contents = ReorientImage.reorient_image(truck.contents) print 'uploading to s3' truck.upload() session = Client().session() image = Image(filename=truck.calculate_filename(), source_url=url, description=request.form.get('description'), title=request.form.get('title'), **metadata) album_id = request.form['album'] if album_id: image.album_id = album_id session.add(image) image.add_tags(tag_names) ResizeImage.make_resizes(image, truck) if request_format == 'html': return redirect(url_for('show_image', image_id=image.image_id)) elif request_format == 'json': return {'url': truck.url()}
def test_url_for_filename__with_extension(self, _url, Config): config = Mock() config.bucket_name.return_value = 'greeble' Config.return_value = config ImageTruck.url_for_filename('CAFEBABE', extension=True) _url.assert_called_once_with('CAFEBABE', 'greeble', extension=True)
def test_calculate_filename(self, hashlib): sha = Mock() sha.hexdigest.return_value = 'indigestible' hashlib.sha1.return_value = sha truck = ImageTruck('razors', None, None) eq_(truck.calculate_filename(), 'indigestible') hashlib.sha1.assert_called_with('razors')
def add(request_format): url = request.form.get("url") if url: try: trucks = [ImageTruck.new_from_url(url)] except RequestException: abort(request_format, 400, "That url is no good.") except TryHTTPError: abort( request_format, 400, "Catsnap couldn't establish an HTTPS connection to that " "image. An HTTP connection may succeed (this is a problem " "on Catsnap's end, not something you did wrong).", ) elif request.files.get("file[]"): trucks = [ImageTruck.new_from_stream(data.stream) for data in request.files.getlist("file[]")] elif request.files.get("file"): data = request.files["file"] trucks = [ImageTruck.new_from_stream(data.stream)] else: abort(request_format, 400, "Please submit either a file or a url.") # These loops are sorta awkwardly phrased to avoid lots of round-tripping # to the database. I hope you don't consider the optimization premature. session = Client().session() images = [] for truck in trucks: image = Image(filename=truck.filename, source_url=url) album_id = request.form.get("album_id") if album_id: image.album_id = int(album_id) session.add(image) images.append(image) session.flush() contentses = [] for i in xrange(0, len(images)): (truck, image) = trucks[i], images[i] contents = ImageContents(image_id=image.image_id, contents=truck.contents, content_type=truck.content_type) session.add(contents) contentses.append(contents) session.flush() task_ids = [] # Hey, this is a loop around a round-trip to redis. Although the Python # Redis library offers a way to send multiple requests in one thwack, # Celery doesn't appear to offer a way to use it. Nothing to be done. for contents in contentses: task_ids.append(delay(g.queued_tasks, process_image, contents.image_contents_id)) if request_format == "html": return redirect(url_for("show_image", image_id=image.image_id)) elif request_format == "json": return [ {"url": trucks[i].url(), "image_id": images[i].image_id, "task_id": task_ids[i]} for i in xrange(0, len(trucks)) ]
def test_get_contents_of_nonexistent_filename(self, MockClient): bucket = Mock() bucket.get_key.return_value = None client = Mock() client.bucket.return_value = bucket MockClient.return_value = client ImageTruck.contents_of_filename('x')
def test_url(self, calculate_filename, Config): config = Mock() config.bucket_name.return_value = 'tune-carrier' Config.return_value = config calculate_filename.return_value = 'greensleeves' truck = ImageTruck('greensleeves', None, None) eq_(truck.url(), 'https://s3.amazonaws.com/tune-carrier/greensleeves')
def test_new_from_url_reraises_non_sni_ssl_errors(self, mock_requests): error = requests.exceptions.SSLError( urllib3.exceptions.SSLError( CertificateError("hostname 'catsinthecity.com' doesn't " "match 'nossl.edgecastcdn.net'"))) mock_requests.get.side_effect = error ImageTruck.new_from_url('https://catsinthecity.com/image.jpg')
def add(request_format): url = request.form.get('url') if url: try: trucks = [ImageTruck.new_from_url(url)] except RequestException: abort(request_format, 400, "That url is no good.") elif request.files.get('file[]'): trucks = [ImageTruck.new_from_stream(data.stream) for data in request.files.getlist('file[]')] elif request.files.get('file'): data = request.files['file'] trucks = [ImageTruck.new_from_stream(data.stream)] else: abort(request_format, 400, "Please submit either a file or a url.") # These loops are sorta awkwardly phrased to avoid lots of round-tripping # to the database. I hope you don't consider the optimization premature. session = Client().session() images = [] for truck in trucks: image = Image(filename=truck.filename, source_url=url) album_id = request.form.get('album_id') if album_id: image.album_id = int(album_id) session.add(image) images.append(image) session.flush() contentses = [] for i in xrange(0, len(images)): (truck, image) = trucks[i], images[i] contents = ImageContents(image_id=image.image_id, contents=truck.contents, content_type=truck.content_type) session.add(contents) contentses.append(contents) session.flush() task_ids = [] # Hey, this is a loop around a round-trip to redis. Although the Python # Redis library offers a way to send multiple requests in one thwack, # Celery doesn't appear to offer a way to use it. Nothing to be done. for contents in contentses: task_ids.append(delay(g.queued_tasks, process_image, contents.image_contents_id)) if request_format == 'html': return redirect(url_for('show_image', image_id=image.image_id)) elif request_format == 'json': return [{ 'url': trucks[i].url(), 'image_id': images[i].image_id, 'task_id': task_ids[i], } for i in xrange(0, len(trucks))]
def test_new_from_url_raises_usefully_for_sni_trouble(self, mock_requests): error = requests.exceptions.SSLError( urllib3.exceptions.SSLError( ssl.SSLError(1, '_ssl.c:503: error:14077410:SSL routines:' 'SSL23_GET_SERVER_HELLO:sslv3 alert handshake ' 'failure'))) mock_requests.get.side_effect = error ImageTruck.new_from_url('https://some.server.using.sni/image.jpg')
def test_url__with_extension(self, calculate_filename, Config, _url): config = Mock() config.bucket_name.return_value = 'tune-carrier' Config.return_value = config calculate_filename.return_value = 'greensleeves' truck = ImageTruck('greensleeves', None, None) truck.url(extension=True) _url.assert_called_once_with('greensleeves', 'tune-carrier', extension=True)
def test_get_bucket_creates_bucket_connection(self, Config): config = Mock() Config.return_value = config mock_bucket = Mock() truck = ImageTruck(None, None, None) truck._stored_bucket = mock_bucket bucket = truck._bucket() eq_(bucket, mock_bucket) eq_(config.table.call_count, 0)
def test_get_bucket_creates_bucket_connection(self, Config): config = Mock() Config.return_value = config mock_bucket = Mock() config.bucket.return_value = mock_bucket truck = ImageTruck(None, None, None) bucket = truck._bucket() eq_(bucket, mock_bucket) eq_(truck._stored_bucket, mock_bucket) config.bucket.assert_called_with()
def test_url__with_cloudfront_url(self, calculate_filename, MockClient): client = Mock() client.cloudfront_url.return_value = \ 'ggaaghlhaagl.cloudfront.net' client.config.return_value = Client().config() MockClient.return_value = client calculate_filename.return_value = 'chumbawamba' truck = ImageTruck('tubthumper', None, None) url = truck.url() eq_(url, 'https://ggaaghlhaagl.cloudfront.net/chumbawamba') client.cloudfront_url.assert_called_with('JEEZAMANDA')
def test_save__uploads_image(self, calculate_filename): bucket = Mock() key = Mock() bucket.new_key.return_value = key calculate_filename.return_value = 'I am the keymaster' truck = ImageTruck('Are you the gatekeeper?', 'image/gif', None) truck._stored_bucket = bucket truck.upload() bucket.new_key.assert_called_with('I am the keymaster') key.set_contents_from_string.assert_called_with( 'Are you the gatekeeper?') key.set_metadata.assert_called_with('Content-Type', 'image/gif') key.make_public.assert_called_with()
def test_upload_resize(self, calculate_filename, MockClient): bucket = Mock() key = Mock() bucket.new_key.return_value = key client = Mock() client.bucket.return_value = bucket MockClient.return_value = client calculate_filename.return_value = 'faceb00c' truck = ImageTruck('contentsoffile', 'image/gif', None) truck.upload_resize('resizedcontents', 'small') bucket.new_key.assert_called_with('faceb00c_small') key.set_contents_from_string.assert_called_with('resizedcontents') key.set_metadata.assert_called_with('Content-Type', 'image/gif') key.make_public.assert_called_once()
def test_new_from_stream(self): stream = StringIO.StringIO() stream.write('encoded jpg file') stream.seek(0) truck = ImageTruck.new_from_stream(stream, 'image/jpg') eq_(truck.contents, 'encoded jpg file') eq_(truck.content_type, 'image/jpg')
def file_type_test(self, bucket_method, test_file, content_type, resized_size): bucket = Mock() bucket_method.return_value = bucket new_key = Mock() bucket.new_key.return_value = new_key image_handler = ImageHandler(filename=test_file) truck = ImageTruck.new_from_file(test_file) session = Client().session() image = ImageTable(filename='badcafe') session.add(image) session.flush() after_upload = Mock() ResizeImage._resize_image(image, image_handler, truck, 'thumbnail', after_upload) new_key.set_metadata.assert_called_with('Content-Type', content_type) resized_contents = new_key.set_contents_from_string.call_args[0][0] image_handler = ImageHandler(blob=resized_contents) eq_(image_handler.size, resized_size) after_upload.assert_called_once_with('thumbnail')
def file_type_test(self, bucket_method, test_file_name, content_type, resized_size): bucket = Mock() bucket_method.return_value = bucket new_key = Mock() bucket.new_key.return_value = new_key test_file = os.path.join(os.path.dirname(__file__), test_file_name) image_handler = ImageHandler.open(test_file) with open(test_file, 'r') as fh: truck = ImageTruck.new_from_stream(fh, content_type) session = Client().session() image = ImageTable(filename='badcafe') session.add(image) session.flush() ResizeImage._resize_image(image, image_handler, truck, 'thumbnail') new_key.set_metadata.assert_called_with('Content-Type', content_type) resized_contents = new_key.set_contents_from_string.call_args[0][0] image_handler = ImageHandler.open(StringIO.StringIO(resized_contents)) eq_(image_handler.size, resized_size)
def test_new_from_url(self, requests): response = Mock() response.content = "Ain't no party like a Liz Lemon party" response.headers = {'content-type': 'party'} requests.get.return_value = response truck = ImageTruck.new_from_url('http://some.url') eq_(truck.contents, "Ain't no party like a Liz Lemon party") eq_(truck.content_type, "party") eq_(truck.source_url, "http://some.url")
def show_image(request_format, image_id, size): session = Client().session() image = session.query(Image).\ filter(Image.image_id == image_id).\ one() if g.user: albums = session.query(Album).all() else: albums = [] if image.album_id is not None: album = session.query(Album).\ filter(Album.album_id == image.album_id).\ one() else: album = None (prev, next) = image.neighbors() resizes = session.query(ImageResize).\ filter(ImageResize.image_id == image_id).\ order_by(ImageResize.width.asc()).\ all() url = ImageTruck.url_for_filename(image.filename) if resizes and size in [r.suffix for r in resizes]: url = '{0}_{1}'.format(url, size) tags = image.get_tags() if request_format == 'html': return render_template('image.html.jinja', image=image, prev=prev, next=next, album=album, albums=albums, url=url, tags=list(tags), metadata_fields=filter(lambda (x,_): getattr(image, x), Image.metadata_fields), getattr=getattr, resizes=resizes, size=size) elif request_format == 'json': return { 'description': image.description, 'title': image.title, 'camera': image.camera, 'photographed_at': image.photographed_at, 'focal_length': image.focal_length, 'aperture': image.aperture, 'shutter_speed': image.shutter_speed, 'iso': image.iso, 'album_id': image.album_id, 'tags': list(tags), 'source_url': url, }
def test_get_contents_of_filename(self, MockClient): key = Mock() key.get_contents_as_string.return_value = 'cow innards' bucket = Mock() bucket.get_key.return_value = key client = Mock() client.bucket.return_value = bucket MockClient.return_value = client contents = ImageTruck.contents_of_filename('deadbeef') eq_(contents, 'cow innards') bucket.get_key.assert_called_with('deadbeef')
def test_new_from_file(self, subprocess): subprocess.check_output.return_value = \ 'space-centurion.png: PNG image data, 1280 x 800, ' \ '8-bit/color RGB, non-interlaced' (_, image) = tempfile.mkstemp() with open(image, 'w') as image_file: image_file.write('here are some contents') truck = ImageTruck.new_from_file(image) eq_(truck.content_type, "image/png") eq_(truck.contents, 'here are some contents') eq_(truck.source_url, None) subprocess.check_output.assert_called_with(['file', image])
def show_image(request_format, image_id, size): session = Client().session() image = session.query(Image).filter(Image.image_id == image_id).one() if g.user: albums = session.query(Album).all() else: albums = [] if image.album_id is not None: album = session.query(Album).filter(Album.album_id == image.album_id).one() else: album = None (prev, next) = image.neighbors() resizes = ( session.query(ImageResize).filter(ImageResize.image_id == image_id).order_by(ImageResize.width.asc()).all() ) url = ImageTruck.url_for_filename(image.filename) if resizes and size in [r.suffix for r in resizes]: url = "{0}_{1}".format(url, size) tags = image.get_tags() if request_format == "html": return render_template( "image.html.jinja", image=image, prev=prev, next=next, album=album, albums=albums, url=url, tags=list(tags), metadata_fields=filter(lambda (x, _): getattr(image, x), Image.metadata_fields), getattr=getattr, resizes=resizes, size=size, ) elif request_format == "json": return { "description": image.description, "title": image.title, "camera": image.camera, "photographed_at": image.photographed_at, "focal_length": image.focal_length, "aperture": image.aperture, "shutter_speed": image.shutter_speed, "iso": image.iso, "album_id": image.album_id, "tags": list(tags), "source_url": url, }
def find(request_format): tag_names = request.args['tags'].strip().split(' ') image_structs = [] image_data = Tag.get_image_data(tag_names) for filename, image_id, caption in image_data: image_structs.append({ 'source_url': ImageTruck.url_for_filename(filename), 'url': url_for('show_image', image_id=image_id), 'caption': caption, }) if request_format == 'html': return render_template('find.html.jinja', images=image_structs) elif request_format == 'json': return image_structs
def reprocess_image(request_format, image_id): session = Client().session() image = session.query(Image).filter(Image.image_id == image_id).one() truck = ImageTruck.new_from_image(image) contents = ImageContents(image_id=image.image_id, contents=truck.contents, content_type=truck.content_type) session.add(contents) session.flush() delay(g.queued_tasks, process_image, contents.image_contents_id) if request_format == "json": return {"status": "ok"} else: return redirect(url_for("show_image", image_id=image.image_id))
def show_image(request_format, image_id, size): session = Client().session() image = session.query(Image).\ filter(Image.image_id == image_id).\ one() if g.user: albums = session.query(Album).all() else: albums = [] try: album = filter(lambda a: a.album_id == image.album_id, albums)[0] except IndexError: album = None resizes = session.query(ImageResize).\ filter(ImageResize.image_id == image_id).\ order_by(ImageResize.width.asc()).\ all() url = ImageTruck.url_for_filename(image.filename) if resizes and size != 'original': if size not in map(lambda r: r.suffix, resizes): size = resizes[0].suffix url = '%s_%s' % (url, size) tags = image.get_tags() if request_format == 'html': return render_template('image.html.jinja', image=image, album=album, albums=albums, url=url, tags=tags, resizes=resizes, user=g.user, size=size) elif request_format == 'json': return { 'description': image.description, 'title': image.title, 'camera': image.camera, 'photographed_at': image.photographed_at, 'focal_length': image.focal_length, 'aperture': image.aperture, 'shutter_speed': image.shutter_speed, 'iso': image.iso, 'album_id': image.album_id, 'tags': list(tags), 'source_url': url, }
def test_new_from_image(self, subprocess, MockClient): subprocess.check_output.return_value = \ 'space-centurion.png: PNG image data, 1280 x 800, ' \ '8-bit/color RGB, non-interlaced' def get_contents_to_filename(filename): with open(filename, 'w') as fh: fh.write('brain, skull, etc') key = Mock() key.get_contents_to_filename.side_effect = get_contents_to_filename bucket = Mock() bucket.get_key.return_value = key client = Mock() client.bucket.return_value = bucket MockClient.return_value = client image = Image(filename='faceface') truck = ImageTruck.new_from_image(image) eq_(truck.contents, 'brain, skull, etc') bucket.get_key.assert_called_with('faceface')
def test_new_from_file__raises_well_for_non_image_files(self): try: truck = ImageTruck.new_from_file(__file__) except Exception, e: eq_(e.message, "'%s' doesn't seem to be an image file" % __file__) eq_(type(e), TypeError)
def test_new_from_url__raises_on_non_200(self, requests): response = Mock() response.raise_for_status.side_effect = HTTPError requests.get.return_value = response ImageTruck.new_from_url('http://some.url')