py-cmdtabs 1.2.0__tar.gz → 1.2.1__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 (211) hide show
  1. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/PKG-INFO +1 -1
  2. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/setup.cfg +2 -0
  3. py_cmdtabs-1.2.1/src/py_cmdtabs/__init__.py +16 -0
  4. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/src/py_cmdtabs/cli_manager.py +136 -13
  5. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/src/py_cmdtabs/cmdtabs.py +178 -73
  6. py_cmdtabs-1.2.1/src/py_cmdtabs/main_modules.py +326 -0
  7. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/src/py_cmdtabs.egg-info/PKG-INFO +1 -1
  8. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/src/py_cmdtabs.egg-info/SOURCES.txt +3 -3
  9. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/src/py_cmdtabs.egg-info/entry_points.txt +2 -0
  10. py_cmdtabs-1.2.1/tests/cli_example_report/Report.html +4111 -0
  11. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/cli_example_report/launch.sh +1 -1
  12. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/cli_example_report/outputs/wide_table +1 -1
  13. py_cmdtabs-1.2.1/tests/cli_example_report/styles.css +130 -0
  14. py_cmdtabs-1.2.1/tests/cli_example_report/subtemplates/aggregate_column_data +52 -0
  15. py_cmdtabs-1.2.1/tests/cli_example_report/subtemplates/column_filter +77 -0
  16. py_cmdtabs-1.2.1/tests/cli_example_report/subtemplates/create_metric_table +27 -0
  17. py_cmdtabs-1.2.1/tests/cli_example_report/subtemplates/desaggregate_column_data +24 -0
  18. py_cmdtabs-1.2.1/tests/cli_example_report/subtemplates/excel_to_tabular +51 -0
  19. py_cmdtabs-1.2.1/tests/cli_example_report/subtemplates/filter_by_list +61 -0
  20. py_cmdtabs-1.2.1/tests/cli_example_report/subtemplates/get_columns +24 -0
  21. py_cmdtabs-1.2.1/tests/cli_example_report/subtemplates/intersect_columns +46 -0
  22. py_cmdtabs-1.2.1/tests/cli_example_report/subtemplates/merge_tabular +23 -0
  23. py_cmdtabs-1.2.1/tests/cli_example_report/subtemplates/records_count +15 -0
  24. py_cmdtabs-1.2.1/tests/cli_example_report/subtemplates/show_n_exec +48 -0
  25. py_cmdtabs-1.2.1/tests/cli_example_report/subtemplates/standard_name_replacer +30 -0
  26. py_cmdtabs-1.2.1/tests/cli_example_report/subtemplates/subset_table +41 -0
  27. py_cmdtabs-1.2.1/tests/cli_example_report/subtemplates/table_linker +46 -0
  28. py_cmdtabs-1.2.1/tests/cli_example_report/subtemplates/tag_table +36 -0
  29. py_cmdtabs-1.2.1/tests/cli_example_report/subtemplates/transform_to_latex +24 -0
  30. py_cmdtabs-1.2.1/tests/cli_example_report/subtemplates/transpose_table +14 -0
  31. py_cmdtabs-1.2.1/tests/cli_example_report/tables/organization +9 -0
  32. py_cmdtabs-1.2.1/tests/cli_example_report/template.txt +87 -0
  33. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/test_cli_manager.py +43 -49
  34. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/test_cmdtabs_lib.py +13 -14
  35. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/test_expanded_methods.py +2 -3
  36. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/test_input_parsing.py +60 -6
  37. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/test_io.py +2 -3
  38. py_cmdtabs-1.2.0/src/py_cmdtabs/__init__.py +0 -2
  39. py_cmdtabs-1.2.0/src/py_cmdtabs/main_modules.py +0 -245
  40. py_cmdtabs-1.2.0/tests/cli_example_report/Report.html +0 -3796
  41. py_cmdtabs-1.2.0/tests/cli_example_report/subtemplates/aggregate_column_data +0 -55
  42. py_cmdtabs-1.2.0/tests/cli_example_report/subtemplates/column_filter +0 -88
  43. py_cmdtabs-1.2.0/tests/cli_example_report/subtemplates/create_metric_table +0 -50
  44. py_cmdtabs-1.2.0/tests/cli_example_report/subtemplates/desaggregate_column_data +0 -25
  45. py_cmdtabs-1.2.0/tests/cli_example_report/subtemplates/example +0 -64
  46. py_cmdtabs-1.2.0/tests/cli_example_report/subtemplates/example_written +0 -71
  47. py_cmdtabs-1.2.0/tests/cli_example_report/subtemplates/excel_to_tabular +0 -56
  48. py_cmdtabs-1.2.0/tests/cli_example_report/subtemplates/filter_by_list +0 -64
  49. py_cmdtabs-1.2.0/tests/cli_example_report/subtemplates/general +0 -41
  50. py_cmdtabs-1.2.0/tests/cli_example_report/subtemplates/get_columns +0 -29
  51. py_cmdtabs-1.2.0/tests/cli_example_report/subtemplates/intersect_columns +0 -59
  52. py_cmdtabs-1.2.0/tests/cli_example_report/subtemplates/merge_tabular +0 -25
  53. py_cmdtabs-1.2.0/tests/cli_example_report/subtemplates/records_count +0 -16
  54. py_cmdtabs-1.2.0/tests/cli_example_report/subtemplates/standard_name_replacer +0 -35
  55. py_cmdtabs-1.2.0/tests/cli_example_report/subtemplates/subset_table +0 -45
  56. py_cmdtabs-1.2.0/tests/cli_example_report/subtemplates/table_linker +0 -47
  57. py_cmdtabs-1.2.0/tests/cli_example_report/subtemplates/tag_table +0 -49
  58. py_cmdtabs-1.2.0/tests/cli_example_report/subtemplates/transform_to_latex +0 -25
  59. py_cmdtabs-1.2.0/tests/cli_example_report/subtemplates/transpose_table +0 -16
  60. py_cmdtabs-1.2.0/tests/cli_example_report/template.txt +0 -104
  61. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/.readthedocs.yml +0 -0
  62. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/AUTHORS.rst +0 -0
  63. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/CHANGELOG.rst +0 -0
  64. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/CONTRIBUTING.rst +0 -0
  65. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/LICENSE.txt +0 -0
  66. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/README.rst +0 -0
  67. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/docs/Makefile +0 -0
  68. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/docs/_static/.gitignore +0 -0
  69. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/docs/authors.rst +0 -0
  70. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/docs/changelog.rst +0 -0
  71. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/docs/conf.py +0 -0
  72. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/docs/contributing.rst +0 -0
  73. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/docs/index.rst +0 -0
  74. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/docs/license.rst +0 -0
  75. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/docs/readme.rst +0 -0
  76. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/docs/requirements.txt +0 -0
  77. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/make_package.sh +0 -0
  78. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/pyproject.toml +0 -0
  79. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/requirements.txt +0 -0
  80. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/setup.py +0 -0
  81. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/src/py_cmdtabs.egg-info/dependency_links.txt +0 -0
  82. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/src/py_cmdtabs.egg-info/not-zip-safe +0 -0
  83. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/src/py_cmdtabs.egg-info/requires.txt +0 -0
  84. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/src/py_cmdtabs.egg-info/top_level.txt +0 -0
  85. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/__init__.py +0 -0
  86. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/cli_example_report/example +0 -0
  87. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/cli_example_report/outputs/blackfiltered_long_table +0 -0
  88. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/cli_example_report/outputs/filtered_long_table +0 -0
  89. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/cli_example_report/outputs/ref_filtered_disease_cluster_ref_rnd +0 -0
  90. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/cli_example_report/outputs/subset_table/disease_cluster_ref_rnd_chunk0 +0 -0
  91. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/cli_example_report/outputs/subset_table/disease_cluster_ref_rnd_chunk1 +0 -0
  92. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/cli_example_report/outputs/subset_table/disease_cluster_ref_rnd_chunk2 +0 -0
  93. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/cli_example_report/outputs/subset_table2/disease_cluster_ref_rnd_chunk0 +0 -0
  94. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/cli_example_report/outputs/subset_table2/disease_cluster_ref_rnd_chunk1 +0 -0
  95. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/cli_example_report/special_files/hoja1.png +0 -0
  96. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/cli_example_report/special_files/hoja2.png +0 -0
  97. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/cli_example_report/special_files/scRNAseq.htm +0 -0
  98. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/cli_example_report/special_files/scRNAseq.xlsx +0 -0
  99. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/cli_example_report/special_files/scRNAseq_archivos/filelist.xml +0 -0
  100. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/cli_example_report/special_files/scRNAseq_archivos/sheet001.htm +0 -0
  101. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/cli_example_report/special_files/scRNAseq_archivos/sheet002.htm +0 -0
  102. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/cli_example_report/special_files/scRNAseq_archivos/stylesheet.css +0 -0
  103. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/cli_example_report/special_files/scRNAseq_archivos/tabstrip.htm +0 -0
  104. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/cli_example_report/special_files/~$scRNAseq.xlsx +0 -0
  105. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/cli_example_report/tables/cluster_genes_dis_agg +0 -0
  106. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/cli_example_report/tables/cluster_genes_dis_agg2 +0 -0
  107. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/cli_example_report/tables/cluster_genes_dis_desagg +0 -0
  108. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/cli_example_report/tables/cluster_genes_dis_desagg_3cols +0 -0
  109. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/cli_example_report/tables/cluster_genes_dis_desagg_4cols +0 -0
  110. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/cli_example_report/tables/cluster_stats +0 -0
  111. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/cli_example_report/tables/clusts_to_filter +0 -0
  112. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/cli_example_report/tables/disease_cluster +0 -0
  113. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/cli_example_report/tables/disease_cluster_ref_rnd +0 -0
  114. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/cli_example_report/tables/disease_cluster_uniq +0 -0
  115. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/cli_example_report/tables/disease_gene +0 -0
  116. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/cli_example_report/tables/long_disease_cluster +0 -0
  117. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/cli_example_report/tables/long_table +0 -0
  118. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/cli_example_report/tables/metrics_table +0 -0
  119. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/cli_example_report/tables/mondo_to_orpha +0 -0
  120. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/cli_example_report/tables/nets_to_filter +0 -0
  121. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/cli_example_report/tables/simple_table +0 -0
  122. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/cli_example_report/tables/tracker +0 -0
  123. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/conftest.py +0 -0
  124. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/agg_2index_2values.txt +0 -0
  125. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/agg_data_3_columns.txt +0 -0
  126. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/all_metrics +0 -0
  127. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/blacklist +0 -0
  128. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/blacklist_partial +0 -0
  129. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/cluster_genes.xlsx +0 -0
  130. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/cluster_genes_dis_agg +0 -0
  131. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/cluster_genes_dis_desagg +0 -0
  132. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/cluster_stats +0 -0
  133. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/cluster_stats_header +0 -0
  134. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/dis_gene_attrs +0 -0
  135. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/disease_cluster +0 -0
  136. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/disease_cluster_uniq +0 -0
  137. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/disease_gene +0 -0
  138. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/filterlist +0 -0
  139. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/filterlist_partial +0 -0
  140. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/hp_long_list.txt +0 -0
  141. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ids2count +0 -0
  142. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ids2count_short +0 -0
  143. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/metric_table +0 -0
  144. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/mondo_genes +0 -0
  145. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/mondo_genes.gz +0 -0
  146. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/TEST_file +0 -0
  147. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/TEST_file_transposed +0 -0
  148. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/agg_2index_2values.txt +0 -0
  149. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/agg_2index_2values_several_aggregators.txt +0 -0
  150. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/agg_data_3_columns_result.txt +0 -0
  151. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/cluster_genes_dis_AGG +0 -0
  152. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/cluster_genes_dis_AGG_stdin +0 -0
  153. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/cluster_genes_dis_DESAGG +0 -0
  154. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/cluster_genes_dis_DESAGG_stdin +0 -0
  155. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/cluster_genes_from_excel.txt +0 -0
  156. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/column_matching_hard +0 -0
  157. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/column_matching_hard_various_keys +0 -0
  158. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/column_matching_hard_various_keys_and_every_columns +0 -0
  159. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/column_matching_hard_various_keys_and_every_columns_header +0 -0
  160. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/column_matching_hard_various_keys_and_some_columns +0 -0
  161. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/column_matching_soft +0 -0
  162. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/column_matching_soft_1_column +0 -0
  163. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/column_matching_soft_1_column_reverse +0 -0
  164. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/column_matching_soft_1_column_uniq +0 -0
  165. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/column_matching_soft_and_every_columns +0 -0
  166. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/column_matching_soft_and_some_columns +0 -0
  167. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/ids2count +0 -0
  168. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/intersect_columns_count +0 -0
  169. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/intersect_columns_default +0 -0
  170. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/intersect_columns_default_stdin_a +0 -0
  171. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/intersect_columns_default_stdin_b +0 -0
  172. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/intersect_columns_full +0 -0
  173. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/linked_table +0 -0
  174. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/linked_table3 +0 -0
  175. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/linked_table_2 +0 -0
  176. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/linked_table_matches +0 -0
  177. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/merge_disease_cluster_gene +0 -0
  178. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/metric_table +0 -0
  179. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/mondo_genes_transposed +0 -0
  180. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/mondo_genes_transposed.gz +0 -0
  181. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/replaced_name +0 -0
  182. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/replaced_name_untranslated +0 -0
  183. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/subset_table +0 -0
  184. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/subset_table_fold/mondo_genes_chunk0 +0 -0
  185. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/subset_table_fold/mondo_genes_chunk1 +0 -0
  186. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/subset_table_fold/mondo_genes_chunk2 +0 -0
  187. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/tag_table +0 -0
  188. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/tag_table_header +0 -0
  189. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/transposed_cluster_genes_dis_AGG +0 -0
  190. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/transposed_cluster_genes_dis_DESAGG +0 -0
  191. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/transposed_cluster_genes_from_excel.txt +0 -0
  192. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/transposed_column_matching_hard +0 -0
  193. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/transposed_intersect_columns_default +0 -0
  194. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/transposed_linked_table +0 -0
  195. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/transposed_merge_disease_cluster_gene +0 -0
  196. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/transposed_metric_table +0 -0
  197. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/transposed_replaced_name +0 -0
  198. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/ref_output_scripts/transposed_tag_table +0 -0
  199. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/simple_table +0 -0
  200. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/tracker +0 -0
  201. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/transposed/all_metrics +0 -0
  202. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/transposed/cluster_genes.xlsx +0 -0
  203. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/transposed/cluster_genes_dis_agg +0 -0
  204. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/transposed/cluster_genes_dis_desagg +0 -0
  205. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/transposed/cluster_stats +0 -0
  206. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/transposed/disease_cluster +0 -0
  207. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/transposed/disease_cluster_uniq +0 -0
  208. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/transposed/disease_gene +0 -0
  209. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/data_tests/transposed/tranpose_data.py +0 -0
  210. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tests/test_compressed_pipes.sh +0 -0
  211. {py_cmdtabs-1.2.0 → py_cmdtabs-1.2.1}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: py_cmdtabs
3
- Version: 1.2.0
3
+ Version: 1.2.1
4
4
  Summary: Set of tools to facilitate parsing of tabulated files
5
5
  Home-page: https://github.com/seoanezonjic/py_cmdtabs
6
6
  Author: seoanezonjic
@@ -39,6 +39,8 @@ testing =
39
39
 
40
40
  [options.entry_points]
41
41
  console_scripts =
42
+ cmdtabs = py_cmdtabs.cli_manager:cmdtabs
43
+ cmdtabs_merge = py_cmdtabs.cli_manager:cmdtabs_merge
42
44
  aggregate_column_data = py_cmdtabs.cli_manager:aggregate_column_data
43
45
  column_filter = py_cmdtabs.cli_manager:column_filter
44
46
  create_metric_table = py_cmdtabs.cli_manager:create_metric_table
@@ -0,0 +1,16 @@
1
+ import sys
2
+
3
+ if sys.version_info[:2] >= (3, 8):
4
+ # TODO: Import directly (no need for conditional) when `python_requires = >= 3.8`
5
+ from importlib.metadata import PackageNotFoundError, version # pragma: no cover
6
+ else:
7
+ from importlib_metadata import PackageNotFoundError, version # pragma: no cover
8
+
9
+ try:
10
+ # Change here if project is renamed and does not equal the package name
11
+ dist_name = __name__
12
+ __version__ = version(dist_name)
13
+ except PackageNotFoundError: # pragma: no cover
14
+ __version__ = "unknown"
15
+ finally:
16
+ del version, PackageNotFoundError
@@ -1,16 +1,14 @@
1
- import argparse
2
- import sys
3
- import os
4
- import codecs
5
-
6
- from py_cmdtabs.cmdtabs import CmdTabs
1
+ import argparse, sys, os, codecs
7
2
  from py_cmdtabs.main_modules import *
8
3
 
9
4
  ## TYPES
10
5
  def based_0(string): return int(string) - 1
11
- def list_based_0(string): return CmdTabs.parse_column_indices(",", string)
6
+ def list_based_0(string):
7
+ from py_cmdtabs.cmdtabs import CmdTabs
8
+ return CmdTabs.parse_column_indices(string.split(','))
12
9
  def list_str(values): return values.split(',')
13
10
  def unescaped_str(arg_str): return codecs.decode(str(arg_str), 'unicode_escape')
11
+ def nested_int_list(arg_str): return [ [int(col) - 1 for col in str_cols.split(',')] for str_cols in arg_str.split(';')]
14
12
 
15
13
  ## Common options
16
14
  def add_common_options(parser, flags_to_skip = [], help_replacer={}):
@@ -82,7 +80,7 @@ def create_metric_table(args=None):
82
80
  add_common_options(parser, flags_to_skip=["--input_file"])
83
81
  parser.add_argument("metric_file", metavar='M',
84
82
  help="File with tabulated metrics")
85
- parser.add_argument("attributes", metavar='A',
83
+ parser.add_argument("attributes", metavar='A', type=list_str,
86
84
  help="String with comma separated attributes")
87
85
  parser.add_argument("output_file", metavar='O',
88
86
  help="Output file path")
@@ -110,10 +108,10 @@ def excel_to_tabular(args=None):
110
108
  add_common_options(parser, flags_to_skip=["--compressed_in"], help_replacer={"--input_file": "Input xlsx file"})
111
109
  parser.add_argument("-o", "--output_file", dest="output_file",
112
110
  help="Path to output file")
113
- parser.add_argument("-c", "--columns2extract", dest="columns2extract", default=[0], type=list_based_0,
114
- help="Column position to extract (1 based). Default 1. Use 0 to extract all columns")
115
- parser.add_argument("-r", "--rows2extract", dest="rows2extract", default=[-1], type=list_based_0,
116
- help="Row positions to extract (1 based). Default 0, which means all rows will be extracted")
111
+ parser.add_argument("-c", "--columns2extract", dest="columns2extract", default=[], type=list_based_0,
112
+ help="Comma-separated column position(s) to extract (1 based). If not used, all columns will be extracted")
113
+ parser.add_argument("-r", "--rows2extract", dest="rows2extract", default=[], type=list_based_0,
114
+ help="Comma-separated row position(s) to extract (1 based). If not used, all rows will be extracted")
117
115
  parser.add_argument("-s", "--sheet_number", dest="sheet_number", default=0, type=based_0,
118
116
  help="Sheet number to work with. Default 1")
119
117
 
@@ -292,4 +290,129 @@ def transpose_table(args=None):
292
290
  parser.add_argument("-o", "--output_file", dest="output_file", default=None,
293
291
  help="Path to output file")
294
292
  opts = parser.parse_args(args)
295
- main_transpose_table(opts)
293
+ main_transpose_table(opts)
294
+
295
+ def cmdtabs(args=None):
296
+ if args == None: args = sys.argv[1:]
297
+ parser = argparse.ArgumentParser(description=f'Usage: {os.path.basename(__file__)} [options]')
298
+ add_common_options(parser)
299
+ parser.add_argument("-c", "--columns", dest="columns", default=[0], type=list_based_0,
300
+ help="Index of columns in base 1 to compare")
301
+ parser.add_argument("-H", "--header", dest="header", default=False, action='store_true',
302
+ help="Indicate if files have header")
303
+ parser.add_argument("-I", "--index_file", dest="index_file", default=None,
304
+ help="Path to index file")
305
+ parser.add_argument("-o", "--output_file", dest="output_file", default=None,
306
+ help="Path to output file")
307
+ parser.add_argument("-s", "--separator", dest="separator", default="\t", type=unescaped_str,
308
+ help="Input table column character separator")
309
+ parser.add_argument("-t", "--tags", dest="tags", default= [],
310
+ help="Strings or files (only first line will be used) sepparated by commas", type=list_str)
311
+ parser.add_argument("-u", "--remove_untranslated", dest="remove_untranslated", default=False, action='store_true',
312
+ help="Activate this flag for outputting the untranslated entries")
313
+ parser.add_argument("-w", "--whole", dest="whole", default=False, action='store_true',
314
+ help="Indicate if you want the whole table and tabular environment to be returned with the table transformed")
315
+
316
+ parser.add_argument("--aggregate", dest="aggregate", default=False, action='store_true',
317
+ help="Aggregate table columns")
318
+ parser.add_argument("--agg_ref_col_index", dest="agg_col_index",
319
+ help="Column index (1 based) to use as reference", type=list_based_0)
320
+ parser.add_argument("--agg_col", dest="col_aggregate",
321
+ help="Column(s) index (1 based) to extract data and join for each id in column index (if more than one, comma separated)", type=list_based_0)
322
+ parser.add_argument("--agg_mode", dest="agg_mode", default="concatenate",
323
+ help="Mode to perform aggregation. Current available: max,min,mean,median,sum,std,var,IQR,PC25,PC75,count & concatenate. Default (concatenate) is string concatenation by defined separator. More than one aggregation mode can be used separated by commas")
324
+ parser.add_argument("--agg_sep", dest="agg_sep", default=",",
325
+ help="Character separator when collapse data")
326
+ parser.add_argument("--count-cols", dest="count_cols", default=None, type=list_based_0,
327
+ help="Index of columns in base 1 to count")
328
+ parser.add_argument("--desaggregate", dest="desaggregate", default=False, action='store_true',
329
+ help="Desaggregate table columns")
330
+ parser.add_argument("--desagg_col", dest="desagg_col",
331
+ help="Column index (1 based) to use as reference", type=list_based_0)
332
+ parser.add_argument("--desagg_sep", dest="desagg_sep", default=",",
333
+ help="Character separator when to split string column")
334
+ parser.add_argument("--excel_cols", dest="excColumns2extract", default=[], type=list_based_0,
335
+ help="Comma-separated column position(s) to extract (1 based). If not used, all columns will be extracted")
336
+ parser.add_argument("--excel_rows", dest="excRows2extract", default=[], type=list_based_0,
337
+ help="Comma-separated row position(s) to extract (1 based). If not used, all rows will be extracted")
338
+ parser.add_argument("--excel_sheet_number", dest="excSheet_number", default=0, type=based_0,
339
+ help="Sheet number to work with. Default 1")
340
+ parser.add_argument("--file_type", dest="file_type", default='text',
341
+ help="Default text. Other options;excel")
342
+ parser.add_argument("--from", dest="frm", default=0, type=based_0,
343
+ help="Column in index file to take reference value. Default 1. Numeration is 1 based")
344
+ parser.add_argument("--to", dest="to", default=1, type=based_0,
345
+ help="Column in index file to take the value that will be used in substitution. Default 2. Numeration is 1 based")
346
+ parser.add_argument("--latex", dest="to_latex", default=False, action='store_true',
347
+ help="Write table in latex code")
348
+ parser.add_argument("--sample_attributes", dest="sample_attributes", default=[], type=list_str,
349
+ help="Define sample atributtes (comma separated list) to colapse a long table in a wide metric table")
350
+ parser.add_argument("--corrupted", dest="corrupted",
351
+ help="File where corrupted metrics are stored")
352
+ parser.add_argument("--offset", dest="offset", default=[], type=list_str,
353
+ help="To subset N rows from table. Indicate as 'start_row,number_row' where start_row es the line to begin the extraction (1 based) and number_row is the amount of lines to extract")
354
+ parser.add_argument("--split_out", dest="split_out", default=False, action='store_true',
355
+ help="Split output table in several files")
356
+ parser.add_argument("--sp_chunk_size", dest="sp_chunk_size", default= 0, type=int,
357
+ help="To split the ouput table in chunks on K lines in different files.")
358
+ parser.add_argument("--sp_file_number", dest="sp_file_number", default= 0, type=int,
359
+ help="To split the output table in N files with the same number of lines.")
360
+ parser.add_argument("--extract_cols", dest="extract_cols", default=[], type=list_str,
361
+ help="Columns to extract from table, comma separated (based 1)")
362
+ parser.add_argument("--ext_col_match", dest="ext_col_match", type=list_based_0,
363
+ help="Select columns where search keywords. Format: x,y,z..")
364
+ parser.add_argument("--ext_keywords", dest="ext_keywords",
365
+ help="Keywords for select rows. Format: key1_col1&key2_col1%%key1_col2&key2_col2")
366
+ parser.add_argument("--ext_keyword_file", dest="ext_keyword_file",
367
+ help="File with one keyword per line. They will be used to search in all the specified columns in --ext_col_match")
368
+ parser.add_argument("--ext_search_mode", dest="ext_search_mode", default='c', choices=['c', 's'],
369
+ help="c for match in every columns set, s some match in some column. Default c")
370
+ parser.add_argument("--ext_match_mode", dest="ext_match_mode", default='i', choices=['i', 'c'],
371
+ help="i string must include the keyword, c for fullmatch. Default i")
372
+ parser.add_argument("--ext_reverse", dest="ext_reverse", default=False, action='store_true',
373
+ help="Select not matching")
374
+ parser.add_argument("--ext_stats", dest="ext_stats", default=False, action='store_true',
375
+ help="Print row extraction statistics")
376
+ parser.add_argument("--uniq", dest="uniq", default=False, action='store_true',
377
+ help="Make rows unique")
378
+ opts = parser.parse_args(args)
379
+ main_cmdtabs(opts)
380
+
381
+
382
+ def cmdtabs_merge(args=None):
383
+ if args == None: args = sys.argv[1:]
384
+ parser = argparse.ArgumentParser(description=f'Usage: {os.path.basename(__file__)} [options]')
385
+ add_common_options(parser)
386
+ parser.add_argument("-H", "--header", dest="header", default=False, action='store_true',
387
+ help="Indicate if files have header")
388
+ parser.add_argument("-o", "--output_file", dest="output_file", default=None,
389
+ help="Path to output file")
390
+ parser.add_argument("-s", "--separator", dest="separator", default="\t", type=unescaped_str,
391
+ help="Input table column character separator")
392
+ parser.add_argument("-a", "--a_file", dest="a_file",
393
+ help="Path to input file")
394
+ parser.add_argument("-b", "--b_file", dest="b_file",
395
+ help="Path to input file")
396
+ parser.add_argument("-A", "--a_cols", dest="a_cols", default=[0], type=list_based_0,
397
+ help="Index of columns in base 1 to compare")
398
+ parser.add_argument("-B", "--b_cols", dest="b_cols", default=[0], type=list_based_0,
399
+ help="Index of columns in base 1 to compare")
400
+ parser.add_argument("-c", "--count", dest="count", default=False, action='store_true',
401
+ help="Only compute number of matches")
402
+ parser.add_argument("--full", dest="full", default=False, action='store_true',
403
+ help="Give full record")
404
+ parser.add_argument("-k", "--keep", dest="keep", default='c', choices=['a', 'b', 'c', 'ab'],
405
+ help="Keep records. c for common, 'a' for specific of file a, 'b' for specific of file b and 'ab' for specific of file a AND b")
406
+
407
+ parser.add_argument("--tables", dest="tables", default=None, type=list_str,
408
+ help="Path to tables, comma separated. Paths could include wildcards")
409
+ parser.add_argument("--fill_character", dest="fill_character", default="-",
410
+ help="Character to fill when a field is empty")
411
+ parser.add_argument("--columns2add", dest="columns2add", default=[], type=nested_int_list,
412
+ help="For each file to add to the first file, column indexes 1 based comma separated. To separate each column set, use semicolon ;")
413
+ parser.add_argument("--union", dest="union", default=False, action='store_true',
414
+ help="If a row in a file has not match in the merging table is added to it")
415
+ opts = parser.parse_args(args)
416
+ main_cmdtabs_merge(opts)
417
+
418
+
@@ -1,25 +1,21 @@
1
- import sys
2
- import gzip
3
- import os
4
- import warnings
5
- import copy
1
+ import sys, gzip, os, warnings, copy
6
2
  import os.path
7
- import numpy as np
8
3
  from collections import defaultdict
9
- import openpyxl
10
- import py_exp_calc.exp_calc as pxc
11
4
 
12
5
  class CmdTabs:
13
6
  transposed = False
14
7
  compressed_input = False
15
8
  compressed_output = False
16
9
 
17
- def load_input_data(input_path, sep="\t", limit=-1, first_only=False, add_empty_fields=True):
18
- open_file = gzip.open if CmdTabs.compressed_input else open
10
+ def load_input_data(input_path, sep="\t", limit=-1, first_only=False, add_empty_fields=True, fill_character = "", autodetect_compression=False):
11
+ is_compressed = CmdTabs.compressed_input
12
+ if autodetect_compression: is_compressed = input_path.endswith('.gz')
13
+
14
+ open_file = gzip.open if is_compressed else open
19
15
  if limit > 0: # THis is due to ruby compute de cuts in other way and this fix enables ruby mode. Think if adapt to python way
20
16
  limit -= 1
21
17
  if input_path == '-':
22
- if CmdTabs.compressed_input:
18
+ if is_compressed:
23
19
  input_data = gzip.decompress(sys.stdin.buffer.read()).decode().strip().split('\n')
24
20
  else:
25
21
  input_data = sys.stdin
@@ -32,9 +28,10 @@ class CmdTabs:
32
28
  #print('---', file=sys.stderr)
33
29
  #print(repr(), file=sys.stderr)
34
30
  fields = line.rstrip().split(sep, limit)
31
+ fields = [ fill_character if field == "" else field for field in fields]
35
32
  if add_empty_fields:
36
33
  limit_fields = 0 if limit <= 0 else limit
37
- fields = fields + ( [""] * (fields_number - len(fields) - limit_fields) )
34
+ fields = fields + ( [fill_character] * (fields_number - len(fields) - limit_fields) )
38
35
  input_data_arr.append(fields)
39
36
  if first_only:
40
37
  break
@@ -54,40 +51,40 @@ class CmdTabs:
54
51
  loaded_files[key_id] = CmdTabs.load_input_data(file, sep, limit, add_empty_fields=add_empty_fields)
55
52
  return loaded_files
56
53
 
57
- def load_files(files_path): #NO TEST # Cleaning an filling behaviour could be sent to load_input_data as options and use on load_several_files
54
+ def load_files(files_path, fill_character = '-'): #NO TEST # Cleaning an filling behaviour could be sent to load_input_data as options and use on load_several_files
58
55
  files = {}
59
56
  for file_name in files_path:
60
57
  input_table = CmdTabs.load_input_data(file_name)
61
58
  file = []
62
59
  for fields in input_table:
63
60
  if fields.count('') == len(fields): continue #skip blank records
64
- file.append([ '-' if field == "" else field for field in fields])
61
+ file.append([ fill_character if field == "" else field for field in fields])
65
62
  files[file_name] = file
66
63
  return files
67
64
 
68
65
  def build_pattern(col_filter, keywords):
69
66
  pattern = defaultdict(lambda: False )
70
67
  if col_filter != None and keywords != None:
71
- keys_per_col = keywords.split('%')
72
- if len(keys_per_col) != len(col_filter): os.abort('Number of keywords not equal to number of filtering columns')
73
- i = 0
74
- for col in col_filter:
75
- pattern[col] = keys_per_col[i].split('&')
76
- i += 1
68
+ if isinstance(keywords, str): # search keywords from given string as species the % and & characters. % is delimiter of keywrod per column and & us delimiter of keywrods in th same column
69
+ keys_per_col = keywords.split('%')
70
+ if len(keys_per_col) != len(col_filter): os.abort('Number of keywords not equal to number of filtering columns')
71
+ for i, col in enumerate(col_filter): pattern[col] = keys_per_col[i].split('&')
72
+ elif isinstance(keywords, list): # search keywords from given list (file) in any column
73
+ for i, col in enumerate(col_filter): pattern[col] = keywords
77
74
  return pattern
78
75
 
79
- def index_array(array, col_from=0, col_to=1, header=False):
80
- indexed_array = defaultdict(lambda: False)
76
+ def index_array(table, col_from=0, col_to=1, header=False):
77
+ index = defaultdict(lambda: False)
81
78
  if type(col_to) != list:
82
79
  f = lambda x: x[col_to]
83
80
  else:
84
81
  f = lambda x: [x[c] for c in col_to]
85
82
  if header:
86
- head = array.pop(0)
87
- indexed_array['header'] = f(head)
88
- for elements in array:
89
- indexed_array[elements[col_from]] = f(elements)
90
- return indexed_array
83
+ head = table.pop(0)
84
+ index['header'] = f(head)
85
+ for row in table:
86
+ index[row[col_from]] = f(row)
87
+ return index
91
88
 
92
89
  def index_metrics(input_data, attributes):
93
90
  n_attrib = len(attributes)
@@ -115,16 +112,43 @@ class CmdTabs:
115
112
  query[metric_name] = metric
116
113
  return metric_names, indexed_metrics
117
114
 
118
- def parse_column_indices(sep, col_string):
115
+ def parse_column_indices(col_str_idxs, has_header= False, table=None):
116
+ if has_header:
117
+ col_str_idxs = CmdTabs.get_name_to_index_equivalences(col_str_idxs, table[0], idx_offset=1)
118
+
119
119
  cols = []
120
- for col in col_string.split(sep):
120
+ for col in col_str_idxs:
121
121
  if "-" in col: # Range of columns (both ends included)
122
122
  start, end = col.split("-")
123
- range_cols = [int(i) - 1 for i in range(int(start), int(end) + 1)]
123
+ range_cols = [i - 1 for i in range(int(start), int(end) + 1)]
124
124
  cols.extend(range_cols)
125
125
  else: # Single column
126
126
  cols.append(int(col) - 1)
127
127
  return cols
128
+
129
+ def get_name_to_index_equivalences(string_list_to_convert, referece_string_list, idx_offset=1):
130
+ cols_header_dict = dict([(col_name, str(idx+idx_offset)) for idx, col_name in enumerate(referece_string_list)])
131
+ cols_to_get_processed = []
132
+ try:
133
+ for col in string_list_to_convert:
134
+ if col.isdigit(): #Single numeric column case: If the column specifier is a number, we leave as it is
135
+ cols_to_get_processed.append(col)
136
+ elif "-" in col and not "%-%" in col: #Range of numeric column case or named column with hyphen
137
+ start_col, end_col = col.split("-")
138
+ if start_col.isdigit() and end_col.isdigit(): #We check if the column specifier is a range of numeric columns, if so we leave as it is
139
+ cols_to_get_processed.append(col)
140
+ else: #This is an edge of a named column with a hyphen in the name but not numeric range, we convert to number
141
+ cols_to_get_processed.append(cols_header_dict[col])
142
+ elif "%-%" not in col: # Single named column case: This is the case of a single column name, we convert to number
143
+ cols_to_get_processed.append(cols_header_dict[col])
144
+ else: # Range of named columns case: This is the case of a range of column names, we convert to numbers and keep the range format
145
+ start_col, end_col = col.split("%-%")
146
+ start_col = cols_header_dict[start_col]
147
+ end_col = cols_header_dict[end_col]
148
+ cols_to_get_processed.append(f"{start_col}-{end_col}")
149
+ except KeyError as e:
150
+ raise KeyError(f"Column '{e.args[0]}' not found in header. Available columns: {', '.join(cols_header_dict.keys())}")
151
+ return cols_to_get_processed
128
152
 
129
153
  def load_and_parse_tags(tags, sep):
130
154
  parsed_tags = []
@@ -146,6 +170,7 @@ class CmdTabs:
146
170
 
147
171
 
148
172
  def aggregate_column(input_table, col_index, cols_agg, sep, agg_mode="concatenate"):
173
+ import py_exp_calc.exp_calc as pxc
149
174
  aggregated_data = defaultdict(lambda: False )
150
175
  if type(cols_agg) == int: cols_agg = [cols_agg]
151
176
  if type(col_index) == int: col_index = [col_index]
@@ -161,6 +186,7 @@ class CmdTabs:
161
186
  return aggregated_data_arr
162
187
 
163
188
  def _make_one_or_several_aggregation(aggregated_column, aggregation_modes, sep):
189
+ import numpy as np
164
190
  make_aggregation = {"concatenate": lambda agg_col: sep.join(agg_col),
165
191
  "mean": np.mean, "median": np.median, "max": np.max, "min": np.min, "sum": np.sum, "std": np.std, "var": np.var,
166
192
  "count": lambda agg_col: len(agg_col), "IQR": lambda agg_col: np.percentile(agg_col, 75) - np.percentile(agg_col, 25),
@@ -251,6 +277,34 @@ class CmdTabs:
251
277
  if not drop_line: linked_table.append(fields)
252
278
  return linked_table
253
279
 
280
+ def merge_tables2mainTab(main_table, table_paths, column_idxs, sep = "\t", fill_character='-', header = False, union= False):
281
+ table_length = len(main_table[0])
282
+ for i, table_path in enumerate(table_paths):
283
+ supp_file = CmdTabs.load_input_data(table_path, sep=sep)
284
+ id_col, data_cols = column_idxs[i]
285
+ supp_file_idx = CmdTabs.index_array(supp_file, id_col, data_cols, header = header)
286
+ for i,row in enumerate(main_table):
287
+ if i == 0 and header: # if we're in first row an is header, search for the header record in the index
288
+ id = 'header'
289
+ else:
290
+ id = row[0]
291
+ supp_data = supp_file_idx.get(id)
292
+ if supp_data:
293
+ if type(supp_data) == list:# list with several row fields
294
+ row.extend(supp_data)
295
+ else:
296
+ row.append(supp_data) # one single field as one single value
297
+ CmdTabs.row_start_fill(row, fill_character, table_length) # When there is no match, fill the gap
298
+ if union: # Add rows present in supp file but not in main_table
299
+ for item in (set(supp_file_idx.keys()) - set([r[0] for r in main_table])):
300
+ new_row = [item]
301
+ CmdTabs.row_start_fill(new_row, fill_character, table_length)
302
+ new_row.extend(supp_file_idx[item])
303
+ main_table.append(new_row)
304
+ table_length += len(supp_file_idx[list(supp_file_idx.keys())[0]])
305
+
306
+ for row in main_table: CmdTabs.row_end_fill(row, fill_character, table_length) # When there is no match, fill the gap
307
+
254
308
  def tag_file(input_file, tags, header):
255
309
  taged_file = []
256
310
  n_row = 0
@@ -264,23 +318,23 @@ class CmdTabs:
264
318
  n_row += 1
265
319
  return taged_file
266
320
 
267
- def filter(line, all_patterns, search_mode, match_mode, reverse = False ):
268
- filter = False
321
+ def match_pattern(line, all_patterns, search_mode, match_mode, reverse = False ):
322
+ match_pat = False
269
323
  for col, patterns in all_patterns.items():
270
324
  is_match = False
271
325
  for pattern in patterns:
272
326
  is_match = CmdTabs.expanded_match(line[col], pattern, match_mode)
273
327
  if is_match: break
274
328
  if is_match and search_mode == 's':
275
- filter = False
329
+ match_pat = False
276
330
  break
277
331
  elif not is_match and search_mode == 'c':
278
- filter = True
332
+ match_pat = True
279
333
  break
280
334
  elif not is_match:
281
- filter = True
282
- if reverse: filter = not filter
283
- return filter
335
+ match_pat = True
336
+ if reverse: match_pat = not match_pat
337
+ return match_pat
284
338
 
285
339
  def expanded_match(string, pattern, match_mode):
286
340
  is_match = False
@@ -288,16 +342,16 @@ class CmdTabs:
288
342
  if string == pattern and match_mode == 'c': is_match = True
289
343
  return is_match
290
344
 
291
- def filter_columns(input_table, options):
292
- pattern = CmdTabs.build_pattern(options['col_filter'], options['keywords'])
345
+ def filter_columns(input_table, cols_to_show, cols_to_match = None, keywords = None, search_mode = None, match_mode = None, reverse = False):
346
+ pattern = CmdTabs.build_pattern(cols_to_match, keywords)
293
347
  filtered_table = []
294
348
  for line in input_table:
295
- if not pattern or not CmdTabs.filter(line, pattern, options['search_mode'], options['match_mode'], options['reverse']):
296
- filtered_table.append(CmdTabs.extract_fields(line, options['cols_to_show']) )
349
+ if not pattern or not CmdTabs.match_pattern(line, pattern, search_mode, match_mode, reverse):
350
+ filtered_table.append(CmdTabs.extract_fields(line, cols_to_show) )
297
351
  return filtered_table
298
352
 
299
353
  def extract_fields(arr_sub, indexes):
300
- if indexes == [-1]:
354
+ if indexes == []:
301
355
  return arr_sub
302
356
  else:
303
357
  return [ str(arr_sub[idx]) for idx in indexes] # The str instruction is used to ensure that always we have string data (i.e: when this function is used with excel objecb it could extrac numerical data)
@@ -310,23 +364,38 @@ class CmdTabs:
310
364
  for fields in file:
311
365
  id = fields.pop(0)
312
366
  local_length = len(fields)
313
- if not parent_table.get(id):
314
- parent_table[id] = [fill_character] * table_length
315
- elif len(parent_table[id]) < table_length:
316
- diference = table_length - len(parent_table[id])
317
- parent_table[id].extend( [fill_character] * diference)
367
+ CmdTabs.row_start_fill_dict(parent_table, id, fill_character, table_length)
318
368
  parent_table[id].extend(fields)
319
369
  table_length += local_length
320
-
321
- parent_table_arr = []
370
+
371
+ parent_table_arr = [] # Fill rows that have not full length (the sum of the row lengths of the all merged tables)
322
372
  for id, fields in parent_table.items():
323
- diference = table_length - len(fields)
324
- if diference > 0: fields.extend([fill_character] * diference)
373
+ CmdTabs.row_end_fill(fields, fill_character, table_length)
325
374
  record = [id]
326
375
  record.extend(fields)
327
376
  parent_table_arr.append(record)
328
377
  return parent_table_arr
329
378
 
379
+ def row_start_fill_dict(indexed_table, row_id, fill_character, table_length):
380
+ if not indexed_table.get(row_id):
381
+ indexed_table[row_id] = [fill_character] * table_length
382
+ elif len(indexed_table[row_id]) < table_length:
383
+ diference = table_length - len(indexed_table[row_id])
384
+ indexed_table[row_id].extend( [fill_character] * diference)
385
+
386
+ def row_start_fill(row, fill_character, table_length):
387
+ n_fields = len(row)
388
+ if n_fields == 0:
389
+ row = [fill_character] * table_length
390
+ elif n_fields < table_length:
391
+ diference = table_length - n_fields
392
+ row.extend( [fill_character] * diference)
393
+ return row
394
+
395
+ def row_end_fill(row, fill_character, table_length):
396
+ diference = table_length - len(row)
397
+ if diference > 0: row.extend([fill_character] * diference)
398
+
330
399
  def merge_and_filter_tables(input_files, options):
331
400
  header = []
332
401
  filtered_table = []
@@ -337,7 +406,8 @@ class CmdTabs:
337
406
  header = file.pop(0)
338
407
  else:
339
408
  file.pop(0)
340
- fields = CmdTabs.filter_columns(file, options)
409
+
410
+ fields = CmdTabs.filter_columns(file, options['cols_to_show'], options['col_filter'], options['keywords'], options['search_mode'], options['match_mode'], options['reverse'])
341
411
  filtered_table.extend(fields)
342
412
  if options.get('uniq') != None and options['uniq']: filtered_table = CmdTabs.get_uniq(filtered_table)
343
413
  if len(header) > 0:
@@ -374,12 +444,13 @@ class CmdTabs:
374
444
  return storage
375
445
 
376
446
  def extract_rows(table, rows2extract):
377
- if rows2extract == [-1]:
447
+ if rows2extract == []:
378
448
  return table
379
449
  else:
380
450
  return [ row for idx, row in enumerate(table) if idx in rows2extract ]
381
451
 
382
452
  def get_table_from_excel(file, sheet_number):
453
+ import openpyxl
383
454
  x = openpyxl.load_workbook(file)
384
455
  sheets = x.sheetnames # list excel sheets by name
385
456
  ws = x[sheets[sheet_number]] #select sheet by index (so, we select by sheet order)
@@ -406,25 +477,23 @@ class CmdTabs:
406
477
  common = [[r] for r in common_set]
407
478
  return common, a_only, b_only
408
479
 
409
- def write_output_data(output_data, output_path=None, sep="\t"):
410
- open_file = gzip.open if CmdTabs.compressed_output else open
411
- if CmdTabs.transposed:
412
- output_data = CmdTabs.transpose(output_data)
413
-
414
- if output_path != None:
415
- with open_file(output_path, 'wt') as out_file:
416
- for line in output_data:
417
- out_file.write(sep.join([str(l) for l in line]) + "\n")
418
- else:
419
- if CmdTabs.compressed_output:
420
- columns_joined = []
421
- for line in output_data:
422
- columns_joined.append(sep.join([str(l) for l in line]))
423
- all_joined = "\n".join(columns_joined) + "\n"
424
- sys.stdout.buffer.write(gzip.compress(bytes(all_joined, 'utf-8')))
425
- else:
426
- for line in output_data:
427
- print(sep.join([str(l) for l in line]))
480
+ def get_subset(common, a_only, b_only, full_a_rec, full_b_rec, keep_subset='c', full=False):
481
+ # As the groups are list with nested list with only one element: [['str1'], ['str2']..] the full mode need to access to 0 element to be use as key in full_X_rec
482
+ if keep_subset == 'c':
483
+ result = common
484
+ if full: result = [full_a_rec[r[0]] + full_b_rec[r[0]] for r in common]
485
+ elif keep_subset == 'a':
486
+ result = a_only
487
+ if full: result = [full_a_rec[r[0]] for r in a_only]
488
+ elif keep_subset == 'b':
489
+ result = b_only
490
+ if full: result = [full_b_rec[r[0]] for r in b_only]
491
+ elif keep_subset == 'ab':
492
+ if full:
493
+ a_only = [full_a_rec[r[0]] for r in a_only]
494
+ b_only = [full_b_rec[r[0]] for r in b_only]
495
+ result = a_only + b_only
496
+ return result
428
497
 
429
498
  def transpose(table):
430
499
  transposed_table = list(map(list, zip(*table)))
@@ -454,4 +523,40 @@ class CmdTabs:
454
523
  final_table += [f"\\end{{tabular}}\n\\label{{table:{name}}}\n\\end{{table}}"]
455
524
  else:
456
525
  final_table = latex_table
457
- return final_table
526
+ return final_table
527
+
528
+ def write_output_data(output_data, output_path=None, sep="\t"):
529
+ open_file = gzip.open if CmdTabs.compressed_output else open
530
+ if CmdTabs.transposed:
531
+ output_data = CmdTabs.transpose(output_data)
532
+
533
+ if output_path != None:
534
+ with open_file(output_path, 'wt') as out_file:
535
+ for line in output_data:
536
+ out_file.write(sep.join([str(l) for l in line]) + "\n")
537
+ else:
538
+ if CmdTabs.compressed_output:
539
+ columns_joined = []
540
+ for line in output_data:
541
+ columns_joined.append(sep.join([str(l) for l in line]))
542
+ all_joined = "\n".join(columns_joined) + "\n"
543
+ sys.stdout.buffer.write(gzip.compress(bytes(all_joined, 'utf-8')))
544
+ else:
545
+ for line in output_data:
546
+ print(sep.join([str(l) for l in line]))
547
+
548
+ def split_by_nFiles(input_table, file_number, output_folder, file_name='table', header = []):
549
+ chunk_size = len(input_table) // file_number
550
+ init_line = 1 if len(header) > 0 else 0
551
+ if len(input_table) % file_number > 0: chunk_size += 1
552
+ chunk_counter = 0
553
+ for idx in range(init_line, len(input_table), chunk_size):
554
+ CmdTabs.write_output_data(header+input_table[idx:idx+chunk_size], os.path.join(output_folder, f"{file_name}_chunk{chunk_counter}"))
555
+ chunk_counter += 1
556
+
557
+ def split_by_chunk(input_table, chunk_size, output_folder, file_name='table', header = []):
558
+ init_line = 1 if len(header) > 0 else 0
559
+ chunk_counter = 0
560
+ for idx in range(init_line, len(input_table), chunk_size):
561
+ CmdTabs.write_output_data(header+input_table[idx:idx+chunk_size], os.path.join(output_folder, f"{file_name}_chunk{chunk_counter}"))
562
+ chunk_counter += 1