From e943f5c864e90498eb1491fb8b174a834a2f661e Mon Sep 17 00:00:00 2001 From: Tony Tam Date: Sun, 15 Feb 2015 19:50:23 -0800 Subject: [PATCH] added readme, rebuilt client --- bin/all-petstore.sh | 2 + bin/python-petstore.sh | 2 +- .../languages/PythonClientCodegen.java | 1 + .../src/main/resources/python/README.mustache | 25 ++ samples/client/petstore/python/README.md | 25 ++ .../client/petstore/python/client/__init__.py | 4 +- .../petstore/python/client/models/__init__.py | 4 +- .../client/petstore/python/client/swagger.py | 406 +++++++++--------- 8 files changed, 259 insertions(+), 210 deletions(-) create mode 100644 modules/swagger-codegen/src/main/resources/python/README.mustache create mode 100644 samples/client/petstore/python/README.md diff --git a/bin/all-petstore.sh b/bin/all-petstore.sh index 8b8fd96226f..515da8a532e 100755 --- a/bin/all-petstore.sh +++ b/bin/all-petstore.sh @@ -26,6 +26,8 @@ cd $APP_DIR ./bin/java-petstore-filemap.sh ./bin/java-petstore.sh ./bin/java-wordnik-api.sh +./bin/php-petstore.sh +./bin/python-petstore.sh ./bin/objc-petstore.sh ./bin/objc-wordnik-api.sh ./bin/tizen-petstore.sh diff --git a/bin/python-petstore.sh b/bin/python-petstore.sh index 48370c71caa..0236c5c2a64 100755 --- a/bin/python-petstore.sh +++ b/bin/python-petstore.sh @@ -31,6 +31,6 @@ fi # if you've executed sbt assembly previously it will use that instead. export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties" -ags="$@ -i http://petstore.swagger.io/v2/swagger.json -l python -o samples/client/petstore/python -t modules/swagger-codegen/src/main/resources/python" +ags="$@ -i http://petstore.swagger.io/v2/swagger.json -l python -o samples/client/petstore/python" java $JAVA_OPTS -jar $executable $ags diff --git a/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/PythonClientCodegen.java b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/PythonClientCodegen.java index e3a3c216501..d37a18f72c4 100755 --- a/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/PythonClientCodegen.java +++ b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/PythonClientCodegen.java @@ -62,6 +62,7 @@ public class PythonClientCodegen extends DefaultCodegen implements CodegenConfig typeMapping.put("date", "datetime"); + supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); supportingFiles.add(new SupportingFile("swagger.mustache", module, "swagger.py")); supportingFiles.add(new SupportingFile("__init__.mustache", module, "__init__.py")); supportingFiles.add(new SupportingFile("__init__.mustache", modelPackage.replaceAll("\\.", File.separator), "__init__.py")); diff --git a/modules/swagger-codegen/src/main/resources/python/README.mustache b/modules/swagger-codegen/src/main/resources/python/README.mustache new file mode 100644 index 00000000000..cf1f7142bc0 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/python/README.mustache @@ -0,0 +1,25 @@ +# Swagger Generated Python client + + +Usage example, based on the swagger petstore: + +```python +# include the client module +from client import * + +# build a client connection. In this example, we are passing the hostname as arg0, and +# sending a header with name `api_key` and value `special-key` on each call to the api. + +client = swagger.ApiClient('http://petstore.swagger.io/v2', 'api_key', 'special-key') + +# create the PetApi class with the client we just created +petApi = PetApi.PetApi(client) + +# call the API and fetch a pet, with petId=3 +pet = petApi.getPetById(petId=3) + +# write it into pretty JSON +json = client.sanitizeForSerialization(pet) +print json +{'category': {'category': None, 'status': None, 'name': 'string', 'tags': None, 'photoUrls': None, 'id': 0L}, 'status': {'category': None, 'status': None, 'name': None, 'tags': None, 'photoUrls': None, 'id': None}, 'name': 'foogly', 'tags': [{'id': 0L, 'name': 'string'}], 'photoUrls': ['string'], 'id': 3L} +``` diff --git a/samples/client/petstore/python/README.md b/samples/client/petstore/python/README.md new file mode 100644 index 00000000000..cf1f7142bc0 --- /dev/null +++ b/samples/client/petstore/python/README.md @@ -0,0 +1,25 @@ +# Swagger Generated Python client + + +Usage example, based on the swagger petstore: + +```python +# include the client module +from client import * + +# build a client connection. In this example, we are passing the hostname as arg0, and +# sending a header with name `api_key` and value `special-key` on each call to the api. + +client = swagger.ApiClient('http://petstore.swagger.io/v2', 'api_key', 'special-key') + +# create the PetApi class with the client we just created +petApi = PetApi.PetApi(client) + +# call the API and fetch a pet, with petId=3 +pet = petApi.getPetById(petId=3) + +# write it into pretty JSON +json = client.sanitizeForSerialization(pet) +print json +{'category': {'category': None, 'status': None, 'name': 'string', 'tags': None, 'photoUrls': None, 'id': 0L}, 'status': {'category': None, 'status': None, 'name': None, 'tags': None, 'photoUrls': None, 'id': None}, 'name': 'foogly', 'tags': [{'id': 0L, 'name': 'string'}], 'photoUrls': ['string'], 'id': 3L} +``` diff --git a/samples/client/petstore/python/client/__init__.py b/samples/client/petstore/python/client/__init__.py index 4b41ee706c7..728aacbb9ab 100644 --- a/samples/client/petstore/python/client/__init__.py +++ b/samples/client/petstore/python/client/__init__.py @@ -5,5 +5,5 @@ import os __all__ = [] for module in os.listdir(os.path.dirname(__file__)): - if module != '__init__.py' and module[-3:] == '.py': - __all__.append(module[:-3]) + if module != '__init__.py' and module[-3:] == '.py': + __all__.append(module[:-3]) diff --git a/samples/client/petstore/python/client/models/__init__.py b/samples/client/petstore/python/client/models/__init__.py index 4b41ee706c7..728aacbb9ab 100644 --- a/samples/client/petstore/python/client/models/__init__.py +++ b/samples/client/petstore/python/client/models/__init__.py @@ -5,5 +5,5 @@ import os __all__ = [] for module in os.listdir(os.path.dirname(__file__)): - if module != '__init__.py' and module[-3:] == '.py': - __all__.append(module[:-3]) + if module != '__init__.py' and module[-3:] == '.py': + __all__.append(module[:-3]) diff --git a/samples/client/petstore/python/client/swagger.py b/samples/client/petstore/python/client/swagger.py index 59b6d38fbd6..8d9053025d1 100644 --- a/samples/client/petstore/python/client/swagger.py +++ b/samples/client/petstore/python/client/swagger.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -"""Wordnik.com's Swagger generic API client. This client handles the client- +"""Swagger generic API client. This client handles the client- server communication, and is invariant across implementations. Specifics of the methods and models for each application are generated from the Swagger templates.""" @@ -20,231 +20,227 @@ from models import * class ApiClient: - """Generic API client for Swagger client library builds""" + """Generic API client for Swagger client library builds - def __init__(self, apiKey=None, apiServer=None): - if apiKey == None: - raise Exception('You must pass an apiKey when instantiating the ' - 'APIClient') - self.apiKey = apiKey - self.apiServer = apiServer - self.cookie = None - self.boundary = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(30)) + Attributes: + host: The base path for the server to call + headerName: a header to pass when making calls to the API + headerValue: a header value to pass when making calls to the API + """ + def __init__(self, host=None, headerName=None, headerValue=None): + self.headerName = headerName + self.headerValue = headerValue + self.host = host + self.cookie = None + self.boundary = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(30)) - def callAPI(self, resourcePath, method, queryParams, postData, - headerParams=None, files=None): + def callAPI(self, resourcePath, method, queryParams, postData, + headerParams=None, files=None): - url = self.apiServer + resourcePath - headers = {} - if headerParams: - for param, value in headerParams.iteritems(): - headers[param] = value + url = self.host + resourcePath + headers = {} + if headerParams: + for param, value in headerParams.iteritems(): + headers[param] = value - headers['api_key'] = self.apiKey + if self.headerName: + headers[self.headerName] = self.headerValue - if self.cookie: - headers['Cookie'] = self.cookie + if self.cookie: + headers['Cookie'] = self.cookie - data = None + data = None - if queryParams: - # Need to remove None values, these should not be sent - sentQueryParams = {} - for param, value in queryParams.items(): - if value != None: - sentQueryParams[param] = value - url = url + '?' + urllib.urlencode(sentQueryParams) + if queryParams: + # Need to remove None values, these should not be sent + sentQueryParams = {} + for param, value in queryParams.items(): + if value != None: + sentQueryParams[param] = value + url = url + '?' + urllib.urlencode(sentQueryParams) - if method in ['GET']: - - #Options to add statements later on and for compatibility - pass - - elif method in ['POST', 'PUT', 'DELETE']: - - if postData: - postData = self.sanitizeForSerialization(postData) - if 'Content-type' not in headers: - headers['Content-type'] = 'application/json' - data = json.dumps(postData) - elif headers['Content-type'] == 'multipart/form-data': - data = self.buildMultipartFormData(postData, files) - headers['Content-type'] = 'multipart/form-data; boundary={0}'.format(self.boundary) - headers['Content-length'] = str(len(data)) - else: - data = urllib.urlencode(postData) + if method in ['GET']: + #Options to add statements later on and for compatibility + pass + elif method in ['POST', 'PUT', 'DELETE']: + if postData: + postData = self.sanitizeForSerialization(postData) + if 'Content-type' not in headers: + headers['Content-type'] = 'application/json' + data = json.dumps(postData) + elif headers['Content-type'] == 'multipart/form-data': + data = self.buildMultipartFormData(postData, files) + headers['Content-type'] = 'multipart/form-data; boundary={0}'.format(self.boundary) + headers['Content-length'] = str(len(data)) else: - raise Exception('Method ' + method + ' is not recognized.') + data = urllib.urlencode(postData) - request = MethodRequest(method=method, url=url, headers=headers, - data=data) + else: + raise Exception('Method ' + method + ' is not recognized.') - # Make the request - response = urllib2.urlopen(request) - if 'Set-Cookie' in response.headers: - self.cookie = response.headers['Set-Cookie'] - string = response.read() + request = MethodRequest(method=method, url=url, headers=headers, + data=data) - try: - data = json.loads(string) - except ValueError: # PUT requests don't return anything - data = None + # Make the request + response = urllib2.urlopen(request) + if 'Set-Cookie' in response.headers: + self.cookie = response.headers['Set-Cookie'] + string = response.read() - return data + try: + data = json.loads(string) + except ValueError: # PUT requests don't return anything + data = None - def toPathValue(self, obj): - """Convert a string or object to a path-friendly value - Args: - obj -- object or string value - Returns: - string -- quoted value - """ - if type(obj) == list: - return urllib.quote(','.join(obj)) - else: - return urllib.quote(str(obj)) + return data - def sanitizeForSerialization(self, obj): - """Dump an object into JSON for POSTing.""" + def toPathValue(self, obj): + """Convert a string or object to a path-friendly value + Args: + obj -- object or string value + Returns: + string -- quoted value + """ + if type(obj) == list: + return urllib.quote(','.join(obj)) + else: + return urllib.quote(str(obj)) - if type(obj) == type(None): - return None - elif type(obj) in [str, int, long, float, bool]: - return obj - elif type(obj) == list: - return [self.sanitizeForSerialization(subObj) for subObj in obj] - elif type(obj) == datetime.datetime: - return obj.isoformat() - else: - if type(obj) == dict: - objDict = obj + def sanitizeForSerialization(self, obj): + """Dump an object into JSON for POSTing.""" + + if type(obj) == type(None): + return None + elif type(obj) in [str, int, long, float, bool]: + return obj + elif type(obj) == list: + return [self.sanitizeForSerialization(subObj) for subObj in obj] + elif type(obj) == datetime.datetime: + return obj.isoformat() + else: + if type(obj) == dict: + objDict = obj + else: + objDict = obj.__dict__ + return {key: self.sanitizeForSerialization(val) + for (key, val) in objDict.iteritems() + if key != 'swaggerTypes'} + + if type(postData) == list: + # Could be a list of objects + if type(postData[0]) in safeToDump: + data = json.dumps(postData) + else: + data = json.dumps([datum.__dict__ for datum in postData]) + elif type(postData) not in safeToDump: + data = json.dumps(postData.__dict__) + + def buildMultipartFormData(self, postData, files): + def escape_quotes(s): + return s.replace('"', '\\"') + + lines = [] + + for name, value in postData.items(): + lines.extend(( + '--{0}'.format(self.boundary), + 'Content-Disposition: form-data; name="{0}"'.format(escape_quotes(name)), + '', + str(value), + )) + + for name, filepath in files.items(): + f = open(filepath, 'r') + filename = filepath.split('/')[-1] + mimetype = mimetypes.guess_type(filename)[0] or 'application/octet-stream' + lines.extend(( + '--{0}'.format(self.boundary), + 'Content-Disposition: form-data; name="{0}"; filename="{1}"'.format(escape_quotes(name), escape_quotes(filename)), + 'Content-Type: {0}'.format(mimetype), + '', + f.read() + )) + + lines.extend(( + '--{0}--'.format(self.boundary), + '' + )) + return '\r\n'.join(lines) + + def deserialize(self, obj, objClass): + """Derialize a JSON string into an object. + + Args: + obj -- string or object to be deserialized + objClass -- class literal for deserialzied object, or string + of class name + Returns: + object -- deserialized object""" + + # Have to accept objClass as string or actual type. Type could be a + # native Python type, or one of the model classes. + if type(objClass) == str: + if 'list[' in objClass: + match = re.match('list\[(.*)\]', objClass) + subClass = match.group(1) + return [self.deserialize(subObj, subClass) for subObj in obj] + + if (objClass in ['int', 'float', 'long', 'dict', 'list', 'str', 'bool', 'datetime']): + objClass = eval(objClass) + else: # not a native type, must be model class + objClass = eval(objClass + '.' + objClass) + + if objClass in [int, long, float, dict, list, str, bool]: + return objClass(obj) + elif objClass == datetime: + # Server will always return a time stamp in UTC, but with + # trailing +0000 indicating no offset from UTC. So don't process + # last 5 characters. + return datetime.datetime.strptime(obj[:-5], "%Y-%m-%dT%H:%M:%S.%f") + + instance = objClass() + + for attr, attrType in instance.swaggerTypes.iteritems(): + if obj is not None and attr in obj and type(obj) in [list, dict]: + value = obj[attr] + if attrType in ['str', 'int', 'long', 'float', 'bool']: + attrType = eval(attrType) + try: + value = attrType(value) + except UnicodeEncodeError: + value = unicode(value) + except TypeError: + value = value + setattr(instance, attr, value) + elif (attrType == 'datetime'): + setattr(instance, attr, datetime.datetime.strptime(value[:-5], "%Y-%m-%dT%H:%M:%S.%f")) + elif 'list[' in attrType: + match = re.match('list\[(.*)\]', attrType) + subClass = match.group(1) + subValues = [] + if not value: + setattr(instance, attr, None) else: - objDict = obj.__dict__ - return {key: self.sanitizeForSerialization(val) - for (key, val) in objDict.iteritems() - if key != 'swaggerTypes'} + for subValue in value: + subValues.append(self.deserialize(subValue, subClass)) + setattr(instance, attr, subValues) + else: + setattr(instance, attr, self.deserialize(value, objClass)) - if type(postData) == list: - # Could be a list of objects - if type(postData[0]) in safeToDump: - data = json.dumps(postData) - else: - data = json.dumps([datum.__dict__ for datum in postData]) - elif type(postData) not in safeToDump: - data = json.dumps(postData.__dict__) - - def buildMultipartFormData(self, postData, files): - def escape_quotes(s): - return s.replace('"', '\\"') - - lines = [] - - for name, value in postData.items(): - lines.extend(( - '--{0}'.format(self.boundary), - 'Content-Disposition: form-data; name="{0}"'.format(escape_quotes(name)), - '', - str(value), - )) - - for name, filepath in files.items(): - f = open(filepath, 'r') - filename = filepath.split('/')[-1] - mimetype = mimetypes.guess_type(filename)[0] or 'application/octet-stream' - lines.extend(( - '--{0}'.format(self.boundary), - 'Content-Disposition: form-data; name="{0}"; filename="{1}"'.format(escape_quotes(name), escape_quotes(filename)), - 'Content-Type: {0}'.format(mimetype), - '', - f.read() - )) - - lines.extend(( - '--{0}--'.format(self.boundary), - '' - )) - return '\r\n'.join(lines) - - def deserialize(self, obj, objClass): - """Derialize a JSON string into an object. - - Args: - obj -- string or object to be deserialized - objClass -- class literal for deserialzied object, or string - of class name - Returns: - object -- deserialized object""" - - # Have to accept objClass as string or actual type. Type could be a - # native Python type, or one of the model classes. - if type(objClass) == str: - if 'list[' in objClass: - match = re.match('list\[(.*)\]', objClass) - subClass = match.group(1) - return [self.deserialize(subObj, subClass) for subObj in obj] - - if (objClass in ['int', 'float', 'long', 'dict', 'list', 'str', 'bool', 'datetime']): - objClass = eval(objClass) - else: # not a native type, must be model class - objClass = eval(objClass + '.' + objClass) - - if objClass in [int, long, float, dict, list, str, bool]: - return objClass(obj) - elif objClass == datetime: - # Server will always return a time stamp in UTC, but with - # trailing +0000 indicating no offset from UTC. So don't process - # last 5 characters. - return datetime.datetime.strptime(obj[:-5], - "%Y-%m-%dT%H:%M:%S.%f") - - instance = objClass() - - for attr, attrType in instance.swaggerTypes.iteritems(): - if obj is not None and attr in obj and type(obj) in [list, dict]: - value = obj[attr] - if attrType in ['str', 'int', 'long', 'float', 'bool']: - attrType = eval(attrType) - try: - value = attrType(value) - except UnicodeEncodeError: - value = unicode(value) - except TypeError: - value = value - setattr(instance, attr, value) - elif (attrType == 'datetime'): - setattr(instance, attr, datetime.datetime.strptime(value[:-5], - "%Y-%m-%dT%H:%M:%S.%f")) - elif 'list[' in attrType: - match = re.match('list\[(.*)\]', attrType) - subClass = match.group(1) - subValues = [] - if not value: - setattr(instance, attr, None) - else: - for subValue in value: - subValues.append(self.deserialize(subValue, - subClass)) - setattr(instance, attr, subValues) - else: - setattr(instance, attr, self.deserialize(value, - objClass)) - - return instance + return instance class MethodRequest(urllib2.Request): + def __init__(self, *args, **kwargs): + """Construct a MethodRequest. Usage is the same as for + `urllib2.Request` except it also takes an optional `method` + keyword argument. If supplied, `method` will be used instead of + the default.""" - def __init__(self, *args, **kwargs): - """Construct a MethodRequest. Usage is the same as for - `urllib2.Request` except it also takes an optional `method` - keyword argument. If supplied, `method` will be used instead of - the default.""" - - if 'method' in kwargs: - self.method = kwargs.pop('method') - return urllib2.Request.__init__(self, *args, **kwargs) - - def get_method(self): - return getattr(self, 'method', urllib2.Request.get_method(self)) + if 'method' in kwargs: + self.method = kwargs.pop('method') + return urllib2.Request.__init__(self, *args, **kwargs) + def get_method(self): + return getattr(self, 'method', urllib2.Request.get_method(self)) \ No newline at end of file