def delete_keys(s3_bucket, key_list): """ Deletes the specified list of keys from the specified bucket :param s3_bucket: The bucket from which to delete :param key_list: The list of keys to delete from the S3 bucket :return: A MultiDeleteResult object detailing the keys that were deleted and any errors encountered """ delete = \ { "Objects" : [ { "Key": key } for key in key_list ] } if len(delete["Objects"]) > 0: response = s3_bucket.delete_objects(Delete = delete) return Struct(deleted = response.get("Deleted", []), errors = response.get("Errors", [])) else: return Struct(deleted=[], errors=[])
def test_drag_controller(self): """Make sure that we can drag photos around.""" # Can we load files? data = Struct({'get_text': lambda: '\n'.join(DEMOFILES)}) self.assertEqual(len(photos), 0) self.assertEqual(len(points), 0) gui.drag.photo_drag_end(None, None, 20, 20, data, None, None, True) self.assertEqual(len(photos), 6) self.assertEqual(len(points), 374) for button in ('select_all', 'close', 'clear'): get_obj(button + '_button').emit('clicked') self.assertEqual(len(photos), 0) self.assertEqual(len(points), 0) gui.open_files(DEMOFILES) for photo in photos.values(): # 'Drag' a ChamplainLabel and make sure the photo location matches. photo.label.set_location(random_coord(80), random_coord(180)) photo.label.emit('drag-finish', Clutter.Event()) self.assertEqual(photo.label.get_latitude(), photo.latitude) self.assertEqual(photo.label.get_longitude(), photo.longitude) self.assertGreater(len(photo.pretty_geoname()), 5) old = [photo.latitude, photo.longitude] # 'Drag' a photo onto the map and make sure that also works. selected.add(photo) data = Struct({'get_text': lambda: photo.filename}) gui.drag.photo_drag_end(None, None, 20, 20, data, None, None, True) self.assertEqual(photo.label.get_latitude(), photo.latitude) self.assertEqual(photo.label.get_longitude(), photo.longitude) self.assertGreater(len(photo.pretty_geoname()), 5) self.assertNotEqual(photo.latitude, old[0]) self.assertNotEqual(photo.longitude, old[1])
def test_get_prefixed_keys_from_bucket_returns_keys(): expected_bucket = "bucket" expected_prefix = "stacks" expected_key_list = \ [ Struct(name = "blah1", etag = "1halb"), Struct(name = "blah2", etag = "2halb"), Struct(name = "blah3", etag = "3halb") ] # define my own implementation of list def hijacked_list(**kwargs): assert kwargs["Bucket"] == expected_bucket assert kwargs["Prefix"] == expected_prefix return \ { "Contents": [{ "Key": key.name, "ETag": key.etag } for key in expected_key_list] } s3 = get_s3_client() s3.list_objects_v2 = hijacked_list # override Bucket's list function with my implementation # should call my list instead of the original keys = list(get_prefixed_keys_from_bucket(s3, expected_bucket, expected_prefix)) assert keys == expected_key_list
def test_string_functions(self): """Ensure that strings print properly.""" environ['TZ'] = 'America/Edmonton' tzset() # Make a photo with a dummy ChamplainLabel. label = Struct() label.get_text = lambda: DEMOFILES[5] photo = Photograph(label.get_text(), lambda x: None) photo.read() photo.label = label photo.latitude = None photo.longitude = None self.assertEqual(photo.pretty_coords(), 'Not geotagged') photo.latitude = 10.0 photo.longitude = 10.0 self.assertEqual(photo.pretty_coords(), 'N 10.00000, E 10.00000') photo.latitude = -10.0 photo.longitude = -10.0 self.assertEqual(photo.pretty_coords(), 'S 10.00000, W 10.00000') photo.timestamp = None self.assertIsNone(photo.pretty_time()) photo.timestamp = 999999999 self.assertEqual(photo.pretty_time(), '2001-09-08 07:46:39 PM') photo.altitude = None self.assertIsNone(photo.pretty_elevation()) photo.altitude = -10.20005 self.assertEqual(photo.pretty_elevation(), '10.2m below sea level') photo.altitude = 600.71 self.assertEqual(photo.pretty_elevation(), '600.7m above sea level') self.assertEqual(photo.short_summary(), """2001-09-08 07:46:39 PM S 10.00000, W 10.00000 600.7m above sea level""") self.assertEqual(photo.long_summary(), """<span size="larger">IMG_2411.JPG</span> <span style="italic" size="smaller">2001-09-08 07:46:39 PM S 10.00000, W 10.00000 600.7m above sea level</span>""") self.assertRegexpMatches( get_obj('maps_link').get_label(), r'href="http://maps.google.com' )
def get_prefixed_keys_from_bucket(s3, bucket, s3_path): """ Gets a list of keys from the S3 bucket in the specified path :param s3: An S3 client :param bucket: The S3 bucket to query :param s3_path: The path into the S3 bucket to query :return: A generator that lists keys from the S3 bucket in the specified path """ kwargs = { "Bucket": bucket, "Prefix": s3_path } while True: response = s3.list_objects_v2(**kwargs) for key in response.get("Contents", []): yield Struct(name = key["Key"], etag = key["ETag"]) try: kwargs["ContinuationToken"] = response["NextContinuationToken"] except KeyError: break
def preferences_dialog(self, button, dialog, region, cities, colorpicker): """Allow the user to configure this application.""" previous = Struct({ 'system': gst.get_boolean('system-timezone'), 'lookup': gst.get_boolean('lookup-timezone'), 'custom': gst.get_boolean('custom-timezone'), 'region': region.get_active(), 'city': cities.get_active(), 'color': colorpicker.get_current_color() }) if not dialog.run(): colorpicker.set_current_color(previous.color) colorpicker.set_previous_color(previous.color) gst.set_boolean('system-timezone', previous.system) gst.set_boolean('lookup-timezone', previous.lookup) gst.set_boolean('custom-timezone', previous.custom) region.set_active(previous.region) cities.set_active(previous.city) dialog.hide()
def my_new_key(key_name, etag): return Struct(name = key_name, etag = etag)
def __format__(self): self.tag = Struct.string(4) self.rootnode_offset = Struct.uint32 self.header_size = Struct.uint32 self.data_offset = Struct.uint32 self.zeroes = Struct.string(16)
def __init__(self): self.progressbar = get_obj('progressbar') self.error = Struct({ 'message': get_obj('error_message'), 'icon': get_obj('error_icon'), 'bar': get_obj('error_bar') }) self.error.bar.connect('response', lambda widget, signal: widget.hide()) self.strings = Struct({ 'quit': get_obj('quit').get_property('secondary-text'), 'preview': get_obj('preview_label').get_text() }) self.liststore = get_obj('loaded_photos') self.liststore.set_sort_column_id(TIMESTAMP, Gtk.SortType.ASCENDING) cell_string = Gtk.CellRendererText() cell_thumb = Gtk.CellRendererPixbuf() cell_thumb.set_property('stock-id', Gtk.STOCK_MISSING_IMAGE) cell_thumb.set_property('ypad', 6) cell_thumb.set_property('xpad', 12) column = Gtk.TreeViewColumn('Photos') column.pack_start(cell_thumb, False) column.add_attribute(cell_thumb, 'pixbuf', THUMB) column.pack_start(cell_string, False) column.add_attribute(cell_string, 'markup', SUMMARY) column.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) get_obj('photos_view').append_column(column) self.drag = DragController(self.open_files) self.navigator = NavigationController() self.search = SearchController() self.prefs = PreferencesController() self.labels = LabelController() self.actors = ActorController() about = get_obj('about') about.set_version(REVISION) about.set_program_name(APPNAME) about.set_logo( GdkPixbuf.Pixbuf.new_from_file_at_size( join(PKG_DATA_DIR, PACKAGE + '.svg'), 192, 192)) click_handlers = { 'open_button': [self.add_files_dialog, get_obj('open')], 'save_button': [self.save_all_files], 'clear_button': [clear_all_gpx], 'close_button': [self.close_selected_photos], 'revert_button': [self.revert_selected_photos], 'about_button': [lambda b, d: d.run() and d.hide(), about], 'apply_button': [self.apply_selected_photos, map_view], 'select_all_button': [toggle_selected_photos, self.labels.selection] } for button, handler in click_handlers.items(): get_obj(button).connect('clicked', *handler) accel = Gtk.AccelGroup() window = get_obj('main') window.resize(*gst.get('window-size')) window.connect('delete_event', self.confirm_quit_dialog) window.add_accel_group(accel) window.show_all() # Hide the unused button that appears beside the map source menu. get_obj('map_source_menu_button').get_child().get_children( )[0].set_visible(False) save_size = lambda v, s, size: gst.set_window_size(size()) for prop in ['width', 'height']: map_view.connect('notify::' + prop, save_size, window.get_size) accel.connect(Gdk.keyval_from_name('q'), Gdk.ModifierType.CONTROL_MASK, 0, self.confirm_quit_dialog) self.labels.selection.emit('changed') clear_all_gpx() metadata.delta = 0 self.secbutton, self.minbutton = get_obj('seconds'), get_obj('minutes') for spinbutton in [self.secbutton, self.minbutton]: spinbutton.connect('value-changed', self.time_offset_changed) gst.bind('offset-minutes', self.minbutton, 'value') gst.bind('offset-seconds', self.secbutton, 'value') gst.bind('left-pane-page', get_obj('photo_camera_gps'), 'page') get_obj('open').connect('update-preview', self.update_preview, get_obj('preview_label'), get_obj('preview_image'))