Merge pull request #5 from mrjf/master

Python templates
This commit is contained in:
Zeke Sikelianos 2011-11-11 10:46:55 -08:00
commit 7339611575
9 changed files with 702 additions and 0 deletions

23
bin/generate-python-lib.sh Executable file
View File

@ -0,0 +1,23 @@
#!/bin/bash
if [ $# -ne 4 ]
then
echo "Error in $0 - Invalid Argument Count"
echo "Syntax: $0 location_of_service api_key package_name library_root"
exit
fi
echo "" > classpath.txt
for file in `ls lib`;
do echo -n 'lib/' >> classpath.txt;
echo -n $file >> classpath.txt;
echo -n ':' >> classpath.txt;
done
for file in `ls build`;
do echo -n 'build/' >> classpath.txt;
echo -n $file >> classpath.txt;
echo -n ':' >> classpath.txt;
done
export CLASSPATH=$(cat classpath.txt):conf/python/templates
export JAVA_OPTS="${JAVA_OPTS} -Dproperty=Xmx2g"
java $WORDNIK_OPTS $JAVA_CONFIG_OPTIONS $JAVA_OPTS -cp $CLASSPATH com.wordnik.swagger.codegen.config.python.PythonLibCodeGen "$@"

View File

@ -0,0 +1,128 @@
#!/usr/bin/env python
"""Wordnik.com's 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."""
import sys
import os
import re
import urllib
import urllib2
import httplib
import json
sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../')
import model
class APIClient:
"""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
def callAPI(self, resourcePath, method, queryParams, postData,
headerParams=None):
url = self.apiServer + resourcePath
headers = {}
if headerParams:
for param, value in headerParams.iteritems():
headers[param] = value
headers['Content-type'] = 'application/json'
headers['api_key'] = self.apiKey
data = None
if method == 'GET':
if queryParams:
# Need to remove None values, these should not be sent
sentQueryParams = {}
for param, value in queryParams.iteritems():
if value != None:
sentQueryParams[param] = value
url = url + '?' + urllib.urlencode(sentQueryParams)
request = urllib2.Request(url=url, headers=headers)
elif method in ['POST', 'PUT', 'DELETE']:
data = postData
if data:
if type(postData) not in [str, int, float, bool]:
data = json.dumps(postData.__dict__)
request = urllib2.Request(url=url, headers=headers, data=data)
if method in ['PUT', 'DELETE']:
# Monkey patch alert! Urllib2 doesn't really do PUT / DELETE
request.get_method = lambda: method
else:
raise Exception('Method ' + method + ' is not recognized.')
# Make the request
response = urllib2.urlopen(request).read()
try:
data = json.loads(response)
except ValueError: # PUT requests don't return anything
data = None
return data
def serialize(self, obj):
"""
Args:
obj -- data object to be serialized
Returns:
string -- json serialization of object
"""
return json.dumps(obj)
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:
try:
objClass = eval(objClass)
except NameError: # not a native type, must be model class
objClass = eval('model.' + objClass + '.' + objClass)
if objClass in [str, int, float, bool]:
return objClass(obj)
instance = objClass()
for attr, attrType in instance.swaggerTypes.iteritems():
if attr in obj:
value = obj[attr]
if attrType in ['str', 'int', 'float', 'bool']:
attrType = eval(attrType)
try:
value = attrType(value)
except UnicodeEncodeError:
value = unicode(value)
setattr(instance, attr, value)
elif 'list<' in attrType:
match = re.match('list<(.*)>', attrType)
subClass = match.group(1)
subValues = []
for subValue in value:
subValues.append(self.deserialize(subValue, subClass))
setattr(instance, attr, subValues)
else:
setattr(instance, attr, self.deserialize(value,
objClass))
return instance

View File

@ -0,0 +1,7 @@
#!/usr/bin/env python
"""Load all of the modules in the models directory."""
import os
for module in os.listdir(os.path.dirname(__file__)):
if module != '__init__.py' and module[-3:] == '.py':
__import__(module[:-3], locals(), globals())

View File

@ -0,0 +1,25 @@
#!/usr/bin/env python
"""
Copyright 2011 Wordnik, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
class $className$:
"""
$enum.description$
NOTE: This class is auto generated by the swagger code generator program.
Do not edit the class manually.
"""
def __init__():
$values: { value | self.$value.name$ = $value.value$};separator=";\n"$

View File

@ -0,0 +1,37 @@
#!/usr/bin/env python
"""
Copyright 2011 Wordnik, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
class $className$:
"""
$model.description$
NOTE: This class is auto generated by the swagger code generator program.
Do not edit the class manually.
"""
def __init__(self):
self.swaggerTypes = {
$fields: { field |'$field.fieldDefinition.name$': '$field.fieldDefinition.returnType$'};separator=",\n"$
}
$fields:{ field |
# $field.description$
self.$field.fieldDefinition.name$ = None # $field.fieldDefinition.returnType$
}$

View File

@ -0,0 +1,115 @@
#!/usr/bin/env python
"""
$resource$.py
Copyright 2011 Wordnik, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
NOTE: This class is auto generated by the swagger code generator program. Do not edit the class manually.
"""
import sys
import os
sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../')
import model
class $resource$(object):
def __init__(self, apiClient):
self.apiClient = apiClient
$methods:{ method |
def $method.name$(self, $method.arguments: { argument | $if(argument.required)$$argument.name$, $endif$}$$method.arguments: { argument | $if(! argument.required)$$argument.name$=None, $endif$}$):
"""$method.title$
$if(method.description)$
$method.description$
$endif$
Args:
$method.arguments:{ argument |$argument.name$ -- $argument.description$
$if(argument.allowedValues)$
Allowed values are - $argument.allowedValues$
$endif$}$
$if(!method.responseVoid)$
Return:
$method.returnValue$ -- an instance of $method.returnClassName$
$endif$"""
# Parse inputs
resourcePath = '$method.resourcePath$'
resourcePath = resourcePath.replace('{format}', 'json')
method = '$method.methodType$'
queryParams = {}
headerParams = {}
$if(method.authToken)$
if not authToken:
raise Exception('missing authToken')
headerParams['auth_token'] = authToken
$endif$
$if(!method.inputModel)$
$method.queryParameters:{ argument |
queryParams['$argument.name$'] = $argument.name$
}$
$method.pathParameters:{ argument |
if $argument.name$ != None:
resourcePath = resourcePath.replace('{$argument.name$}', $argument.name$)
}$
$endif$
$if(method.inputModel)$
$method.queryParameters:{ argument |
if $argument.inputModelClassArgument$ != None and $argument.inputModelClassArgument$.$argument.name$ != None:
queryParams['$argument.name$'] = $argument.inputModelClassArgument$.$argument.name$
}$
$method.pathParameters:{ argument |
if $argument.inputModelClassArgument$ != None and $argument.inputModelClassArgument$.$argument.name$ != None:
resourcePath = resourcePath.replace('{$argument.name$}', $argument.inputModelClassArgument$.$argument.name$)
}$
$endif$
# Make the API Call
$if(method.postObject)$
response = self.apiClient.callAPI(resourcePath, method, queryParams,
postData, headerParams)
$endif$
$if(!method.postObject)$
response = self.apiClient.callAPI(resourcePath, method, queryParams,
None, headerParams)
$endif$
$if(!method.responseVoid)$
if not response:
return None
$if(!method.returnValueList)$
# Create output objects if the response has more than one object
responseObject = self.apiClient.deserialize(response,
model.$method.returnClassName$.$method.returnClassName$)
return responseObject
$endif$
$if(method.returnValueList)$
responseObjects = []
for responseObject in response:
responseObjects.append(self.apiClient.deserialize(responseObject,
model.$method.returnClassName$.$method.returnClassName$))
return responseObjects
$endif$
$endif$
}$

View File

@ -0,0 +1,36 @@
<?php
/**
* Copyright 2011 Wordnik, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
*
* Maintains the compatible server version against which the drive is written
* NOTE: This class is auto generated by the swagger code generator program. Do not edit the class manually.
*/
class VersionChecker {
public static compatibleVersion = "$apiVersion$";
/**
* Gets the version against which the library code was written
*/
public function getCompatibleVersion() {
return self::\$compatibleVersion;
}
}
?>

View File

@ -0,0 +1,228 @@
/**
* Copyright 2011 Wordnik, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wordnik.swagger.codegen.config.python;
import com.wordnik.swagger.codegen.config.DataTypeMappingProvider;
import com.wordnik.swagger.codegen.config.NamingPolicyProvider;
import com.wordnik.swagger.codegen.config.common.CamelCaseNamingPolicyProvider;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* User: ramesh
* Date: 5/31/11
* Time: 7:03 AM
*/
public class PythonDataTypeMappingProvider implements DataTypeMappingProvider {
public static Map<String, String> primitiveValueMap = new HashMap<String, String>();
static{
primitiveValueMap.put("string", "str");
primitiveValueMap.put("String", "str");
primitiveValueMap.put("int", "int");
primitiveValueMap.put("integer", "int");
primitiveValueMap.put("Integer", "int");
primitiveValueMap.put("boolean", "bool");
primitiveValueMap.put("Boolean", "bool");
primitiveValueMap.put("long", "int");
primitiveValueMap.put("Long", "int");
primitiveValueMap.put("float", "float");
primitiveValueMap.put("Float", "float");
primitiveValueMap.put("Date", "str");
primitiveValueMap.put("date", "str");
primitiveValueMap.put("Double", "float");
primitiveValueMap.put("double", "float");
}
public static Map<String, String> primitiveObjectMap = new HashMap<String, String>();
static{
primitiveObjectMap.put("string", "str");
primitiveObjectMap.put("String", "str");
primitiveObjectMap.put("java.lang.String", "str");
primitiveObjectMap.put("int", "int");
primitiveObjectMap.put("integer", "int");
primitiveObjectMap.put("Integer", "int");
primitiveObjectMap.put("java.lang.Integer", "int");
primitiveObjectMap.put("bool", "bool");
primitiveObjectMap.put("boolean", "bool");
primitiveObjectMap.put("Boolean", "bool");
primitiveObjectMap.put("java.lang.Boolean", "bool");
primitiveObjectMap.put("long", "int");
primitiveObjectMap.put("Long", "int");
primitiveObjectMap.put("java.lang.Long", "int");
primitiveObjectMap.put("float", "float");
primitiveObjectMap.put("Float", "float");
primitiveObjectMap.put("double", "float");
primitiveObjectMap.put("Double", "float");
primitiveObjectMap.put("java.lang.Float", "float");
primitiveObjectMap.put("Date", "str");
primitiveObjectMap.put("date", "str");
primitiveObjectMap.put("java.util.Date", "str");
}
private NamingPolicyProvider nameGenerator = new CamelCaseNamingPolicyProvider();
public boolean isPrimitiveType(String type) {
if(primitiveObjectMap.containsKey(type)){
return true;
}
return false;
}
public String getListReturnTypeSignature(String typeClass) {
if (isPrimitiveType(typeClass)) {
return "list<"+typeClass+">";
} else {
return "list<"+nameGenerator.applyClassNamingPolicy(typeClass)+">";
}
}
public String getMapReturnTypeSignature(String typeClass) {
return "dict<"+nameGenerator.applyClassNamingPolicy(typeClass)+">";
}
public String getSetReturnTypeSignature(String typeClass) {
return "set<"+nameGenerator.applyClassNamingPolicy(typeClass)+">";
}
public String generateListInitialization(String typeClass) {
return " list()";
}
public String generateMapInitialization(String typeClass) {
return " dict()";
}
public String generateSetInitialization(String typeClass) {
return " set()";
}
public List<String> getListIncludes() {
List<String> imports = new ArrayList<String>();
return imports;
}
public List<String> getMapIncludes() {
List<String> imports = new ArrayList<String>();
return imports;
}
public List<String> getSetIncludes() {
List<String> imports = new ArrayList<String>();
return imports; }
public List<String> getDateIncludes() {
List<String> imports = new ArrayList<String>();
return imports;
}
/**
* Gets the short name of the class the class.
* Input can be MAP, LIST or regular string. In case of map or list the class name will be class name
* that map or list is returning.
* @param type
* @return
*/
public String getGenericType(String type) {
String classShortName = "";
if(type.startsWith("List[")){
classShortName = type.substring(5, type.length()-1);
classShortName = getClassType(classShortName, true);
}else if (type.startsWith("Map[")) {
classShortName = type.substring(4, type.length()-1);
classShortName = getClassType(classShortName, true);
}else if (type.startsWith("Set[")) {
classShortName = type.substring(4, type.length()-1);
classShortName = getClassType(classShortName, true);
}else if (type.equalsIgnoreCase("ok")) {
classShortName = "void";
}else{
classShortName = getClassType(type, true);
}
return classShortName;
}
/**
* Returns the syntax for defintion of an object of type and name
*
* @param argumentType
* @param argumentName
* @return
*/
public String getArgumentDefinition(String argumentType, String argumentName) {
return argumentType + " " + argumentName;
}
/**
* Gets the class of the expected return value for a type string. Examples of type Strings are int, User, List[User]
* If the type string is a collection type like a map or list the string value returned would be the class
* that map or list is returning.
*
* @param type
* @return
*/
public String getClassType(String type, boolean primitiveObject) {
if(type.equalsIgnoreCase("void")|| type.equalsIgnoreCase("ok")){
return "void";
}
String classShortName = "";
if(type.startsWith("List[")){
classShortName = type.substring(5, type.length()-1);
classShortName = "list<"+ getClassName(classShortName, true)+">";
}else if (type.startsWith("Map[")) {
classShortName = type.substring(4, type.length()-1);
classShortName = "dict<"+ getClassName(classShortName, true) +">";
}else if (type.startsWith("Set[")) {
classShortName = type.substring(4, type.length()-1);
classShortName = "set<"+ getClassName(classShortName, true) +">";
}else{
classShortName = getClassName(type, true);
}
return classShortName;
}
/**
* If the data type is primitive and it is expecting object structure then return primitive objects
* else return primitive types
* @param type
* @param primitiveObject -- indicates if the object is primitive or not
* @return
*/
private String getClassName(String type, boolean primitiveObject) {
if(isPrimitiveType(type)){
if(primitiveObject){
return primitiveObjectMap.get(type);
}else{
return primitiveValueMap.get(type);
}
}else{
return nameGenerator.applyClassNamingPolicy(type);
}
}
@Override
public String generateVariableInitialization(String typeClass) {
return "";
}
}

View File

@ -0,0 +1,103 @@
/**
* Copyright 2011 Wordnik, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wordnik.swagger.codegen.config.python;
import com.wordnik.swagger.codegen.LibraryCodeGenerator;
import com.wordnik.swagger.codegen.config.LanguageConfiguration;
import com.wordnik.swagger.codegen.config.common.CamelCaseNamingPolicyProvider;
import com.wordnik.swagger.codegen.exception.CodeGenerationException;
import com.wordnik.swagger.codegen.util.FileUtil;
import java.io.File;
/**
* User: russ
* Date: 9/1/11
* Time: 11:00 PM
*/
public class PythonLibCodeGen extends LibraryCodeGenerator {
public static void main(String[] args) {
if(args.length < 1){
throw new CodeGenerationException("Invalid number of arguments passed: No command line argument was passed to the program for config json");
}
if(args.length == 1) {
String configPath = args[0];
PythonLibCodeGen codeGenerator = new PythonLibCodeGen(configPath);
codeGenerator.generateCode();
}
if(args.length == 4) {
String apiServerURL = args[0];
if(!apiServerURL.endsWith("/")){
apiServerURL = apiServerURL + "/";
}
String apiKey = args[1];
String packageName = args[2];
String libraryHome = args[3];
if(libraryHome.endsWith("/")){
libraryHome = libraryHome.substring(0, libraryHome.length()-1);
}
String modelPackageName = packageName+".model";
String apiPackageName = packageName+".api";
String classOutputDir = libraryHome + packageName.replace(".","/");
PythonLibCodeGen codeGenerator = new PythonLibCodeGen(apiServerURL, apiKey, modelPackageName,
apiPackageName, classOutputDir, libraryHome);
codeGenerator.generateCode();
}
}
public PythonLibCodeGen(String apiServerURL, String apiKey, String modelPackageName, String apiPackageName,
String classOutputDir, String libraryHome){
super(apiServerURL, apiKey, modelPackageName, apiPackageName, classOutputDir, libraryHome);
this.setDataTypeMappingProvider(new PythonDataTypeMappingProvider());
this.setNameGenerator(new CamelCaseNamingPolicyProvider());
}
public PythonLibCodeGen(String configPath){
super(configPath);
this.setDataTypeMappingProvider(new PythonDataTypeMappingProvider());
this.setNameGenerator(new CamelCaseNamingPolicyProvider());
}
@Override
protected LanguageConfiguration initializeLangConfig(LanguageConfiguration PythonConfiguration) {
PythonConfiguration.setClassFileExtension(".py");
PythonConfiguration.setTemplateLocation("conf/python/templates");
PythonConfiguration.setStructureLocation("conf/python/structure");
PythonConfiguration.setExceptionPackageName("com.wordnik.swagger.exception");
PythonConfiguration.setAnnotationPackageName("com.wordnik.swagger.annotations");
//create ouput directories
FileUtil.createOutputDirectories(PythonConfiguration.getModelClassLocation(), PythonConfiguration.getClassFileExtension());
FileUtil.createOutputDirectories(PythonConfiguration.getResourceClassLocation(), PythonConfiguration.getClassFileExtension());
FileUtil.clearFolder(PythonConfiguration.getModelClassLocation());
FileUtil.clearFolder(PythonConfiguration.getResourceClassLocation());
FileUtil.copyDirectory(new File(PythonConfiguration.getStructureLocation()), new File(PythonConfiguration.getResourceClassLocation()));
File initFile = new File(PythonConfiguration.getResourceClassLocation() + "__init__.py");
File newInitFile = new File(PythonConfiguration.getModelClassLocation() + "__init__.py");
initFile.renameTo(newInitFile);
// try {
// initFile.createNewFile();
// } catch (java.io.IOException e) {
// e.printStackTrace();
// throw new CodeGenerationException("Creating model/__init__.py failed");
// }
return PythonConfiguration;
}
}