Skip to content

Commit ed0d508

Browse files
committed
Merge branch 'release/0.8.37'
2 parents b5feaff + 64fb487 commit ed0d508

19 files changed

Lines changed: 244 additions & 85 deletions

File tree

CHANGES.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
## Changes
22

3+
### 0.8.37
4+
5+
- Fix loading error on 'yaml' document
6+
- Fix parameter renderer failed on int/number without 'format'
7+
- Windows Support
8+
39
### 0.8.33
410

511
- Support customized headers when making requests

README.md

Lines changed: 15 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,28 +8,25 @@ A python client for [Swagger](https://helloreverb.com/developers/swagger) enable
88
try Swagger REST API by [Swagger-UI](https://github.com/wordnik/swagger-ui). However, when it's time to **unittest**
99
your API, the first option you find would be [Swagger-codegen](https://github.com/wordnik/swagger-codegen), but the better option is us.
1010

11-
This project is developed after [swagger-py](https://github.com/digium/swagger-py), which is a nicely implemented one, and inspired many aspects of this project. Another project is [flex](https://github.com/pipermerriam/flex), which focuses on parameter validation, try it if you can handle other parts by yourselves.
12-
13-
For other projects related to Swagger tools in python, check [here](https://github.com/swagger-api/swagger-spec#python).
11+
This project is developed after [swagger-py](https://github.com/digium/swagger-py), which is a nicely implemented one, and inspired many aspects of this project. Another project is [flex](https://github.com/pipermerriam/flex), which focuses on parameter validation, try it if you can handle other parts by yourselves. For other projects related to Swagger tools in python, check [here](https://github.com/swagger-api/swagger-spec#python).
1412

1513
**pyswagger** is much easier to use (compared to swagger-codegen, you don't need to prepare a scala environment) and tries hard to **fully supports** [Swagger Spec](https://helloreverb.com/developers/swagger) in all aspects.
1614

17-
Read the [Document](http://pyswagger.readthedocs.org/en/latest/), or just go through this README.
18-
15+
- [NEWs: upcoming support for OpenAPI 3.0](docs/md/news.md)
1916
- [Features](README.md#features)
2017
- [Tutorial](README.md#tutorial)
2118
- [Quick Start](README.md#quick-start)
2219
- [Installation](README.md#installation)
2320
- [Reference](README.md#reference)
2421
- [Contributors](README.md#contributors)
2522
- [Contribution Guideline](README.md#contribution-guildeline)
26-
- [FAQ](README.md#faq)
23+
- [FAQ](docs/md/faq.md)
2724
- [Changes](CHANGES.md)
2825

2926
---------
3027

3128
## Features
32-
- **NEW** convert Swagger Document from older version to newer one. (ex. convert from 1.2 to 2.0)
29+
- convert Swagger Document from older version to newer one. (ex. convert from 1.2 to 2.0)
3330
- support Swagger **1.2**, **2.0** on python ~~2.6~~, **2.7**, **3.3**, **3.5**, **3.6**
3431
- support YAML via [Pretty-YAML](https://github.com/mk-fg/pretty-yaml)
3532
- support $ref to **External Document**, multiple swagger.json will be organized into a group of App. And external document with self-describing resource is also supported (refer to [issue](https://github.com/swagger-api/swagger-spec/issues/219)).
@@ -94,13 +91,18 @@ client.request(app.op['addPet'](body=pet_Tom))
9491

9592
# - access an Operation object via App.op when operationId is defined
9693
# - a request to get the pet back
97-
pet = client.request(app.op['getPetById'](petId=1)).data
94+
req, resp = app.op['getPetById'](petId=1)
95+
# prefer json as response
96+
req.produce('application/json')
97+
pet = client.request((req, resp)).data
9898
assert pet.id == 1
9999
assert pet.name == 'Tom'
100100

101101
# new ways to get Operation object corresponding to 'getPetById'.
102102
# 'jp_compose' stands for JSON-Pointer composition
103-
pet = client.request(app.resolve(jp_compose('/pet/{petId}', base='#/paths')).get(petId=1)).data
103+
req, resp = app.resolve(jp_compose('/pet/{petId}', base='#/paths')).get(petId=1)
104+
req.produce('application/json')
105+
pet = client.request((req, resp)).data
104106
assert pet.id == 1
105107
```
106108

@@ -148,7 +150,8 @@ All exported API are described in following sections. ![A diagram about relation
148150
---------
149151

150152
## Contribution Guildeline
151-
report an issue:
153+
154+
#### report an issue:
152155
- issues can be reported [here](https://github.com/mission-liao/pyswagger/issues)
153156
- include swagger.json if possible
154157
- turn on logging and report with messages on console
@@ -171,9 +174,9 @@ logger.setLevel(logging.DEBUG)
171174

172175
- describe expected behavior, or more specific, the input/output
173176

174-
request a merge
175-
- try not to decrease the coverage rate
177+
#### submit a PR
176178
- test included
179+
- only PR to `develop` would be accepted
177180

178181
env preparation
179182
```bash
@@ -185,17 +188,3 @@ unit testing
185188
python -m pytest -s -v --cov=pyswagger --cov-config=.coveragerc pyswagger/tests
186189
```
187190

188-
---------
189-
190-
## FAQ
191-
- Format of byte?
192-
- The way to encode/decode byte is [base64](https://github.com/wordnik/swagger-spec/issues/50).
193-
- Format of datetime on the wire?
194-
- should be an ISO8601 string, according to this [issue](https://github.com/wordnik/swagger-spec/issues/95).
195-
- How **allowMultiple** is handled?
196-
- Take type integer as example, you can pass ~~an integer or~~ an array/tuple of integer for this parameter. (a single value is no longer supported)
197-
- What do we need to take care of when upgrading from Swagger 1.2 to 2.0?
198-
- **allowMultiple** is no longer supported, always passing an array even with a single value.
199-
- 'different host for different resource' is no longer supported in Swagger 2.0, only one host and one basePath is allowed in one swagger.json.
200-
- refer to [Migration Guide](https://github.com/swagger-api/swagger-spec/wiki/Swagger-1.2-to-2.0-Migration-Guide) from Swagger team.
201-
- The name of body parameters is no longer included in requests, refer to this [issue](https://github.com/mission-liao/pyswagger/issues/13) for details.

appveyor.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
environment:
2+
matrix:
3+
- PYTHON: "C:\\Python27"
4+
- PYTHON: "C:\\Python27-x64"
5+
- PYTHON: "C:\\Python35"
6+
- PYTHON: "C:\\Python35-x64"
7+
- PYTHON: "C:\\Python36"
8+
- PYTHON: "C:\\Python36-x64"
9+
10+
install:
11+
- "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
12+
- "python --version"
13+
- "python -c \"import struct; print(struct.calcsize('P') * 8)\""
14+
- "pip install --disable-pip-version-check --user --upgrade pip"
15+
- "pip install -r requirements-dev.txt"
16+
17+
build: off
18+
19+
test_script:
20+
- "python -m pytest -s -v pyswagger/tests"

docs/md/faq.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
### FAQ
2+
3+
#### Format of byte?
4+
5+
The way to encode/decode byte is [base64](https://github.com/wordnik/swagger-spec/issues/50).
6+
7+
#### Format of datetime on the wire?
8+
9+
should be an ISO8601 string, according to this [issue](https://github.com/wordnik/swagger-spec/issues/95).
10+
11+
12+
#### How **allowMultiple** is handled?
13+
14+
Take type integer as example, you can pass ~~an integer or~~ an array/tuple of integer for this parameter. (a single value is no longer supported)
15+
16+
#### What do we need to take care of when upgrading from Swagger 1.2 to 2.0?
17+
18+
- **allowMultiple** is no longer supported, always passing an array even with a single value.
19+
- 'different host for different resource' is no longer supported in Swagger 2.0, only one host and one basePath is allowed in one swagger.json.
20+
- refer to [Migration Guide](https://github.com/swagger-api/swagger-spec/wiki/Swagger-1.2-to-2.0-Migration-Guide) from Swagger team.
21+
- The name of body parameters is no longer included in requests, refer to this [issue](https://github.com/mission-liao/pyswagger/issues/13) for details.

docs/md/news.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
### NEWs
2+
3+
Upcoming changes for OpenAPI 3.0 would be:
4+
5+
- version changes to: `1.0.0`, if you need a stabler version, please use `pyswagger<1.0.0` in pip's requirement file.
6+
- most logic would be divided to this [repo](https://github.com/mission-liao/pyopenapi) and **pyswagger** would only contains code related to 'making reuqests' (just like what gophers did in [go-openapi](https://github.com/go-openapi))
7+
- **$ref** would not be normalized anymore. Every field from API spec would be left unchanged and create another field for patched version.

pyswagger/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
__version__ = '0.8.36'
1+
__version__ = '0.8.37'
22

33
from .getter import Getter
44
from .core import App, Security

pyswagger/consts/private.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,18 @@
33

44
FILE_EXT_JSON = 'json'
55
FILE_EXT_YAML = 'yaml'
6+
FILE_EXT_YML = 'yml'
67

78
VALID_FILE_EXT = [
89
'.'+FILE_EXT_JSON,
910
'.'+FILE_EXT_YAML,
11+
'.'+FILE_EXT_YML,
1012
]
1113
SWAGGER_FILE_NAMES = [
1214
'resource_list' + '.' + FILE_EXT_JSON,
1315
'swagger' + '.' + FILE_EXT_JSON,
1416
'swagger' + '.' + FILE_EXT_YAML,
17+
'swagger' + '.' + FILE_EXT_YML,
1518
]
1619

1720
SCOPE_SEPARATOR = '!##!'

pyswagger/core.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -210,12 +210,11 @@ def prepare_obj(self, obj, jref):
210210

211211
s.scan(root=obj, route=[AssignParent()])
212212

213+
# fix for yaml that treat response code as number
214+
s.scan(root=obj, route=[YamlFixer()], leaves=[Operation])
213215
# normalize $ref
214216
url, jp = utils.jr_split(jref)
215217
s.scan(root=obj, route=[NormalizeRef(url)])
216-
# fix for yaml that treat response code as number
217-
s.scan(root=obj, route=[YamlFixer()], leaves=[Operation])
218-
219218
# cache this object
220219
if url not in self.__objs:
221220
if jp == '#':
@@ -287,7 +286,7 @@ def load(kls, url, getter=None, parser=None, url_load_hook=None, sep=consts.priv
287286
if app.__version not in ['1.2', '2.0']:
288287
raise NotImplementedError('Unsupported Version: {0}'.format(self.__version))
289288

290-
# update schem if any
289+
# update scheme if any
291290
p = six.moves.urllib.parse.urlparse(url)
292291
if p.scheme:
293292
app.schemes.append(p.scheme)
@@ -316,8 +315,8 @@ def prepare(self, strict=True):
316315
:param bool strict: when in strict mode, exception would be raised if not valid.
317316
"""
318317

319-
self.validate(strict=strict)
320318
self.__root = self.prepare_obj(self.raw, self.__url)
319+
self.validate(strict=strict)
321320

322321
if hasattr(self.__root, 'schemes') and self.__root.schemes:
323322
if len(self.__root.schemes) > 0:

pyswagger/getter.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import six
77
import os
88
import logging
9+
import re
910

1011

1112
logger = logging.getLogger(__name__)
@@ -64,6 +65,12 @@ class LocalGetter(Getter):
6465
def __init__(self, path):
6566
super(LocalGetter, self).__init__(path)
6667

68+
if path.startswith('file://'):
69+
parsed = six.moves.urllib.parse.urlparse(path)
70+
path = parsed.path
71+
if re.match('^/[A-Z]+:', path) is not None:
72+
path = os.path.abspath(path[1:])
73+
6774
for n in private.SWAGGER_FILE_NAMES:
6875
if self.base_path.endswith(n):
6976
self.base_path = os.path.dirname(self.base_path)
@@ -82,13 +89,14 @@ def __init__(self, path):
8289
# - when 'path' points to a specific file, and its
8390
# extension is either 'json' or 'yaml'.
8491
_, ext = os.path.splitext(path)
85-
for e in [private.FILE_EXT_JSON, private.FILE_EXT_YAML]:
92+
for e in [private.FILE_EXT_JSON, private.FILE_EXT_YAML, private.FILE_EXT_YML]:
8693
if ext.endswith(e):
8794
self.base_path = os.path.dirname(path)
8895
self.urls = [path]
8996
break
9097
else:
91-
for e in [private.FILE_EXT_JSON, private.FILE_EXT_YAML]:
98+
for e in [private.FILE_EXT_JSON, private.FILE_EXT_YAML, private.FILE_EXT_YML]:
99+
#print(path + '.' + e)
92100
if os.path.isfile(path + '.' + e):
93101
self.urls = [path + '.' + e]
94102
break
@@ -163,4 +171,3 @@ def load(self, path):
163171
logger.info('to load: [{0}]'.format(path))
164172

165173
return self._path2dict.get(path, {})
166-

pyswagger/primitives/_model.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def apply_with(self, obj, val, ctx):
4646

4747
not_found = set(obj.required) - set(six.iterkeys(self))
4848
if len(not_found):
49-
raise ValueError('requirement not meet: {0}'.format(not_found))
49+
raise ValueError('Model missing required key(s): {0}'.format(', '.join(not_found)))
5050

5151
# remove assigned properties to avoid duplicated
5252
# primitive creation
@@ -75,7 +75,7 @@ def cleanup(self, val, ctx):
7575
return {}
7676

7777
def __eq__(self, other):
78-
""" equality operater,
78+
""" equality operater,
7979
will skip checking when both value are None or no attribute.
8080
8181
:param other: another model
@@ -97,4 +97,3 @@ def __eq__(self, other):
9797

9898
def __ne__(self, other):
9999
return not self.__eq__(other)
100-

0 commit comments

Comments
 (0)