pax_global_header 0000666 0000000 0000000 00000000064 13546172022 0014514 g ustar 00root root 0000000 0000000 52 comment=85b16a0f9d51de8373cbd1db40bd9ea9f0fd2fab
jschema-to-python-1.2.3/ 0000775 0000000 0000000 00000000000 13546172022 0015070 5 ustar 00root root 0000000 0000000 jschema-to-python-1.2.3/.gitignore 0000664 0000000 0000000 00000002316 13546172022 0017062 0 ustar 00root root 0000000 0000000 .vscode/
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
AUTHORS
ChangeLog
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
jschema-to-python-1.2.3/CODE_OF_CONDUCT.md 0000664 0000000 0000000 00000000705 13546172022 0017671 0 ustar 00root root 0000000 0000000 # Microsoft Open Source Code of Conduct
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
Resources:
- [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
- [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
- Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns
jschema-to-python-1.2.3/LICENSE 0000664 0000000 0000000 00000002212 13546172022 0016072 0 ustar 00root root 0000000 0000000 MIT License
Copyright (c) Microsoft Corporation.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE
jschema-to-python-1.2.3/README.rst 0000664 0000000 0000000 00000004477 13546172022 0016573 0 ustar 00root root 0000000 0000000 jschema-to-python
=================
Generate Python classes from a JSON schema.
Usage
=====
::
python -m jschema_to_python [-h] -s SCHEMA_PATH -o OUTPUT_DIRECTORY [-m MODULE_NAME] -r ROOT_CLASS_NAME [-g HINTS_FILE_PATH] [-f] [-v]
Generate source code for a set of Python classes from a JSON schema.
optional arguments:
-h, --help show this help message and exit
-s SCHEMA_PATH, --schema-path SCHEMA_PATH
path to the JSON schema file
-o OUTPUT_DIRECTORY, --output-directory OUTPUT_DIRECTORY
directory in which the generated classes will be
created
-m MODULE_NAME, --module-name MODULE_NAME
name of the module containing the object model classes
-r ROOT_CLASS_NAME, --root-class-name ROOT_CLASS_NAME
the name of the class at the root of the object model
represented by the schema
-g HINTS_FILE_PATH, --hints-file-path HINTS_FILE_PATH
path to a file containing hints that control code
generation
-f, --force overwrite the output directory if it exists
-v, --verbose increase output verbosity (may be specified up to two
times)
Contributing
============
This project welcomes contributions and suggestions. Most contributions require you to agree to a
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.
When you submit a pull request, a CLA bot will automatically determine whether you need to provide
a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions
provided by the bot. You will only need to do this once across all repos using our CLA.
This project has adopted the `Microsoft Open Source Code of Conduct `_.
For more information see the `Code of Conduct FAQ `_ or
contact `opencode@microsoft.com `_ with any additional questions or comments.
jschema-to-python-1.2.3/SECURITY.md 0000664 0000000 0000000 00000005372 13546172022 0016670 0 ustar 00root root 0000000 0000000
## Security
Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [many more](https://opensource.microsoft.com/).
If you believe you have found a security vulnerability in any Microsoft-owned repository that meets Microsoft's [definition](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)) of a security vulnerability, please report it to us as described below.
## Reporting Security Issues
**Please do not report security vulnerabilities through public GitHub issues.**
Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report).
If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc).
You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc).
Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
* Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
* Full paths of source file(s) related to the manifestation of the issue
* The location of the affected source code (tag/branch/commit or direct URL)
* Any special configuration required to reproduce the issue
* Step-by-step instructions to reproduce the issue
* Proof-of-concept or exploit code (if possible)
* Impact of the issue, including how an attacker might exploit the issue
This information will help us triage your report more quickly.
If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs.
## Preferred Languages
We prefer all communications to be in English.
## Policy
Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd).
jschema-to-python-1.2.3/jschema_to_python/ 0000775 0000000 0000000 00000000000 13546172022 0020605 5 ustar 00root root 0000000 0000000 jschema-to-python-1.2.3/jschema_to_python/__init__.py 0000664 0000000 0000000 00000000173 13546172022 0022717 0 ustar 00root root 0000000 0000000 import pbr
from pbr.version import VersionInfo
__version__ = VersionInfo(__package__).semantic_version().release_string()
jschema-to-python-1.2.3/jschema_to_python/__main__.py 0000664 0000000 0000000 00000000423 13546172022 0022676 0 ustar 00root root 0000000 0000000 from __future__ import absolute_import
import os
import sys
if not __package__:
path = os.path.dirname(os.path.dirname(__file__))
sys.path.insert(0, path)
from jschema_to_python.driver import main as _main # noqa
if __name__ == "__main__":
sys.exit(_main())
jschema-to-python-1.2.3/jschema_to_python/class_generator.py 0000664 0000000 0000000 00000011777 13546172022 0024347 0 ustar 00root root 0000000 0000000 import sys
from jschema_to_python.python_file_generator import PythonFileGenerator
import jschema_to_python.utilities as util
class ClassGenerator(PythonFileGenerator):
def __init__(self, class_schema, class_name, code_gen_hints, output_directory):
super(ClassGenerator, self).__init__(output_directory)
self.class_schema = class_schema
self.required_property_names = class_schema.get("required")
if self.required_property_names:
self.required_property_names.sort()
self.class_name = class_name
self.code_gen_hints = code_gen_hints
self.file_path = self.make_class_file_path()
def __del__(self):
sys.stdout = sys.__stdout__
def generate(self):
with open(self.file_path, "w") as sys.stdout:
self.write_generation_comment()
self.write_class_declaration()
self.write_class_description()
self.write_class_body()
def make_class_file_path(self):
class_module_name = util.class_name_to_private_module_name(self.class_name)
return self.make_output_file_path(class_module_name + ".py")
def write_class_declaration(self):
print("import attr")
print("")
print("") # The black formatter wants two blank lines here.
print("@attr.s")
print("class " + self.class_name + "(object):")
def write_class_description(self):
description = self.class_schema.get("description")
if description:
print(' """' + description + '"""')
print("") # The black formatter wants a blank line here.
def write_class_body(self):
property_schemas = self.class_schema["properties"]
if not property_schemas:
print(" pass")
return
schema_property_names = sorted(property_schemas.keys())
# attrs requires that mandatory attributes be declared before optional
# attributes.
if self.required_property_names:
for schema_property_name in self.required_property_names:
attrib = self.make_attrib(schema_property_name)
print(attrib)
for schema_property_name in schema_property_names:
if self.is_optional(schema_property_name):
attrib = self.make_attrib(schema_property_name)
print(attrib)
def make_attrib(self, schema_property_name):
python_property_name = self.make_python_property_name_from_schema_property_name(
schema_property_name
)
attrib = "".join([" ", python_property_name, " = attr.ib("])
if self.is_optional(schema_property_name):
property_schema = self.class_schema["properties"][schema_property_name]
default_setter = self.make_default_setter(property_schema)
attrib = "".join([attrib, default_setter, ", "])
attrib = "".join([attrib, "metadata={\"schema_property_name\": \"", schema_property_name, "\"})"])
return attrib
def is_optional(self, schema_property_name):
return (
not self.required_property_names
or schema_property_name not in self.required_property_names
)
def make_default_setter(self, property_schema):
initializer = self.make_initializer(property_schema)
return "default=" + str(initializer)
def make_initializer(self, property_schema):
default = property_schema.get("default")
if default:
type = property_schema.get("type")
if type:
if type == "string":
default = (
'"' + default + '"'
) # The black formatter wants double-quotes.
elif type == "array":
# It isn't safe to specify a mutable object as a default value,
# because all new instances share the same mutable object, and
# one of them might mutate it, affecting all future instances!
# attr.Factory creates a new value for each instance.
default="attr.Factory(lambda: " + str(default) + ")"
elif property_schema.get("enum"):
default = '"' + default + '"'
return default
return "None"
def make_python_property_name_from_schema_property_name(self, schema_property_name):
hint_key = self.class_name + "." + schema_property_name
property_name_hint = self.get_hint(hint_key, "PropertyNameHint")
if not property_name_hint:
property_name = schema_property_name
else:
property_name = property_name_hint["arguments"]["pythonPropertyName"]
return util.to_underscore_separated_name(property_name)
def get_hint(self, hint_key, hint_kind):
if not self.code_gen_hints or hint_key not in self.code_gen_hints:
return None
hint_array = self.code_gen_hints[hint_key]
for hint in hint_array:
if hint["kind"] == hint_kind:
return hint
return None
jschema-to-python-1.2.3/jschema_to_python/driver.py 0000664 0000000 0000000 00000004365 13546172022 0022462 0 ustar 00root root 0000000 0000000 import argparse
from jschema_to_python.object_model_module_generator import ObjectModelModuleGenerator
from jschema_to_python import __version__
def main():
parser = init_parser()
args = parser.parse_args()
display_args(args)
generator = ObjectModelModuleGenerator(args)
generator.generate()
if args.verbose:
print("Done.")
def init_parser():
parser = argparse.ArgumentParser(
description="Generate source code for a set of Python classes from a JSON schema."
)
parser.add_argument(
"-s", "--schema-path", help="path to the JSON schema file", required=True
)
parser.add_argument(
"-o",
"--output-directory",
help="directory in which the generated classes will be created",
required=True,
)
parser.add_argument(
"-m",
"--module-name",
help="name of the module containing the object model classes",
)
parser.add_argument(
"-r",
"--root-class-name",
help="the name of the class at the root of the object model represented by the schema",
required=True,
)
parser.add_argument(
"-g",
"--hints-file-path",
help="path to a file containing hints that control code generation",
)
parser.add_argument(
"-f",
"--force",
action="store_true",
help="overwrite the output directory if it exists",
)
parser.add_argument(
"-v",
"--verbose",
action="count",
default=0,
help="increase output verbosity (may be specified up to two times)",
)
return parser
def display_args(args):
if args.verbose:
print(
__package__
+ ": JSON schema to Python object model generator, version "
+ __version__
)
print("Generating Python classes...")
if args.verbose > 1:
print(" from JSON schema " + args.schema_path)
print(" to module " + args.module_name)
print(" in directory " + args.output_directory)
print(" with root class " + args.root_class_name)
if args.hints_file_path:
print(" with code generation hints from " + args.hints_file_path)
if __name__ == "__main__":
main()
jschema-to-python-1.2.3/jschema_to_python/init_file_generator.py 0000664 0000000 0000000 00000002707 13546172022 0025175 0 ustar 00root root 0000000 0000000 import sys
from jschema_to_python.python_file_generator import PythonFileGenerator
import jschema_to_python.utilities as util
class InitFileGenerator(PythonFileGenerator):
def __init__(self, module_name, root_schema, root_class_name, output_directory):
super(InitFileGenerator, self).__init__(output_directory)
self.module_name = module_name
self.root_schema = root_schema
self.root_class_name = root_class_name
def __del__(self):
sys.stdout = sys.__stdout__
def generate(self):
file_path = self.make_output_file_path("__init__.py")
with open(file_path, "w") as sys.stdout:
self.write_generation_comment()
self.write_import_statements()
def write_import_statements(self):
self.write_import_statement(self.root_class_name)
definition_schemas = self.root_schema.get("definitions")
if definition_schemas:
definition_keys = sorted(definition_schemas.keys())
for definition_key in definition_keys:
class_name = util.capitalize_first_letter(definition_key)
self.write_import_statement(class_name)
def write_import_statement(self, class_name):
class_module_name = util.class_name_to_private_module_name(class_name)
print(
"from "
+ self.module_name
+ "."
+ class_module_name
+ " import "
+ class_name
)
jschema-to-python-1.2.3/jschema_to_python/object_model_module_generator.py 0000664 0000000 0000000 00000004557 13546172022 0027233 0 ustar 00root root 0000000 0000000 import os
import jschema_to_python.utilities as util
from jschema_to_python.init_file_generator import InitFileGenerator
from jschema_to_python.class_generator import ClassGenerator
class ObjectModelModuleGenerator:
def __init__(self, args):
self.output_directory = args.output_directory
self.force = args.force
self.module_name = args.module_name
self.root_schema = self.read_schema(args.schema_path)
self.code_gen_hints = self.read_code_gen_hints(args.hints_file_path)
self.root_class_name = args.root_class_name
def generate(self):
util.create_directory(self.output_directory, self.force)
self.generate_root_class()
self.generate_definition_classes()
self.generate_init_file()
def generate_init_file(self):
init_file_generator = InitFileGenerator(
self.module_name,
self.root_schema,
self.root_class_name,
self.output_directory,
)
init_file_generator.generate()
def generate_root_class(self):
class_generator = ClassGenerator(
self.root_schema,
self.root_class_name,
self.code_gen_hints,
self.output_directory,
)
class_generator.generate()
def generate_definition_classes(self):
definition_schemas = self.root_schema.get("definitions")
if definition_schemas:
for key in definition_schemas:
self.generate_definition_class(key, definition_schemas[key])
def generate_definition_class(self, definition_key, definition_schema):
class_name = util.capitalize_first_letter(definition_key)
class_generator = ClassGenerator(
definition_schema, class_name, self.code_gen_hints, self.output_directory
)
class_generator.generate()
def read_schema(self, schema_path):
if not os.path.exists(schema_path):
util.exit_with_error("schema file {} does not exist", schema_path)
return util.unpickle_file(schema_path)
def read_code_gen_hints(self, hints_file_path):
if not hints_file_path:
return None
if not os.path.exists(hints_file_path):
util.exit_with_error(
"code generation hints file {} does not exist", hints_file_path
)
return util.unpickle_file(hints_file_path)
jschema-to-python-1.2.3/jschema_to_python/python_file_generator.py 0000664 0000000 0000000 00000000764 13546172022 0025554 0 ustar 00root root 0000000 0000000 import os
from jschema_to_python import __version__
class PythonFileGenerator(object):
def __init__(self, output_directory):
self.output_directory = output_directory
def write_generation_comment(self):
print(
"# This file was generated by "
+ __package__
+ " version "
+ __version__
+ ".\n"
)
def make_output_file_path(self, file_name):
return os.path.join(self.output_directory, file_name)
jschema-to-python-1.2.3/jschema_to_python/to_json.py 0000664 0000000 0000000 00000003517 13546172022 0022640 0 ustar 00root root 0000000 0000000 # Copyright (c) Microsoft. All Rights Reserved.
# Licensed under the MIT license. See LICENSE file in the project root for full license information.
import attr
import copy
import json
def to_json(obj):
"""''Serializes an instance of a generated class to JSON.
:param obj: an instance of any class generated by jschema-to-python.
Before serializing the instance to JSON, this function maps the Python
property names to the corresponding JSON schema property names. It also
removes any property that has the default value specified by attr.ib,
making the resulting JSON smaller.
"""
return json.dumps(obj, indent=2, default=_generated_class_serializer)
def _generated_class_serializer(obj):
if hasattr(obj, "__dict__"):
dict = getattr(obj, "__dict__")
dict = copy.deepcopy(dict)
_remove_properties_with_default_values(obj, dict)
_change_python_property_names_to_schema_property_names(obj, dict)
return dict
else:
return str(obj)
def _remove_properties_with_default_values(obj, dict):
for field in attr.fields(obj.__class__):
dict_entry = dict.get(field.name)
if value_is_default(dict_entry, field.default) and field.name in dict:
del dict[field.name]
def value_is_default(dict_entry, default_value):
if type(default_value) == attr._make.Factory:
value = default_value.factory()
else:
value = default_value
return dict_entry == value
def _change_python_property_names_to_schema_property_names(obj, dict):
for field in attr.fields(obj.__class__):
schema_property_name = field.metadata.get("schema_property_name")
if schema_property_name and schema_property_name != field.name and field.name in dict:
dict[schema_property_name] = dict[field.name]
del dict[field.name]
jschema-to-python-1.2.3/jschema_to_python/utilities.py 0000664 0000000 0000000 00000002361 13546172022 0023174 0 ustar 00root root 0000000 0000000 import os
import shutil
import sys
import jsonpickle
def capitalize_first_letter(identifier):
return identifier[0].capitalize() + identifier[1:]
def create_directory(directory, force):
if os.path.exists(directory):
if force:
shutil.rmtree(directory, ignore_errors=True)
else:
exit_with_error("output directory {} already exists", directory)
os.makedirs(directory)
def to_underscore_separated_name(name):
result = ""
first_char = True
for ch in name:
if ch.islower():
next_char = ch
else:
next_char = ch.lower()
if not first_char:
next_char = "_" + next_char
first_char = False
result += next_char
return result
def class_name_to_private_module_name(class_name):
# The leading underscore indicates that users are not intended to import
# the class module individually.
return "_" + to_underscore_separated_name(class_name)
def unpickle_file(path):
with open(path, mode="rt") as file_obj:
contents = file_obj.read()
return jsonpickle.decode(contents)
def exit_with_error(message, *args):
sys.stderr.write("error : " + message.format(*args) + "\n")
sys.exit(1)
jschema-to-python-1.2.3/pytest.ini 0000664 0000000 0000000 00000000032 13546172022 0017114 0 ustar 00root root 0000000 0000000 [pytest]
testpaths = tests jschema-to-python-1.2.3/setup.cfg 0000664 0000000 0000000 00000001370 13546172022 0016712 0 ustar 00root root 0000000 0000000 [metadata]
name = jschema_to_python
author = Microsoft Corporation
author-email = v-lgold@microsoft.com
summary = Generate source code for Python classes from a JSON schema.
home-page = https://github.com/microsoft/jschema-to-python
description-file = README.rst
license = MIT
classifier =
Development Status :: 5 - Production/Stable
Environment :: Console
Intended Audience :: Developers
Intended Audience :: Information Technology
License :: OSI Approved :: MIT License
Operating System :: OS Independent
Programming Language :: Python
Topic :: Software Development :: Libraries :: Python Modules
[options]
python_requires = >= 2.7
install_requires =
attrs
jsonpickle
pbr
[files]
packages =
jschema_to_python jschema-to-python-1.2.3/setup.py 0000664 0000000 0000000 00000000135 13546172022 0016601 0 ustar 00root root 0000000 0000000 #!/usr/bin/env python
from setuptools import setup
setup(setup_requires=["pbr"], pbr=True)
jschema-to-python-1.2.3/tests/ 0000775 0000000 0000000 00000000000 13546172022 0016232 5 ustar 00root root 0000000 0000000 jschema-to-python-1.2.3/tests/__init__.py 0000664 0000000 0000000 00000000000 13546172022 0020331 0 ustar 00root root 0000000 0000000 jschema-to-python-1.2.3/tests/test_class_generator.py 0000664 0000000 0000000 00000002316 13546172022 0023020 0 ustar 00root root 0000000 0000000 import pytest
import jschema_to_python as js2p
import jschema_to_python.class_generator as cg
def test_required_property(tmp_path):
verify(
class_schema={"properties": {"requiredProperty": {"type": "int"}}, "required": ["requiredProperty"]},
class_name="RequiredProperty",
expected_file_name="_required_property.py",
tmp_path=tmp_path,
)
def test_optional_property(tmp_path):
verify(
class_schema={"properties": {"optionalProperty": {"type": "int", "default": 42}}},
class_name="OptionalProperty",
expected_file_name="_optional_property.py",
tmp_path=tmp_path,
)
def verify(class_schema, class_name, expected_file_name, tmp_path):
class_generator = cg.ClassGenerator(
class_schema=class_schema,
class_name=class_name,
code_gen_hints=None,
output_directory=str(tmp_path),
)
class_generator.generate()
with open(class_generator.file_path, "r") as fileObj:
actual = fileObj.read()
with open("tests/test_files/" + expected_file_name, "r") as fileObj:
expected = fileObj.read()
expected = expected.replace("$js2p_version$", js2p.__version__)
assert actual == expected
jschema-to-python-1.2.3/tests/test_files/ 0000775 0000000 0000000 00000000000 13546172022 0020373 5 ustar 00root root 0000000 0000000 jschema-to-python-1.2.3/tests/test_files/_optional_property.py 0000664 0000000 0000000 00000000341 13546172022 0024673 0 ustar 00root root 0000000 0000000 # This file was generated by jschema_to_python version $js2p_version$.
import attr
@attr.s
class OptionalProperty(object):
optional_property = attr.ib(default=42, metadata={"schema_property_name": "optionalProperty"})
jschema-to-python-1.2.3/tests/test_files/_required_property.py 0000664 0000000 0000000 00000000325 13546172022 0024670 0 ustar 00root root 0000000 0000000 # This file was generated by jschema_to_python version $js2p_version$.
import attr
@attr.s
class RequiredProperty(object):
required_property = attr.ib(metadata={"schema_property_name": "requiredProperty"})