Skip to content

Commit 59b9a6d

Browse files
committed
v0.1.0
2 parents d3235f5 + 5fe940d commit 59b9a6d

39 files changed

+1432
-1337
lines changed

.travis.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
language: python
2+
python:
3+
- "2.7"
4+
install:
5+
- python setup.py install
6+
before_script:
7+
- pip install pytest
8+
script: py.test
9+
deploy:
10+
provider: pypi
11+
user: rejown
12+
password:
13+
secure: "K6eW3+2aB0vc5BRFw9NmrN7jqTdFID5/AsmXlOfPDfFtdkoRKH4bFZxW22qXQ40Kn5qygWOUlymh1Z1/kb0W0HVInjOIz7NekSyjHlIMLAa9S/bj0ydOoh6wLBBD5SQbtnO7yC2ARtnQ1OEPR2IosqYYNfhXRvnyp0GLHRb14KYQmCnwvAW7JzWPPs8jniJHqir78XmpwhvxD2u3ObjtTpFey6lRzQ1EaWdGWumJmlwooDI+rbJ5DSs/+sPK239ujLHZsiIPZOivlVdwL1S/wErV0TFOZcCNTNJ04dquC7tns8MqxDCz6Rb/9TG4TgevpShp8jTXIaV89dPptDKX3aa9zMXpBf09jiAagjwnvBwbUaNqdUsRCzgw4MFKRzWv1JTqSuHdPM1cU4BRRIVgOvPoLknZJo/thhdtw0Torff63RjVRWAt9bwx0VpMGiovI3ny6cXKSqMmthWOjAWdxcmp0dAXcBH5TP7+LaxDPoPBYwhU2Hd2DP6AZ39yZ9WzApaOvtbIy6wBqvaCDY/sdi6nKjQwMvy/TamKR96/w1BAX6YME3IjKjmZRsiQlEFZckxWQjIqj+/odTHhiqwt3a/7jko5gPVGjPUTA1V2x9W7MEgFyW90JuYud/2BlkKgVyQKjBwRaa99cMLQtmpEmctv1LD/KI0KAKrp3Eql2Xo="
14+
on:
15+
pythoni: 2.7
16+
tags: true
17+
branch: master

AUTHORS

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Maintainer:
2+
3+
* Rejown (rejown@gmail.com);
4+
5+
6+
Contributors:
7+
8+
* yimiqisan (yimiqisan@gmail.com);
9+
* softlns (softliunaisen@gmai.com);

README.md

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Flask RESTful Application Code Generator
22

3+
[![Build Status](https://travis-ci.org/softlns/swagger-py-codegen.svg)](https://travis-ci.org/softlns/swagger-py-codegen)
34

45
## Overview
56

@@ -22,8 +23,64 @@ Create all:
2223
swagger-py-codegen --swagger-doc api.yml example-app
2324
```
2425

25-
## TODO
26+
Command Options:
2627

27-
- validation support
28-
- generate client
29-
- generate tests
28+
-s, --swagger, --swagger-doc Swagger doc file. [required]
29+
-f, --force Force overwrite.
30+
-p, --package Package name / application name.
31+
-t, --template-dir Path of your custom templates directory.
32+
--spec, --specification Generate online specification json response.
33+
--ui Generate swagger ui.
34+
--help Show this message and exit.
35+
36+
## Examples:
37+
38+
Generate example-app from [apis.yml](https://github.com/guokr/swagger-py-codegen/blob/master/api.yml "Title"):
39+
40+
$tree
41+
.
42+
|__ api.yml
43+
44+
$ swagger_py_codegen -s api.yml example-app -p demo
45+
$ tree
46+
.
47+
|__ api.yml
48+
|__ example-app
49+
|__ demo
50+
| |__ __init__.py
51+
| |__ v1
52+
| |__ api
53+
| | |__ __init__.py
54+
| | |__ oauth_auth_approach_approach.py
55+
| | |__ oauth_auth_approach.py
56+
| | |__ users_token.py
57+
| | |__ users_current.py
58+
| | |__ users.py
59+
| |__ __init__.py
60+
| |__ routes.py
61+
| |__ schemas.py
62+
| |__ validators.py
63+
|__ requirements.txt
64+
65+
Install example-app requirements:
66+
67+
$ cd example-app
68+
$ pip install -r requirements.txt
69+
70+
Start example-app:
71+
72+
$ cd demo
73+
$ python __init__.py
74+
75+
And generate example-app-ui from apis.yml with ui:
76+
77+
$ swagger_py_codegen -s api.yml example-app-ui -p demo-ui --ui
78+
79+
## Authors
80+
--------
81+
See the [AUTHORS](https://github.com/guokr/swagger-py-codegen/blob/master/AUTHORS "Title").
82+
83+
84+
## License
85+
--------
86+
MIT
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ definitions:
6161
- register
6262
- open
6363
Approach:
64+
required:
65+
- approach
6466
properties:
6567
approach:
6668
type: string
@@ -87,7 +89,7 @@ definitions:
8789
type: string
8890
parameters:
8991
AccessToken:
90-
name: access_token
92+
name: Authentication
9193
in: header
9294
required: true
9395
type: string

setup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@
2020
include_package_data=True,
2121
entry_points={
2222
'console_scripts': [
23-
'swagger_py_codegen=swagger_py_codegen:codegen'
23+
'swagger_py_codegen=swagger_py_codegen:generate'
2424
]
2525
},
26-
install_requires=['PyYAML', 'click', 'jinja2'],
26+
install_requires=['PyYAML', 'click', 'jinja2', 'dpath'],
2727
tests_require=['pytest'],
2828
classifiers=[
2929
'Development Status :: 3 - Alpha',

swagger_py_codegen/__init__.py

Lines changed: 2 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,3 @@
1-
# -*- coding: utf-8 -*-
2-
import codecs
3-
import click
1+
from .command import generate
42

5-
from parser import parse_yaml
6-
import writer
7-
8-
__version__ = '0.0.9'
9-
10-
11-
@click.command()
12-
@click.argument('path', required=True)
13-
@click.option('-s', '--swagger-doc', required=True, help='Swagger doc file.')
14-
@click.option('-f', '--force', is_flag=True, help='Force overwrite.')
15-
@click.option('-a', '--appname', help='Application name or package name.')
16-
@click.option('--specification', is_flag=True, help='Generate online specification.')
17-
@click.option('--ui', is_flag=True, help='Generate swagger ui.')
18-
def codegen(path, swagger_doc, force=False, appname=None, specification=True, ui=True):
19-
if appname is None:
20-
appname = path.split('/')[-1].replace('-', '_')
21-
22-
with codecs.open(swagger_doc, 'r', 'utf-8') as f:
23-
m = parse_yaml(f)
24-
if not m:
25-
print 'swagger-doc could not be read.'
26-
exit(-1)
27-
28-
if specification:
29-
import yaml
30-
import model
31-
res = model.Resource('/_swagger', m)
32-
method = model.Method('get', res)
33-
with codecs.open(swagger_doc, 'r', 'utf-8') as f:
34-
method.response_example = yaml.load(f)
35-
res.methods = {'GET': method}
36-
m.add_resource(res)
37-
38-
writer.write(model=m, base_path=path, appname=appname,
39-
overwrite=force, ui=ui)
40-
41-
if __name__ == '__main__':
42-
codegen()
3+
__version__ = '0.1.0'

swagger_py_codegen/__main__.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
# -*- coding: utf-8 -*-
2-
import swagger_py_codegen
1+
from .command import generate
32

4-
if __name__ == '__main__':
5-
swagger_py_codegen.codegen()
3+
generate()

swagger_py_codegen/base.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import os
2+
3+
from jinja2 import Environment, FileSystemLoader
4+
5+
6+
class Code(object):
7+
8+
template = 'code.tpl'
9+
dest_template = '%(package)s/%(basePath)s'
10+
override = False
11+
12+
def __init__(self, data=None, dist_template=None, dist_env=None):
13+
self.data = data or {}
14+
self.dest_template = dist_template or self.dest_template
15+
self.dist_env = dist_env or {}
16+
17+
def dest(self, env=None):
18+
env = env or {}
19+
env.update(self.dist_env)
20+
return self.dest_template % env
21+
22+
def before_render(self, jinja_env):
23+
pass
24+
25+
26+
class CodeGenerator(object):
27+
28+
dependencies = []
29+
30+
def __init__(self, swagger):
31+
self.swagger = swagger
32+
33+
def _dependence_callback(self, code):
34+
return code
35+
36+
def _process(self):
37+
raise NotImplementedError
38+
39+
def generate(self):
40+
for clz in self.dependencies:
41+
dependence = clz(self.swagger)
42+
g = dependence.generate()
43+
for code in g:
44+
yield self._dependence_callback(code)
45+
46+
for code in self._process():
47+
yield code
48+
49+
50+
class Template(object):
51+
52+
def __init__(self):
53+
self.loader = FileSystemLoader(os.path.join(
54+
os.path.dirname(__file__), 'templates'))
55+
self.env = Environment(loader=self.loader)
56+
57+
def add_searchpath(self, path):
58+
self.loader.searchpath.append(path)
59+
60+
def render(self, template_name, **kwargs):
61+
template = self.env.get_template(template_name)
62+
return template.render(**kwargs)
63+
64+
def render_code(self, code):
65+
code.before_render(self)
66+
return self.render(code.template, **code.data)
67+

swagger_py_codegen/command.py

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import codecs
2+
try:
3+
import simplejson as json
4+
except ImportError:
5+
import json
6+
from os import makedirs
7+
from os.path import join, exists, dirname
8+
9+
import yaml
10+
import click
11+
12+
from .flask import FlaskGenerator
13+
from .parser import Swagger
14+
from .base import Template
15+
16+
17+
def spec_load(filename):
18+
if filename.endswith('.json'):
19+
loader = json.load
20+
elif filename.endswith('.yml') or filename.endswith('.yaml'):
21+
loader = yaml.load
22+
else:
23+
with codecs.open(filename, 'r', 'utf-8') as f:
24+
contents = f.read()
25+
contents = contents.strip()
26+
if contents[0] in ['{', '[']:
27+
loader = json.load
28+
else:
29+
loader = yaml.load
30+
with codecs.open(filename, 'r', 'utf-8') as f:
31+
return loader(f)
32+
33+
34+
def write(dist, content):
35+
dir_ = dirname(dist)
36+
if not exists(dir_):
37+
makedirs(dir_)
38+
with codecs.open(dist, 'w', 'utf-8') as f:
39+
f.write(content)
40+
41+
42+
def _copy_ui_dir(ui_dest, ui_src):
43+
from distutils.dir_util import copy_tree
44+
from os import unlink
45+
46+
if exists(ui_dest):
47+
status = 'skip'
48+
else:
49+
status = 'generate'
50+
makedirs(ui_dest)
51+
copy_tree(ui_src, ui_dest)
52+
unlink(join(ui_dest, 'index.html'))
53+
return status
54+
55+
56+
@click.command()
57+
@click.argument('destination', required=True)
58+
@click.option('-s', '--swagger', '--swagger-doc',
59+
required=True, help='Swagger doc file.')
60+
@click.option('-f', '--force',
61+
default=False, is_flag=True, help='Force overwrite.')
62+
@click.option('-p', '--package',
63+
help='Package name / application name.')
64+
@click.option('-t', '--template-dir',
65+
help='Path of your custom templates directory.')
66+
@click.option('--spec', '--specification',
67+
default=False, is_flag=True,
68+
help='Generate online specification json response.')
69+
@click.option('--ui',
70+
default=False, is_flag=True,
71+
help='Generate swagger ui.')
72+
def generate(destination, swagger_doc, force=False, package=None,
73+
template_dir=None, specification=False, ui=False):
74+
75+
package = package or destination.replace('-', '_')
76+
data = spec_load(swagger_doc)
77+
swagger = Swagger(data)
78+
generator = FlaskGenerator(swagger)
79+
generator.with_spec = specification
80+
generator.with_ui = ui
81+
template = Template()
82+
if template_dir:
83+
template.add_searchpath(template_dir)
84+
env = dict(package=package,
85+
module=swagger.module_name)
86+
87+
if ui:
88+
ui_dest = join(destination, '%(package)s/static/swagger-ui' % env)
89+
ui_src = join(dirname(__file__), 'templates/ui')
90+
status = _copy_ui_dir(ui_dest, ui_src)
91+
click.secho('%-12s%s' % (status, ui_dest))
92+
93+
for code in generator.generate():
94+
source = template.render_code(code)
95+
dest = join(destination, code.dest(env))
96+
dest_exists = exists(dest)
97+
can_override = force or code.override
98+
statuses = {
99+
(False, False): 'generate',
100+
(False, True): 'generate',
101+
(True, False): 'skip',
102+
(True, True): 'override'
103+
}
104+
status = statuses[(dest_exists, can_override)]
105+
click.secho('%-12s' % status, nl=False)
106+
click.secho(dest)
107+
108+
if status != 'skipped':
109+
write(dest, source)
110+

0 commit comments

Comments
 (0)