def fake_upload_from_url(url): """ Return a 'fake' upload data record, so that upload errors can be mitigated by using an original / alternative URL. """ return parts.Bunch(image=parts.Bunch( animated='false', bandwidth=0, caption=None, views=0, deletehash=None, hash=None, name=(url.rsplit('/', 1) + [url])[1], title=None, type='image/*', width=0, height=0, size=0, datetime=fmt.iso_datetime(), ), links=parts.Bunch( delete_page=None, imgur_page=None, original=url, large_thumbnail=url, small_square=url, ))
def cache_image_data(cache_dir, cache_key, uploader, *args, **kwargs): """ Call uploader and cache its results. """ use_cache = True if "use_cache" in kwargs: use_cache = kwargs["use_cache"] del kwargs["use_cache"] json_path = None if cache_dir: json_path = os.path.join(cache_dir, "cached-img-%s.json" % cache_key) if use_cache and os.path.exists(json_path): LOG.info("Fetching %r from cache..." % (args, )) try: with closing(open(json_path, "r")) as handle: img_data = json.load(handle) return parts.Bunch([ (key, parts.Bunch(val)) for key, val in img_data.items() # BOGUS pylint: disable=E1103 ]) except (EnvironmentError, TypeError, ValueError) as exc: LOG.warn( "Problem reading cached data from '%s', ignoring cache... (%s)" % (json_path, exc)) LOG.info("Copying %r..." % (args, )) img_data = uploader(*args, **kwargs) if json_path: with closing(open(json_path, "w")) as handle: json.dump(img_data, handle) return img_data
def upload(self, image, name=None): """ Upload the given image, which can be a http[s] URL, a path to an existing file, binary image data, or an open file handle. """ assert self.client_id, "imgur client ID is not set! Export the IMGUR_CLIENT_ID environment variable..." assert self.client_secret, "imgur client secret is not set! Export the IMGUR_CLIENT_SECRET environment variable..." # Prepare image try: image_data = (image + '') except (TypeError, ValueError): assert hasattr( image, "read"), "Image is neither a string nor an open file handle" image_type = "file" image_data = image # XXX are streams supported? need a temp file? image_repr = repr(image) else: if image.startswith("http:") or image.startswith("https:"): image_type = "url" image_data = image image_repr = image elif all(ord(i) >= 32 for i in image) and os.path.exists(image): image_type = "file" image_data = image # XXX open(image, "rb") image_repr = "file:" + image else: # XXX Not supported anymore (maybe use a temp file?) image_type = "base64" image_data = image_data.encode(image_type) image_repr = "<binary data>" # Upload image # XXX "name", name or hashlib.md5(str(image)).hexdigest()), client = ImgurClient(self.client_id, self.client_secret) result = (client.upload_from_url if image_type == 'url' else client.upload_from_path)( image_data) # XXX config=None, anon=True) if result['link'].startswith('http:'): result['link'] = 'https:' + result['link'][5:] result['hash'] = result['id'] # compatibility to API v1 result['caption'] = result['description'] # compatibility to API v1 return parts.Bunch( image=parts.Bunch(result), links=parts.Bunch( delete_page=None, imgur_page=None, original=result['link'], large_thumbnail="{0}s.{1}".format( *result['link'].rsplit('.', 1)), small_square="{0}l.{1}".format(*result['link'].rsplit('.', 1)), ))
def test_bunch_janus(): bunch = parts.Bunch() bunch.a = 1 bunch["z"] = 2 assert bunch["a"] == 1 assert bunch.z == 2
def fake_upload_from_url(url): """ Return a 'fake' upload data record, so that upload errors can be mitigated by using an original / alternative URL, especially when cross-loading from the web. """ return parts.Bunch( image=parts.Bunch( animated='false', bandwidth=0, caption=None, views=0, deletehash=None, hash=None, name=(url.rsplit('/', 1) + [url])[1], title=None, type='image/*', width=0, height=0, size=0, datetime=int( time.time() ), # XXX was fmt.iso_datetime() - in API v2 this is a UNIX timestamp id='xxxxxxx', link=url, account_id=0, account_url=None, ad_type=0, ad_url='', description=None, favorite=False, in_gallery=False, in_most_viral=False, is_ad=False, nsfw=None, section=None, tags=[], vote=None, ), links=parts.Bunch( delete_page=None, imgur_page=None, original=url, large_thumbnail=url, small_square=url, ))
def send(self): """ Post fields and files to an HTTP server as multipart/form-data. Return the server's response. """ scheme, location, path, query, _ = urllib.parse.urlsplit(self.url) assert scheme in ("http", "https"), "Unsupported scheme %r" % scheme content_type, body = self._encode_multipart_formdata() handle = getattr(httplib, scheme.upper() + "Connection")(location) if self.mock_http: # Don't actually send anything, print to stdout instead handle.sock = parts.Bunch( sendall=lambda x: sys.stdout.write( fmt.to_utf8(''.join( (c if 32 <= ord(c) < 127 or ord(c) in (8, 10) else u'\u27ea%02X\u27eb' % ord(c)) for c in x))), makefile=lambda dummy, _: StringIO.StringIO("\r\n".join(( "HTTP/1.0 204 NO CONTENT", "Content-Length: 0", "", ))), close=lambda: None, ) handle.putrequest('POST', urllib.parse.urlunsplit(('', '', path, query, ''))) handle.putheader('Content-Type', content_type) handle.putheader('Content-Length', str(len(body))) for key, val in self.headers.items(): handle.putheader(key, val) handle.endheaders() handle.send(body) #print handle.__dict__ return handle.getresponse()
def test_bunch_no_attr(): bunch = parts.Bunch() with pytest.raises(AttributeError): return bunch.not_there
def test_bunch_repr(): bunch = repr(parts.Bunch(a=1, z=2)) assert bunch.startswith("Bunch(") assert "a=" in bunch assert bunch.index("a=") < bunch.index("z=")
class ImgurUploader(object): # pylint: disable=R0903 """ Upload an image to "imgur.com". Sample code:: imgur = ImgurUploader() image = imgur.upload("favicon.jpg") # OR: image = imgur.upload(open("favicon.jpg", "rb")) # OR: image = imgur.upload(open("favicon.jpg", "rb").read()) # OR: image = imgur.upload("http://i.imgur.com/5EuUx.jpg") print image.links.original """ UPLOAD_URL = "http://api.imgur.com/2/upload.json" def __init__(self, api_key=None, mock_http=False): """ Initialize upload parameters. @param api_key: the API key (optionally taken from IMGUR_APIKEY environment variable). """ self.api_key = api_key or os.environ.get("IMGUR_APIKEY") self.mock_http = mock_http def upload(self, image, name=None): """ Upload the given image, which can be a http[s] URL, a path to an existing file, binary image data, or an open file handle. """ assert self.api_key, "imgur API key is not set! Export the IMGUR_APIKEY environment variable..." # Prepare image try: image_data = (image + '') except (TypeError, ValueError): assert hasattr( image, "read"), "Image is neither a string nor an open file handle" image_type = "file" image_data = image image_repr = repr(image) else: if image.startswith("http:") or image.startswith("https:"): image_type = "url" image_data = image image_repr = image elif all(ord(i) >= 32 for i in image) and os.path.exists(image): image_type = "file" image_data = open(image, "rb") image_repr = "file:" + image else: image_type = "base64" image_data = image_data.encode(image_type) image_repr = "<binary data>" # See http://api.imgur.com/resources_anon#upload fields = [ ("key", self.api_key), ("type", image_type), ("image", image_data), ("name", name or hashlib.md5(str(image)).hexdigest()), ] handle = http.HttpPost(self.UPLOAD_URL, fields, mock_http=self.mock_http) response = handle.send() if response.status >= 300: LOG.warn("Image %s upload failed with result %d %s" % (image_repr, response.status, response.reason)) else: LOG.debug("Image %s uploaded with result %d %s" % (image_repr, response.status, response.reason)) body = response.read() LOG.debug("Response size: %d" % len(body)) LOG.debug( "Response headers:\n %s" % "\n ".join(["%s: %s" % item for item in response.getheaders()])) try: result = json.loads(body) except (ValueError, TypeError), exc: raise httplib.HTTPException( "Bad JSON data from imgur upload%s [%s]: %s" % (", looking like a CAPTCHA challenge" if "captcha" in body else "", exc, logutil.shorten(body))) if "error" in result: raise httplib.HTTPException( "Error response from imgur.com: %(message)s" % result["error"], result) return parts.Bunch([(key, parts.Bunch(val)) for key, val in result["upload"].items()])
def test_exc(self): b = parts.Bunch() try: b.not_there except AttributeError, exc: assert "not_there" in str(exc)
def test_repr(self): b = repr(parts.Bunch(a=1, z=2)) assert b.startswith("Bunch(") assert "a=" in b assert b.index("a=") < b.index("z=")
def test_janus(self): b = parts.Bunch() b.a = 1 b["z"] = 2 assert b["a"] == 1 assert b.z == 2