io_developers_guide.rst 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. .. _io_dev_guide:
  2. ********************
  3. IO developers' guide
  4. ********************
  5. .. _io_guiline:
  6. Guidelines for IO implementation
  7. ================================
  8. There are two ways to add a new IO module:
  9. * By directly adding a new IO class in a module within :mod:`neo.io`: the reader/writer will deal directly with Neo objects
  10. * By adding a RawIO class in a module within :mod:`neo.rawio`: the reader should work with raw buffers from the file and provide
  11. some internal headers for the scale/units/name/...
  12. You can then generate an IO module simply by inheriting from your RawIO class and from :class:`neo.io.BaseFromRaw`
  13. For read only classes, we encourage you to write a :class:`RawIO` class because it allows slice reading,
  14. and is generally much quicker and easier (although only for reading) than implementing a full IO class.
  15. For read/write classes you can mix the two levels neo.rawio for reading and neo.io for writing.
  16. Recipe to develop an IO module for a new data format:
  17. 1. Fully understand the object model. See :doc:`core`. If in doubt ask the `mailing list`_.
  18. 2. Fully understand :mod:`neo.io.examplerawio`, It is a fake IO to explain the API. If in doubt ask the list.
  19. 3. Copy/paste ``examplerawio.py`` and choose clear file and class names for your IO.
  20. 4. implement all methods that **raise(NotImplementedError)** in :mod:`neo.rawio.baserawio`. Return None when the object is not supported (spike/waveform)
  21. 5. Write good docstrings. List dependencies, including minimum version numbers.
  22. 6. Add your class to :mod:`neo.rawio.__init__`. Keep imports inside ``try/except`` for dependency reasons.
  23. 7. Create a class in :file:`neo/io/`
  24. 8. Add your class to :mod:`neo.io.__init__`. Keep imports inside ``try/except`` for dependency reasons.
  25. 9. Create an account at https://gin.g-node.org and deposit files in :file:`NeuralEnsemble/ephy_testing_data`.
  26. 10. Write tests in :file:`neo/rawio/test_xxxxxrawio.py`. You must at least pass the standard tests (inherited from :class:`BaseTestRawIO`). See :file:`test_examplerawio.py`
  27. 11. Write a similar test in :file:`neo.tests/iotests/test_xxxxxio.py`. See :file:`test_exampleio.py`
  28. 12. Make a pull request when all tests pass.
  29. Miscellaneous
  30. =============
  31. * If your IO supports several versions of a format (like ABF1, ABF2), upload to the gin.g-node.org test file repository all file versions possible. (for test coverage).
  32. * :py:func:`neo.core.Block.create_many_to_one_relationship` offers a utility to complete the hierachy when all one-to-many relationships have been created.
  33. * In the docstring, explain where you obtained the file format specification if it is a closed one.
  34. * If your IO is based on a database mapper, keep in mind that the returned object MUST be detached,
  35. because this object can be written to another url for copying.
  36. Tests
  37. =====
  38. :py:class:`neo.rawio.tests.common_rawio_test.BaseTestRawIO` and :py:class:`neo.test.io.commun_io_test.BaseTestIO` provide standard tests.
  39. To use these you need to upload some sample data files at `gin-gnode`_. They will be publicly accessible for testing Neo.
  40. These tests:
  41. * check the compliance with the schema: hierachy, attribute types, ...
  42. * For IO modules able to both write and read data, it compares a generated dataset with the same data after a write/read cycle.
  43. The test scripts download all files from `gin-gnode`_ and stores them locally in ``/tmp/files_for_tests/``.
  44. Subsequent test runs use the previously downloaded files, rather than trying to download them each time.
  45. Each test must have at least one class that inherits ``BaseTestRawIO`` and that has 3 attributes:
  46. * ``rawioclass``: the class
  47. * ``entities_to_test``: a list of files (or directories) to be tested one by one
  48. * ``files_to_download``: a list of files to download (sometimes bigger than ``entities_to_test``)
  49. Here is an example test script taken from the distribution: :file:`test_axonrawio.py`:
  50. .. literalinclude:: ../../neo/rawio/tests/test_axonrawio.py
  51. Logging
  52. =======
  53. All IO classes by default have logging using the standard :mod:`logging` module: already set up.
  54. The logger name is the same as the fully qualified class name, e.g. :class:`neo.io.hdf5io.NeoHdf5IO`.
  55. The :attr:`class.logger` attribute holds the logger for easy access.
  56. There are generally 3 types of situations in which an IO class should use a logger
  57. * Recoverable errors with the file that the users need to be notified about.
  58. In this case, please use :meth:`logger.warning` or :meth:`logger.error`.
  59. If there is an exception associated with the issue, you can use :meth:`logger.exception` in the exception handler to automatically include a backtrace with the log.
  60. By default, all users will see messages at this level, so please restrict it only to problems the user absolutely needs to know about.
  61. * Informational messages that advanced users might want to see in order to get some insight into the file.
  62. In this case, please use :meth:`logger.info`.
  63. * Messages useful to developers to fix problems with the io class.
  64. In this case, please use :meth:`logger.debug`.
  65. A log handler is automatically added to :mod:`neo`, so please do not user your own handler.
  66. Please use the :attr:`class.logger` attribute for accessing the logger inside the class rather than :meth:`logging.getLogger`.
  67. Please do not log directly to the root logger (e.g. :meth:`logging.warning`), use the class's logger instead (:meth:`class.logger.warning`).
  68. In the tests for the io class, if you intentionally test broken files, please disable logs by setting the logging level to `100`.
  69. ExampleIO
  70. =========
  71. .. autoclass:: neo.rawio.ExampleRawIO
  72. .. autoclass:: neo.io.ExampleIO
  73. Here is the entire file:
  74. .. literalinclude:: ../../neo/rawio/examplerawio.py
  75. .. literalinclude:: ../../neo/io/exampleio.py
  76. .. _`mailing list`: http://groups.google.com/group/neuralensemble
  77. .. _gin-gnode: https://web.gin.g-node.org/NeuralEnsemble/ephy_testing_data