Skip to content

Commit

Permalink
Added abstract types in default parameters and '-l' language argument
Browse files Browse the repository at this point in the history
  • Loading branch information
Ananya2003Gupta committed Sep 14, 2023
1 parent dfee261 commit 7a4eafe
Show file tree
Hide file tree
Showing 11 changed files with 95 additions and 82 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ install
tests/src
tests/datamodel
tests/extension_model
tests/datamodeljulia

# Python
*pyc
Expand Down
15 changes: 12 additions & 3 deletions cmake/podioMacros.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -128,13 +128,15 @@ set_property(CACHE PODIO_USE_CLANG_FORMAT PROPERTY STRINGS AUTO ON OFF)
# passed directly to podio_class_generator.py and validated there
# Default is ROOT
# SCHEMA_EVOLUTION OPTIONAL: The path to the yaml file declaring the necessary schema evolution
# )
# LANG OPTIONAL: The programming language choice
# Default is cpp
# )
#
# Note that the create_${datamodel} target will always be called, but if the YAML_FILE has not changed
# this is essentially a no-op, and should not cause re-compilation.
#---------------------------------------------------------------------------------------------------
function(PODIO_GENERATE_DATAMODEL datamodel YAML_FILE RETURN_HEADERS RETURN_SOURCES)
CMAKE_PARSE_ARGUMENTS(ARG "" "OLD_DESCRIPTION;OUTPUT_FOLDER;UPSTREAM_EDM;SCHEMA_EVOLUTION" "IO_BACKEND_HANDLERS" ${ARGN})
CMAKE_PARSE_ARGUMENTS(ARG "" "OLD_DESCRIPTION;OUTPUT_FOLDER;UPSTREAM_EDM;SCHEMA_EVOLUTION" "IO_BACKEND_HANDLERS;LANG" ${ARGN})
IF(NOT ARG_OUTPUT_FOLDER)
SET(ARG_OUTPUT_FOLDER ${CMAKE_CURRENT_SOURCE_DIR})
ENDIF()
Expand All @@ -153,6 +155,13 @@ function(PODIO_GENERATE_DATAMODEL datamodel YAML_FILE RETURN_HEADERS RETURN_SOUR
SET(ARG_IO_BACKEND_HANDLERS "ROOT")
ENDIF()

# Check if the LANG argument is specified and set the language accordingly.
IF(ARG_LANG)
SET(LANGUAGE_ARG "-l=${ARG_LANG}")
ELSE()
SET(LANGUAGE_ARG "-l=cpp") # Default to C++
ENDIF()

SET(SCHEMA_EVOLUTION_ARG "")
IF (ARG_SCHEMA_EVOLUTION)
SET(SCHEMA_EVOLUTION_ARG "--evolution_file=${ARG_SCHEMA_EVOLUTION}")
Expand Down Expand Up @@ -201,7 +210,7 @@ function(PODIO_GENERATE_DATAMODEL datamodel YAML_FILE RETURN_HEADERS RETURN_SOUR
message(STATUS "Creating '${datamodel}' datamodel")
# we need to boostrap the data model, so this has to be executed in the cmake run
execute_process(
COMMAND ${Python_EXECUTABLE} ${podio_PYTHON_DIR}/podio_class_generator.py ${CLANG_FORMAT_ARG} ${OLD_DESCRIPTION_ARG} ${SCHEMA_EVOLUTION_ARG} ${UPSTREAM_EDM_ARG} ${YAML_FILE} ${ARG_OUTPUT_FOLDER} ${datamodel} ${ARG_IO_BACKEND_HANDLERS}
COMMAND ${Python_EXECUTABLE} ${podio_PYTHON_DIR}/podio_class_generator.py ${CLANG_FORMAT_ARG} ${OLD_DESCRIPTION_ARG} ${SCHEMA_EVOLUTION_ARG} ${UPSTREAM_EDM_ARG} ${YAML_FILE} ${ARG_OUTPUT_FOLDER} ${datamodel} ${ARG_IO_BACKEND_HANDLERS} ${LANGUAGE_ARG}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
RESULT_VARIABLE podio_generate_command_retval
)
Expand Down
1 change: 1 addition & 0 deletions python/podio/test_MemberParser.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ def test_parse_invalid(self):
try:
self.assertRaises(DefinitionError, parser.parse, inp)
except AssertionError:
# pylint: disable-next=raise-missing-from
raise AssertionError(f"'{inp}' should raise a DefinitionError from the MemberParser")

def test_parse_valid_no_description(self):
Expand Down
56 changes: 35 additions & 21 deletions python/podio_class_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,12 @@ class IncludeFrom(IntEnum):
class ClassGenerator:
"""The entry point for reading a datamodel definition and generating the
necessary source code from it."""
def __init__(self, yamlfile, install_dir, package_name, io_handlers, verbose, dryrun,
def __init__(self, yamlfile, install_dir, package_name, io_handlers, proglang, verbose, dryrun,
upstream_edm, old_description, evolution_file):
self.install_dir = install_dir
self.package_name = package_name
self.io_handlers = io_handlers
self.proglang = proglang
self.verbose = verbose
self.dryrun = dryrun
self.yamlfile = yamlfile
Expand Down Expand Up @@ -130,15 +131,18 @@ def process(self):
for name, datatype in self.datamodel.datatypes.items():
datamodel['datatypes'].append(self._process_datatype(name, datatype))

self._write_edm_def_file()
self._process_parent_module(datamodel)
if self.proglang == "julia":
self._process_parent_module(datamodel)

if 'ROOT' in self.io_handlers:
self._create_selection_xml()
if self.proglang == "cpp":
self._write_edm_def_file()

self._write_cmake_lists_file()
self.process_schema_evolution()
if 'ROOT' in self.io_handlers:
self._create_selection_xml()

self._write_cmake_lists_file()

self.process_schema_evolution()
self.print_report()

def process_schema_evolution(self):
Expand Down Expand Up @@ -264,23 +268,30 @@ def _process_component(self, name, component):
component['includes_jl'] = {'struct': sorted(includes_jl)}
component['class'] = DataType(name)

self._fill_templates('Component', component)
self._fill_templates('MutableStruct', component)
if self.proglang == "cpp":
self._fill_templates('Component', component)
if self.proglang == "julia":
self._fill_templates('MutableStruct', component)

return component

def _process_datatype(self, name, definition):
"""Process one datatype"""
datatype = self._preprocess_datatype(name, definition)
self._fill_templates('Data', datatype)
self._fill_templates('Object', datatype)
self._fill_templates('MutableObject', datatype)
self._fill_templates('Obj', datatype)
self._fill_templates('Collection', datatype)
self._fill_templates('CollectionData', datatype)
self._fill_templates('MutableStruct', datatype)

if 'SIO' in self.io_handlers:
self._fill_templates('SIOBlock', datatype)
if self.proglang == "julia":
self._fill_templates('MutableStruct', datatype)

if self.proglang == "cpp":
self._fill_templates('Data', datatype)
self._fill_templates('Object', datatype)
self._fill_templates('MutableObject', datatype)
self._fill_templates('Obj', datatype)
self._fill_templates('Collection', datatype)
self._fill_templates('CollectionData', datatype)

if 'SIO' in self.io_handlers:
self._fill_templates('SIOBlock', datatype)

return datatype

Expand Down Expand Up @@ -608,15 +619,18 @@ def read_upstream_edm(name_path):
import argparse
# pylint: disable=invalid-name # before 2.5.0 pylint is too strict with the naming here
parser = argparse.ArgumentParser(description='Given a description yaml file this script generates '
'the necessary c++ files in the target directory')
'the necessary c++ or julia files in the target directory')

parser.add_argument('description', help='yaml file describing the datamodel')
parser.add_argument('targetdir', help='Target directory where the generated data classes will be put. '
'Header files will be put under <targetdir>/<packagename>/*.h. '
'Source files will be put under <targetdir>/src/*.cc')
'Source files will be put under <targetdir>/src/*.cc. '
'Julia files will be put under <targetdir>/<packagename>/*.jl.')
parser.add_argument('packagename', help='Name of the package.')
parser.add_argument('iohandlers', choices=['ROOT', 'SIO'], nargs='+',
help='The IO backend specific code that should be generated')
parser.add_argument('-l', '--lang', choices=['cpp', 'julia'], default='cpp',
help='Specify the programming language (default: cpp)')
parser.add_argument('-q', '--quiet', dest='verbose', action='store_false', default=True,
help='Don\'t write a report to screen')
parser.add_argument('-d', '--dryrun', action='store_true', default=False,
Expand Down Expand Up @@ -644,7 +658,7 @@ def read_upstream_edm(name_path):
if not os.path.exists(directory):
os.makedirs(directory)

gen = ClassGenerator(args.description, args.targetdir, args.packagename, args.iohandlers,
gen = ClassGenerator(args.description, args.targetdir, args.packagename, args.iohandlers, proglang=args.lang,
verbose=args.verbose, dryrun=args.dryrun, upstream_edm=args.upstream_edm,
old_description=args.old_description, evolution_file=args.evolution_file)
if args.clangformat:
Expand Down
2 changes: 2 additions & 0 deletions python/templates/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,6 @@ set(PODIO_TEMPLATES

${CMAKE_CURRENT_LIST_DIR}/MutableStruct.jl.jinja2
${CMAKE_CURRENT_LIST_DIR}/ParentModule.jl.jinja2
${CMAKE_CURRENT_LIST_DIR}/macros/abstracttypes.jinja2
${CMAKE_CURRENT_LIST_DIR}/macros/params.jinja2
)
49 changes: 0 additions & 49 deletions python/templates/Constructor.jl.jinja2

This file was deleted.

5 changes: 0 additions & 5 deletions python/templates/JuliaCollection.jl.jinja2

This file was deleted.

13 changes: 11 additions & 2 deletions python/templates/ParentModule.jl.jinja2
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{% import "macros/params.jinja2" as params %}
{% import "macros/abstracttypes.jinja2" as abstdatatype %}
module {{ class.bare_type }}
{% for component in components %}
export {{ component['class'].bare_type }}
Expand All @@ -21,7 +22,7 @@ function {{ component['class'].bare_type }}(
{% if member.is_array %}
{{ member.name }}::{{ member.julia_type }} = {{ member.julia_type }}(undef),
{% elif member.is_builtin %}
{{ member.name }}::{{ member.julia_type }} = {{ member.julia_type }}(0),
{{ member.name }}::{{ abstdatatype.classify_data_type(member.julia_type) }} = {{ member.julia_type }}(0),
{% else %}
{{ member.name }}::{{ member.julia_type }}Struct = {{ member.julia_type }}(),
{% endif %}
Expand All @@ -42,7 +43,11 @@ function {{ component['class'].bare_type }}(
)
return {{ component['class'].bare_type }}Struct{{ params.julia_parameters(component['params_jl'], "", "Struct") }}(
{% for member in component['Members'] %}
{% if member.is_builtin %}
{{ member.julia_type }}({{ member.name }}),
{% else %}
{{ member.name }},
{% endif %}
{% endfor %}
{% for relation in component['OneToManyRelations'] %}
{{ relation.name }},
Expand All @@ -64,7 +69,7 @@ function {{ datatype['class'].bare_type }}(
{% if member.is_array %}
{{ member.name }}::{{ member.julia_type }} = {{ member.julia_type }}(undef),
{% elif member.is_builtin %}
{{ member.name }}::{{ member.julia_type }} = {{ member.julia_type }}(0),
{{ member.name }}::{{ abstdatatype.classify_data_type(member.julia_type) }} = {{ member.julia_type }}(0),
{% else %}
{{ member.name }}::{{ member.julia_type }}Struct = {{ member.julia_type }}(),
{% endif %}
Expand All @@ -85,7 +90,11 @@ function {{ datatype['class'].bare_type }}(
)
return {{ datatype['class'].bare_type }}Struct{{ params.julia_parameters(datatype['params_jl'], "", "Struct") }}(
{% for member in datatype['Members'] %}
{% if member.is_builtin %}
{{ member.julia_type }}({{ member.name }}),
{% else %}
{{ member.name }},
{% endif %}
{% endfor %}
{% for relation in datatype['OneToManyRelations'] %}
{{ relation.name }},
Expand Down
17 changes: 17 additions & 0 deletions python/templates/macros/abstracttypes.jinja2
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{% macro classify_data_type(data_type) %}
{%- set type_map = {
'Int8': 'Integer',
'UInt8': 'Integer',
'Int16': 'Integer',
'UInt16': 'Integer',
'Int32': 'Integer',
'UInt32': 'Integer',
'Int64': 'Integer',
'UInt64': 'Integer',
'Float16': 'Real',
'Float32': 'Real',
'Float64': 'Real'
} -%}

{{ type_map.get(data_type, data_type) }}
{%- endmacro -%}
14 changes: 14 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,20 @@ add_subdirectory(dumpmodel)
CREATE_PODIO_TEST(ostream_operator.cpp "")
CREATE_PODIO_TEST(write_ascii.cpp "")

PODIO_GENERATE_DATAMODEL(datamodeljulia datalayout.yaml headers sources
IO_BACKEND_HANDLERS ${PODIO_IO_HANDLERS}
OLD_DESCRIPTION datalayout_old.yaml
SCHEMA_EVOLUTION schema_evolution.yaml
LANG julia
)

PODIO_GENERATE_DATAMODEL(extensionmodeljulia datalayout_extension.yaml ext_headers ext_sources
UPSTREAM_EDM datamodel:datalayout.yaml
IO_BACKEND_HANDLERS ${PODIO_IO_HANDLERS}
OUTPUT_FOLDER ${CMAKE_CURRENT_SOURCE_DIR}/extension_model
LANG julia
)

# Customize CTest to potentially disable some of the tests with known problems
configure_file(CTestCustom.cmake ${PROJECT_BINARY_DIR}/CTestCustom.cmake @ONLY)
find_program(Julia_EXECUTABLE julia)
Expand Down
4 changes: 2 additions & 2 deletions tests/unittest.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
include("datamodel/Datamodel.jl")
using .Datamodel
include("datamodeljulia/Datamodeljulia.jl")
using .Datamodeljulia
using Test
@testset "Julia Bindings" begin
@testset "Relations" begin
Expand Down

0 comments on commit 7a4eafe

Please sign in to comment.