def _imports(graph: mapry.Graph, py: mapry.Py) -> str: """ Generate the import statements. :param graph: mapry definition of the object graph :param py: Python settings :return: generated code """ # pylint: disable=too-many-branches # pylint: disable=too-many-statements stdlib_block = {'import collections', 'import typing'} if mapry.needs_type(a_type=graph, query=mapry.Duration): stdlib_block.add('import datetime') if (mapry.needs_type(a_type=graph, query=mapry.Class) or mapry.needs_type(a_type=graph, query=mapry.Embed)): stdlib_block.add('import collections') first_party_block = {'import {}'.format(py.module_name)} # yapf: disable return '\n\n'.join([ '\n'.join(sorted(stdlib_block)), '\n'.join(sorted(first_party_block)) ])
def test_value_needs_type(self) -> None: type_definition = mapry.Path() self.assertTrue( mapry.needs_type(a_type=type_definition, query=mapry.Path)) self.assertFalse( mapry.needs_type(a_type=type_definition, query=mapry.Date))
def test_embed_needs_type(self) -> None: embed = mapry.Embed(name='some_embed', description='', ref='') embed.properties = { 'some_property': dummy_property(name='some_property', a_type=mapry.Path(), composite=embed) } self.assertTrue(mapry.needs_type(a_type=embed, query=mapry.Path)) self.assertFalse(mapry.needs_type(a_type=embed, query=mapry.Date))
def test_class_needs_type(self) -> None: cls = mapry.Class(name='some_class', plural='', description='', ref='') cls.name = 'some_class' cls.properties = { 'some_property': dummy_property(name='some_property', a_type=mapry.Path(), composite=cls) } self.assertTrue(mapry.needs_type(a_type=cls, query=mapry.Path)) self.assertFalse(mapry.needs_type(a_type=cls, query=mapry.Date))
def generate(graph: mapry.Graph, py: mapry.Py) -> str: """ Generate the source file to parse an object graph from a JSONable object. :param graph: mapry definition of the object graph :param py: Python settings :return: content of the source file """ blocks = [ mapry.py.generate.WARNING, mapry.py.generate.docstring("serializes to JSONable objects."), _imports(graph=graph, py=py) ] if mapry.needs_type(a_type=graph, query=mapry.Duration): blocks.append(_duration_to_string()) nongraph_composites = [] # type: List[Union[mapry.Class, mapry.Embed]] nongraph_composites.extend(graph.classes.values()) nongraph_composites.extend(graph.embeds.values()) for class_or_embed in nongraph_composites: blocks.append( _serialize_class_or_embed(class_or_embed=class_or_embed, py=py)) blocks.append(_serialize_graph(graph=graph, py=py)) blocks.append(mapry.py.generate.WARNING) return '\n\n\n'.join(blocks) + '\n'
def generate(graph: mapry.Graph, go: mapry.Go) -> str: """ Generate the source file to test serializing to a JSONable. :param graph: mapry definition of the object graph :param go: Go settings :return: content of the source file """ blocks = [ 'package {}'.format(go.package), mapry.go.generate.WARNING, ] has_body = False import_decl = _imports(graph=graph) if len(import_decl) > 0: blocks.append(import_decl) has_body = True if mapry.needs_type(a_type=graph, query=mapry.Duration): blocks.append(_example_duration_to_string()) has_body = True # Include the footer only if there was something after the header if has_body: blocks.append(mapry.go.generate.WARNING) return mapry.indention.reindent(text='\n\n'.join(blocks) + '\n', indention='\t')
def generate(graph: mapry.Graph, go: mapry.Go) -> str: """ Generate the source file to serialize an object graph to a JSONable object. :param graph: mapry definition of the object graph :param go: Go settings :return: content of the source file """ blocks = [ 'package {}'.format(go.package), mapry.go.generate.WARNING, ] import_block = _imports(graph=graph) if len(import_block) > 0: blocks.append(import_block) if mapry.needs_type(a_type=graph, query=mapry.Duration): blocks.append(_duration_to_string()) nongraph_composites = [] # type: List[Union[mapry.Class, mapry.Embed]] nongraph_composites.extend(graph.classes.values()) nongraph_composites.extend(graph.embeds.values()) for class_or_embed in nongraph_composites: blocks.append( _serialize_class_or_embed(class_or_embed=class_or_embed, go=go)) blocks.append(_serialize_graph(graph=graph, go=go)) blocks.append(mapry.go.generate.WARNING) return mapry.indention.reindent(text='\n\n'.join(blocks) + '\n', indention='\t')
def _imports(graph: mapry.Graph, py: mapry.Py) -> str: """ Generate the import statements. :param graph: mapry definition of the object graph :param py: Python settings :return: generated code """ # pylint: disable=too-many-branches # pylint: disable=too-many-statements stdlib_block = {'import typing'} if mapry.needs_type(a_type=graph, query=mapry.Path): if py.path_as == 'str': pass elif py.path_as == "pathlib.Path": stdlib_block.add("import pathlib") else: raise NotImplementedError("Unhandled path_as: {!r}".format( py.path_as)) if mapry.needs_type(a_type=graph, query=mapry.TimeZone): if py.timezone_as == 'str': pass elif py.timezone_as == 'pytz.timezone': stdlib_block.add('import datetime') else: raise NotImplementedError('Unhandled timezone_as: {}'.format( py.timezone_as)) # yapf: disable if any(mapry.needs_type(a_type=graph, query=query) for query in (mapry.Date, mapry.Time, mapry.Datetime, mapry.Duration)): # yapf: enable stdlib_block.add('import datetime') if len(graph.classes) > 0: # Needed for the initialization of class registries stdlib_block.add('import collections') return '\n'.join(sorted(stdlib_block))
def _imports(graph: mapry.Graph) -> str: """ Generate the import declaration. :param graph: mapry definition of the object graph :return: generated code """ import_set = set() # type: Set[str] if mapry.needs_type(a_type=graph, query=mapry.Duration): import_set.add('fmt') return mapry.go.generate.import_declarations(import_set)
def _imports(graph: mapry.Graph) -> str: """ Generate the import declaration(s). :param graph: mapry definition of the object graph :return: generated code """ import_set = set() # type: Set[str] # yapf: disable if any(mapry.needs_type(a_type=graph, query=query) for query in (mapry.Date, mapry.Time, mapry.Datetime, mapry.Duration, mapry.TimeZone)): # yapf: enable import_set.add('time') return mapry.go.generate.import_declarations(import_set=import_set)
def test_graph_needs_type(self) -> None: # Property of an object graph graph = mapry.Graph() graph.properties = { "some_property": dummy_property(name='some_property', a_type=mapry.Path(), composite=graph) } self.assertTrue(mapry.needs_type(a_type=graph, query=mapry.Path)) self.assertFalse(mapry.needs_type(a_type=graph, query=mapry.Date)) # Recursively needs type by a property of a class cls = mapry.Class(name='some_class', plural='', description='', ref='') cls.properties = { 'some_property': dummy_property(name='some_property', a_type=mapry.Path(), composite=cls) } graph = mapry.Graph() graph.classes = {cls.name: cls} self.assertTrue(mapry.needs_type(a_type=graph, query=mapry.Path)) self.assertFalse(mapry.needs_type(a_type=graph, query=mapry.Date)) # Recursively needs type by a property of an embeddable structure embed = mapry.Embed(name='some_embed', description='', ref='') embed.properties = { 'some_property': dummy_property(name='some_property', a_type=mapry.Path(), composite=embed) } graph = mapry.Graph() graph.embeds = {embed.name: embed} self.assertTrue(mapry.needs_type(a_type=graph, query=mapry.Path)) self.assertFalse(mapry.needs_type(a_type=graph, query=mapry.Date))
def _includes(graph: mapry.Graph, cpp: mapry.Cpp) -> str: """ Generate the include directives. :param graph: mapry definition of the object graph :param cpp: C++ settings :return: generated code """ # pylint: disable=too-many-branches # pylint: disable=too-many-statements stl_block = set() # type: Set[str] third_party_block = set() # type: Set[str] if mapry.needs_type(a_type=graph, query=mapry.Integer): stl_block.add("#include <cstdint>") if mapry.needs_type(a_type=graph, query=mapry.String): stl_block.add("#include <string>") if mapry.needs_type(a_type=graph, query=mapry.Path): if cpp.path_as == 'std::filesystem::path': stl_block.add("#include <filesystem>") elif cpp.path_as == "boost::filesystem::path": third_party_block.add("#include <boost/filesystem/path.hpp>") else: raise NotImplementedError( "Unhandled cpp.path_as: {!r}".format(cpp.path_as)) date_time_types = [mapry.Date, mapry.Time, mapry.Datetime] if cpp.datetime_library == 'ctime': for query_type in date_time_types: if mapry.needs_type(a_type=graph, query=query_type): stl_block.add("#include <ctime>") if mapry.needs_type(a_type=graph, query=mapry.TimeZone): stl_block.add("#include <string>") elif cpp.datetime_library == 'date.h': if any(mapry.needs_type(a_type=graph, query=query_type) for query_type in [mapry.Date, mapry.Time, mapry.Datetime]): third_party_block.add("#include <date/date.h>") if mapry.needs_type(a_type=graph, query=mapry.Time): stl_block.add("#include <chrono>") if mapry.needs_type(a_type=graph, query=mapry.TimeZone): third_party_block.add("#include <date/tz.h>") else: raise NotImplementedError( "Unhandled cpp.datetime_library: {!r}".format(cpp.datetime_library)) if mapry.needs_type(a_type=graph, query=mapry.Duration): stl_block.add("#include <chrono>") if mapry.needs_type(a_type=graph, query=mapry.Array): stl_block.add("#include <vector>") if mapry.needs_type(a_type=graph, query=mapry.Map): stl_block.add("#include <map>") if graph.classes: stl_block.add("#include <map>") stl_block.add("#include <string>") stl_block.add("#include <memory>") # Check for optional fields # yapf: disable has_optional = ( any(prop.optional for prop in graph.properties.values()) or any(prop.optional for cls in graph.classes.values() for prop in cls.properties.values()) or any(prop.optional for embed in graph.embeds.values() for prop in embed.properties.values())) # yapf: enable if has_optional: if cpp.optional_as == "boost::optional": third_party_block.add("#include <boost/optional.hpp>") elif cpp.optional_as == "std::optional": stl_block.add("#include <optional>") elif cpp.optional_as == "std::experimental::optional": third_party_block.add("#include <optional.hpp>") else: raise NotImplementedError( "Unhandled cpp.optional_as: {!r}".format(cpp.optional_as)) block_strs = [] # type: List[str] if len(third_party_block) > 0: block_strs.append('\n'.join(sorted(third_party_block))) if len(stl_block) > 0: block_strs.append('\n'.join(sorted(stl_block))) return '\n\n'.join(block_strs)
def test_map_needs_type(self) -> None: a_map = mapry.Map(values=mapry.Path()) self.assertTrue(mapry.needs_type(a_type=a_map, query=mapry.Path)) self.assertFalse(mapry.needs_type(a_type=a_map, query=mapry.Date))
def test_array_needs_type(self) -> None: array = mapry.Array(values=mapry.Path(), minimum_size=None) self.assertTrue(mapry.needs_type(a_type=array, query=mapry.Path)) self.assertFalse(mapry.needs_type(a_type=array, query=mapry.Date))
def _includes( graph: mapry.Graph, cpp: mapry.Cpp, types_header_path: str, parse_header_path: str) -> str: """ Generate the include directives of the header file. :param graph: definition of the object graph :param cpp: C++ settings :param types_header_path: path to the header file that defines the types of the object graph :param parse_header_path: path to the header file that defines the general parsing structures :return: generated code """ # pylint: disable=too-many-branches stl_block = set() # type: Set[str] third_party_block = {"#include <json/json.h> // jsoncpp"} # yapf: disable first_party_block = { '#include "{}"'.format(pth) for pth in [types_header_path, parse_header_path]} # yapf: enable if mapry.needs_type(a_type=graph, query=mapry.String): stl_block.add("#include <string>") if mapry.needs_type(a_type=graph, query=mapry.Path): if cpp.path_as == 'std::filesystem::path': stl_block.add("#include <filesystem>") elif cpp.path_as == "boost::filesystem::path": third_party_block.add("#include <boost/filesystem/path.hpp>") else: raise NotImplementedError( "Unhandled schema.cpp.path_as: {!r}".format(cpp.path_as)) if graph.classes: stl_block.add("#include <map>") stl_block.add("#include <string>") # Check for optional fields has_optional = False for prop in graph.properties.values(): if prop.optional: has_optional = True break if not has_optional: for cls in graph.classes.values(): for prop in cls.properties.values(): if prop.optional: has_optional = True break if not has_optional: for embed in graph.embeds.values(): for prop in embed.properties.values(): if prop.optional: has_optional = True break if has_optional: if cpp.optional_as == "boost::optional": third_party_block.add("#include <boost/optional.hpp>") elif cpp.optional_as == "std::optional": stl_block.add("#include <optional>") elif cpp.optional_as == "std::experimental::optional": third_party_block.add("#include <optional.hpp>") else: raise NotImplementedError( "Unhandled schema.cpp.optional_as: {!r}".format( cpp.optional_as)) block_strs = [ '\n'.join(sorted(third_party_block)), '\n'.join(sorted(stl_block)), '\n'.join(sorted(first_party_block)) ] assert all(block_str == block_str.strip() for block_str in block_strs), \ "No empty blocks in include blocks." return '\n\n'.join(block_strs)