Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,21 @@
import io.swagger.codegen.CliOption;
import io.swagger.codegen.CodegenConfig;
import io.swagger.codegen.CodegenConstants;
import io.swagger.codegen.CodegenModel;
import io.swagger.codegen.CodegenParameter;
import io.swagger.codegen.CodegenProperty;
import io.swagger.codegen.CodegenType;
import io.swagger.codegen.DefaultCodegen;
import io.swagger.codegen.SupportingFile;
import io.swagger.models.properties.*;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;

Expand All @@ -21,6 +27,8 @@ public class PythonClientCodegen extends DefaultCodegen implements CodegenConfig
protected String apiDocPath = "docs/";
protected String modelDocPath = "docs/";

protected Map<Character, String> regexModifiers;

private String testFolder;

public PythonClientCodegen() {
Expand Down Expand Up @@ -87,6 +95,14 @@ public PythonClientCodegen() {
"assert", "else", "if", "pass", "yield", "break", "except", "import",
"print", "class", "exec", "in", "raise", "continue", "finally", "is",
"return", "def", "for", "lambda", "try", "self"));

regexModifiers = new HashMap<Character, String>();
regexModifiers.put('i', "IGNORECASE");
regexModifiers.put('l', "LOCALE");
regexModifiers.put('m', "MULTILINE");
regexModifiers.put('s', "DOTALL");
regexModifiers.put('u', "UNICODE");
regexModifiers.put('x', "VERBOSE");

cliOptions.clear();
cliOptions.add(new CliOption(CodegenConstants.PACKAGE_NAME, "python package name (convention: snake_case).")
Expand Down Expand Up @@ -143,6 +159,46 @@ public void processOpts() {
private static String dropDots(String str) {
return str.replaceAll("\\.", "_");
}

@Override
public void postProcessParameter(CodegenParameter parameter){
postProcessPattern(parameter.pattern, parameter.vendorExtensions);
}

@Override
public void postProcessModelProperty(CodegenModel model, CodegenProperty property) {
postProcessPattern(property.pattern, property.vendorExtensions);
}

/*
* The swagger pattern spec follows the Perl convention and style of modifiers. Python
* does not support this in as natural a way so it needs to convert it. See
* https://docs.python.org/2/howto/regex.html#compilation-flags for details.
*/
public void postProcessPattern(String pattern, Map<String, Object> vendorExtensions){
if(pattern != null) {
int i = pattern.lastIndexOf('/');

//Must follow Perl /pattern/modifiers convention
if(pattern.charAt(0) != '/' || i < 2) {
throw new IllegalArgumentException("Pattern must follow the Perl "
+ "/pattern/modifiers convention. "+pattern+" is not valid.");
}

String regex = pattern.substring(1, i).replace("'", "\'");
List<String> modifiers = new ArrayList<String>();

for(char c : pattern.substring(i).toCharArray()) {
if(regexModifiers.containsKey(c)) {
String modifier = regexModifiers.get(c);
modifiers.add(modifier);
}
}

vendorExtensions.put("x-regex", regex);
vendorExtensions.put("x-modifiers", modifiers);
}
}

@Override
public CodegenType getTag() {
Expand Down
26 changes: 26 additions & 0 deletions modules/swagger-codegen/src/main/resources/python/api.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ from __future__ import absolute_import

import sys
import os
import re

# python 2 and python 3 compatibility library
from six import iteritems
Expand Down Expand Up @@ -94,6 +95,31 @@ class {{classname}}(object):
if ('{{paramName}}' not in params) or (params['{{paramName}}'] is None):
raise ValueError("Missing the required parameter `{{paramName}}` when calling `{{operationId}}`")
{{/required}}
{{/allParams}}

{{#allParams}}
{{#hasValidation}}
{{#maxLength}}
if '{{paramName}}' in params and len(params['{{paramName}}']) > {{maxLength}}:
raise ValueError("Invalid value for parameter `{{paramName}}` when calling `{{operationId}}`, length must be less than or equal to `{{maxLength}}`")
{{/maxLength}}
{{#minLength}}
if '{{paramName}}' in params and len(params['{{paramName}}']) < {{minLength}}:
raise ValueError("Invalid value for parameter `{{paramName}}` when calling `{{operationId}}`, length must be greater than or equal to `{{minLength}}`")
{{/minLength}}
{{#maximum}}
if '{{paramName}}' in params and params['{{paramName}}'] > {{maximum}}:
raise ValueError("Invalid value for parameter `{{paramName}}` when calling `{{operationId}}`, must be a value less than or equal to `{{maximum}}`")
{{/maximum}}
{{#minimum}}
if '{{paramName}}' in params and params['{{paramName}}'] < {{minimum}}:
raise ValueError("Invalid value for parameter `{{paramName}}` when calling `{{operationId}}`, must be a value greater than or equal to `{{minimum}}`")
{{/minimum}}
{{#pattern}}
if '{{paramName}}' in params and not re.search('{{vendorExtensions.x-regex}}', params['{{paramName}}']{{#vendorExtensions.x-modifiers}}{{#-first}}, flags={{/-first}}re.{{.}}{{^-last}} | {{/-last}}{{/vendorExtensions.x-modifiers}}):
raise ValueError("Invalid value for parameter `{{paramName}}` when calling `{{operationId}}`, must conform to the pattern `{{pattern}}`")
{{/pattern}}
{{/hasValidation}}
{{/allParams}}

resource_path = '{{path}}'.replace('{format}', 'json')
Expand Down
32 changes: 31 additions & 1 deletion modules/swagger-codegen/src/main/resources/python/model.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Copyright 2016 SmartBear Software
{{#model}}
from pprint import pformat
from six import iteritems
import re


class {{classname}}(object):
Expand Down Expand Up @@ -79,7 +80,36 @@ class {{classname}}(object):
"Invalid value for `{{name}}`, must be one of {0}"
.format(allowed_values)
)
{{/isEnum}}self._{{name}} = {{name}}
{{/isEnum}}
{{^isEnum}}
{{#hasValidation}}

if not {{name}}:
raise ValueError("Invalid value for `{{name}}`, must not be `None`")
{{#maxLength}}
if len({{name}}) > {{maxLength}}:
raise ValueError("Invalid value for `{{name}}`, length must be less than `{{maxLength}}`")
{{/maxLength}}
{{#minLength}}
if len({{name}}) < {{minLength}}:
raise ValueError("Invalid value for `{{name}}`, length must be greater than or equal to `{{minLength}}`")
{{/minLength}}
{{#maximum}}
if {{name}} > {{maximum}}:
raise ValueError("Invalid value for `{{name}}`, must be a value less than or equal to `{{maximum}}`")
{{/maximum}}
{{#minimum}}
if {{name}} < {{minimum}}:
raise ValueError("Invalid value for `{{name}}`, must be a value greater than or equal to `{{minimum}}`")
{{/minimum}}
{{#pattern}}
if not re.search('{{vendorExtensions.x-regex}}', {{name}}{{#vendorExtensions.x-modifiers}}{{#-first}}, flags={{/-first}}re.{{.}}{{^-last}} | {{/-last}}{{/vendorExtensions.x-modifiers}}):
raise ValueError("Invalid value for `{{name}}`, must be a follow pattern or equal to `{{pattern}}`")
{{/pattern}}
{{/hasValidation}}
{{/isEnum}}

self._{{name}} = {{name}}

{{/vars}}
def to_dict(self):
Expand Down
6 changes: 3 additions & 3 deletions samples/client/petstore/python/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ This Python package is automatically generated by the [Swagger Codegen](https://

- API version: 1.0.0
- Package version: 1.0.0
- Build date: 2016-04-27T22:50:21.115+01:00
- Build date: 2016-05-09T01:08:25.311+01:00
- Build package: class io.swagger.codegen.languages.PythonClientCodegen

## Requirements.
Expand All @@ -18,9 +18,9 @@ Python 2.7 and 3.4+
If the python package is hosted on Github, you can install directly from Github

```sh
pip install git+https://github.com/YOUR_GIT_USR_ID/YOUR_GIT_REPO_ID.git
pip install git+https://github.com/GIT_USER_ID/GIT_REPO_ID.git
```
(you may need to run `pip` with root permission: `sudo pip install git+https://github.com/YOUR_GIT_USR_ID/YOUR_GIT_REPO_ID.git`)
(you may need to run `pip` with root permission: `sudo pip install git+https://github.com/GIT_USER_ID/GIT_REPO_ID.git`)

Then import the package:
```python
Expand Down
4 changes: 2 additions & 2 deletions samples/client/petstore/python/git_push.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ git_repo_id=$2
release_note=$3

if [ "$git_user_id" = "" ]; then
git_user_id="YOUR_GIT_USR_ID"
git_user_id="GIT_USER_ID"
echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id"
fi

if [ "$git_repo_id" = "" ]; then
git_repo_id="YOUR_GIT_REPO_ID"
git_repo_id="GIT_REPO_ID"
echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id"
fi

Expand Down
26 changes: 26 additions & 0 deletions samples/client/petstore/python/swagger_client/apis/fake_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import sys
import os
import re

# python 2 and python 3 compatibility library
from six import iteritems
Expand Down Expand Up @@ -103,6 +104,31 @@ def test_endpoint_parameters(self, number, double, string, byte, **kwargs):
if ('byte' not in params) or (params['byte'] is None):
raise ValueError("Missing the required parameter `byte` when calling `test_endpoint_parameters`")

if 'number' in params and params['number'] > 543.2:
raise ValueError("Invalid value for parameter `number` when calling `test_endpoint_parameters`, must be a value less than or equal to `543.2`")
if 'number' in params and params['number'] < 32.1:
raise ValueError("Invalid value for parameter `number` when calling `test_endpoint_parameters`, must be a value greater than or equal to `32.1`")
if 'double' in params and params['double'] > 123.4:
raise ValueError("Invalid value for parameter `double` when calling `test_endpoint_parameters`, must be a value less than or equal to `123.4`")
if 'double' in params and params['double'] < 67.8:
raise ValueError("Invalid value for parameter `double` when calling `test_endpoint_parameters`, must be a value greater than or equal to `67.8`")
if 'string' in params and not re.search('[a-z]', params['string'], flags=re.IGNORECASE):
raise ValueError("Invalid value for parameter `string` when calling `test_endpoint_parameters`, must conform to the pattern `/[a-z]/i`")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An example of why the toRegexMethod won't work.

Copy link
Contributor

@wing328 wing328 May 9, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I looked at this earlier (http://stackoverflow.com/a/23613042/677735), I was thinking about updating the pattern to '[a-z]',re.IGNORECASE with the following template:

{{#pattern}}
pattern = re.compile({{{.}}})
if pattern.match(params['{{name}}]):
...
{{/pattern}}

Of course your solution using vendor extension works as well.

if 'integer' in params and params['integer'] > 100.0:
raise ValueError("Invalid value for parameter `integer` when calling `test_endpoint_parameters`, must be a value less than or equal to `100.0`")
if 'integer' in params and params['integer'] < 10.0:
raise ValueError("Invalid value for parameter `integer` when calling `test_endpoint_parameters`, must be a value greater than or equal to `10.0`")
if 'int32' in params and params['int32'] > 200.0:
raise ValueError("Invalid value for parameter `int32` when calling `test_endpoint_parameters`, must be a value less than or equal to `200.0`")
if 'int32' in params and params['int32'] < 20.0:
raise ValueError("Invalid value for parameter `int32` when calling `test_endpoint_parameters`, must be a value greater than or equal to `20.0`")
if 'float' in params and params['float'] > 987.6:
raise ValueError("Invalid value for parameter `float` when calling `test_endpoint_parameters`, must be a value less than or equal to `987.6`")
if 'password' in params and len(params['password']) > 64:
raise ValueError("Invalid value for parameter `password` when calling `test_endpoint_parameters`, length must be less than or equal to `64`")
if 'password' in params and len(params['password']) < 10:
raise ValueError("Invalid value for parameter `password` when calling `test_endpoint_parameters`, length must be greater than or equal to `10`")

resource_path = '/fake'.replace('{format}', 'json')
path_params = {}

Expand Down
9 changes: 9 additions & 0 deletions samples/client/petstore/python/swagger_client/apis/pet_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import sys
import os
import re

# python 2 and python 3 compatibility library
from six import iteritems
Expand Down Expand Up @@ -83,6 +84,7 @@ def add_pet(self, body, **kwargs):
if ('body' not in params) or (params['body'] is None):
raise ValueError("Missing the required parameter `body` when calling `add_pet`")


resource_path = '/pet'.replace('{format}', 'json')
path_params = {}

Expand Down Expand Up @@ -161,6 +163,7 @@ def delete_pet(self, pet_id, **kwargs):
if ('pet_id' not in params) or (params['pet_id'] is None):
raise ValueError("Missing the required parameter `pet_id` when calling `delete_pet`")


resource_path = '/pet/{petId}'.replace('{format}', 'json')
path_params = {}
if 'pet_id' in params:
Expand Down Expand Up @@ -240,6 +243,7 @@ def find_pets_by_status(self, status, **kwargs):
if ('status' not in params) or (params['status'] is None):
raise ValueError("Missing the required parameter `status` when calling `find_pets_by_status`")


resource_path = '/pet/findByStatus'.replace('{format}', 'json')
path_params = {}

Expand Down Expand Up @@ -317,6 +321,7 @@ def find_pets_by_tags(self, tags, **kwargs):
if ('tags' not in params) or (params['tags'] is None):
raise ValueError("Missing the required parameter `tags` when calling `find_pets_by_tags`")


resource_path = '/pet/findByTags'.replace('{format}', 'json')
path_params = {}

Expand Down Expand Up @@ -394,6 +399,7 @@ def get_pet_by_id(self, pet_id, **kwargs):
if ('pet_id' not in params) or (params['pet_id'] is None):
raise ValueError("Missing the required parameter `pet_id` when calling `get_pet_by_id`")


resource_path = '/pet/{petId}'.replace('{format}', 'json')
path_params = {}
if 'pet_id' in params:
Expand Down Expand Up @@ -471,6 +477,7 @@ def update_pet(self, body, **kwargs):
if ('body' not in params) or (params['body'] is None):
raise ValueError("Missing the required parameter `body` when calling `update_pet`")


resource_path = '/pet'.replace('{format}', 'json')
path_params = {}

Expand Down Expand Up @@ -550,6 +557,7 @@ def update_pet_with_form(self, pet_id, **kwargs):
if ('pet_id' not in params) or (params['pet_id'] is None):
raise ValueError("Missing the required parameter `pet_id` when calling `update_pet_with_form`")


resource_path = '/pet/{petId}'.replace('{format}', 'json')
path_params = {}
if 'pet_id' in params:
Expand Down Expand Up @@ -633,6 +641,7 @@ def upload_file(self, pet_id, **kwargs):
if ('pet_id' not in params) or (params['pet_id'] is None):
raise ValueError("Missing the required parameter `pet_id` when calling `upload_file`")


resource_path = '/pet/{petId}/uploadImage'.replace('{format}', 'json')
path_params = {}
if 'pet_id' in params:
Expand Down
11 changes: 11 additions & 0 deletions samples/client/petstore/python/swagger_client/apis/store_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import sys
import os
import re

# python 2 and python 3 compatibility library
from six import iteritems
Expand Down Expand Up @@ -83,6 +84,9 @@ def delete_order(self, order_id, **kwargs):
if ('order_id' not in params) or (params['order_id'] is None):
raise ValueError("Missing the required parameter `order_id` when calling `delete_order`")

if 'order_id' in params and params['order_id'] < 1.0:
raise ValueError("Invalid value for parameter `order_id` when calling `delete_order`, must be a value greater than or equal to `1.0`")

resource_path = '/store/order/{orderId}'.replace('{format}', 'json')
path_params = {}
if 'order_id' in params:
Expand Down Expand Up @@ -156,6 +160,7 @@ def get_inventory(self, **kwargs):
del params['kwargs']



resource_path = '/store/inventory'.replace('{format}', 'json')
path_params = {}

Expand Down Expand Up @@ -231,6 +236,11 @@ def get_order_by_id(self, order_id, **kwargs):
if ('order_id' not in params) or (params['order_id'] is None):
raise ValueError("Missing the required parameter `order_id` when calling `get_order_by_id`")

if 'order_id' in params and params['order_id'] > 5.0:
raise ValueError("Invalid value for parameter `order_id` when calling `get_order_by_id`, must be a value less than or equal to `5.0`")
if 'order_id' in params and params['order_id'] < 1.0:
raise ValueError("Invalid value for parameter `order_id` when calling `get_order_by_id`, must be a value greater than or equal to `1.0`")

resource_path = '/store/order/{orderId}'.replace('{format}', 'json')
path_params = {}
if 'order_id' in params:
Expand Down Expand Up @@ -308,6 +318,7 @@ def place_order(self, body, **kwargs):
if ('body' not in params) or (params['body'] is None):
raise ValueError("Missing the required parameter `body` when calling `place_order`")


resource_path = '/store/order'.replace('{format}', 'json')
path_params = {}

Expand Down
Loading