Commit 40c32f9f
Changed files (33)
openai
api_resources
abstract
experimental
tests
public
openai/api_resources/abstract/__init__.py
@@ -1,28 +1,12 @@
-from __future__ import absolute_import, division, print_function
-
# flake8: noqa
from openai.api_resources.abstract.api_resource import APIResource
-from openai.api_resources.abstract.singleton_api_resource import (
- SingletonAPIResource,
-)
-
-from openai.api_resources.abstract.createable_api_resource import (
- CreateableAPIResource,
-)
-from openai.api_resources.abstract.updateable_api_resource import (
- UpdateableAPIResource,
-)
-from openai.api_resources.abstract.deletable_api_resource import (
- DeletableAPIResource,
-)
-from openai.api_resources.abstract.listable_api_resource import (
- ListableAPIResource,
-)
-from openai.api_resources.abstract.verify_mixin import VerifyMixin
-
+from openai.api_resources.abstract.singleton_api_resource import SingletonAPIResource
+from openai.api_resources.abstract.createable_api_resource import CreateableAPIResource
+from openai.api_resources.abstract.updateable_api_resource import UpdateableAPIResource
+from openai.api_resources.abstract.deletable_api_resource import DeletableAPIResource
+from openai.api_resources.abstract.listable_api_resource import ListableAPIResource
from openai.api_resources.abstract.custom_method import custom_method
-
from openai.api_resources.abstract.nested_resource_class_methods import (
nested_resource_class_methods,
)
openai/api_resources/abstract/api_resource.py
@@ -1,8 +1,7 @@
-from __future__ import absolute_import, division, print_function
+from urllib.parse import quote_plus
-from openai import api_requestor, error, six, util
+from openai import api_requestor, error, util
from openai.openai_object import OpenAIObject
-from openai.six.moves.urllib.parse import quote_plus
class APIResource(OpenAIObject):
@@ -28,13 +27,13 @@ class APIResource(OpenAIObject):
)
# Namespaces are separated in object names with periods (.) and in URLs
# with forward slashes (/), so replace the former with the latter.
- base = cls.OBJECT_NAME.replace(".", "/")
+ base = cls.OBJECT_NAME.replace(".", "/") # type: ignore
return "/%s/%ss" % (cls.api_prefix, base)
def instance_url(self):
id = self.get("id")
- if not isinstance(id, six.string_types):
+ if not isinstance(id, str):
raise error.InvalidRequestError(
"Could not determine which URL to request: %s instance "
"has invalid ID: %r, %s. ID should be of type `str` (or"
@@ -42,7 +41,6 @@ class APIResource(OpenAIObject):
"id",
)
- id = util.utf8(id)
base = self.class_url()
extn = quote_plus(id)
return "%s/%s" % (base, extn)
@@ -60,7 +58,7 @@ class APIResource(OpenAIObject):
request_id=None,
api_version=None,
organization=None,
- **params
+ **params,
):
requestor = api_requestor.APIRequestor(
api_key,
openai/api_resources/abstract/createable_api_resource.py
@@ -16,7 +16,7 @@ class CreateableAPIResource(APIResource):
request_id=None,
api_version=None,
organization=None,
- **params
+ **params,
):
requestor = api_requestor.APIRequestor(
api_key,
openai/api_resources/abstract/custom_method.py
@@ -1,7 +1,6 @@
-from __future__ import absolute_import, division, print_function
+from urllib.parse import quote_plus
from openai import util
-from openai.six.moves.urllib.parse import quote_plus
def custom_method(name, http_verb, http_path=None):
@@ -17,7 +16,7 @@ def custom_method(name, http_verb, http_path=None):
def custom_method_request(cls, sid, **params):
url = "%s/%s/%s" % (
cls.class_url(),
- quote_plus(util.utf8(sid)),
+ quote_plus(sid),
http_path,
)
return cls._static_request(http_verb, url, **params)
@@ -33,9 +32,7 @@ def custom_method(name, http_verb, http_path=None):
# that the new class method is called when the original method is
# called as a class method.
setattr(cls, "_cls_" + name, classmethod(custom_method_request))
- instance_method = util.class_method_variant("_cls_" + name)(
- existing_method
- )
+ instance_method = util.class_method_variant("_cls_" + name)(existing_method)
setattr(cls, name, instance_method)
return cls
openai/api_resources/abstract/deletable_api_resource.py
@@ -1,14 +1,13 @@
-from __future__ import absolute_import, division, print_function
+from urllib.parse import quote_plus
from openai import util
from openai.api_resources.abstract.api_resource import APIResource
-from openai.six.moves.urllib.parse import quote_plus
class DeletableAPIResource(APIResource):
@classmethod
def _cls_delete(cls, sid, **params):
- url = "%s/%s" % (cls.class_url(), quote_plus(util.utf8(sid)))
+ url = "%s/%s" % (cls.class_url(), quote_plus(sid))
return cls._static_request("delete", url, **params)
@util.class_method_variant("_cls_delete")
openai/api_resources/abstract/engine_api_resource.py
@@ -1,8 +1,9 @@
import time
+from typing import Optional
+from urllib.parse import quote_plus
-from openai import api_requestor, error, six, util
+from openai import api_requestor, error, util
from openai.api_resources.abstract.api_resource import APIResource
-from openai.six.moves.urllib.parse import quote_plus
MAX_TIMEOUT = 20
@@ -11,56 +12,20 @@ class EngineAPIResource(APIResource):
engine_required = True
plain_old_data = False
- def __init__(self, *args, **kwargs):
- engine = kwargs.pop("engine", None)
- super().__init__(*args, engine=engine, **kwargs)
+ def __init__(self, engine: Optional[str] = None, **kwargs):
+ super().__init__(engine=engine, **kwargs)
@classmethod
- def class_url(cls, engine=None):
+ def class_url(cls, engine: Optional[str] = None):
# Namespaces are separated in object names with periods (.) and in URLs
# with forward slashes (/), so replace the former with the latter.
- base = cls.OBJECT_NAME.replace(".", "/")
+ base = cls.OBJECT_NAME.replace(".", "/") # type: ignore
if engine is None:
return "/%s/%ss" % (cls.api_prefix, base)
- engine = util.utf8(engine)
extn = quote_plus(engine)
return "/%s/engines/%s/%ss" % (cls.api_prefix, extn, base)
- @classmethod
- def retrieve(cls, id, api_key=None, request_id=None, **params):
- engine = params.pop("engine", None)
- instance = cls(id, api_key, engine=engine, **params)
- instance.refresh(request_id=request_id)
- return instance
-
- @classmethod
- def update(
- cls,
- api_key=None,
- api_base=None,
- idempotency_key=None,
- request_id=None,
- api_version=None,
- organization=None,
- **params,
- ):
- # TODO max
- engine_id = params.get("id")
- replicas = params.get("replicas")
-
- engine = EngineAPIResource(id=id)
-
- requestor = api_requestor.APIRequestor(
- api_key,
- api_base=api_base,
- api_version=api_version,
- organization=organization,
- )
- url = cls.class_url(engine)
- headers = util.populate_headers(idempotency_key, request_id)
- response, _, api_key = requestor.request("post", url, params, headers)
-
@classmethod
def create(
cls,
@@ -138,7 +103,7 @@ class EngineAPIResource(APIResource):
def instance_url(self):
id = self.get("id")
- if not isinstance(id, six.string_types):
+ if not isinstance(id, str):
raise error.InvalidRequestError(
"Could not determine which URL to request: %s instance "
"has invalid ID: %r, %s. ID should be of type `str` (or"
@@ -146,7 +111,6 @@ class EngineAPIResource(APIResource):
"id",
)
- id = util.utf8(id)
base = self.class_url(self.engine)
extn = quote_plus(id)
url = "%s/%s" % (base, extn)
@@ -158,7 +122,6 @@ class EngineAPIResource(APIResource):
return url
def wait(self, timeout=None):
- engine = self.engine
start = time.time()
while self.status != "complete":
self.timeout = (
openai/api_resources/abstract/listable_api_resource.py
@@ -17,7 +17,7 @@ class ListableAPIResource(APIResource):
api_version=None,
organization=None,
api_base=None,
- **params
+ **params,
):
headers = util.populate_headers(request_id=request_id)
requestor = api_requestor.APIRequestor(
openai/api_resources/abstract/nested_resource_class_methods.py
@@ -1,7 +1,6 @@
-from __future__ import absolute_import, division, print_function
+from urllib.parse import quote_plus
from openai import api_requestor, util
-from openai.six.moves.urllib.parse import quote_plus
def nested_resource_class_methods(
@@ -33,7 +32,7 @@ def nested_resource_class_methods(
request_id=None,
api_version=None,
organization=None,
- **params
+ **params,
):
requestor = api_requestor.APIRequestor(
api_key, api_version=api_version, organization=organization
openai/api_resources/abstract/singleton_api_resource.py
@@ -17,7 +17,7 @@ class SingletonAPIResource(APIResource):
)
# Namespaces are separated in object names with periods (.) and in URLs
# with forward slashes (/), so replace the former with the latter.
- base = cls.OBJECT_NAME.replace(".", "/")
+ base = cls.OBJECT_NAME.replace(".", "/") # type: ignore
return "/v1/%s" % (base,)
def instance_url(self):
openai/api_resources/abstract/updateable_api_resource.py
@@ -1,14 +1,13 @@
-from __future__ import absolute_import, division, print_function
+from urllib.parse import quote_plus
from openai import util
from openai.api_resources.abstract.api_resource import APIResource
-from openai.six.moves.urllib.parse import quote_plus
class UpdateableAPIResource(APIResource):
@classmethod
def modify(cls, sid, **params):
- url = "%s/%s" % (cls.class_url(), quote_plus(util.utf8(sid)))
+ url = "%s/%s" % (cls.class_url(), quote_plus(sid))
return cls._static_request("post", url, **params)
def save(self, idempotency_key=None, request_id=None):
openai/api_resources/abstract/verify_mixin.py
@@ -1,11 +0,0 @@
-from __future__ import absolute_import, division, print_function
-
-from openai import util
-
-
-class VerifyMixin(object):
- def verify(self, idempotency_key=None, request_id=None, **params):
- url = self.instance_url() + "/verify"
- headers = util.populate_headers(idempotency_key, request_id)
- self.refresh_from(self.request("post", url, params, headers))
- return self
openai/api_resources/experimental/__init__.py
@@ -1,1 +1,3 @@
-from openai.api_resources.experimental.completion_config import CompletionConfig
+from openai.api_resources.experimental.completion_config import ( # noqa: F401
+ CompletionConfig,
+)
openai/api_resources/__init__.py
@@ -1,8 +1,8 @@
-from openai.api_resources.completion import Completion
-from openai.api_resources.engine import Engine
-from openai.api_resources.error_object import ErrorObject
-from openai.api_resources.file import File
-from openai.api_resources.answer import Answer
-from openai.api_resources.classification import Classification
-from openai.api_resources.snapshot import Snapshot
-from openai.api_resources.fine_tune import FineTune
+from openai.api_resources.completion import Completion # noqa: F401
+from openai.api_resources.engine import Engine # noqa: F401
+from openai.api_resources.error_object import ErrorObject # noqa: F401
+from openai.api_resources.file import File # noqa: F401
+from openai.api_resources.answer import Answer # noqa: F401
+from openai.api_resources.classification import Classification # noqa: F401
+from openai.api_resources.snapshot import Snapshot # noqa: F401
+from openai.api_resources.fine_tune import FineTune # noqa: F401
openai/api_resources/engine.py
@@ -1,8 +1,6 @@
-from __future__ import absolute_import, division, print_function
-
import time
-from openai import api_requestor, util
+from openai import util
from openai.api_resources.abstract import (
ListableAPIResource,
UpdateableAPIResource,
openai/api_resources/fine_tune.py
@@ -1,9 +1,10 @@
+from urllib.parse import quote_plus
+
from openai.api_resources.abstract import (
ListableAPIResource,
CreateableAPIResource,
nested_resource_class_methods,
)
-from openai.six.moves.urllib.parse import quote_plus
from openai import api_requestor, util
@@ -29,7 +30,7 @@ class FineTune(ListableAPIResource, CreateableAPIResource):
request_id=None,
api_version=None,
organization=None,
- **params
+ **params,
):
base = cls.class_url()
extn = quote_plus(id)
openai/api_resources/list_object.py
@@ -1,176 +0,0 @@
-from __future__ import absolute_import, division, print_function
-
-from openai import api_requestor, six, util
-from openai.openai_object import OpenAIObject
-
-from openai.six.moves.urllib.parse import quote_plus
-
-
-class ListObject(OpenAIObject):
- OBJECT_NAME = "list"
-
- def list(self, api_key=None, openai_version=None, openai_account=None, **params):
- openai_object = self._request(
- "get",
- self.get("url"),
- api_key=api_key,
- openai_version=openai_version,
- openai_account=openai_account,
- **params
- )
- openai_object._retrieve_params = params
- return openai_object
-
- def create(
- self,
- api_key=None,
- idempotency_key=None,
- openai_version=None,
- openai_account=None,
- **params
- ):
- return self._request(
- "post",
- self.get("url"),
- api_key=api_key,
- idempotency_key=idempotency_key,
- openai_version=openai_version,
- openai_account=openai_account,
- **params
- )
-
- def retrieve(
- self, id, api_key=None, openai_version=None, openai_account=None, **params
- ):
- url = "%s/%s" % (self.get("url"), quote_plus(util.utf8(id)))
- return self._request(
- "get",
- url,
- api_key=api_key,
- openai_version=openai_version,
- openai_account=openai_account,
- **params
- )
-
- def _request(
- self,
- method_,
- url_,
- api_key=None,
- idempotency_key=None,
- openai_version=None,
- openai_account=None,
- **params
- ):
- api_key = api_key or self.api_key
- openai_version = openai_version or self.openai_version
- openai_account = openai_account or self.openai_account
-
- requestor = api_requestor.APIRequestor(
- api_key, api_version=openai_version, account=openai_account
- )
- headers = util.populate_headers(idempotency_key)
- response, api_key = requestor.request(method_, url_, params, headers)
- openai_object = util.convert_to_openai_object(
- response, api_key, openai_version, openai_account
- )
- return openai_object
-
- def __getitem__(self, k):
- if isinstance(k, six.string_types):
- return super(ListObject, self).__getitem__(k)
- else:
- raise KeyError(
- "You tried to access the %s index, but ListObject types only "
- "support string keys. (HINT: List calls return an object with "
- "a 'data' (which is the data array). You likely want to call "
- ".data[%s])" % (repr(k), repr(k))
- )
-
- def __iter__(self):
- return getattr(self, "data", []).__iter__()
-
- def __len__(self):
- return getattr(self, "data", []).__len__()
-
- def __reversed__(self):
- return getattr(self, "data", []).__reversed__()
-
- def auto_paging_iter(self):
- page = self
-
- while True:
- if (
- "ending_before" in self._retrieve_params
- and "starting_after" not in self._retrieve_params
- ):
- for item in reversed(page):
- yield item
- page = page.previous_page()
- else:
- for item in page:
- yield item
- page = page.next_page()
-
- if page.is_empty:
- break
-
- @classmethod
- def empty_list(cls, api_key=None, openai_version=None, openai_account=None):
- return cls.construct_from(
- {"data": []},
- key=api_key,
- openai_version=openai_version,
- openai_account=openai_account,
- last_response=None,
- )
-
- @property
- def is_empty(self):
- return not self.data
-
- def next_page(
- self, api_key=None, openai_version=None, openai_account=None, **params
- ):
- if not self.has_more:
- return self.empty_list(
- api_key=api_key,
- openai_version=openai_version,
- openai_account=openai_account,
- )
-
- last_id = self.data[-1].id
-
- params_with_filters = self._retrieve_params.copy()
- params_with_filters.update({"starting_after": last_id})
- params_with_filters.update(params)
-
- return self.list(
- api_key=api_key,
- openai_version=openai_version,
- openai_account=openai_account,
- **params_with_filters
- )
-
- def previous_page(
- self, api_key=None, openai_version=None, openai_account=None, **params
- ):
- if not self.has_more:
- return self.empty_list(
- api_key=api_key,
- openai_version=openai_version,
- openai_account=openai_account,
- )
-
- first_id = self.data[0].id
-
- params_with_filters = self._retrieve_params.copy()
- params_with_filters.update({"ending_before": first_id})
- params_with_filters.update(params)
-
- return self.list(
- api_key=api_key,
- openai_version=openai_version,
- openai_account=openai_account,
- **params_with_filters
- )
openai/api_resources/snapshot.py
@@ -1,4 +1,3 @@
-from openai.api_resources.abstract.engine_api_resource import EngineAPIResource
from openai.api_resources.abstract import (
ListableAPIResource,
DeletableAPIResource,
openai/tests/test_endpoints.py
@@ -1,9 +1,9 @@
import openai
import io
import json
-import uuid
-### FILE TESTS
+
+# FILE TESTS
def test_file_upload():
result = openai.File.create(
file=io.StringIO(json.dumps({"text": "test file data"})),
@@ -13,7 +13,7 @@ def test_file_upload():
assert "id" in result
-### COMPLETION TESTS
+# COMPLETION TESTS
def test_completions():
result = openai.Completion.create(prompt="This was a test", n=5, engine="davinci")
assert len(result.choices) == 5
openai/__init__.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import, division, print_function
-
import os
# OpenAI Python bindings.
@@ -27,6 +25,15 @@ debug = False
log = None
# API resources
-from openai.api_resources import * # noqa
+from openai.api_resources import ( # noqa: E402,F401
+ Answer,
+ Classification,
+ Completion,
+ Engine,
+ ErrorObject,
+ File,
+ FineTune,
+ Snapshot,
+)
-from openai.error import OpenAIError, APIError, InvalidRequestError
+from openai.error import OpenAIError, APIError, InvalidRequestError # noqa: E402,F401
openai/api_requestor.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import, division, print_function
-
import calendar
import datetime
import json
@@ -7,19 +5,19 @@ import platform
import time
import uuid
import warnings
-import gzip
from io import BytesIO
from collections import OrderedDict
+from urllib.parse import urlencode, urlsplit, urlunsplit
import openai
-from openai import error, http_client, version, util, six
+from openai import error, http_client, version, util
from openai.multipart_data_generator import MultipartDataGenerator
-from openai.six.moves.urllib.parse import urlencode, urlsplit, urlunsplit
from openai.openai_response import OpenAIResponse
from openai.upload_progress import BufferReader
-def _encode_datetime(dttime):
+def _encode_datetime(dttime) -> int:
+ utc_timestamp: float
if dttime.tzinfo and dttime.tzinfo.utcoffset(dttime) is not None:
utc_timestamp = calendar.timegm(dttime.utctimetuple())
else:
@@ -30,14 +28,13 @@ def _encode_datetime(dttime):
def _encode_nested_dict(key, data, fmt="%s[%s]"):
d = OrderedDict()
- for subkey, subvalue in six.iteritems(data):
+ for subkey, subvalue in data.items():
d[fmt % (key, subkey)] = subvalue
return d
def _api_encode(data):
- for key, value in six.iteritems(data):
- key = util.utf8(key)
+ for key, value in data.items():
if value is None:
continue
elif hasattr(value, "openai_id"):
@@ -49,7 +46,7 @@ def _api_encode(data):
for k, v in _api_encode(subdict):
yield (k, v)
else:
- yield ("%s[%d]" % (key, i), util.utf8(sv))
+ yield ("%s[%d]" % (key, i), sv)
elif isinstance(value, dict):
subdict = _encode_nested_dict(key, value)
for subkey, subvalue in _api_encode(subdict):
@@ -57,7 +54,7 @@ def _api_encode(data):
elif isinstance(value, datetime.datetime):
yield (key, _encode_datetime(value))
else:
- yield (key, util.utf8(value))
+ yield (key, value)
def _build_api_url(url, query):
@@ -81,7 +78,7 @@ def parse_stream(rbody):
yield line
-class APIRequestor(object):
+class APIRequestor:
def __init__(
self, key=None, client=None, api_base=None, api_version=None, organization=None
):
@@ -205,20 +202,13 @@ class APIRequestor(object):
ua = {
"bindings_version": version.VERSION,
+ "httplib": self._client.name,
"lang": "python",
+ "lang_version": platform.python_version(),
+ "platform": platform.platform(),
"publisher": "openai",
- "httplib": self._client.name,
+ "uname": " ".join(platform.uname()),
}
- for attr, func in [
- ["lang_version", platform.python_version],
- ["platform", platform.platform],
- ["uname", lambda: " ".join(platform.uname())],
- ]:
- try:
- val = func()
- except Exception as e:
- val = "!! %s" % (e,)
- ua[attr] = val
if openai.app_info:
ua["application"] = openai.app_info
@@ -257,7 +247,7 @@ class APIRequestor(object):
if my_api_key is None:
raise error.AuthenticationError(
- "No API key provided. (HINT: set your API key using in code using "
+ "No API key provided. (HINT: set your API key in code using "
'"openai.api_key = <API-KEY>", or you can set the environment variable OPENAI_API_KEY=<API-KEY>). You can generate API keys '
"in the OpenAI web interface. See https://onboard.openai.com "
"for details, or email support@openai.com if you have any "
@@ -320,7 +310,7 @@ class APIRequestor(object):
headers = self.request_headers(my_api_key, method, headers)
if supplied_headers is not None:
- for key, value in six.iteritems(supplied_headers):
+ for key, value in supplied_headers.items():
headers[key] = value
util.log_info("Request to OpenAI API", method=method, path=abs_url)
openai/cli.py
@@ -285,7 +285,7 @@ class FineTune:
@classmethod
def events(cls, args):
if not args.stream:
- resp = openai.FineTune.list_events(id=args.id)
+ resp = openai.FineTune.list_events(id=args.id) # type: ignore
print(resp)
return
cls._stream_events(args.id)
@@ -420,7 +420,7 @@ Mutually exclusive with `top_p`.""",
sub.add_argument("-q", "--query", required=True, help="Search query")
sub.set_defaults(func=Engine.search)
- ## Completions
+ # Completions
sub = subparsers.add_parser("completions.create")
sub.add_argument("-e", "--engine", required=True, help="The engine to use")
sub.add_argument(
@@ -462,7 +462,7 @@ Mutually exclusive with `top_p`.""",
)
sub.set_defaults(func=Completion.create)
- ## Snapshots
+ # Snapshots
sub = subparsers.add_parser("snapshots.list")
sub.set_defaults(func=Snapshot.list)
openai/error.py
@@ -1,10 +1,8 @@
from __future__ import absolute_import, division, print_function
import openai
-from openai.six import python_2_unicode_compatible
-@python_2_unicode_compatible
class OpenAIError(Exception):
def __init__(
self,
@@ -39,7 +37,7 @@ class OpenAIError(Exception):
def __str__(self):
msg = self._message or "<empty message>"
if self.request_id is not None:
- return u"Request {0}: {1}".format(self.request_id, msg)
+ return "Request {0}: {1}".format(self.request_id, msg)
else:
return msg
@@ -97,40 +95,11 @@ class APIConnectionError(OpenAIError):
self.should_retry = should_retry
-class OpenAIErrorWithParamCode(OpenAIError):
- def __repr__(self):
- return "%s(message=%r, param=%r, code=%r, http_status=%r, " "request_id=%r)" % (
- self.__class__.__name__,
- self._message,
- self.param,
- self.code,
- self.http_status,
- self.request_id,
- )
-
-
-class CardError(OpenAIErrorWithParamCode):
- def __init__(
- self,
- message,
- param,
- code,
- http_body=None,
- http_status=None,
- json_body=None,
- headers=None,
- ):
- super(CardError, self).__init__(
- message, http_body, http_status, json_body, headers, code
- )
- self.param = param
-
-
class IdempotencyError(OpenAIError):
pass
-class InvalidRequestError(OpenAIErrorWithParamCode):
+class InvalidRequestError(OpenAIError):
def __init__(
self,
message,
@@ -146,6 +115,16 @@ class InvalidRequestError(OpenAIErrorWithParamCode):
)
self.param = param
+ def __repr__(self):
+ return "%s(message=%r, param=%r, code=%r, http_status=%r, " "request_id=%r)" % (
+ self.__class__.__name__,
+ self._message,
+ self.param,
+ self.code,
+ self.http_status,
+ self.request_id,
+ )
+
class AuthenticationError(OpenAIError):
pass
openai/http_client.py
@@ -1,93 +1,28 @@
-from __future__ import absolute_import, division, print_function
-
-import sys
-import textwrap
-import warnings
-import email
-import time
+import abc
+import json
import random
+import textwrap
import threading
-import json
+import time
+from typing import Any, Dict
+
+import requests
+from urllib.parse import urlparse
import openai
-from openai import error, util, six
+from openai import error, util
from openai.request_metrics import RequestMetrics
-# - Requests is the preferred HTTP library
-# - Google App Engine has urlfetch
-# - Use Pycurl if it's there (at least it verifies SSL certs)
-# - Fall back to urllib2 with a warning if needed
-try:
- from openai.six.moves import urllib
-except ImportError:
- # Try to load in urllib2, but don't sweat it if it's not available.
- pass
-
-try:
- import pycurl
-except ImportError:
- pycurl = None
-
-try:
- import requests
-except ImportError:
- requests = None
-else:
- try:
- # Require version 0.8.8, but don't want to depend on distutils
- version = requests.__version__
- major, minor, patch = [int(i) for i in version.split(".")]
- except Exception:
- # Probably some new-fangled version, so it should support verify
- pass
- else:
- if (major, minor, patch) < (0, 8, 8):
- sys.stderr.write(
- "Warning: the OpenAI library requires that your Python "
- '"requests" library be newer than version 0.8.8, but your '
- '"requests" library is version %s. OpenAI will fall back to '
- "an alternate HTTP library so everything should work. We "
- 'recommend upgrading your "requests" library. If you have any '
- "questions, please contact support@openai.com. (HINT: running "
- '"pip install -U requests" should upgrade your requests '
- "library to the latest version.)" % (version,)
- )
- requests = None
-
-try:
- from google.appengine.api import urlfetch
-except ImportError:
- urlfetch = None
-
-# proxy support for the pycurl client
-from openai.six.moves.urllib.parse import urlparse
-
def _now_ms():
return int(round(time.time() * 1000))
def new_default_http_client(*args, **kwargs):
- if urlfetch:
- impl = UrlFetchClient
- elif requests:
- impl = RequestsClient
- elif pycurl:
- impl = PycurlClient
- else:
- impl = Urllib2Client
- warnings.warn(
- "Warning: the OpenAI library is falling back to urllib2/urllib "
- "because neither requests nor pycurl are installed. "
- "urllib2's SSL implementation doesn't verify server "
- "certificates. For improved security, we suggest installing "
- "requests."
- )
+ return RequestsClient(*args, **kwargs)
- return impl(*args, **kwargs)
-
-class HTTPClient(object):
+class HTTPClient(abc.ABC):
MAX_DELAY = 2
INITIAL_DELAY = 0.5
MAX_RETRY_AFTER = 60
@@ -148,6 +83,7 @@ class HTTPClient(object):
return response
else:
+ assert connection_error is not None
raise connection_error
def request(self, method, url, headers, post_data=None, stream=False):
@@ -247,8 +183,9 @@ class HTTPClient(object):
request_id, request_duration_ms
)
+ @abc.abstractmethod
def close(self):
- raise NotImplementedError("HTTPClient subclasses must implement `close`")
+ ...
class RequestsClient(HTTPClient):
@@ -260,7 +197,7 @@ class RequestsClient(HTTPClient):
self._timeout = timeout
def request(self, method, url, headers, post_data=None, stream=False):
- kwargs = {}
+ kwargs: Dict[str, Any] = {}
if self._verify_ssl_certs:
kwargs["verify"] = openai.ca_bundle_path
else:
@@ -281,7 +218,7 @@ class RequestsClient(HTTPClient):
data=post_data,
timeout=self._timeout,
stream=stream,
- **kwargs
+ **kwargs,
)
except TypeError as e:
raise TypeError(
@@ -314,7 +251,7 @@ class RequestsClient(HTTPClient):
# but we don't want to retry, unless it is caused by dropped
# SSL connection
if isinstance(e, requests.exceptions.SSLError):
- if 'ECONNRESET' not in repr(e):
+ if "ECONNRESET" not in repr(e):
msg = (
"Could not verify OpenAI's SSL certificate. Please make "
"sure that your network is not intercepting certificates. "
@@ -377,258 +314,3 @@ class RequestsClient(HTTPClient):
def close(self):
if getattr(self._thread_local, "session", None) is not None:
self._thread_local.session.close()
-
-
-class UrlFetchClient(HTTPClient):
- name = "urlfetch"
-
- def __init__(self, verify_ssl_certs=True, proxy=None, deadline=55):
- super(UrlFetchClient, self).__init__(
- verify_ssl_certs=verify_ssl_certs, proxy=proxy
- )
-
- # no proxy support in urlfetch. for a patch, see:
- # https://code.google.com/p/googleappengine/issues/detail?id=544
- if proxy:
- raise ValueError(
- "No proxy support in urlfetch library. "
- "Set openai.default_http_client to either RequestsClient, "
- "PycurlClient, or Urllib2Client instance to use a proxy."
- )
-
- self._verify_ssl_certs = verify_ssl_certs
- # GAE requests time out after 60 seconds, so make sure to default
- # to 55 seconds to allow for a slow OpenAI
- self._deadline = deadline
-
- def request(self, method, url, headers, post_data=None, stream=False):
- if stream:
- raise NotImplementedError("Stream not yet implemented for {}".format(self))
- try:
- result = urlfetch.fetch(
- url=url,
- method=method,
- headers=headers,
- # Google App Engine doesn't let us specify our own cert bundle.
- # However, that's ok because the CA bundle they use recognizes
- # api.openai.com.
- validate_certificate=self._verify_ssl_certs,
- deadline=self._deadline,
- payload=post_data,
- )
- except urlfetch.Error as e:
- self._handle_request_error(e, url)
-
- return result.content, result.status_code, result.headers, stream
-
- def _handle_request_error(self, e, url):
- if isinstance(e, urlfetch.InvalidURLError):
- msg = (
- "The OpenAI library attempted to fetch an "
- "invalid URL (%r). This is likely due to a bug "
- "in the OpenAI Python bindings. Please let us know "
- "at support@openai.com." % (url,)
- )
- elif isinstance(e, urlfetch.DownloadError):
- msg = "There was a problem retrieving data from OpenAI."
- elif isinstance(e, urlfetch.ResponseTooLargeError):
- msg = (
- "There was a problem receiving all of your data from "
- "OpenAI. This is likely due to a bug in OpenAI. "
- "Please let us know at support@openai.com."
- )
- else:
- msg = (
- "Unexpected error communicating with OpenAI. If this "
- "problem persists, let us know at support@openai.com."
- )
-
- msg = textwrap.fill(msg) + "\n\n(Network error: " + str(e) + ")"
- raise error.APIConnectionError(msg)
-
- def close(self):
- pass
-
-
-class PycurlClient(HTTPClient):
- name = "pycurl"
-
- def __init__(self, verify_ssl_certs=True, proxy=None):
- super(PycurlClient, self).__init__(
- verify_ssl_certs=verify_ssl_certs, proxy=proxy
- )
-
- # Initialize this within the object so that we can reuse connections.
- self._curl = pycurl.Curl()
-
- # need to urlparse the proxy, since PyCurl
- # consumes the proxy url in small pieces
- if self._proxy:
- # now that we have the parser, get the proxy url pieces
- proxy = self._proxy
- for scheme, value in six.iteritems(proxy):
- proxy[scheme] = urlparse(value)
-
- def parse_headers(self, data):
- if "\r\n" not in data:
- return {}
- raw_headers = data.split("\r\n", 1)[1]
- headers = email.message_from_string(raw_headers)
- return dict((k.lower(), v) for k, v in six.iteritems(dict(headers)))
-
- def request(self, method, url, headers, post_data=None, stream=False):
- if stream:
- raise NotImplementedError("Stream not yet implemented for {}".format(self))
- b = util.io.BytesIO()
- rheaders = util.io.BytesIO()
-
- # Pycurl's design is a little weird: although we set per-request
- # options on this object, it's also capable of maintaining established
- # connections. Here we call reset() between uses to make sure it's in a
- # pristine state, but notably reset() doesn't reset connections, so we
- # still get to take advantage of those by virtue of re-using the same
- # object.
- self._curl.reset()
-
- proxy = self._get_proxy(url)
- if proxy:
- if proxy.hostname:
- self._curl.setopt(pycurl.PROXY, proxy.hostname)
- if proxy.port:
- self._curl.setopt(pycurl.PROXYPORT, proxy.port)
- if proxy.username or proxy.password:
- self._curl.setopt(
- pycurl.PROXYUSERPWD, "%s:%s" % (proxy.username, proxy.password)
- )
-
- if method == "get":
- self._curl.setopt(pycurl.HTTPGET, 1)
- elif method == "post":
- self._curl.setopt(pycurl.POST, 1)
- self._curl.setopt(pycurl.POSTFIELDS, post_data)
- else:
- self._curl.setopt(pycurl.CUSTOMREQUEST, method.upper())
-
- # pycurl doesn't like unicode URLs
- self._curl.setopt(pycurl.URL, util.utf8(url))
-
- self._curl.setopt(pycurl.WRITEFUNCTION, b.write)
- self._curl.setopt(pycurl.HEADERFUNCTION, rheaders.write)
- self._curl.setopt(pycurl.NOSIGNAL, 1)
- self._curl.setopt(pycurl.CONNECTTIMEOUT, 30)
- self._curl.setopt(pycurl.TIMEOUT, 80)
- self._curl.setopt(
- pycurl.HTTPHEADER,
- ["%s: %s" % (k, v) for k, v in six.iteritems(dict(headers))],
- )
- if self._verify_ssl_certs:
- self._curl.setopt(pycurl.CAINFO, openai.ca_bundle_path)
- else:
- self._curl.setopt(pycurl.SSL_VERIFYHOST, False)
-
- try:
- self._curl.perform()
- except pycurl.error as e:
- self._handle_request_error(e)
- rbody = b.getvalue().decode("utf-8")
- rcode = self._curl.getinfo(pycurl.RESPONSE_CODE)
- headers = self.parse_headers(rheaders.getvalue().decode("utf-8"))
-
- return rbody, rcode, headers, stream
-
- def _handle_request_error(self, e):
- if e.args[0] in [
- pycurl.E_COULDNT_CONNECT,
- pycurl.E_COULDNT_RESOLVE_HOST,
- pycurl.E_OPERATION_TIMEOUTED,
- ]:
- msg = (
- "Could not connect to OpenAI. Please check your "
- "internet connection and try again. If this problem "
- "persists, you should check OpenAI's service status at "
- "https://twitter.com/openaistatus, or let us know at "
- "support@openai.com."
- )
- should_retry = True
- elif e.args[0] in [pycurl.E_SSL_CACERT, pycurl.E_SSL_PEER_CERTIFICATE]:
- msg = (
- "Could not verify OpenAI's SSL certificate. Please make "
- "sure that your network is not intercepting certificates. "
- "If this problem persists, let us know at "
- "support@openai.com."
- )
- should_retry = False
- else:
- msg = (
- "Unexpected error communicating with OpenAI. If this "
- "problem persists, let us know at support@openai.com."
- )
- should_retry = False
-
- msg = textwrap.fill(msg) + "\n\n(Network error: " + e.args[1] + ")"
- raise error.APIConnectionError(msg, should_retry=should_retry)
-
- def _get_proxy(self, url):
- if self._proxy:
- proxy = self._proxy
- scheme = url.split(":")[0] if url else None
- if scheme:
- return proxy.get(scheme, proxy.get(scheme[0:-1]))
- return None
-
- def close(self):
- pass
-
-
-class Urllib2Client(HTTPClient):
- name = "urllib.request"
-
- def __init__(self, verify_ssl_certs=True, proxy=None):
- super(Urllib2Client, self).__init__(
- verify_ssl_certs=verify_ssl_certs, proxy=proxy
- )
- # prepare and cache proxy tied opener here
- self._opener = None
- if self._proxy:
- proxy = urllib.request.ProxyHandler(self._proxy)
- self._opener = urllib.request.build_opener(proxy)
-
- def request(self, method, url, headers, post_data=None, stream=False):
- if stream:
- raise NotImplementedError("Stream not yet implemented for {}".format(self))
- if six.PY3 and isinstance(post_data, six.string_types):
- post_data = post_data.encode("utf-8")
-
- req = urllib.request.Request(url, post_data, headers)
-
- if method not in ("get", "post"):
- req.get_method = lambda: method.upper()
-
- try:
- # use the custom proxy tied opener, if any.
- # otherwise, fall to the default urllib opener.
- response = (
- self._opener.open(req) if self._opener else urllib.request.urlopen(req)
- )
- rbody = response.read()
- rcode = response.code
- headers = dict(response.info())
- except urllib.error.HTTPError as e:
- rcode = e.code
- rbody = e.read()
- headers = dict(e.info())
- except (urllib.error.URLError, ValueError) as e:
- self._handle_request_error(e)
- lh = dict((k.lower(), v) for k, v in six.iteritems(dict(headers)))
- return rbody, rcode, lh, stream
-
- def _handle_request_error(self, e):
- msg = (
- "Unexpected error communicating with OpenAI. "
- "If this problem persists, let us know at support@openai.com."
- )
- msg = textwrap.fill(msg) + "\n\n(Network error: " + str(e) + ")"
- raise error.APIConnectionError(msg)
-
- def close(self):
- pass
openai/multipart_data_generator.py
@@ -22,7 +22,7 @@ class MultipartDataGenerator(object):
# Flatten parameters first
params = dict(openai.api_requestor._api_encode(params))
- for key, value in openai.six.iteritems(params):
+ for key, value in params.items():
# strip array elements if present from key
key = self._remove_array_element(key)
@@ -38,7 +38,7 @@ class MultipartDataGenerator(object):
# Convert the filename to string, just in case it's not
# already one. E.g. `tempfile.TemporaryFile` has a `name`
# attribute but it's an `int`.
- filename = openai.six.text_type(value.name)
+ filename = str(value.name)
self._write('Content-Disposition: form-data; name="')
self._write(key)
@@ -70,9 +70,9 @@ class MultipartDataGenerator(object):
return self.data.getvalue()
def _write(self, value):
- if isinstance(value, openai.six.binary_type):
+ if isinstance(value, bytes):
array = bytearray(value)
- elif isinstance(value, openai.six.text_type):
+ elif isinstance(value, str):
array = bytearray(value, encoding="utf-8")
else:
raise TypeError(
openai/openai_object.py
@@ -5,7 +5,7 @@ import json
from copy import deepcopy
import openai
-from openai import api_requestor, util, six
+from openai import api_requestor, util
def _compute_diff(current, previous):
@@ -51,7 +51,7 @@ class OpenAIObject(dict):
last_response=None,
api_base=None,
engine=None,
- **params
+ **params,
):
super(OpenAIObject, self).__init__()
@@ -218,7 +218,7 @@ class OpenAIObject(dict):
self._transient_values = self._transient_values - set(values)
- for k, v in six.iteritems(values):
+ for k, v in values.items():
super(OpenAIObject, self).__setitem__(
k, util.convert_to_openai_object(v, api_key, api_version, organization)
)
@@ -267,10 +267,11 @@ class OpenAIObject(dict):
def __repr__(self):
ident_parts = [type(self).__name__]
- if isinstance(self.get("object"), six.string_types):
- ident_parts.append(self.get("object"))
+ obj = self.get("object")
+ if isinstance(obj, str):
+ ident_parts.append(obj)
- if isinstance(self.get("id"), six.string_types):
+ if isinstance(self.get("id"), str):
ident_parts.append("id=%s" % (self.get("id"),))
unicode_repr = "<%s at %s> JSON: %s" % (
@@ -279,10 +280,7 @@ class OpenAIObject(dict):
str(self),
)
- if six.PY2:
- return unicode_repr.encode("utf-8")
- else:
- return unicode_repr
+ return unicode_repr
def __str__(self):
obj = self.to_dict_recursive()
@@ -293,7 +291,7 @@ class OpenAIObject(dict):
def to_dict_recursive(self):
d = dict(self)
- for k, v in six.iteritems(d):
+ for k, v in d.items():
if isinstance(v, OpenAIObject):
d[k] = v.to_dict_recursive()
elif isinstance(v, list):
@@ -312,7 +310,7 @@ class OpenAIObject(dict):
unsaved_keys = self._unsaved_values or set()
previous = previous or self._previous or {}
- for k, v in six.iteritems(self):
+ for k, v in self.items():
if k == "id" or (isinstance(k, str) and k.startswith("_")):
continue
elif isinstance(v, openai.api_resources.abstract.APIResource):
@@ -343,7 +341,7 @@ class OpenAIObject(dict):
copied._retrieve_params = self._retrieve_params
- for k, v in six.iteritems(self):
+ for k, v in self.items():
# Call parent's __setitem__ to avoid checks that we've added in the
# overridden version that can throw exceptions.
super(OpenAIObject, copied).__setitem__(k, v)
@@ -359,7 +357,7 @@ class OpenAIObject(dict):
copied = self.__copy__()
memo[id(self)] = copied
- for k, v in six.iteritems(self):
+ for k, v in self.items():
# Call parent's __setitem__ to avoid checks that we've added in the
# overridden version that can throw exceptions.
super(OpenAIObject, copied).__setitem__(k, deepcopy(v, memo))
openai/py.typed
openai/six.py
@@ -1,953 +0,0 @@
-# Copyright (c) 2010-2019 Benjamin Peterson
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in all
-# copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-
-"""Utilities for writing code that runs on Python 2 and 3"""
-
-from __future__ import absolute_import
-
-import functools
-import itertools
-import operator
-import sys
-import types
-
-__author__ = "Benjamin Peterson <benjamin@python.org>"
-__version__ = "1.12.0"
-
-
-# Useful for very coarse version differentiation.
-PY2 = sys.version_info[0] == 2
-PY3 = sys.version_info[0] == 3
-PY34 = sys.version_info[0:2] >= (3, 4)
-
-if PY3:
- string_types = str,
- integer_types = int,
- class_types = type,
- text_type = str
- binary_type = bytes
-
- MAXSIZE = sys.maxsize
-else:
- string_types = basestring,
- integer_types = (int, long)
- class_types = (type, types.ClassType)
- text_type = unicode
- binary_type = str
-
- if sys.platform.startswith("java"):
- # Jython always uses 32 bits.
- MAXSIZE = int((1 << 31) - 1)
- else:
- # It's possible to have sizeof(long) != sizeof(Py_ssize_t).
- class X(object):
-
- def __len__(self):
- return 1 << 31
- try:
- len(X())
- except OverflowError:
- # 32-bit
- MAXSIZE = int((1 << 31) - 1)
- else:
- # 64-bit
- MAXSIZE = int((1 << 63) - 1)
- del X
-
-
-def _add_doc(func, doc):
- """Add documentation to a function."""
- func.__doc__ = doc
-
-
-def _import_module(name):
- """Import module, returning the module after the last dot."""
- __import__(name)
- return sys.modules[name]
-
-
-class _LazyDescr(object):
-
- def __init__(self, name):
- self.name = name
-
- def __get__(self, obj, tp):
- result = self._resolve()
- setattr(obj, self.name, result) # Invokes __set__.
- try:
- # This is a bit ugly, but it avoids running this again by
- # removing this descriptor.
- delattr(obj.__class__, self.name)
- except AttributeError:
- pass
- return result
-
-
-class MovedModule(_LazyDescr):
-
- def __init__(self, name, old, new=None):
- super(MovedModule, self).__init__(name)
- if PY3:
- if new is None:
- new = name
- self.mod = new
- else:
- self.mod = old
-
- def _resolve(self):
- return _import_module(self.mod)
-
- def __getattr__(self, attr):
- _module = self._resolve()
- value = getattr(_module, attr)
- setattr(self, attr, value)
- return value
-
-
-class _LazyModule(types.ModuleType):
-
- def __init__(self, name):
- super(_LazyModule, self).__init__(name)
- self.__doc__ = self.__class__.__doc__
-
- def __dir__(self):
- attrs = ["__doc__", "__name__"]
- attrs += [attr.name for attr in self._moved_attributes]
- return attrs
-
- # Subclasses should override this
- _moved_attributes = []
-
-
-class MovedAttribute(_LazyDescr):
-
- def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None):
- super(MovedAttribute, self).__init__(name)
- if PY3:
- if new_mod is None:
- new_mod = name
- self.mod = new_mod
- if new_attr is None:
- if old_attr is None:
- new_attr = name
- else:
- new_attr = old_attr
- self.attr = new_attr
- else:
- self.mod = old_mod
- if old_attr is None:
- old_attr = name
- self.attr = old_attr
-
- def _resolve(self):
- module = _import_module(self.mod)
- return getattr(module, self.attr)
-
-
-class _SixMetaPathImporter(object):
-
- """
- A meta path importer to import six.moves and its submodules.
-
- This class implements a PEP302 finder and loader. It should be compatible
- with Python 2.5 and all existing versions of Python3
- """
-
- def __init__(self, six_module_name):
- self.name = six_module_name
- self.known_modules = {}
-
- def _add_module(self, mod, *fullnames):
- for fullname in fullnames:
- self.known_modules[self.name + "." + fullname] = mod
-
- def _get_module(self, fullname):
- return self.known_modules[self.name + "." + fullname]
-
- def find_module(self, fullname, path=None):
- if fullname in self.known_modules:
- return self
- return None
-
- def __get_module(self, fullname):
- try:
- return self.known_modules[fullname]
- except KeyError:
- raise ImportError("This loader does not know module " + fullname)
-
- def load_module(self, fullname):
- try:
- # in case of a reload
- return sys.modules[fullname]
- except KeyError:
- pass
- mod = self.__get_module(fullname)
- if isinstance(mod, MovedModule):
- mod = mod._resolve()
- else:
- mod.__loader__ = self
- sys.modules[fullname] = mod
- return mod
-
- def is_package(self, fullname):
- """
- Return true, if the named module is a package.
-
- We need this method to get correct spec objects with
- Python 3.4 (see PEP451)
- """
- return hasattr(self.__get_module(fullname), "__path__")
-
- def get_code(self, fullname):
- """Return None
-
- Required, if is_package is implemented"""
- self.__get_module(fullname) # eventually raises ImportError
- return None
- get_source = get_code # same as get_code
-
-_importer = _SixMetaPathImporter(__name__)
-
-
-class _MovedItems(_LazyModule):
-
- """Lazy loading of moved objects"""
- __path__ = [] # mark as package
-
-
-_moved_attributes = [
- MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"),
- MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"),
- MovedAttribute("filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"),
- MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"),
- MovedAttribute("intern", "__builtin__", "sys"),
- MovedAttribute("map", "itertools", "builtins", "imap", "map"),
- MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"),
- MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"),
- MovedAttribute("getoutput", "commands", "subprocess"),
- MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"),
- MovedAttribute("reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload"),
- MovedAttribute("reduce", "__builtin__", "functools"),
- MovedAttribute("shlex_quote", "pipes", "shlex", "quote"),
- MovedAttribute("StringIO", "StringIO", "io"),
- MovedAttribute("UserDict", "UserDict", "collections"),
- MovedAttribute("UserList", "UserList", "collections"),
- MovedAttribute("UserString", "UserString", "collections"),
- MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"),
- MovedAttribute("zip", "itertools", "builtins", "izip", "zip"),
- MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"),
- MovedModule("builtins", "__builtin__"),
- MovedModule("configparser", "ConfigParser"),
- MovedModule("copyreg", "copy_reg"),
- MovedModule("dbm_gnu", "gdbm", "dbm.gnu"),
- MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread"),
- MovedModule("http_cookiejar", "cookielib", "http.cookiejar"),
- MovedModule("http_cookies", "Cookie", "http.cookies"),
- MovedModule("html_entities", "htmlentitydefs", "html.entities"),
- MovedModule("html_parser", "HTMLParser", "html.parser"),
- MovedModule("http_client", "httplib", "http.client"),
- MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"),
- MovedModule("email_mime_image", "email.MIMEImage", "email.mime.image"),
- MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"),
- MovedModule("email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart"),
- MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"),
- MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"),
- MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"),
- MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"),
- MovedModule("cPickle", "cPickle", "pickle"),
- MovedModule("queue", "Queue"),
- MovedModule("reprlib", "repr"),
- MovedModule("socketserver", "SocketServer"),
- MovedModule("_thread", "thread", "_thread"),
- MovedModule("tkinter", "Tkinter"),
- MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"),
- MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"),
- MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"),
- MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"),
- MovedModule("tkinter_tix", "Tix", "tkinter.tix"),
- MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"),
- MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"),
- MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"),
- MovedModule("tkinter_colorchooser", "tkColorChooser",
- "tkinter.colorchooser"),
- MovedModule("tkinter_commondialog", "tkCommonDialog",
- "tkinter.commondialog"),
- MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"),
- MovedModule("tkinter_font", "tkFont", "tkinter.font"),
- MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"),
- MovedModule("tkinter_tksimpledialog", "tkSimpleDialog",
- "tkinter.simpledialog"),
- MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"),
- MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"),
- MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"),
- MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"),
- MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"),
- MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"),
-]
-# Add windows specific modules.
-if sys.platform == "win32":
- _moved_attributes += [
- MovedModule("winreg", "_winreg"),
- ]
-
-for attr in _moved_attributes:
- setattr(_MovedItems, attr.name, attr)
- if isinstance(attr, MovedModule):
- _importer._add_module(attr, "moves." + attr.name)
-del attr
-
-_MovedItems._moved_attributes = _moved_attributes
-
-moves = _MovedItems(__name__ + ".moves")
-_importer._add_module(moves, "moves")
-
-
-class Module_six_moves_urllib_parse(_LazyModule):
-
- """Lazy loading of moved objects in six.moves.urllib_parse"""
-
-
-_urllib_parse_moved_attributes = [
- MovedAttribute("ParseResult", "urlparse", "urllib.parse"),
- MovedAttribute("SplitResult", "urlparse", "urllib.parse"),
- MovedAttribute("parse_qs", "urlparse", "urllib.parse"),
- MovedAttribute("parse_qsl", "urlparse", "urllib.parse"),
- MovedAttribute("urldefrag", "urlparse", "urllib.parse"),
- MovedAttribute("urljoin", "urlparse", "urllib.parse"),
- MovedAttribute("urlparse", "urlparse", "urllib.parse"),
- MovedAttribute("urlsplit", "urlparse", "urllib.parse"),
- MovedAttribute("urlunparse", "urlparse", "urllib.parse"),
- MovedAttribute("urlunsplit", "urlparse", "urllib.parse"),
- MovedAttribute("quote", "urllib", "urllib.parse"),
- MovedAttribute("quote_plus", "urllib", "urllib.parse"),
- MovedAttribute("unquote", "urllib", "urllib.parse"),
- MovedAttribute("unquote_plus", "urllib", "urllib.parse"),
- MovedAttribute("unquote_to_bytes", "urllib", "urllib.parse", "unquote", "unquote_to_bytes"),
- MovedAttribute("urlencode", "urllib", "urllib.parse"),
- MovedAttribute("splitquery", "urllib", "urllib.parse"),
- MovedAttribute("splittag", "urllib", "urllib.parse"),
- MovedAttribute("splituser", "urllib", "urllib.parse"),
- MovedAttribute("splitvalue", "urllib", "urllib.parse"),
- MovedAttribute("uses_fragment", "urlparse", "urllib.parse"),
- MovedAttribute("uses_netloc", "urlparse", "urllib.parse"),
- MovedAttribute("uses_params", "urlparse", "urllib.parse"),
- MovedAttribute("uses_query", "urlparse", "urllib.parse"),
- MovedAttribute("uses_relative", "urlparse", "urllib.parse"),
-]
-for attr in _urllib_parse_moved_attributes:
- setattr(Module_six_moves_urllib_parse, attr.name, attr)
-del attr
-
-Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes
-
-_importer._add_module(Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"),
- "moves.urllib_parse", "moves.urllib.parse")
-
-
-class Module_six_moves_urllib_error(_LazyModule):
-
- """Lazy loading of moved objects in six.moves.urllib_error"""
-
-
-_urllib_error_moved_attributes = [
- MovedAttribute("URLError", "urllib2", "urllib.error"),
- MovedAttribute("HTTPError", "urllib2", "urllib.error"),
- MovedAttribute("ContentTooShortError", "urllib", "urllib.error"),
-]
-for attr in _urllib_error_moved_attributes:
- setattr(Module_six_moves_urllib_error, attr.name, attr)
-del attr
-
-Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes
-
-_importer._add_module(Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"),
- "moves.urllib_error", "moves.urllib.error")
-
-
-class Module_six_moves_urllib_request(_LazyModule):
-
- """Lazy loading of moved objects in six.moves.urllib_request"""
-
-
-_urllib_request_moved_attributes = [
- MovedAttribute("urlopen", "urllib2", "urllib.request"),
- MovedAttribute("install_opener", "urllib2", "urllib.request"),
- MovedAttribute("build_opener", "urllib2", "urllib.request"),
- MovedAttribute("pathname2url", "urllib", "urllib.request"),
- MovedAttribute("url2pathname", "urllib", "urllib.request"),
- MovedAttribute("getproxies", "urllib", "urllib.request"),
- MovedAttribute("Request", "urllib2", "urllib.request"),
- MovedAttribute("OpenerDirector", "urllib2", "urllib.request"),
- MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"),
- MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"),
- MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"),
- MovedAttribute("ProxyHandler", "urllib2", "urllib.request"),
- MovedAttribute("BaseHandler", "urllib2", "urllib.request"),
- MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"),
- MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"),
- MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"),
- MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"),
- MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"),
- MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"),
- MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"),
- MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"),
- MovedAttribute("HTTPHandler", "urllib2", "urllib.request"),
- MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"),
- MovedAttribute("FileHandler", "urllib2", "urllib.request"),
- MovedAttribute("FTPHandler", "urllib2", "urllib.request"),
- MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"),
- MovedAttribute("UnknownHandler", "urllib2", "urllib.request"),
- MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"),
- MovedAttribute("urlretrieve", "urllib", "urllib.request"),
- MovedAttribute("urlcleanup", "urllib", "urllib.request"),
- MovedAttribute("URLopener", "urllib", "urllib.request"),
- MovedAttribute("FancyURLopener", "urllib", "urllib.request"),
- MovedAttribute("proxy_bypass", "urllib", "urllib.request"),
- MovedAttribute("parse_http_list", "urllib2", "urllib.request"),
- MovedAttribute("parse_keqv_list", "urllib2", "urllib.request"),
-]
-for attr in _urllib_request_moved_attributes:
- setattr(Module_six_moves_urllib_request, attr.name, attr)
-del attr
-
-Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes
-
-_importer._add_module(Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"),
- "moves.urllib_request", "moves.urllib.request")
-
-
-class Module_six_moves_urllib_response(_LazyModule):
-
- """Lazy loading of moved objects in six.moves.urllib_response"""
-
-
-_urllib_response_moved_attributes = [
- MovedAttribute("addbase", "urllib", "urllib.response"),
- MovedAttribute("addclosehook", "urllib", "urllib.response"),
- MovedAttribute("addinfo", "urllib", "urllib.response"),
- MovedAttribute("addinfourl", "urllib", "urllib.response"),
-]
-for attr in _urllib_response_moved_attributes:
- setattr(Module_six_moves_urllib_response, attr.name, attr)
-del attr
-
-Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes
-
-_importer._add_module(Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"),
- "moves.urllib_response", "moves.urllib.response")
-
-
-class Module_six_moves_urllib_robotparser(_LazyModule):
-
- """Lazy loading of moved objects in six.moves.urllib_robotparser"""
-
-
-_urllib_robotparser_moved_attributes = [
- MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"),
-]
-for attr in _urllib_robotparser_moved_attributes:
- setattr(Module_six_moves_urllib_robotparser, attr.name, attr)
-del attr
-
-Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes
-
-_importer._add_module(Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"),
- "moves.urllib_robotparser", "moves.urllib.robotparser")
-
-
-class Module_six_moves_urllib(types.ModuleType):
-
- """Create a six.moves.urllib namespace that resembles the Python 3 namespace"""
- __path__ = [] # mark as package
- parse = _importer._get_module("moves.urllib_parse")
- error = _importer._get_module("moves.urllib_error")
- request = _importer._get_module("moves.urllib_request")
- response = _importer._get_module("moves.urllib_response")
- robotparser = _importer._get_module("moves.urllib_robotparser")
-
- def __dir__(self):
- return ['parse', 'error', 'request', 'response', 'robotparser']
-
-_importer._add_module(Module_six_moves_urllib(__name__ + ".moves.urllib"),
- "moves.urllib")
-
-
-def add_move(move):
- """Add an item to six.moves."""
- setattr(_MovedItems, move.name, move)
-
-
-def remove_move(name):
- """Remove item from six.moves."""
- try:
- delattr(_MovedItems, name)
- except AttributeError:
- try:
- del moves.__dict__[name]
- except KeyError:
- raise AttributeError("no such move, %r" % (name,))
-
-
-if PY3:
- _meth_func = "__func__"
- _meth_self = "__self__"
-
- _func_closure = "__closure__"
- _func_code = "__code__"
- _func_defaults = "__defaults__"
- _func_globals = "__globals__"
-else:
- _meth_func = "im_func"
- _meth_self = "im_self"
-
- _func_closure = "func_closure"
- _func_code = "func_code"
- _func_defaults = "func_defaults"
- _func_globals = "func_globals"
-
-
-try:
- advance_iterator = next
-except NameError:
- def advance_iterator(it):
- return it.next()
-next = advance_iterator
-
-
-try:
- callable = callable
-except NameError:
- def callable(obj):
- return any("__call__" in klass.__dict__ for klass in type(obj).__mro__)
-
-
-if PY3:
- def get_unbound_function(unbound):
- return unbound
-
- create_bound_method = types.MethodType
-
- def create_unbound_method(func, cls):
- return func
-
- Iterator = object
-else:
- def get_unbound_function(unbound):
- return unbound.im_func
-
- def create_bound_method(func, obj):
- return types.MethodType(func, obj, obj.__class__)
-
- def create_unbound_method(func, cls):
- return types.MethodType(func, None, cls)
-
- class Iterator(object):
-
- def next(self):
- return type(self).__next__(self)
-
- callable = callable
-_add_doc(get_unbound_function,
- """Get the function out of a possibly unbound function""")
-
-
-get_method_function = operator.attrgetter(_meth_func)
-get_method_self = operator.attrgetter(_meth_self)
-get_function_closure = operator.attrgetter(_func_closure)
-get_function_code = operator.attrgetter(_func_code)
-get_function_defaults = operator.attrgetter(_func_defaults)
-get_function_globals = operator.attrgetter(_func_globals)
-
-
-if PY3:
- def iterkeys(d, **kw):
- return iter(d.keys(**kw))
-
- def itervalues(d, **kw):
- return iter(d.values(**kw))
-
- def iteritems(d, **kw):
- return iter(d.items(**kw))
-
- def iterlists(d, **kw):
- return iter(d.lists(**kw))
-
- viewkeys = operator.methodcaller("keys")
-
- viewvalues = operator.methodcaller("values")
-
- viewitems = operator.methodcaller("items")
-else:
- def iterkeys(d, **kw):
- return d.iterkeys(**kw)
-
- def itervalues(d, **kw):
- return d.itervalues(**kw)
-
- def iteritems(d, **kw):
- return d.iteritems(**kw)
-
- def iterlists(d, **kw):
- return d.iterlists(**kw)
-
- viewkeys = operator.methodcaller("viewkeys")
-
- viewvalues = operator.methodcaller("viewvalues")
-
- viewitems = operator.methodcaller("viewitems")
-
-_add_doc(iterkeys, "Return an iterator over the keys of a dictionary.")
-_add_doc(itervalues, "Return an iterator over the values of a dictionary.")
-_add_doc(iteritems,
- "Return an iterator over the (key, value) pairs of a dictionary.")
-_add_doc(iterlists,
- "Return an iterator over the (key, [values]) pairs of a dictionary.")
-
-
-if PY3:
- def b(s):
- return s.encode("latin-1")
-
- def u(s):
- return s
- unichr = chr
- import struct
- int2byte = struct.Struct(">B").pack
- del struct
- byte2int = operator.itemgetter(0)
- indexbytes = operator.getitem
- iterbytes = iter
- import io
- StringIO = io.StringIO
- BytesIO = io.BytesIO
- del io
- _assertCountEqual = "assertCountEqual"
- if sys.version_info[1] <= 1:
- _assertRaisesRegex = "assertRaisesRegexp"
- _assertRegex = "assertRegexpMatches"
- else:
- _assertRaisesRegex = "assertRaisesRegex"
- _assertRegex = "assertRegex"
-else:
- def b(s):
- return s
- # Workaround for standalone backslash
-
- def u(s):
- return unicode(s.replace(r'\\', r'\\\\'), "unicode_escape")
- unichr = unichr
- int2byte = chr
-
- def byte2int(bs):
- return ord(bs[0])
-
- def indexbytes(buf, i):
- return ord(buf[i])
- iterbytes = functools.partial(itertools.imap, ord)
- import StringIO
- StringIO = BytesIO = StringIO.StringIO
- _assertCountEqual = "assertItemsEqual"
- _assertRaisesRegex = "assertRaisesRegexp"
- _assertRegex = "assertRegexpMatches"
-_add_doc(b, """Byte literal""")
-_add_doc(u, """Text literal""")
-
-
-def assertCountEqual(self, *args, **kwargs):
- return getattr(self, _assertCountEqual)(*args, **kwargs)
-
-
-def assertRaisesRegex(self, *args, **kwargs):
- return getattr(self, _assertRaisesRegex)(*args, **kwargs)
-
-
-def assertRegex(self, *args, **kwargs):
- return getattr(self, _assertRegex)(*args, **kwargs)
-
-
-if PY3:
- exec_ = getattr(moves.builtins, "exec")
-
- def reraise(tp, value, tb=None):
- try:
- if value is None:
- value = tp()
- if value.__traceback__ is not tb:
- raise value.with_traceback(tb)
- raise value
- finally:
- value = None
- tb = None
-
-else:
- def exec_(_code_, _globs_=None, _locs_=None):
- """Execute code in a namespace."""
- if _globs_ is None:
- frame = sys._getframe(1)
- _globs_ = frame.f_globals
- if _locs_ is None:
- _locs_ = frame.f_locals
- del frame
- elif _locs_ is None:
- _locs_ = _globs_
- exec("""exec _code_ in _globs_, _locs_""")
-
- exec_("""def reraise(tp, value, tb=None):
- try:
- raise tp, value, tb
- finally:
- tb = None
-""")
-
-
-if sys.version_info[:2] == (3, 2):
- exec_("""def raise_from(value, from_value):
- try:
- if from_value is None:
- raise value
- raise value from from_value
- finally:
- value = None
-""")
-elif sys.version_info[:2] > (3, 2):
- exec_("""def raise_from(value, from_value):
- try:
- raise value from from_value
- finally:
- value = None
-""")
-else:
- def raise_from(value, from_value):
- raise value
-
-
-print_ = getattr(moves.builtins, "print", None)
-if print_ is None:
- def print_(*args, **kwargs):
- """The new-style print function for Python 2.4 and 2.5."""
- fp = kwargs.pop("file", sys.stdout)
- if fp is None:
- return
-
- def write(data):
- if not isinstance(data, basestring):
- data = str(data)
- # If the file has an encoding, encode unicode with it.
- if (isinstance(fp, file) and
- isinstance(data, unicode) and
- fp.encoding is not None):
- errors = getattr(fp, "errors", None)
- if errors is None:
- errors = "strict"
- data = data.encode(fp.encoding, errors)
- fp.write(data)
- want_unicode = False
- sep = kwargs.pop("sep", None)
- if sep is not None:
- if isinstance(sep, unicode):
- want_unicode = True
- elif not isinstance(sep, str):
- raise TypeError("sep must be None or a string")
- end = kwargs.pop("end", None)
- if end is not None:
- if isinstance(end, unicode):
- want_unicode = True
- elif not isinstance(end, str):
- raise TypeError("end must be None or a string")
- if kwargs:
- raise TypeError("invalid keyword arguments to print()")
- if not want_unicode:
- for arg in args:
- if isinstance(arg, unicode):
- want_unicode = True
- break
- if want_unicode:
- newline = unicode("\n")
- space = unicode(" ")
- else:
- newline = "\n"
- space = " "
- if sep is None:
- sep = space
- if end is None:
- end = newline
- for i, arg in enumerate(args):
- if i:
- write(sep)
- write(arg)
- write(end)
-if sys.version_info[:2] < (3, 3):
- _print = print_
-
- def print_(*args, **kwargs):
- fp = kwargs.get("file", sys.stdout)
- flush = kwargs.pop("flush", False)
- _print(*args, **kwargs)
- if flush and fp is not None:
- fp.flush()
-
-_add_doc(reraise, """Reraise an exception.""")
-
-if sys.version_info[0:2] < (3, 4):
- def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS,
- updated=functools.WRAPPER_UPDATES):
- def wrapper(f):
- f = functools.wraps(wrapped, assigned, updated)(f)
- f.__wrapped__ = wrapped
- return f
- return wrapper
-else:
- wraps = functools.wraps
-
-
-def with_metaclass(meta, *bases):
- """Create a base class with a metaclass."""
- # This requires a bit of explanation: the basic idea is to make a dummy
- # metaclass for one level of class instantiation that replaces itself with
- # the actual metaclass.
- class metaclass(type):
-
- def __new__(cls, name, this_bases, d):
- return meta(name, bases, d)
-
- @classmethod
- def __prepare__(cls, name, this_bases):
- return meta.__prepare__(name, bases)
- return type.__new__(metaclass, 'temporary_class', (), {})
-
-
-def add_metaclass(metaclass):
- """Class decorator for creating a class with a metaclass."""
- def wrapper(cls):
- orig_vars = cls.__dict__.copy()
- slots = orig_vars.get('__slots__')
- if slots is not None:
- if isinstance(slots, str):
- slots = [slots]
- for slots_var in slots:
- orig_vars.pop(slots_var)
- orig_vars.pop('__dict__', None)
- orig_vars.pop('__weakref__', None)
- if hasattr(cls, '__qualname__'):
- orig_vars['__qualname__'] = cls.__qualname__
- return metaclass(cls.__name__, cls.__bases__, orig_vars)
- return wrapper
-
-
-def ensure_binary(s, encoding='utf-8', errors='strict'):
- """Coerce **s** to six.binary_type.
-
- For Python 2:
- - `unicode` -> encoded to `str`
- - `str` -> `str`
-
- For Python 3:
- - `str` -> encoded to `bytes`
- - `bytes` -> `bytes`
- """
- if isinstance(s, text_type):
- return s.encode(encoding, errors)
- elif isinstance(s, binary_type):
- return s
- else:
- raise TypeError("not expecting type '%s'" % type(s))
-
-
-def ensure_str(s, encoding='utf-8', errors='strict'):
- """Coerce *s* to `str`.
-
- For Python 2:
- - `unicode` -> encoded to `str`
- - `str` -> `str`
-
- For Python 3:
- - `str` -> `str`
- - `bytes` -> decoded to `str`
- """
- if not isinstance(s, (text_type, binary_type)):
- raise TypeError("not expecting type '%s'" % type(s))
- if PY2 and isinstance(s, text_type):
- s = s.encode(encoding, errors)
- elif PY3 and isinstance(s, binary_type):
- s = s.decode(encoding, errors)
- return s
-
-
-def ensure_text(s, encoding='utf-8', errors='strict'):
- """Coerce *s* to six.text_type.
-
- For Python 2:
- - `unicode` -> `unicode`
- - `str` -> `unicode`
-
- For Python 3:
- - `str` -> `str`
- - `bytes` -> decoded to `str`
- """
- if isinstance(s, binary_type):
- return s.decode(encoding, errors)
- elif isinstance(s, text_type):
- return s
- else:
- raise TypeError("not expecting type '%s'" % type(s))
-
-
-
-def python_2_unicode_compatible(klass):
- """
- A decorator that defines __unicode__ and __str__ methods under Python 2.
- Under Python 3 it does nothing.
-
- To support Python 2 and 3 with a single code base, define a __str__ method
- returning text and apply this decorator to the class.
- """
- if PY2:
- if '__str__' not in klass.__dict__:
- raise ValueError("@python_2_unicode_compatible cannot be applied "
- "to %s because it doesn't define __str__()." %
- klass.__name__)
- klass.__unicode__ = klass.__str__
- klass.__str__ = lambda self: self.__unicode__().encode('utf-8')
- return klass
-
-
-# Complete the moves implementation.
-# This code is at the end of this module to speed up module loading.
-# Turn this module into a package.
-__path__ = [] # required for PEP 302 and PEP 451
-__package__ = __name__ # see PEP 366 @ReservedAssignment
-if globals().get("__spec__") is not None:
- __spec__.submodule_search_locations = [] # PEP 451 @UndefinedVariable
-# Remove other six meta path importers, since they cause problems. This can
-# happen if six is removed from sys.modules and then reloaded. (Setuptools does
-# this for some reason.)
-if sys.meta_path:
- for i, importer in enumerate(sys.meta_path):
- # Here's some real nastiness: Another "instance" of the six module might
- # be floating around. Therefore, we can't use isinstance() to check for
- # the six meta path importer, since the other six instance will have
- # inserted an importer with different class.
- if (type(importer).__name__ == "_SixMetaPathImporter" and
- importer.name == __name__):
- del sys.meta_path[i]
- break
- del i, importer
-# Finally, add the importer to the meta path import hook.
-sys.meta_path.append(_importer)
openai/upload_progress.py
@@ -1,4 +1,3 @@
-import requests
import io
@@ -35,7 +34,7 @@ class BufferReader(io.BytesIO):
def progress(total, desc):
- import tqdm
+ import tqdm # type: ignore
meter = tqdm.tqdm(total=total, unit_scale=True, desc=desc)
openai/util.py
@@ -1,16 +1,13 @@
-from __future__ import absolute_import, division, print_function
-
import functools
import hmac
import io
import logging
-import sys
import os
import re
+import sys
+from urllib.parse import parse_qsl
import openai
-from openai import six
-from openai.six.moves.urllib.parse import parse_qsl
OPENAI_LOG = os.environ.get("OPENAI_LOG")
@@ -20,7 +17,6 @@ logger = logging.getLogger("openai")
__all__ = [
"io",
"parse_qsl",
- "utf8",
"log_info",
"log_debug",
"log_warn",
@@ -29,13 +25,6 @@ __all__ = [
]
-def utf8(value):
- if six.PY2 and isinstance(value, six.text_type):
- return value.encode("utf-8")
- else:
- return value
-
-
def is_appengine_dev():
return "APPENGINE_RUNTIME" in os.environ and "Dev" in os.environ.get(
"SERVER_SOFTWARE", ""
@@ -89,52 +78,23 @@ def dashboard_link(request_id):
def logfmt(props):
def fmt(key, val):
# Handle case where val is a bytes or bytesarray
- if six.PY3 and hasattr(val, "decode"):
+ if hasattr(val, "decode"):
val = val.decode("utf-8")
- # Check if val is already a string to avoid re-encoding into
- # ascii. Since the code is sent through 2to3, we can't just
- # use unicode(val, encoding='utf8') since it will be
- # translated incorrectly.
- if not isinstance(val, six.string_types):
- val = six.text_type(val)
+ # Check if val is already a string to avoid re-encoding into ascii.
+ if not isinstance(val, str):
+ val = str(val)
if re.search(r"\s", val):
val = repr(val)
# key should already be a string
if re.search(r"\s", key):
key = repr(key)
- return u"{key}={val}".format(key=key, val=val)
-
- return u" ".join([fmt(key, val) for key, val in sorted(props.items())])
-
-
-# Borrowed from Django's source code
-if hasattr(hmac, "compare_digest"):
- # Prefer the stdlib implementation, when available.
- def secure_compare(val1, val2):
- return hmac.compare_digest(utf8(val1), utf8(val2))
-
-
-else:
-
- def secure_compare(val1, val2):
- """
- Returns True if the two strings are equal, False otherwise.
- The time taken is independent of the number of characters that match.
- For the sake of simplicity, this function executes in constant time
- only when the two strings have the same length. It short-circuits when
- they have different lengths.
- """
- val1, val2 = utf8(val1), utf8(val2)
- if len(val1) != len(val2):
- return False
- result = 0
- if six.PY3 and isinstance(val1, bytes) and isinstance(val2, bytes):
- for x, y in zip(val1, val2):
- result |= x ^ y
- else:
- for x, y in zip(val1, val2):
- result |= ord(x) ^ ord(y)
- return result == 0
+ return "{key}={val}".format(key=key, val=val)
+
+ return " ".join([fmt(key, val) for key, val in sorted(props.items())])
+
+
+def secure_compare(val1, val2):
+ return hmac.compare_digest(val1, val2)
def get_object_classes():
@@ -179,7 +139,7 @@ def convert_to_openai_object(
):
resp = resp.copy()
klass_name = resp.get("object")
- if isinstance(klass_name, six.string_types):
+ if isinstance(klass_name, str):
klass = get_object_classes().get(
klass_name, openai.openai_object.OpenAIObject
)
@@ -213,7 +173,7 @@ def convert_to_dict(obj):
# comprehension returns a regular dict and recursively applies the
# conversion to each value.
elif isinstance(obj, dict):
- return {k: convert_to_dict(v) for k, v in six.iteritems(obj)}
+ return {k: convert_to_dict(v) for k, v in obj.items()}
else:
return obj
openai/version.py
@@ -1,1 +1,1 @@
-VERSION = "0.6.4"
+VERSION = "0.7.0"
public/setup.py
@@ -1,6 +1,6 @@
import os
-from setuptools import find_packages, setup
+from setuptools import setup
if os.getenv("OPENAI_UPLOAD") != "y":
raise RuntimeError(
README.md
@@ -68,7 +68,7 @@ openai api completions.create -e ada -p "Hello world"
## Requirements
-- Python 3.4+
+- Python 3.6+
In general we want to support the versions of Python that our
customers are using, so if you run into issues with any version
setup.py
@@ -3,9 +3,10 @@ import os
from setuptools import find_packages, setup
version_contents = {}
-with open(
- os.path.join(os.path.abspath(os.path.dirname(__file__)), "openai/version.py")
-) as f:
+version_path = os.path.join(
+ os.path.abspath(os.path.dirname(__file__)), "openai/version.py"
+)
+with open(version_path, "rt") as f:
exec(f.read(), version_contents)
setup(
@@ -13,15 +14,19 @@ setup(
description="Python client library for the OpenAI API",
version=version_contents["VERSION"],
install_requires=[
- 'requests >= 2.20; python_version >= "3.0"',
- 'requests[security] >= 2.20; python_version < "3.0"',
+ "requests>=2.20", # to get the patch for CVE-2018-18074
"tqdm", # Needed for progress bars
],
extras_require={"dev": ["black==20.8b1", "pytest==6.*"]},
- python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*",
+ python_requires=">=3.6",
scripts=["bin/openai"],
packages=find_packages(exclude=["tests", "tests.*"]),
- package_data={"openai": ["data/ca-certificates.crt"]},
+ package_data={
+ "openai": [
+ "data/ca-certificates.crt",
+ "py.typed",
+ ]
+ },
author="OpenAI",
author_email="support@openai.com",
url="https://github.com/openai/openai-python",