Exemple #1
0
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,
                       ))
Exemple #2
0
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
Exemple #3
0
    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)),
            ))
Exemple #4
0
def test_bunch_janus():
    bunch = parts.Bunch()
    bunch.a = 1
    bunch["z"] = 2

    assert bunch["a"] == 1
    assert bunch.z == 2
Exemple #5
0
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,
        ))
Exemple #6
0
    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()
Exemple #7
0
def test_bunch_no_attr():
    bunch = parts.Bunch()
    with pytest.raises(AttributeError):
        return bunch.not_there
Exemple #8
0
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=")
Exemple #9
0
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()])
Exemple #10
0
 def test_exc(self):
     b = parts.Bunch()
     try:
         b.not_there
     except AttributeError, exc:
         assert "not_there" in str(exc)
Exemple #11
0
 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=")
Exemple #12
0
 def test_janus(self):
     b = parts.Bunch()
     b.a = 1
     b["z"] = 2
     assert b["a"] == 1
     assert b.z == 2