Skip to content

Commit

Permalink
Fixed pylint issue and documentation + Added tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Ananya2003Gupta committed Oct 3, 2023
1 parent 508154f commit cd44b51
Show file tree
Hide file tree
Showing 9 changed files with 47 additions and 44 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ The generation script has the following additional options:
- `--clangformat` (`-c`): Apply clang-format after file creation (uses [option `-style=file`](https://clang.llvm.org/docs/ClangFormatStyleOptions.html) with llvm as backup style), needs clang-format in `$PATH`.
- `--quiet` (`-q`): Suppress all print out to STDOUT
- `--dryrun` (`-d`): Only run the generation logic and validate yaml, do not write files to disk
- `--lang` (`-l`): Specify the programming language (default: cpp), choices: cpp, julia

## Running tests
After compilation you can run rudimentary tests with
Expand Down
23 changes: 17 additions & 6 deletions doc/templates.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,8 @@ They are broadly split along the classes that are generated for each datatype or
| `CollectionData.{h,cc}.jinja2` | The classes managing the collection storage (not user facing!) | `[<package>/]<datatype-name>CollectionData.h`, `src/<datatype-name>CollectionData.cc` |
| `selection.xml.jinja2` | The `selection.xml` file that is necessary for generating a root dictionary for the generated datamodel | `src/selection.xml` |
| `SIOBlock.{h,cc}.jinja2` | The SIO blocks that are necessary for the SIO backend | `[<package>/]<datatype-name>SIOBlock.h`, `src/<datatype-name>SIOBlock.cc` |
| `MutableStruct.jl.jinja2` | The Structs define components and datatypes for julia |`[<package>/]<datatype-name>Struct.jl`, `[<package>/]<component-name>Struct.jl` |
| `Constructor.jl.jinja2` | Initializes components and datatypes for julia |`[<package>/]<datatype-name>.jl`, `[<package>/]<component-name>.jl` |
| `JuliaCollection.jl.jinja2` | Vectorizes components and datatypes for julia |`[<package>/]<datatype-name>Collection.jl` |
| `ParentModule.jl.jinja2` | The top level namespace with collected children |`[<package>/]<datatype-name>Collection.jl` |
| `MutableStruct.jl.jinja2` | The mutable struct definitions of components and datatypes for julia |`[<package>/]<datatype-name>Struct.jl`, `[<package>/]<component-name>Struct.jl` |
| `ParentModule.jl.jinja2` | The constructor and collection definitions of components and datatypes in the data model are contained within a single module named after the package-name |`[<package>/]<package-name>.jl` |


The presence of a `[<package>]` subdirectory for the header files is controlled by the `includeSubfolder` option in the yaml definition file.
Expand All @@ -60,7 +58,7 @@ The main entry point to the generation is the `process` method which essentially
The following gives an overview of the information that is available from the dictionary that is passed to the templates from the `ClassGenerator`.
Each (top level) key in this dict is directly available as a variable in the Jinja2 templates, e.g.
```python
component['include'] = # list of includes
component['includes'] = # list of includes
```
will become available as
```jinja2
Expand Down Expand Up @@ -143,4 +141,17 @@ The available fields are
| `full_type` | The fully qualified type, corresponding to `{{ namespace }}::{{ bare_type }}`. |

### Julia code generation
Julia code generation was done as a part of Google Summer of Code [*documented here*](https://hepsoftwarefoundation.org/gsoc/blogs/2022/blog_PODIO_SoumilBaldota.html) in detail.
Builtin types mapping in Julia
| cpp | julia |
|-------------|--------------------------------------------------------------------------------|
| `bool` | `Bool` |
| `char` | `Char` |
| `short` | `Int16` |
| `int` | `Int32` |
| `unsigned int` | `UInt32` |
| `float` | `Float32` |
| `double` | `Float64` |
| `long` | `Int64` |
| `unsigned long` | `UInt64` |
| `long long` | `Int64` |
| `unsigned long long` | `UInt64` |
4 changes: 2 additions & 2 deletions python/podio/generator_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ def _prefix_name(name, prefix):
def get_julia_type(cpp_type=None, is_array=False, array_type=None, array_size=None):
"""Parse the given c++ type to a Julia type"""
builtin_types_map = {"int": "Int32", "float": "Float32", "double": "Float64",
"bool": "Bool", "long": "Int32", "unsigned int": "UInt32",
"unsigned long": "UInt32", "char": "Char", "short": "Int16",
"bool": "Bool", "long": "Int64", "unsigned int": "UInt32",
"unsigned long": "UInt64", "char": "Char", "short": "Int16",
"long long": "Int64", "unsigned long long": "UInt64"}
# is a global type as described in test_MemberParser.py #L121
if cpp_type and cpp_type.startswith("::"):
Expand Down
4 changes: 2 additions & 2 deletions python/podio/test_MemberParser.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,12 +249,12 @@ def test_parse_valid_no_description(self):
self.assertEqual(parsed.name, 'unDescribedArray')
self.assertEqual(parsed.array_type, 'unsigned long')
self.assertTrue(parsed.is_builtin_array)
self.assertEqual(parsed.julia_type, r'MVector{123, UInt32}')
self.assertEqual(parsed.julia_type, r'MVector{123, UInt64}')

parsed = parser.parse('unsigned long longWithReallyStupidName', False)
self.assertEqual(parsed.full_type, 'unsigned long')
self.assertEqual(parsed.name, 'longWithReallyStupidName')
self.assertEqual(parsed.julia_type, r'UInt32')
self.assertEqual(parsed.julia_type, r'UInt64')

parsed = parser.parse('NonBuiltIn aType // descriptions are not ignored even though they are not required', False)
self.assertEqual(parsed.full_type, 'NonBuiltIn')
Expand Down
7 changes: 5 additions & 2 deletions python/podio_class_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
Read instructions in the README.md to run your first example!
"""
REPORT_TEXT_JULIA = """
Warning: ExtraCode and MutableExtraCode will be ignored during julia code generation.
PODIO Data Model
================
Used {yamlfile} to create {nclasses} julia files in {installdir}/
Expand Down Expand Up @@ -86,6 +87,7 @@ class IncludeFrom(IntEnum):
class ClassGenerator:
"""The entry point for reading a datamodel definition and generating the
necessary source code from it."""
# pylint: disable=too-many-arguments
def __init__(self, yamlfile, install_dir, package_name, io_handlers, proglang, verbose, dryrun,
upstream_edm, old_description, evolution_file):
self.install_dir = install_dir
Expand Down Expand Up @@ -292,6 +294,7 @@ def _process_component(self, name, component):
"""Process one component"""
# Make a copy here and add the preprocessing steps to that such that the
# original definition can be left untouched
# pylint: disable=too-many-nested-blocks
component = deepcopy(component)
includes, includes_jl = set(), set()
includes.update(*(m.includes for m in component['Members']))
Expand All @@ -316,7 +319,6 @@ def _process_component(self, name, component):

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

# Add potentially older schema for schema evolution
# based on ROOT capabilities for now
if name in self.root_schema_dict:
Expand Down Expand Up @@ -697,7 +699,8 @@ def _build_julia_include(self, member) -> str:
"""Return the include statement for julia"""
return self._build_julia_include_for_class(member.bare_type, self._needs_include(member.full_type))

def _build_julia_include_for_class(self, classname, include_from: IncludeFrom) -> str:
@staticmethod
def _build_julia_include_for_class(classname, include_from: IncludeFrom) -> str:
"""Return the include statement for julia for this specific class"""
if include_from == IncludeFrom.INTERNAL:
# If we have an internal include all includes should be relative
Expand Down
2 changes: 1 addition & 1 deletion python/templates/ParentModule.jl.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -167,4 +167,4 @@ end
{{ datatype['class'].bare_type }}Collection = Vector{ {{ datatype['class'].bare_type }}Struct{{ params.julia_parameters(datatype['params_jl'], "Struct", upstream_edm, upstream_edm_name) }} }

{% endfor %}
end
end
4 changes: 2 additions & 2 deletions python/templates/macros/abstracttypes.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@
'Float32': 'Real',
'Float64': 'Real'
} -%}

{{ type_map.get(data_type, data_type) }}
{%- endmacro -%}
{%- endmacro -%}
2 changes: 1 addition & 1 deletion python/templates/macros/params.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@
{%- endif %}
{%- endfor -%}
}{%- endif -%}
{%- endmacro -%}
{%- endmacro -%}
44 changes: 16 additions & 28 deletions tests/unittest.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
include("datamodeljulia/Datamodeljulia.jl")
# datamodeljulia/Datamodeljulia.jl file included inside extension_model/extensionmodeljulia/Extensionmodeljulia.jl file
include("extension_model/extensionmodeljulia/Extensionmodeljulia.jl")
using .Datamodeljulia
using .Extensionmodeljulia
using Test
@testset "Julia Bindings" begin
@testset "Relations" begin
Expand Down Expand Up @@ -90,36 +92,22 @@ using Test
@test mc3.parents[1] == mc1
end

@testset "Namespaces" begin
@testset "Upstream EDM" begin
# Upstream EDM : Datamodeljulia
s1 = NamespaceStruct(1, 2)
s2 = SimpleStruct(1, 2, 3)
s3 = NotSoSimpleStruct(s2)

s1 = NamespaceStruct()
s1.x = Int32(1)
s1.y = Int32(2)

s2 = NamespaceInNamespaceStruct()
s2.data = s1

s3 = NamespaceStruct()
s3.x = Int32(2)
s3.y = Int32(3)

ex1 = ExampleWithNamespace()
ex1.component = s3

ex3 = ExampleWithARelation()
ex3.number = Float32(5.55)
push!(ex3.refs, ex1)
ex3.ref = ex1
# Extensionmodeljulia
ec1 = ExtComponent(s3, s1)

@test s1.x == Int32(1)
@test s1.y == Int32(2)
@test s2.data.x == Int32(1)
@test s2.data.y == Int32(2)
@test ex1.component.x == Int32(2)
@test ex1.component.y == Int32(3)
@test ex3.number == Float32(5.55)
@test ex3.refs[1] === ex1
@test ex3.ref.component.x == Int32(2)
@test ex3.ref.component.y == Int32(3)
@test s3.data.x == Int32(1)
@test s3.data.y == Int32(2)
@test ec1.nspStruct.x == Int32(1)
@test ec1.nspStruct.y == Int32(2)
@test ec1.aStruct.data.x == Int32(1)
@test ec1.aStruct.data.y == Int32(2)
end
end;

0 comments on commit cd44b51

Please sign in to comment.