10 - Plug-in structure: |
10 - Plug-in structure: |
11 - Reader class |
11 - Reader class |
12 - Implementation class |
12 - Implementation class |
13 - Implementation model |
13 - Implementation model |
14 - Using ``cone.public.utils`` for ConfML setting reference handling |
14 - Using ``cone.public.utils`` for ConfML setting reference handling |
|
15 - Providing XML schema validation and model-level validation |
15 - Unit tests: |
16 - Unit tests: |
16 - Testing the reader class, the implementation class and the model classes separately |
17 - Testing the reader class, the implementation class and the model classes separately |
17 - Output generation testing (plug-in scope integration test) |
18 - Output generation testing (plug-in scope integration test) |
|
19 - Validation testing |
18 |
20 |
19 The ExampleML language |
21 The ExampleML language |
20 ---------------------- |
22 ---------------------- |
21 |
23 |
22 The Implementation Markup Language in the example plug-in is ExampleML. The language |
24 The Implementation Markup Language in the example plug-in is ExampleML. The language |
53 - ``plugins/`` - Root directory for all ConE plug-in sources |
55 - ``plugins/`` - Root directory for all ConE plug-in sources |
54 - ``example/`` - Example plug-in package directory |
56 - ``example/`` - Example plug-in package directory |
55 - ``ConeExamplePlugin/`` - Source for the example plug-in |
57 - ``ConeExamplePlugin/`` - Source for the example plug-in |
56 - ``examplemlplugin/`` - Module directory containing all plug-in code |
58 - ``examplemlplugin/`` - Module directory containing all plug-in code |
57 - ``tests/`` - Unit tests and test data for the plug-in |
59 - ``tests/`` - Unit tests and test data for the plug-in |
58 - ``project/`` - Configuration project used in the tests |
60 - ``testdata/`` - Directory containing all test data needed by the test cases |
59 - ``gen_expected/`` - Expected output for generation test case |
|
60 - ``__init__.py`` - Test module initialization file |
61 - ``__init__.py`` - Test module initialization file |
61 - ``runtests.py`` - Script for running all test cases |
62 - ``runtests.py`` - Script for running all test cases |
62 - ``unittest_exampleml_impl.py`` - File containing test cases |
63 - ``unittest_exampleml_impl.py`` - File containing test cases |
63 - ``unittest_exampleml_reader.py`` - File containing test cases |
64 - ``unittest_exampleml_reader.py`` - File containing test cases |
64 - ``unittest_exampleml_generation.py`` - File containing test cases |
65 - ``unittest_exampleml_generation.py`` - File containing test cases |
|
66 - ``unittest_exampleml_validation.py`` - File containing test cases |
|
67 - ``xsd/`` - XML Schema files for schema validation |
|
68 - ``exampleml.xsd`` - Schema file for schema validation |
65 - ``__init__.py`` - Plug-in module initialization file |
69 - ``__init__.py`` - Plug-in module initialization file |
66 - ``exampleml_impl.py`` - Plug-in source file |
70 - ``exampleml_impl.py`` - Plug-in source file |
67 - ``exampleml_reader.py`` - Plug-in source file |
71 - ``exampleml_reader.py`` - Plug-in source file |
|
72 - ``exampleml_validators.py`` - Plug-in source file |
68 - ``setup.py`` - Setup script for packaging the plug-in into an .egg file |
73 - ``setup.py`` - Setup script for packaging the plug-in into an .egg file |
69 - ``setup.cfg`` - Configuration file for ``setup.py`` |
74 - ``setup.cfg`` - Configuration file for ``setup.py`` |
70 - ``integration-test/`` - Integration tests for the example plug-in package |
75 - ``integration-test/`` - Integration tests for the example plug-in package |
71 - ``testdata/`` - Test data for the integration tests |
76 - ``testdata/`` - Test data for the integration tests |
72 - ``__init__.py`` - Test module initialization file |
77 - ``__init__.py`` - Test module initialization file |
81 |
86 |
82 - *Implementation model*, represents the logical model of the implementation specified in the XML data |
87 - *Implementation model*, represents the logical model of the implementation specified in the XML data |
83 - *Implementation class*, works as the interface of the plug-in towards ConE and uses the model to do the actual work |
88 - *Implementation class*, works as the interface of the plug-in towards ConE and uses the model to do the actual work |
84 - *Implementation reader*, converts the XML data into the logical model and creates a new implementation class instance |
89 - *Implementation reader*, converts the XML data into the logical model and creates a new implementation class instance |
85 |
90 |
86 In this case the *model* consists just of the class Output, which corresponds to the ``<output>`` element. |
91 Here the *model* consists just of the class Output, which corresponds to the ``<output>`` element. |
|
92 |
|
93 In addition to these, there is a collection of *validator classes* that are |
|
94 responsible for handling model-level validation. |
87 |
95 |
88 Plug-in code |
96 Plug-in code |
89 ------------ |
97 ------------ |
90 |
98 |
91 exampleml_model.py |
99 exampleml_model.py |
133 own method. Again, this is to make unit testing easier. |
141 own method. Again, this is to make unit testing easier. |
134 |
142 |
135 .. literalinclude:: /../source/plugins/example/ConeExamplePlugin/examplemlplugin/exampleml_reader.py |
143 .. literalinclude:: /../source/plugins/example/ConeExamplePlugin/examplemlplugin/exampleml_reader.py |
136 :linenos: |
144 :linenos: |
137 |
145 |
|
146 Note that the reader class provides the XML schema by overriding |
|
147 ``get_schema_data()``. If this method was not overridden, a default schema |
|
148 that accepts (almost) anything would be used for schema validation. |
|
149 |
|
150 |
|
151 exampleml_validators.py |
|
152 ................... |
|
153 |
|
154 This file defines all validator classes. Since ExampleML is so simple, there |
|
155 are only two cases that need to be validated on the model level: setting |
|
156 references and the encoding. Notice that the setting reference validator |
|
157 uses the method ``check_feature_reference()`` inherited from ``ImplValidatorBase``. |
|
158 As there are utility functions for handling references in a uniform way, there |
|
159 is also a utility function for validating them. |
|
160 |
|
161 Note also the class list VALIDATOR_CLASSES at the bottom, which contains both |
|
162 of the validator classes. The file ``setup.py`` contains an entry point |
|
163 definition that points to this list, and the validation framework finds the |
|
164 validators via that. |
|
165 |
|
166 .. literalinclude:: /../source/plugins/example/ConeExamplePlugin/examplemlplugin/exampleml_validators.py |
|
167 :linenos: |
138 |
168 |
139 Unit tests |
169 Unit tests |
140 ---------- |
170 ---------- |
141 |
171 |
142 Due to the dynamic nature of Python, an extensive set of unit tests is required for every plug-in. |
172 Due to the dynamic nature of Python, an extensive set of unit tests is required for every plug-in. |
202 the workding copy. |
232 the workding copy. |
203 |
233 |
204 .. literalinclude:: /../source/plugins/example/ConeExamplePlugin/examplemlplugin/tests/unittest_exampleml_generation.py |
234 .. literalinclude:: /../source/plugins/example/ConeExamplePlugin/examplemlplugin/tests/unittest_exampleml_generation.py |
205 :linenos: |
235 :linenos: |
206 |
236 |
|
237 unittest_exampleml_validation.py |
|
238 ................................ |
|
239 |
|
240 Like ``unittest_exampleml_generation.py`` test output generation, this file |
|
241 tests validation. The test cases themselves are pretty simple, since there are |
|
242 pre-existing helper methods for running the tests, and the tests mainly consist |
|
243 of test data and expected. |
|
244 |
|
245 .. literalinclude:: /../source/plugins/example/ConeExamplePlugin/examplemlplugin/tests/unittest_exampleml_validation.py |
|
246 :linenos: |
|
247 |
|
248 |
207 Plug-in packaging |
249 Plug-in packaging |
208 ----------------- |
250 ----------------- |
209 |
251 |
210 The file ``setup.py`` handles the packaging of the plug-in into an egg file. |
252 The file ``setup.py`` handles the packaging of the plug-in into an egg file. |
211 |
253 |
212 The most important thing here is the plug-in's entry point info. The |
254 The most important thing here is the plug-in's entry point info. The |
213 plug-in's reader classes must be specified as entry points, or they won't be |
255 plug-in's reader and validator classes must be specified as entry points, |
214 loaded. |
256 or they won't be loaded. |
215 |
257 |
216 .. literalinclude:: /../source/plugins/example/ConeExamplePlugin/setup.py |
258 .. literalinclude:: /../source/plugins/example/ConeExamplePlugin/setup.py |
217 :linenos: |
259 :linenos: |
218 |
260 |
219 |
261 |
266 .................... |
308 .................... |
267 |
309 |
268 This file contains tests for generating output using the example plug-in. |
310 This file contains tests for generating output using the example plug-in. |
269 Note the following things: |
311 Note the following things: |
270 |
312 |
271 - The use of the variable ``CONE_CMD`` in ``get_cmd()``. This variable is set to |
313 - The check if ``CONE_CMD`` is in the environment variables in ``get_cmd()``. |
272 contain the actual ConE command to run if the tests are being run from the |
314 This variable is set to contain the actual ConE command to run if the tests |
273 exported standalone test set. In practice this will be something like |
315 are being run from the exported standalone test set. In practice this will be |
274 ``C:/cone_test/cone/cone.cmd``. |
316 something like ``C:/cone_test/cone/cone.cmd``. |
275 - The actual generation and testing is done in a separate function, ``run_test_generate()``, |
317 - The actual generation and testing is done in a separate function, ``_run_test_generate()``, |
276 and there are two actual test functions that call it. One runs the test directly on the |
318 and there are two actual test functions that call it. One runs the test directly on the |
277 test project on the file system, and another first zips the test project and then runs |
319 test project on the file system, and another first zips the test project and then runs |
278 the test on that. It is a good idea to test that generation works the same in both cases, |
320 the test on that. It is a good idea to test that generation works the same in both cases, |
279 since it can be easy to forget to take into account generation from a ZIP file when creating |
321 since it can be easy to forget to take into account generation from a ZIP file when creating |
280 a plug-in (e.g. using ``shutil`` functions to perform copy operations when the ConE API |
322 a plug-in (e.g. using ``shutil`` functions to perform copy operations when the ConE API |