Skip to content

Commit

Permalink
Merge pull request #2 from guokr/master
Browse files Browse the repository at this point in the history
merge
  • Loading branch information
zrq495 authored Apr 13, 2017
2 parents 3c5360c + 841abfe commit 47b8dfe
Show file tree
Hide file tree
Showing 23 changed files with 185 additions and 56 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ dist/
*.egg-info
*.egg
.idea
*~
*.pyc
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
language: python
python:
- "2.7"
- "3.5"
install:
- python setup.py install
before_script:
Expand Down
3 changes: 3 additions & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ Contributors:

* yimiqisan ([email protected]);
* softlns ([email protected]);
* Justin ([email protected]);
* teknolog2000 (https://github.com/teknolog2000);
* ChaosEternal (https://github.com/ChaosEternal);
* SimplicityGuy (https://github.com/SimplicityGuy);
* Roy Williams (https://github.com/rowillia);
* Vinod Gupta (https://github.com/codervinod)
6 changes: 4 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
from __future__ import absolute_import
import re
import ast
from setuptools import setup

_version_re = re.compile(r'__version__\s+=\s+(.*)')

with open('swagger_py_codegen/__init__.py', 'rb') as f:
with open('swagger_py_codegen/_version.py', 'rb') as f:
version = str(ast.literal_eval(_version_re.search(
f.read().decode('utf-8')).group(1)))

Expand All @@ -23,11 +24,12 @@
'swagger_py_codegen=swagger_py_codegen:generate'
]
},
install_requires=['PyYAML', 'click', 'jinja2', 'dpath'],
install_requires=['PyYAML', 'click', 'jinja2', 'dpath', 'six'],
tests_require=['pytest'],
classifiers=[
'Development Status :: 3 - Alpha',
'License :: OSI Approved :: MIT License',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
],
)
5 changes: 3 additions & 2 deletions swagger_py_codegen/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from .command import generate
from __future__ import absolute_import

__version__ = '0.1.19'
from ._version import __version__
from .command import generate
2 changes: 2 additions & 0 deletions swagger_py_codegen/__main__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import absolute_import

from .command import generate

generate()
4 changes: 4 additions & 0 deletions swagger_py_codegen/_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"""Version information."""

# The following line *must* be the last in the module, exactly as formatted:
__version__ = "0.2.4"
1 change: 1 addition & 0 deletions swagger_py_codegen/base.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from __future__ import absolute_import
import os

from jinja2 import Environment, FileSystemLoader
Expand Down
21 changes: 18 additions & 3 deletions swagger_py_codegen/command.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
from __future__ import absolute_import
import codecs
try:
import simplejson as json
except ImportError:
import json
from multiprocessing import Pool
from os import makedirs
from os.path import join, exists, dirname

import yaml
import click

from ._version import __version__
from .flask import FlaskGenerator
from .parser import Swagger
from .base import Template
Expand Down Expand Up @@ -53,6 +56,13 @@ def _copy_ui_dir(ui_dest, ui_src):
return status


def print_version(ctx, param, value):
if not value or ctx.resilient_parsing:
return
click.echo('current version: %s' % __version__)
ctx.exit()


@click.command()
@click.argument('destination', required=True)
@click.option('-s', '--swagger', '--swagger-doc',
Expand All @@ -69,12 +79,17 @@ def _copy_ui_dir(ui_dest, ui_src):
@click.option('--ui',
default=False, is_flag=True,
help='Generate swagger ui.')
@click.option('-j', '--jobs',
default=4, help='Parallel jobs for processing.')
@click.option('--version', is_flag=True, callback=print_version,
expose_value=False, is_eager=True,
help='Show current version.')
def generate(destination, swagger_doc, force=False, package=None,
template_dir=None, specification=False, ui=False):

template_dir=None, specification=False, ui=False, jobs=4):
pool = Pool(processes=int(jobs))
package = package or destination.replace('-', '_')
data = spec_load(swagger_doc)
swagger = Swagger(data)
swagger = Swagger(data, pool)
generator = FlaskGenerator(swagger)
generator.with_spec = specification
generator.with_ui = ui
Expand Down
29 changes: 20 additions & 9 deletions swagger_py_codegen/flask.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from __future__ import absolute_import
import re
from collections import OrderedDict

from .base import Code, CodeGenerator
from .jsonschema import Schema, SchemaGenerator, build_default
import six

SUPPORT_METHODS = ['get', 'post', 'put', 'delete', 'patch', 'options', 'head']

Expand Down Expand Up @@ -94,13 +96,21 @@ def _type(parameters):

return url, params

if six.PY3:
def _remove_characters(text, deletechars):
return text.translate({ord(x): None for x in deletechars})
else:
def _remove_characters(text, deletechars):
return text.translate(None, deletechars)

def _path_to_endpoint(swagger_path):
return swagger_path.strip('/').replace('/', '_').replace('-', '_').translate(None, '{}')
return _remove_characters(
swagger_path.strip('/').replace('/', '_').replace('-', '_'),
'{}')


def _path_to_resource_name(swagger_path):
return swagger_path.title().translate(None, '{}/_-')
return _remove_characters(swagger_path.title(), '{}/_-')


def _location(swagger_location):
Expand Down Expand Up @@ -130,18 +140,18 @@ def _dependence_callback(self, code):
# use flask endpoint to replace default validator's key,
# example: `('some_path_param', 'method')`
validators = OrderedDict()
for k, v in schemas.data['validators'].iteritems():
locations = {_location(loc): val for loc, val in v.iteritems()}
for k, v in six.iteritems(schemas.data['validators']):
locations = {_location(loc): val for loc, val in six.iteritems(v)}
validators[(_path_to_endpoint(k[0]), k[1])] = locations

# filters
filters = OrderedDict()
for k, v in schemas.data['filters'].iteritems():
for k, v in six.iteritems(schemas.data['filters']):
filters[(_path_to_endpoint(k[0]), k[1])] = v

# scopes
scopes = OrderedDict()
for k, v in schemas.data['scopes'].iteritems():
for k, v in six.iteritems(schemas.data['scopes']):
scopes[(_path_to_endpoint(k[0]), k[1])] = v

schemas.data['validators'] = validators
Expand Down Expand Up @@ -169,11 +179,12 @@ def _process_data(self):
methods[method] = {}
validator = self.validators.get((endpoint, method.upper()))
if validator:
methods[method]['requests'] = validator.keys()
methods[method]['requests'] = list(validator.keys())

for status, res_data in data[method].get('responses', {}).iteritems():
for status, res_data in six.iteritems(data[method].get('responses', {})):
if isinstance(status, int) or status.isdigit():
example = res_data.get('schema', {}).get('application/json')
example = res_data.get('examples', {}).get('application/json')

if not example:
example = build_default(res_data.get('schema'))
response = example, int(status), build_default(res_data.get('headers'))
Expand Down
32 changes: 19 additions & 13 deletions swagger_py_codegen/jsonschema.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from __future__ import absolute_import
from collections import OrderedDict
from inspect import getsource

from .base import Code, CodeGenerator
from .parser import schema_var_name
import six


class Schema(Code):
Expand Down Expand Up @@ -74,7 +76,7 @@ def build_data(swagger):
responses = data.get('responses')
if responses:
filter = {}
for status, res_data in responses.iteritems():
for status, res_data in six.iteritems(responses):
if isinstance(status, int) or status.isdigit():
filter[int(status)] = dict(
headers=res_data.get('headers'),
Expand All @@ -84,7 +86,7 @@ def build_data(swagger):

# scopes
for security in data.get('security', []):
scopes[(endpoint, method)] = security.values().pop()
scopes[(endpoint, method)] = list(security.values()).pop()
break

schemas = OrderedDict([(schema_var_name(path), swagger.get(path)) for path in swagger.definitions])
Expand All @@ -106,7 +108,7 @@ def _process(self):
yield Schema(build_data(self.swagger))


def merge_default(schema, value):
def merge_default(schema, value, get_first=True):
# TODO: more types support
type_defaults = {
'integer': 9573,
Expand All @@ -116,7 +118,10 @@ def merge_default(schema, value):
'boolean': False
}

return normalize(schema, value, type_defaults)[0]
results = normalize(schema, value, type_defaults)
if get_first:
return results[0]
return results


def build_default(schema):
Expand All @@ -125,6 +130,8 @@ def build_default(schema):

def normalize(schema, data, required_defaults=None):

import six

if required_defaults is None:
required_defaults = {}
errors = []
Expand All @@ -147,8 +154,8 @@ def has(self, key):

def keys(self):
if isinstance(self.data, dict):
return self.data.keys()
return vars(self.data).keys()
return list(self.data.keys())
return list(vars(self.data).keys())

def get_check(self, key, default=None):
if isinstance(self.data, dict):
Expand All @@ -169,13 +176,9 @@ def _normalize_dict(schema, data):
if not isinstance(data, DataWrapper):
data = DataWrapper(data)

for key, _schema in schema.get('properties', {}).iteritems():
for key, _schema in six.iteritems(schema.get('properties', {})):
# set default
type_ = _schema.get('type', 'object')
if ('default' not in _schema
and key in schema.get('required', [])
and type_ in required_defaults):
_schema['default'] = required_defaults[type_]

# get value
value, has_key = data.get_check(key)
Expand All @@ -184,8 +187,11 @@ def _normalize_dict(schema, data):
elif 'default' in _schema:
result[key] = _schema['default']
elif key in schema.get('required', []):
errors.append(dict(name='property_missing',
message='`%s` is required' % key))
if type_ in required_defaults:
result[key] = required_defaults[type_]
else:
errors.append(dict(name='property_missing',
message='`%s` is required' % key))

for _schema in schema.get('allOf', []):
rs_component = _normalize(_schema, data)
Expand Down
Loading

0 comments on commit 47b8dfe

Please sign in to comment.