data_pipeline_api 0.6.0__tar.gz → 0.7.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (181) hide show
  1. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/.travis.yml +3 -1
  2. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/PKG-INFO +1 -1
  3. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/README.md +4 -0
  4. data_pipeline_api-0.7.0/data_pipeline_api/data_processing_api.py +14 -0
  5. data_pipeline_api-0.7.0/data_pipeline_api/file_api.py +318 -0
  6. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/data_pipeline_api/file_formats/object_file.py +22 -15
  7. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/data_pipeline_api/file_formats/parameter_file.py +8 -2
  8. data_pipeline_api-0.7.0/data_pipeline_api/git_info.py +56 -0
  9. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/data_pipeline_api/metadata.py +1 -0
  10. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/data_pipeline_api/metadata_store.py +15 -12
  11. data_pipeline_api-0.7.0/data_pipeline_api/registry/README.md +166 -0
  12. data_pipeline_api-0.7.0/data_pipeline_api/registry/__init__.py +1 -0
  13. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/data_pipeline_api/registry/access_upload.py +71 -55
  14. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/data_pipeline_api/registry/common.py +124 -83
  15. data_pipeline_api-0.7.0/data_pipeline_api/registry/download.py +133 -0
  16. data_pipeline_api-0.7.0/data_pipeline_api/registry/downloader.py +407 -0
  17. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/data_pipeline_api/registry/upload.py +64 -3
  18. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/data_pipeline_api/registry/upload_data_product.py +17 -11
  19. data_pipeline_api-0.7.0/data_pipeline_api/registry/utils.py +22 -0
  20. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/data_pipeline_api/standard_api.py +14 -9
  21. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/data_pipeline_api.egg-info/PKG-INFO +1 -1
  22. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/data_pipeline_api.egg-info/SOURCES.txt +62 -1
  23. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/data_pipeline_api.egg-info/entry_points.txt +1 -2
  24. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/data_pipeline_api.egg-info/requires.txt +1 -0
  25. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/environment.yml +1 -0
  26. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/examples/standard_api_usage.py +6 -14
  27. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/build.gradle +13 -1
  28. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/main/java/uk/ramp/api/FileApi.java +22 -6
  29. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/main/java/uk/ramp/metadata/MetadataItem.java +58 -13
  30. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/main/java/uk/ramp/overrides/OverridesApplier.java +4 -2
  31. data_pipeline_api-0.7.0/java_api/standard_api/build.gradle +68 -0
  32. data_pipeline_api-0.7.0/java_api/standard_api/src/main/java/uk/ramp/api/StandardApi.java +130 -0
  33. data_pipeline_api-0.7.0/java_api/standard_api/src/main/java/uk/ramp/distribution/Distribution.java +149 -0
  34. data_pipeline_api-0.7.0/java_api/standard_api/src/main/java/uk/ramp/distribution/MinMax.java +39 -0
  35. data_pipeline_api-0.7.0/java_api/standard_api/src/main/java/uk/ramp/distribution/MinMaxDeserializer.java +59 -0
  36. data_pipeline_api-0.7.0/java_api/standard_api/src/main/java/uk/ramp/distribution/MinMaxSerializer.java +23 -0
  37. data_pipeline_api-0.7.0/java_api/standard_api/src/main/java/uk/ramp/estimate/Estimate.java +38 -0
  38. data_pipeline_api-0.7.0/java_api/standard_api/src/main/java/uk/ramp/objects/NumericalArray.java +13 -0
  39. data_pipeline_api-0.7.0/java_api/standard_api/src/main/java/uk/ramp/objects/NumericalArrayImpl.java +34 -0
  40. data_pipeline_api-0.7.0/java_api/standard_api/src/main/java/uk/ramp/objects/StandardArrayDataReader.java +7 -0
  41. data_pipeline_api-0.7.0/java_api/standard_api/src/main/java/uk/ramp/objects/StandardTable.java +3 -0
  42. data_pipeline_api-0.7.0/java_api/standard_api/src/main/java/uk/ramp/objects/StandardTableDataReader.java +7 -0
  43. data_pipeline_api-0.7.0/java_api/standard_api/src/main/java/uk/ramp/parameters/Component.java +3 -0
  44. data_pipeline_api-0.7.0/java_api/standard_api/src/main/java/uk/ramp/parameters/Components.java +13 -0
  45. data_pipeline_api-0.7.0/java_api/standard_api/src/main/java/uk/ramp/parameters/ComponentsDeserializer.java +59 -0
  46. data_pipeline_api-0.7.0/java_api/standard_api/src/main/java/uk/ramp/parameters/ComponentsSerializer.java +45 -0
  47. data_pipeline_api-0.7.0/java_api/standard_api/src/main/java/uk/ramp/parameters/ParameterDataReader.java +8 -0
  48. data_pipeline_api-0.7.0/java_api/standard_api/src/main/java/uk/ramp/parameters/ParameterDataReaderImpl.java +24 -0
  49. data_pipeline_api-0.7.0/java_api/standard_api/src/main/java/uk/ramp/parameters/ParameterDataWriter.java +8 -0
  50. data_pipeline_api-0.7.0/java_api/standard_api/src/main/java/uk/ramp/parameters/ParameterDataWriterImpl.java +29 -0
  51. data_pipeline_api-0.7.0/java_api/standard_api/src/main/java/uk/ramp/parameters/ReadComponent.java +12 -0
  52. data_pipeline_api-0.7.0/java_api/standard_api/src/main/java/uk/ramp/parameters/WriteComponent.java +3 -0
  53. data_pipeline_api-0.7.0/java_api/standard_api/src/main/java/uk/ramp/samples/Sampler.java +20 -0
  54. data_pipeline_api-0.7.0/java_api/standard_api/src/main/java/uk/ramp/samples/Samples.java +44 -0
  55. data_pipeline_api-0.7.0/java_api/standard_api/src/main/java/uk/ramp/toml/TOMLFactory.java +11 -0
  56. data_pipeline_api-0.7.0/java_api/standard_api/src/main/java/uk/ramp/toml/TOMLInputDecorator.java +45 -0
  57. data_pipeline_api-0.7.0/java_api/standard_api/src/main/java/uk/ramp/toml/TOMLMapper.java +13 -0
  58. data_pipeline_api-0.7.0/java_api/standard_api/src/main/java/uk/ramp/toml/TOMLOutputDecorator.java +55 -0
  59. data_pipeline_api-0.7.0/java_api/standard_api/src/main/java/uk/ramp/toml/TomlReader.java +22 -0
  60. data_pipeline_api-0.7.0/java_api/standard_api/src/main/java/uk/ramp/toml/TomlWriter.java +21 -0
  61. data_pipeline_api-0.7.0/java_api/standard_api/src/test/java/uk/ramp/api/StandardApiIntegrationTest.java +239 -0
  62. data_pipeline_api-0.7.0/java_api/standard_api/src/test/java/uk/ramp/api/StandardApiTest.java +143 -0
  63. data_pipeline_api-0.7.0/java_api/standard_api/src/test/java/uk/ramp/distribution/DistributionTest.java +110 -0
  64. data_pipeline_api-0.7.0/java_api/standard_api/src/test/java/uk/ramp/estimate/EstimateTest.java +27 -0
  65. data_pipeline_api-0.7.0/java_api/standard_api/src/test/java/uk/ramp/parameters/ComponentsDeserializerTest.java +75 -0
  66. data_pipeline_api-0.7.0/java_api/standard_api/src/test/java/uk/ramp/parameters/ComponentsSerializerTest.java +75 -0
  67. data_pipeline_api-0.7.0/java_api/standard_api/src/test/java/uk/ramp/parameters/ParameterDataReaderTest.java +43 -0
  68. data_pipeline_api-0.7.0/java_api/standard_api/src/test/java/uk/ramp/parameters/ParameterDataWriterImplTest.java +40 -0
  69. data_pipeline_api-0.7.0/java_api/standard_api/src/test/java/uk/ramp/samples/SamplerTest.java +27 -0
  70. data_pipeline_api-0.7.0/java_api/standard_api/src/test/java/uk/ramp/samples/SamplesTest.java +49 -0
  71. data_pipeline_api-0.7.0/java_api/standard_api/src/test/java/uk/ramp/toml/TomlReaderPairwiseIntegrationTest.java +27 -0
  72. data_pipeline_api-0.7.0/java_api/standard_api/src/test/java/uk/ramp/toml/TomlWriterPairwiseIntegrationTest.java +68 -0
  73. data_pipeline_api-0.7.0/java_api/standard_api/src/test/resources/config.yaml +59 -0
  74. data_pipeline_api-0.7.0/java_api/standard_api/src/test/resources/folder/data/expectedDistribution.toml +5 -0
  75. data_pipeline_api-0.7.0/java_api/standard_api/src/test/resources/folder/data/expectedDistributionCategorical.toml +5 -0
  76. data_pipeline_api-0.7.0/java_api/standard_api/src/test/resources/folder/data/expectedEstimate.toml +3 -0
  77. data_pipeline_api-0.7.0/java_api/standard_api/src/test/resources/folder/data/expectedSamples.toml +3 -0
  78. data_pipeline_api-0.7.0/java_api/standard_api/src/test/resources/folder/data/expectedSamplesMultiple.toml +6 -0
  79. data_pipeline_api-0.7.0/java_api/standard_api/src/test/resources/folder/data/metadata.yaml +35 -0
  80. data_pipeline_api-0.7.0/java_api/standard_api/src/test/resources/folder/data/object/example5.h5 +4 -0
  81. data_pipeline_api-0.7.0/java_api/standard_api/src/test/resources/folder/data/parameter/example1.toml +19 -0
  82. data_pipeline_api-0.7.0/java_api/standard_api/src/test/resources/location.txt +1 -0
  83. data_pipeline_api-0.7.0/java_api/standard_api/src/test/resources/table.csv +4 -0
  84. data_pipeline_api-0.7.0/java_api/standard_api/src/test/resources/table.h5 +0 -0
  85. data_pipeline_api-0.7.0/jitpack.yml +2 -0
  86. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/scripts/convert_access_to_config.py +3 -0
  87. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/setup.py +2 -3
  88. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/tests/data/object/example.h5 +0 -0
  89. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/tests/file_formats/test_object_file.py +10 -1
  90. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/tests/file_formats/test_parameter_file.py +14 -2
  91. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/tests/registry/test_access_upload.py +2 -12
  92. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/tests/registry/test_common.py +128 -25
  93. data_pipeline_api-0.7.0/tests/registry/test_download.py +59 -0
  94. data_pipeline_api-0.7.0/tests/registry/test_downloader.py +581 -0
  95. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/tests/registry/test_upload.py +85 -17
  96. data_pipeline_api-0.7.0/tests/registry/test_utils.py +25 -0
  97. data_pipeline_api-0.7.0/tests/test_data_processing_api.py +21 -0
  98. data_pipeline_api-0.7.0/tests/test_file_api.py +263 -0
  99. data_pipeline_api-0.7.0/tests/test_git_info.py +40 -0
  100. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/tests/test_metadata_store.py +4 -0
  101. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/tests/test_standard_api.py +42 -32
  102. data_pipeline_api-0.6.0/data_pipeline_api/file_api.py +0 -267
  103. data_pipeline_api-0.6.0/data_pipeline_api/registry/README.md +0 -98
  104. data_pipeline_api-0.6.0/data_pipeline_api/registry/download.py +0 -353
  105. data_pipeline_api-0.6.0/java_api/standard_api/build.gradle +0 -14
  106. data_pipeline_api-0.6.0/java_api/standard_api/src/main/java/uk/ramp/api/StandardApi.java +0 -5
  107. data_pipeline_api-0.6.0/tests/registry/__init__.py +0 -0
  108. data_pipeline_api-0.6.0/tests/registry/test_download.py +0 -204
  109. data_pipeline_api-0.6.0/tests/test_file_api.py +0 -126
  110. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/.gitignore +0 -0
  111. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/.pylintrc +0 -0
  112. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/LICENSE +0 -0
  113. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/conda/meta.yaml +0 -0
  114. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/contributing.md +0 -0
  115. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/data_pipeline_api/__init__.py +0 -0
  116. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/data_pipeline_api/overrides.py +0 -0
  117. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/data_pipeline_api/registry/templates/data_product.yaml +0 -0
  118. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/data_pipeline_api.egg-info/dependency_links.txt +0 -0
  119. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/data_pipeline_api.egg-info/top_level.txt +0 -0
  120. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/examples/example_configs/simple_network_sim_config.yaml +0 -0
  121. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/examples/example_configs/simple_network_sim_upload.yaml +0 -0
  122. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/build.gradle +0 -0
  123. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/main/java/uk/ramp/access/AccessEntry.java +0 -0
  124. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/main/java/uk/ramp/access/AccessLog.java +0 -0
  125. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/main/java/uk/ramp/access/AccessLogWriter.java +0 -0
  126. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/main/java/uk/ramp/access/AccessLogger.java +0 -0
  127. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/main/java/uk/ramp/access/AccessLoggerFactory.java +0 -0
  128. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/main/java/uk/ramp/access/AccessLoggerImpl.java +0 -0
  129. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/main/java/uk/ramp/access/NoImplAccessLogger.java +0 -0
  130. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/main/java/uk/ramp/config/Config.java +0 -0
  131. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/main/java/uk/ramp/config/ConfigFactory.java +0 -0
  132. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/main/java/uk/ramp/config/ConfigReader.java +0 -0
  133. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/main/java/uk/ramp/file/CleanableFileChannel.java +0 -0
  134. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/main/java/uk/ramp/file/FileDirectoryNormaliser.java +0 -0
  135. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/main/java/uk/ramp/file/FileReader.java +0 -0
  136. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/main/java/uk/ramp/hash/HashMetadataAppender.java +0 -0
  137. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/main/java/uk/ramp/hash/Hasher.java +0 -0
  138. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/main/java/uk/ramp/hash/Sha1Hasher.java +0 -0
  139. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/main/java/uk/ramp/metadata/IssueItem.java +0 -0
  140. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/main/java/uk/ramp/metadata/MatchingMetadataSelector.java +0 -0
  141. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/main/java/uk/ramp/metadata/MetaDataReader.java +0 -0
  142. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/main/java/uk/ramp/metadata/MetadataFactory.java +0 -0
  143. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/main/java/uk/ramp/metadata/MetadataSelector.java +0 -0
  144. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/main/java/uk/ramp/metadata/ReadOnlyRunMetadata.java +0 -0
  145. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/main/java/uk/ramp/metadata/RunMetadata.java +0 -0
  146. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/main/java/uk/ramp/metadata/WriteOnlyRunMetadata.java +0 -0
  147. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/main/java/uk/ramp/yaml/BaseYamlReader.java +0 -0
  148. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/main/java/uk/ramp/yaml/BaseYamlWriter.java +0 -0
  149. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/main/java/uk/ramp/yaml/YamlFactory.java +0 -0
  150. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/main/java/uk/ramp/yaml/YamlReader.java +0 -0
  151. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/main/java/uk/ramp/yaml/YamlWriter.java +0 -0
  152. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/test/java/uk/ramp/access/AccessLoggerTest.java +0 -0
  153. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/test/java/uk/ramp/api/FileApiIntegrationTest.java +0 -0
  154. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/test/java/uk/ramp/file/CleanableFileChannelIntegrationTest.java +0 -0
  155. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/test/java/uk/ramp/file/FileDirectoryNormaliserTest.java +0 -0
  156. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/test/java/uk/ramp/hash/HashMetadataAppenderTest.java +0 -0
  157. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/test/java/uk/ramp/hash/Sha1HasherTest.java +0 -0
  158. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/test/java/uk/ramp/metadata/MatchingMetadataSelectorTest.java +0 -0
  159. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/test/java/uk/ramp/metadata/MetadataItemTest.java +0 -0
  160. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/test/java/uk/ramp/metadata/MetadataItemVersionComparisonTest.java +0 -0
  161. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/test/java/uk/ramp/yaml/BaseYamlWriterTest.java +0 -0
  162. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/test/resources/config.yaml +0 -0
  163. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/test/resources/folder/data/metadata.yaml +0 -0
  164. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/file_api/src/test/resources/folder/data/parameter/example1.toml +0 -0
  165. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/gradle/wrapper/gradle-wrapper.jar +0 -0
  166. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/gradle/wrapper/gradle-wrapper.properties +0 -0
  167. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/gradlew +0 -0
  168. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/gradlew.bat +0 -0
  169. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/java_api/settings.gradle +0 -0
  170. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/scripts/release.sh +0 -0
  171. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/setup.cfg +0 -0
  172. {data_pipeline_api-0.6.0/data_pipeline_api/registry → data_pipeline_api-0.7.0/tests}/__init__.py +0 -0
  173. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/tests/conftest.py +0 -0
  174. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/tests/data/config.yaml +0 -0
  175. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/tests/data/demographics.h5 +0 -0
  176. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/tests/data/metadata.yaml +0 -0
  177. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/tests/data/object/example-v2.h5 +0 -0
  178. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/tests/data/parameter/example-v2.toml +0 -0
  179. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/tests/data/parameter/example.toml +0 -0
  180. {data_pipeline_api-0.6.0/tests → data_pipeline_api-0.7.0/tests/registry}/__init__.py +0 -0
  181. {data_pipeline_api-0.6.0 → data_pipeline_api-0.7.0}/tests/test_overrides.py +0 -0
@@ -58,5 +58,7 @@ matrix:
58
58
  jdk: openjdk11
59
59
  language: java
60
60
  script: "./gradlew build"
61
- after_success: "./gradlew publish"
61
+ after_success:
62
+ - bash <(curl -s https://codecov.io/bash)
63
+ - ./gradlew publish
62
64
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 1.0
2
2
  Name: data_pipeline_api
3
- Version: 0.6.0
3
+ Version: 0.7.0
4
4
  Summary: Interacts with SCRC data pipeline
5
5
  Home-page: UNKNOWN
6
6
  Author: SCRC
@@ -53,6 +53,10 @@ cd data_pipeline_api
53
53
  git tag --sort=v:refname
54
54
  ```
55
55
 
56
+ ## Data Registry Interactions
57
+
58
+ See [registry README](data_pipeline_api/registry/README.md).
59
+
56
60
  ## Releasing a new version
57
61
 
58
62
  New versions can be released from the master branch at any time. Whenever a git
@@ -0,0 +1,14 @@
1
+ from io import IOBase
2
+ from data_pipeline_api.standard_api import StandardAPI
3
+
4
+
5
+ class DataProcessingAPI(StandardAPI):
6
+ """The DataProcessingAPI extends the StandardAPI with access to external objects.
7
+ """
8
+
9
+ def read_external_object(self, doi_or_unique_name: str, component: str) -> IOBase:
10
+ """Return an open file handle to read the given external object.
11
+ """
12
+ return self.file_api.open_for_read(
13
+ doi_or_unique_name=doi_or_unique_name, component=component
14
+ )
@@ -0,0 +1,318 @@
1
+ from io import IOBase
2
+ from uuid import uuid4
3
+ from datetime import datetime
4
+ from pathlib import Path
5
+ from typing import Union, Optional, Any, Iterable, Dict, List
6
+ from dataclasses import dataclass
7
+ from hashlib import sha1
8
+ from logging import getLogger, WARNING, DEBUG
9
+ import yaml
10
+
11
+ from data_pipeline_api.metadata import Metadata, MetadataKey, log_format_metadata
12
+ from data_pipeline_api.metadata_store import MetadataStore
13
+ from data_pipeline_api.overrides import Overrides
14
+
15
+ logger = getLogger(__name__)
16
+
17
+
18
+ @dataclass(frozen=True)
19
+ class FileAccess:
20
+ """Represents a generic file access.
21
+ """
22
+
23
+ timestamp: datetime
24
+ call_metadata: Metadata
25
+ access_metadata: Metadata
26
+ path: Path
27
+
28
+ def to_access_log_record(
29
+ self, hash_cache: Optional[Dict[Path, str]] = None
30
+ ) -> Dict[str, Any]:
31
+ if hash_cache is None:
32
+ hash_cache = {}
33
+ access_metadata = self.access_metadata.copy()
34
+ if MetadataKey.calculated_hash not in access_metadata:
35
+ absolute_path = self.path.resolve()
36
+ try:
37
+ access_metadata[MetadataKey.calculated_hash] = hash_cache[absolute_path]
38
+ except KeyError:
39
+ access_metadata[MetadataKey.calculated_hash] = hash_cache[
40
+ absolute_path
41
+ ] = FileAPI.calculate_hash(absolute_path)
42
+ return {
43
+ "timestamp": self.timestamp,
44
+ "call_metadata": self.call_metadata,
45
+ "access_metadata": access_metadata,
46
+ }
47
+
48
+
49
+ class ReadAccess(FileAccess):
50
+ """Represents a file read.
51
+ """
52
+
53
+ def to_access_log_record(
54
+ self, hash_cache: Optional[Dict[Path, str]] = None
55
+ ) -> Dict[str, Any]:
56
+ return dict(type="read", **super().to_access_log_record(hash_cache))
57
+
58
+
59
+ @dataclass(frozen=True)
60
+ class WriteAccess(FileAccess):
61
+ """Represents a file write.
62
+ """
63
+
64
+ file_handle: IOBase
65
+
66
+ def to_access_log_record(
67
+ self, hash_cache: Optional[Dict[Path, str]] = None
68
+ ) -> Dict[str, Any]:
69
+ if not self.file_handle.closed:
70
+ logger.warning(
71
+ "the file handle to write to %s is still open, attempting to flush",
72
+ self.path,
73
+ )
74
+ self.file_handle.flush()
75
+ return dict(type="write", **super().to_access_log_record(hash_cache))
76
+
77
+
78
+ class FileAPI:
79
+ RESERVED_RUN_METADATA_KEYS = {
80
+ "run_id",
81
+ "open_timestamp",
82
+ "close_timestamp",
83
+ "data_directory",
84
+ }
85
+
86
+ @staticmethod
87
+ def normalise_path(root: Path, path: Path) -> Path:
88
+ """Normalise a path by prepending a known root if it is not absolute.
89
+ """
90
+ return path if path.is_absolute() else root / path
91
+
92
+ @staticmethod
93
+ def calculate_hash(filename: Path, extra_bytes: Optional[bytes] = None) -> str:
94
+ """Calculate the SHA1 hash of a file, optionally appending extra bytes.
95
+ """
96
+ with open(filename, "rb") as file:
97
+ message = sha1(file.read())
98
+ if extra_bytes:
99
+ message.update(extra_bytes)
100
+ hexdigest = message.hexdigest()
101
+ logger.debug(
102
+ "calculated hash of %s as %s", filename, hexdigest,
103
+ )
104
+ return hexdigest
105
+
106
+ @staticmethod
107
+ def construct_overrides(overrides: Iterable[Dict[str, Dict[str, Any]]]):
108
+ """Construct an Overrides given the structure found in the FileAPI config.
109
+ """
110
+ return Overrides(
111
+ (override.get("where", {}), override.get("use", {}))
112
+ for override in overrides
113
+ )
114
+
115
+ @staticmethod
116
+ def construct_metadata_store(metadata_filename: Path) -> MetadataStore:
117
+ """Construct a MetadataStore corresponding to a file.
118
+ """
119
+ metadata_store = None
120
+ if metadata_filename.exists():
121
+ logger.debug("loading metadata from %s", metadata_filename)
122
+ with open(metadata_filename) as metadata_store_file:
123
+ metadata_store = yaml.safe_load(metadata_store_file)
124
+ else:
125
+ logger.warning("could not find metadata.yaml")
126
+ return MetadataStore(metadata_store)
127
+
128
+ def __init__(self, config_filename: Optional[Union[Path, str]] = None):
129
+ """The FileAPI class provides tracked interaction with the filesystem.
130
+
131
+ Files are located through a metadata lookup system based on two files: a
132
+ metadata database file, which lists all known files and their associated
133
+ metadata, and a configuration file, which provides mechanisms for influencing
134
+ the metadata lookup process.
135
+ """
136
+ self._accesses: List[FileAccess] = []
137
+ self._run_metadata = {}
138
+
139
+ self._open_timestamp = datetime.now()
140
+ self._run_metadata["open_timestamp"] = self._open_timestamp
141
+ logger.debug("open_timestamp = %s", self._open_timestamp)
142
+
143
+ if config_filename is None:
144
+ self._config_filename = None
145
+ self._config = {}
146
+ self._root = Path()
147
+ else:
148
+ self._config_filename = Path(config_filename)
149
+ with open(self._config_filename) as config_file:
150
+ self._config = yaml.safe_load(config_file)
151
+ self._root = self._config_filename.parent
152
+ logger.debug("config_filename = %s", self._config_filename)
153
+ logger.debug("root = %s", self._root.resolve())
154
+
155
+ self._run_id = self._config.get("run_id", uuid4().hex)
156
+ self._run_metadata["run_id"] = self._run_id
157
+ logger.debug("run_id = %s", self._run_id)
158
+
159
+ self._fail_on_hash_mismatch = self._config.get("fail_on_hash_mismatch", True)
160
+ logger.log(
161
+ DEBUG if self._fail_on_hash_mismatch else WARNING,
162
+ "fail_on_hash_mismatch = %s",
163
+ self._fail_on_hash_mismatch,
164
+ )
165
+
166
+ data_directory = self._config.get("data_directory", self._root)
167
+ self._unnormalised_data_directory = Path(data_directory)
168
+ self._run_metadata["data_directory"] = str(self._unnormalised_data_directory)
169
+ self._data_directory = FileAPI.normalise_path(
170
+ self._root, self._unnormalised_data_directory
171
+ )
172
+ logger.debug("data_directory = %s", self._data_directory)
173
+
174
+ access_log = self._config.get("access_log", "access-{run_id}.yaml")
175
+ if access_log is False:
176
+ self._access_log_path = None
177
+ logger.warning("disabled access log")
178
+ else:
179
+ self._access_log_path = FileAPI.normalise_path(
180
+ self._root, Path(access_log.format(run_id=self._run_id)),
181
+ )
182
+ logger.debug("access_log_path = %s", self._access_log_path)
183
+
184
+ self._run_metadata.update(self._config.get("metadata", {}))
185
+ self._read_overrides = FileAPI.construct_overrides(self._config.get("read", ()))
186
+ self._write_overrides = FileAPI.construct_overrides(
187
+ self._config.get("write", ())
188
+ )
189
+
190
+ self.load_metadata_store()
191
+
192
+ def load_metadata_store(self):
193
+ metadata_store_filename = self._data_directory / "metadata.yaml"
194
+ logger.debug("loading metadata store from %s", metadata_store_filename)
195
+ self._metadata_store = FileAPI.construct_metadata_store(metadata_store_filename)
196
+
197
+ def get_read_metadata(self, metadata: Metadata) -> Metadata:
198
+ read_metadata = metadata.copy()
199
+ self._read_overrides.apply(read_metadata)
200
+ return self._metadata_store.find(read_metadata) or read_metadata
201
+
202
+ def open_for_read(self, **call_metadata) -> IOBase:
203
+ """Return a file open for reading corresponding to the given metadata.
204
+
205
+ The file contents are hashed, and a record is made of the read.
206
+ """
207
+ logger.debug("starting open_for_read(%s)", log_format_metadata(call_metadata))
208
+ read_metadata = self.get_read_metadata(call_metadata)
209
+ path = self._data_directory / read_metadata[MetadataKey.filename]
210
+ read_metadata[MetadataKey.calculated_hash] = FileAPI.calculate_hash(path)
211
+
212
+ if self._fail_on_hash_mismatch:
213
+ if (
214
+ read_metadata[MetadataKey.calculated_hash]
215
+ == read_metadata[MetadataKey.verified_hash]
216
+ ):
217
+ logger.debug("verified hash")
218
+ raise ValueError(
219
+ (
220
+ "calculated hash {calculated_hash} != "
221
+ "verified hash {verified_hash}"
222
+ ).format(**read_metadata)
223
+ )
224
+
225
+ logger.debug("open('%s', mode='rb')", path)
226
+ file = open(path, mode="rb")
227
+ self._accesses.append(
228
+ ReadAccess(
229
+ timestamp=datetime.now(),
230
+ call_metadata=call_metadata,
231
+ access_metadata=read_metadata,
232
+ path=path,
233
+ )
234
+ )
235
+ logger.info("recorded read(%s)", log_format_metadata(call_metadata))
236
+ return file
237
+
238
+ def get_write_metadata(self, metadata: Metadata) -> Metadata:
239
+ write_metadata = metadata.copy()
240
+ self._write_overrides.apply(write_metadata)
241
+ if MetadataKey.filename not in write_metadata:
242
+ write_metadata[MetadataKey.filename] = str(
243
+ Path(write_metadata[MetadataKey.data_product])
244
+ / "{}.{}".format(self._run_id, write_metadata[MetadataKey.extension])
245
+ )
246
+ logger.debug("generated filename %s", write_metadata[MetadataKey.filename])
247
+ return write_metadata
248
+
249
+ def open_for_write(self, **call_metadata) -> IOBase:
250
+ """Return a file open for update corresponding to the given metadata.
251
+
252
+ When the file is closed the file contents are hashed, and a record is made of
253
+ the write.
254
+ """
255
+ logger.debug("starting open_for_write(%s)", log_format_metadata(call_metadata))
256
+ write_metadata = self.get_write_metadata(call_metadata)
257
+
258
+ path = self._data_directory / write_metadata[MetadataKey.filename]
259
+ if path.exists():
260
+ mode = "r+b"
261
+ else:
262
+ path.parent.mkdir(parents=True, exist_ok=True)
263
+ mode = "w+b"
264
+ logger.debug("open('%s', mode='%s')", path, mode)
265
+ file = open(path, mode=mode)
266
+ self._accesses.append(
267
+ WriteAccess(
268
+ timestamp=datetime.now(),
269
+ call_metadata=call_metadata,
270
+ access_metadata=write_metadata,
271
+ path=path,
272
+ file_handle=file,
273
+ )
274
+ )
275
+ logger.info("recorded write(%s)", log_format_metadata(call_metadata))
276
+ return file
277
+
278
+ def set_run_metadata(self, key: str, value: Any):
279
+ """Set run-level metadata.
280
+ """
281
+ if key in FileAPI.RESERVED_RUN_METADATA_KEYS:
282
+ raise ValueError(f"{key} is reserved")
283
+ self._run_metadata[key] = value
284
+
285
+ def get_run_metadata(self, key: str) -> Any:
286
+ """Get run-level metadata.
287
+ """
288
+ return self._run_metadata[key]
289
+
290
+ def _generate_access_log(self) -> Dict[str, Any]:
291
+ calculated_path_hashes = {}
292
+ return {
293
+ "run_metadata": dict(close_timestamp=datetime.now(), **self._run_metadata),
294
+ "config": self._config,
295
+ "io": [
296
+ access.to_access_log_record(calculated_path_hashes)
297
+ for access in self._accesses
298
+ ],
299
+ }
300
+
301
+ def close(self):
302
+ """Close the session and write the access log.
303
+ """
304
+ if self._access_log_path:
305
+ with open(self._access_log_path, "w") as output_file:
306
+ yaml.dump(
307
+ self._generate_access_log(), output_file, sort_keys=False,
308
+ )
309
+ logger.info("wrote access log")
310
+ else:
311
+ logger.warning("did not write access log")
312
+
313
+ def __enter__(self):
314
+ return self
315
+
316
+ def __exit__(self, exc_type, exc_value, traceback):
317
+ if exc_type is None:
318
+ self.close()
@@ -77,16 +77,15 @@ def write_table(file: IOBase, component: str, table: Table):
77
77
  index=False,
78
78
  column_dtypes={
79
79
  column: (
80
- table[column].values.astype(np.string_).dtype
81
- if dtype == "O"
82
- else dtype
80
+ table[column].values.astype(np.string_).dtype if dtype == "O" else dtype
83
81
  )
84
82
  for column, dtype in table.dtypes.items()
85
83
  },
86
84
  )
87
- get_write_group(file, component).require_dataset(
88
- "table", shape=records.shape, dtype=records.dtype, data=records
89
- )
85
+ group = get_write_group(file, component)
86
+ for dataset in group:
87
+ del group[dataset]
88
+ group.create_dataset("table", data=records, track_times=False)
90
89
 
91
90
 
92
91
  DIMENSION_PREFIX = "Dimension_"
@@ -172,42 +171,50 @@ def read_array(file: IOBase, component: str) -> Array:
172
171
  def write_array(file: IOBase, component: str, array: Array):
173
172
  # TODO : More validation on the inputs?
174
173
  group = get_write_group(file, component)
175
- group.require_dataset(
176
- "array", shape=array.data.shape, dtype=array.data.dtype, data=array.data
177
- )
174
+ for dataset in group:
175
+ del group[dataset]
176
+ group.create_dataset("array", data=array.data, track_times=False)
178
177
  if array.dimensions is not None:
179
178
  for i, dimension in enumerate(array.dimensions, start=1):
180
179
  if dimension.title is not None:
181
- group.require_dataset(
180
+ group.create_dataset(
182
181
  f"Dimension_{i}_title",
183
182
  dtype=h5py.string_dtype(),
184
183
  shape=(),
185
184
  data=dimension.title,
185
+ track_times=False,
186
186
  )
187
187
  if dimension.names is not None:
188
188
  encoded_names = np.char.encode(dimension.names)
189
- group.require_dataset(
189
+ group.create_dataset(
190
190
  f"Dimension_{i}_names",
191
191
  dtype=h5py.string_dtype(),
192
192
  shape=encoded_names.shape,
193
193
  data=encoded_names,
194
+ track_times=False,
194
195
  )
195
196
  if dimension.values is not None:
196
197
  values = np.array(dimension.values)
197
- group.require_dataset(
198
+ group.create_dataset(
198
199
  f"Dimension_{i}_values",
199
200
  dtype=values.dtype,
200
201
  shape=values.shape,
201
202
  data=values,
203
+ track_times=False,
202
204
  )
203
205
  if dimension.units is not None:
204
- group.require_dataset(
206
+ group.create_dataset(
205
207
  f"Dimension_{i}_units",
206
208
  dtype=h5py.string_dtype(),
207
209
  shape=(),
208
210
  data=dimension.units,
211
+ track_times=False,
209
212
  )
210
213
  if array.units is not None:
211
- group.require_dataset(
212
- "units", dtype=h5py.string_dtype(), shape=(), data=array.units,
214
+ group.create_dataset(
215
+ "units",
216
+ dtype=h5py.string_dtype(),
217
+ shape=(),
218
+ data=array.units,
219
+ track_times=False,
213
220
  )
@@ -79,7 +79,8 @@ def read_distribution(file: TextIOBase, component: str) -> Distribution:
79
79
  raise ValueError(f"{parameter['type']} != 'distribution'")
80
80
 
81
81
 
82
- def write_distribution(file: TextIOBase, component: str, distribution: Distribution):
82
+ def encode_distribution(distribution: Distribution) -> Dict[str, Any]:
83
+ """Encode distribution into a serialisable format."""
83
84
  shape, loc, scale = distribution.dist._parse_args(
84
85
  *distribution.args, **distribution.kwds
85
86
  )
@@ -93,8 +94,13 @@ def write_distribution(file: TextIOBase, component: str, distribution: Distribut
93
94
  parameter["shape"] = shape[0]
94
95
  if scale:
95
96
  parameter["scale"] = scale
97
+ return parameter
98
+
99
+
100
+ def write_distribution(file: TextIOBase, component: str, distribution: Distribution):
101
+ """Write distribution to file under component."""
96
102
  write_parameter(
97
- file, component, parameter,
103
+ file, component, encode_distribution(distribution),
98
104
  )
99
105
 
100
106
 
@@ -0,0 +1,56 @@
1
+ from typing import NamedTuple, Optional
2
+ from pathlib import Path
3
+ try:
4
+ from git import Repo, InvalidGitRepositoryError # type: ignore
5
+ git_installed = True
6
+ except ImportError:
7
+ Repo = None
8
+ InvalidGitRepositoryError = None
9
+ git_installed = False
10
+
11
+
12
+ class RepoInfo(NamedTuple):
13
+ """
14
+ The info needed by the data pipeline API
15
+ """
16
+
17
+ git_sha: str
18
+ uri: str
19
+ is_dirty: bool
20
+
21
+
22
+ def get_repo(path: Optional[Path] = None) -> Repo:
23
+ """Attempt to get a repo from path, or the working directory.
24
+ """
25
+ if Repo is None:
26
+ raise ImportError("Could not import git")
27
+ else:
28
+ return Repo(path=path, search_parent_directories=True)
29
+
30
+
31
+ def get_repo_info(path: Optional[Path] = None, default_repo: str = "") -> RepoInfo:
32
+ """Get the git sha and uri for path, or the working directory.
33
+
34
+ :path: A path to use to start looking for the root of the repo.
35
+ :default_repo: A default repo url to use if we cannot obtain one.
36
+ :return: A RepoInfo object. If not inside a git repo, is_dirty will be True, git_sha empty and uri will be a
37
+ default value
38
+ """
39
+ try:
40
+ repo = get_repo(path)
41
+ return RepoInfo(
42
+ git_sha=repo.head.commit.hexsha,
43
+ uri=next(repo.remote("origin").urls),
44
+ is_dirty=repo.is_dirty(),
45
+ )
46
+ except (ImportError, InvalidGitRepositoryError):
47
+ return RepoInfo(git_sha="", uri=default_repo, is_dirty=True)
48
+
49
+
50
+ def get_path_relative_to_repo(path: Path) -> Path:
51
+ """Get path relative to the repo which contains it, or raise an exception.
52
+ """
53
+ result = get_repo(path).git.execute(['git', 'ls-files', '--full-name', str(path)])
54
+ if result:
55
+ return Path(result)
56
+ raise ValueError(f"Could not get {path} relative to repo")
@@ -19,6 +19,7 @@ class MetadataKey:
19
19
  verified_hash = "verified_hash"
20
20
  calculated_hash = "calculated_hash"
21
21
  accessibility = "accessibility"
22
+ doi_or_unique_name = "doi_or_unique_name"
22
23
 
23
24
 
24
25
  def value_matches(value_a: Any, value_b: Any) -> bool:
@@ -20,24 +20,27 @@ class MetadataRecord(NamedTuple):
20
20
 
21
21
 
22
22
  class MetadataStore:
23
- def __init__(self, metadata_sequence: Sequence[Metadata]):
23
+ def __init__(self, metadata_sequence: Optional[Sequence[Metadata]] = None):
24
24
  """The MetadataStore class provides a simple metadata lookup mechanism.
25
25
 
26
26
  A MetadataStore is initialised with a Sequence of Metadata objects, which can
27
27
  then be searched by matching against Metadata fragments.
28
28
  """
29
- try:
30
- self._metadata_records = tuple(
31
- MetadataRecord(
32
- metadata=metadata,
33
- version=VersionInfo.parse(metadata[MetadataKey.version])
34
- if MetadataKey.version in metadata
35
- else None,
29
+ if metadata_sequence is None:
30
+ self._metadata_records = ()
31
+ else:
32
+ try:
33
+ self._metadata_records = tuple(
34
+ MetadataRecord(
35
+ metadata=metadata,
36
+ version=VersionInfo.parse(metadata[MetadataKey.version])
37
+ if MetadataKey.version in metadata
38
+ else None,
39
+ )
40
+ for metadata in metadata_sequence
36
41
  )
37
- for metadata in metadata_sequence
38
- )
39
- except Exception as exception:
40
- raise ValueError("invalid metadata") from exception
42
+ except Exception as exception:
43
+ raise ValueError("invalid metadata") from exception
41
44
 
42
45
  def find(self, metadata: Metadata) -> Optional[Metadata]:
43
46
  try: