cardinal-pythonlib 2.0.2__tar.gz → 2.0.4__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 (190) hide show
  1. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/PKG-INFO +1 -4
  2. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/sql/validation.py +5 -1
  3. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/sqlalchemy/alembic_func.py +78 -86
  4. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/sqlalchemy/schema.py +11 -1
  5. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/version_string.py +1 -1
  6. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib.egg-info/PKG-INFO +1 -4
  7. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib.egg-info/entry_points.txt +0 -1
  8. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/LICENSE +0 -0
  9. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/README.rst +0 -0
  10. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/__init__.py +0 -0
  11. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/argparse_func.py +0 -0
  12. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/athena_ohdsi.py +0 -0
  13. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/betweendict.py +0 -0
  14. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/buildfunc.py +0 -0
  15. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/bulk_email/__init__.py +0 -0
  16. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/bulk_email/constants.py +0 -0
  17. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/bulk_email/main.py +0 -0
  18. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/bulk_email/models.py +0 -0
  19. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/chebi.py +0 -0
  20. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/classes.py +0 -0
  21. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/cmdline.py +0 -0
  22. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/colander_utils.py +0 -0
  23. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/compression.py +0 -0
  24. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/configfiles.py +0 -0
  25. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/contexts.py +0 -0
  26. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/convert.py +0 -0
  27. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/crypto.py +0 -0
  28. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/datamapping.py +0 -0
  29. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/datetimefunc.py +0 -0
  30. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/dbfunc.py +0 -0
  31. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/debugging.py +0 -0
  32. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/deform_utils.py +0 -0
  33. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/dicts.py +0 -0
  34. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/django/__init__.py +0 -0
  35. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/django/admin.py +0 -0
  36. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/django/django_constants.py +0 -0
  37. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/django/fields/__init__.py +0 -0
  38. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/django/fields/helpers.py +0 -0
  39. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/django/fields/isodatetimetz.py +0 -0
  40. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/django/fields/jsonclassfield.py +0 -0
  41. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/django/fields/restrictedcontentfile.py +0 -0
  42. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/django/files.py +0 -0
  43. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/django/forms.py +0 -0
  44. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/django/function_cache.py +0 -0
  45. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/django/mail.py +0 -0
  46. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/django/middleware.py +0 -0
  47. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/django/reprfunc.py +0 -0
  48. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/django/request_cache.py +0 -0
  49. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/django/serve.py +0 -0
  50. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/django/tools/__init__.py +0 -0
  51. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/django/tools/generate_new_django_secret_key.py +0 -0
  52. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/docker.py +0 -0
  53. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/dogpile_cache.py +0 -0
  54. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/dsp.py +0 -0
  55. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/email/__init__.py +0 -0
  56. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/email/mailboxpurge.py +0 -0
  57. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/email/sendmail.py +0 -0
  58. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/ensure_test_executed_correctly.py +0 -0
  59. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/enumlike.py +0 -0
  60. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/excel.py +0 -0
  61. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/exceptions.py +0 -0
  62. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/extract_text.py +0 -0
  63. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/file_io.py +0 -0
  64. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/fileops.py +0 -0
  65. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/formatting.py +0 -0
  66. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/getch.py +0 -0
  67. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/hash.py +0 -0
  68. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/httpconst.py +0 -0
  69. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/interval.py +0 -0
  70. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/iterhelp.py +0 -0
  71. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/json/__init__.py +0 -0
  72. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/json/serialize.py +0 -0
  73. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/json/typing_helpers.py +0 -0
  74. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/lang.py +0 -0
  75. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/lists.py +0 -0
  76. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/logs.py +0 -0
  77. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/maths_numpy.py +0 -0
  78. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/maths_py.py +0 -0
  79. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/metaclasses.py +0 -0
  80. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/module_version.py +0 -0
  81. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/modules.py +0 -0
  82. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/network.py +0 -0
  83. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/nhs.py +0 -0
  84. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/openxml/__init__.py +0 -0
  85. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/openxml/find_bad_openxml.py +0 -0
  86. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/openxml/find_recovered_openxml.py +0 -0
  87. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/openxml/grep_in_openxml.py +0 -0
  88. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/openxml/pause_process_by_disk_space.py +0 -0
  89. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/parallel.py +0 -0
  90. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/pdf.py +0 -0
  91. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/platformfunc.py +0 -0
  92. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/plot.py +0 -0
  93. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/probability.py +0 -0
  94. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/process.py +0 -0
  95. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/profile.py +0 -0
  96. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/progress.py +0 -0
  97. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/psychiatry/__init__.py +0 -0
  98. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/psychiatry/drugs.py +0 -0
  99. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/psychiatry/mk_r_druglists.py +0 -0
  100. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/psychiatry/rfunc.py +0 -0
  101. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/psychiatry/simhelpers.py +0 -0
  102. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/psychiatry/timeline.py +0 -0
  103. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/psychiatry/treatment_resistant_depression.py +0 -0
  104. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/pyramid/__init__.py +0 -0
  105. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/pyramid/compression.py +0 -0
  106. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/pyramid/constants.py +0 -0
  107. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/pyramid/requests.py +0 -0
  108. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/pyramid/responses.py +0 -0
  109. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/randomness.py +0 -0
  110. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/rate_limiting.py +0 -0
  111. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/regexfunc.py +0 -0
  112. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/register_db_with_odbc.py +0 -0
  113. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/reprfunc.py +0 -0
  114. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/rnc_text.py +0 -0
  115. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/rnc_web.py +0 -0
  116. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/rounding.py +0 -0
  117. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/rpm.py +0 -0
  118. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/run_all_tests.py +0 -0
  119. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/signalfunc.py +0 -0
  120. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/sizeformatter.py +0 -0
  121. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/slurm.py +0 -0
  122. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/snomed.py +0 -0
  123. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/sort.py +0 -0
  124. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/source_reformatting.py +0 -0
  125. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/sphinxtools.py +0 -0
  126. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/spreadsheets.py +0 -0
  127. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/sql/__init__.py +0 -0
  128. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/sql/literals.py +0 -0
  129. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/sql/sql_grammar.py +0 -0
  130. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/sql/sql_grammar_factory.py +0 -0
  131. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/sql/sql_grammar_mssql.py +0 -0
  132. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/sql/sql_grammar_mysql.py +0 -0
  133. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/sqlalchemy/__init__.py +0 -0
  134. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/sqlalchemy/alembic_ops.py +0 -0
  135. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/sqlalchemy/arrow_types.py +0 -0
  136. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/sqlalchemy/core_query.py +0 -0
  137. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/sqlalchemy/dialect.py +0 -0
  138. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/sqlalchemy/dump.py +0 -0
  139. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/sqlalchemy/engine_func.py +0 -0
  140. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/sqlalchemy/insert_on_duplicate.py +0 -0
  141. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/sqlalchemy/list_types.py +0 -0
  142. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/sqlalchemy/logs.py +0 -0
  143. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/sqlalchemy/merge_db.py +0 -0
  144. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/sqlalchemy/orm_inspect.py +0 -0
  145. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/sqlalchemy/orm_query.py +0 -0
  146. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/sqlalchemy/orm_schema.py +0 -0
  147. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/sqlalchemy/semantic_version_coltype.py +0 -0
  148. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/sqlalchemy/session.py +0 -0
  149. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/sqlalchemy/sqla_version.py +0 -0
  150. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/sqlalchemy/sqlfunc.py +0 -0
  151. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/sqlalchemy/sqlserver.py +0 -0
  152. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/sqlalchemy/table_identity.py +0 -0
  153. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/stringfunc.py +0 -0
  154. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/subproc.py +0 -0
  155. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/sysops.py +0 -0
  156. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/tcpipconst.py +0 -0
  157. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/tee.py +0 -0
  158. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/text.py +0 -0
  159. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/timing.py +0 -0
  160. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/tools/__init__.py +0 -0
  161. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/tools/backup_mysql_database.py +0 -0
  162. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/tools/convert_athena_ohdsi_codes.py +0 -0
  163. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/tools/convert_mdb_to_mysql.py +0 -0
  164. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/tools/estimate_mysql_memory_usage.py +0 -0
  165. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/tools/explore_clang_format_config.py +0 -0
  166. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/tools/list_all_file_extensions.py +0 -0
  167. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/tools/merge_csv.py +0 -0
  168. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/tools/pdf_to_booklet.py +0 -0
  169. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/tools/remove_duplicate_files.py +0 -0
  170. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/tsv.py +0 -0
  171. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/typetests.py +0 -0
  172. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/typing_helpers.py +0 -0
  173. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/ui.py +0 -0
  174. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/ui_commandline.py +0 -0
  175. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/uriconst.py +0 -0
  176. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/version.py +0 -0
  177. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/winservice.py +0 -0
  178. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/wsgi/__init__.py +0 -0
  179. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/wsgi/cache_mw.py +0 -0
  180. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/wsgi/constants.py +0 -0
  181. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/wsgi/errorreporter_mw.py +0 -0
  182. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/wsgi/headers_mw.py +0 -0
  183. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/wsgi/request_logging_mw.py +0 -0
  184. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib/wsgi/reverse_proxied_mw.py +0 -0
  185. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib.egg-info/SOURCES.txt +0 -0
  186. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib.egg-info/dependency_links.txt +0 -0
  187. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib.egg-info/requires.txt +2 -2
  188. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/cardinal_pythonlib.egg-info/top_level.txt +0 -0
  189. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/setup.cfg +0 -0
  190. {cardinal_pythonlib-2.0.2 → cardinal_pythonlib-2.0.4}/setup.py +0 -0
@@ -1,13 +1,12 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cardinal_pythonlib
3
- Version: 2.0.2
3
+ Version: 2.0.4
4
4
  Summary: Miscellaneous Python libraries
5
5
  Home-page: https://github.com/RudolfCardinal/pythonlib
6
6
  Author: Rudolf Cardinal
7
7
  Author-email: rudolf@pobox.com
8
8
  License: Apache License 2.0
9
9
  Keywords: cardinal
10
- Platform: UNKNOWN
11
10
  Classifier: Development Status :: 4 - Beta
12
11
  Classifier: Intended Audience :: Developers
13
12
  Classifier: License :: OSI Approved :: Apache Software License
@@ -43,5 +42,3 @@ By Rudolf Cardinal (rudolf@pobox.com)
43
42
  Install with ``pip install cardinal_pythonlib``.
44
43
 
45
44
  Documentation is at https://cardinalpythonlib.readthedocs.io/.
46
-
47
-
@@ -212,6 +212,7 @@ SQLTYPES_DATETIME_ALL = SQLTYPES_WITH_DATE + SQLTYPES_DATETIME_OTHER
212
212
  SQLTYPES_ALL = (
213
213
  SQLTYPES_INTEGER
214
214
  + SQLTYPES_FLOAT
215
+ + SQLTYPES_BIT
215
216
  + SQLTYPES_OTHER_NUMERIC
216
217
  + SQLTYPES_TEXT
217
218
  + SQLTYPES_BINARY
@@ -221,11 +222,14 @@ SQLTYPES_ALL = (
221
222
  SQLTYPES_NOT_TEXT = (
222
223
  SQLTYPES_INTEGER
223
224
  + SQLTYPES_FLOAT
225
+ + SQLTYPES_BIT
224
226
  + SQLTYPES_OTHER_NUMERIC
225
227
  + SQLTYPES_DATETIME_ALL
226
228
  + SQLTYPES_OTHER
227
229
  )
228
- SQLTYPES_NUMERIC = SQLTYPES_INTEGER + SQLTYPES_FLOAT + SQLTYPES_OTHER_NUMERIC
230
+ SQLTYPES_NUMERIC = (
231
+ SQLTYPES_INTEGER + SQLTYPES_FLOAT + SQLTYPES_BIT + SQLTYPES_OTHER_NUMERIC
232
+ )
229
233
 
230
234
 
231
235
  # =============================================================================
@@ -26,22 +26,22 @@
26
26
 
27
27
  """
28
28
 
29
+ import logging
29
30
  import os
30
31
  import re
31
- import subprocess
32
32
  from typing import Tuple
33
33
 
34
- from alembic.config import Config
35
- from alembic.util.exc import CommandError
34
+ from alembic.command import revision as mk_revision
35
+ from alembic.config import CommandLine, Config as AlembicConfig
36
36
  from alembic.runtime.migration import MigrationContext
37
37
  from alembic.runtime.environment import EnvironmentContext
38
38
  from alembic.script import ScriptDirectory
39
+ from alembic.util.exc import CommandError
39
40
  from sqlalchemy.engine import create_engine
40
41
 
41
42
  from cardinal_pythonlib.fileops import preserve_cwd
42
- from cardinal_pythonlib.logs import get_brace_style_log_with_null_handler
43
43
 
44
- log = get_brace_style_log_with_null_handler(__name__)
44
+ log = logging.getLogger(__name__)
45
45
 
46
46
 
47
47
  # =============================================================================
@@ -80,7 +80,7 @@ def get_head_revision_from_alembic(
80
80
 
81
81
  Arguments:
82
82
  alembic_config_filename:
83
- config filename
83
+ config filename (usually a full path to an alembic.ini file)
84
84
  alembic_base_dir:
85
85
  directory to start in, so relative paths in the config file work.
86
86
  version_table:
@@ -89,9 +89,9 @@ def get_head_revision_from_alembic(
89
89
  if alembic_base_dir is None:
90
90
  alembic_base_dir = os.path.dirname(alembic_config_filename)
91
91
  os.chdir(alembic_base_dir) # so the directory in the config file works
92
- config = Config(alembic_config_filename)
93
- script = ScriptDirectory.from_config(config)
94
- with EnvironmentContext(config, script, version_table=version_table):
92
+ alembic_cfg = AlembicConfig(alembic_config_filename)
93
+ script = ScriptDirectory.from_config(alembic_cfg)
94
+ with EnvironmentContext(alembic_cfg, script, version_table=version_table):
95
95
  return script.get_current_head()
96
96
 
97
97
 
@@ -123,11 +123,14 @@ def get_current_and_head_revision(
123
123
  :func:`get_current_revision` and :func:`get_head_revision_from_alembic`.
124
124
 
125
125
  Arguments:
126
- database_url: SQLAlchemy URL for the database
127
- alembic_config_filename: config filename
128
- alembic_base_dir: directory to start in, so relative paths in the
129
- config file work.
130
- version_table: table name for Alembic versions
126
+ database_url:
127
+ SQLAlchemy URL for the database
128
+ alembic_config_filename:
129
+ config filename (usually a full path to an alembic.ini file)
130
+ alembic_base_dir:
131
+ directory to start in, so relative paths in the config file work.
132
+ version_table:
133
+ table name for Alembic versions
131
134
  """
132
135
  # Where we are
133
136
  head_revision = get_head_revision_from_alembic(
@@ -135,13 +138,13 @@ def get_current_and_head_revision(
135
138
  alembic_base_dir=alembic_base_dir,
136
139
  version_table=version_table,
137
140
  )
138
- log.debug("Intended database version: {}", head_revision)
141
+ log.debug(f"Intended database version: {head_revision}")
139
142
 
140
143
  # Where we want to be
141
144
  current_revision = get_current_revision(
142
145
  database_url=database_url, version_table=version_table
143
146
  )
144
- log.debug("Current database version: {}", current_revision)
147
+ log.debug(f"Current database version: {current_revision}")
145
148
 
146
149
  # Are we where we want to be?
147
150
  return current_revision, head_revision
@@ -165,49 +168,43 @@ def upgrade_database(
165
168
 
166
169
  Arguments:
167
170
  alembic_config_filename:
168
- config filename
169
-
171
+ config filename (usually a full path to an alembic.ini file)
170
172
  db_url:
171
173
  Optional database URL to use, by way of override.
172
-
173
174
  alembic_base_dir:
174
175
  directory to start in, so relative paths in the config file work
175
-
176
176
  starting_revision:
177
177
  revision to start at (typically ``None`` to ask the database)
178
-
179
178
  destination_revision:
180
179
  revision to aim for (typically ``"head"`` to migrate to the latest
181
180
  structure)
182
-
183
- version_table: table name for Alembic versions
184
-
181
+ version_table:
182
+ table name for Alembic versions
185
183
  as_sql:
186
184
  run in "offline" mode: print the migration SQL, rather than
187
185
  modifying the database. See
188
186
  https://alembic.zzzcomputing.com/en/latest/offline.html
189
-
190
187
  """
191
188
 
192
189
  if alembic_base_dir is None:
193
190
  alembic_base_dir = os.path.dirname(alembic_config_filename)
194
191
  os.chdir(alembic_base_dir) # so the directory in the config file works
195
- config = Config(alembic_config_filename)
192
+ alembic_cfg = AlembicConfig(alembic_config_filename)
196
193
  if db_url:
197
- config.set_main_option("sqlalchemy.url", db_url)
198
- script = ScriptDirectory.from_config(config)
194
+ alembic_cfg.set_main_option("sqlalchemy.url", db_url)
195
+ script = ScriptDirectory.from_config(alembic_cfg)
199
196
 
200
197
  # noinspection PyUnusedLocal,PyProtectedMember
201
198
  def upgrade(rev, context):
202
199
  return script._upgrade_revs(destination_revision, rev)
203
200
 
204
201
  log.info(
205
- "Upgrading database to revision {!r} using Alembic",
206
- destination_revision,
202
+ f"Upgrading database to revision {destination_revision!r} "
203
+ f"using Alembic"
207
204
  )
208
205
 
209
206
  with EnvironmentContext(
210
- config,
207
+ alembic_cfg,
211
208
  script,
212
209
  fn=upgrade,
213
210
  as_sql=as_sql,
@@ -240,48 +237,42 @@ def downgrade_database(
240
237
 
241
238
  Arguments:
242
239
  alembic_config_filename:
243
- config filename
244
-
240
+ config filename (usually a full path to an alembic.ini file)
245
241
  db_url:
246
242
  Optional database URL to use, by way of override.
247
-
248
243
  alembic_base_dir:
249
244
  directory to start in, so relative paths in the config file work
250
-
251
245
  starting_revision:
252
246
  revision to start at (typically ``None`` to ask the database)
253
-
254
247
  destination_revision:
255
248
  revision to aim for
256
-
257
- version_table: table name for Alembic versions
258
-
249
+ version_table:
250
+ table name for Alembic versions
259
251
  as_sql:
260
252
  run in "offline" mode: print the migration SQL, rather than
261
253
  modifying the database. See
262
254
  https://alembic.zzzcomputing.com/en/latest/offline.html
263
-
264
255
  """
265
256
 
266
257
  if alembic_base_dir is None:
267
258
  alembic_base_dir = os.path.dirname(alembic_config_filename)
268
259
  os.chdir(alembic_base_dir) # so the directory in the config file works
269
- config = Config(alembic_config_filename)
260
+ alembic_cfg = AlembicConfig(alembic_config_filename)
270
261
  if db_url:
271
- config.set_main_option("sqlalchemy.url", db_url)
272
- script = ScriptDirectory.from_config(config)
262
+ alembic_cfg.set_main_option("sqlalchemy.url", db_url)
263
+ script = ScriptDirectory.from_config(alembic_cfg)
273
264
 
274
265
  # noinspection PyUnusedLocal,PyProtectedMember
275
266
  def downgrade(rev, context):
276
267
  return script._downgrade_revs(destination_revision, rev)
277
268
 
278
269
  log.info(
279
- "Downgrading database to revision {!r} using Alembic",
280
- destination_revision,
270
+ f"Downgrading database to revision {destination_revision!r} "
271
+ f"using Alembic"
281
272
  )
282
273
 
283
274
  with EnvironmentContext(
284
- config,
275
+ alembic_cfg,
285
276
  script,
286
277
  fn=downgrade,
287
278
  as_sql=as_sql,
@@ -301,6 +292,7 @@ def create_database_migration_numbered_style(
301
292
  alembic_versions_dir: str,
302
293
  message: str,
303
294
  n_sequence_chars: int = 4,
295
+ db_url: str = None,
304
296
  ) -> None:
305
297
  """
306
298
  Create a new Alembic migration script.
@@ -331,26 +323,34 @@ def create_database_migration_numbered_style(
331
323
 
332
324
  See https://alembic.zzzcomputing.com/en/latest/autogenerate.html.
333
325
 
334
- Regarding filenames: the default ``n_sequence_chars`` of 4 is like Django
335
- and gives files with names like
326
+ Regarding filenames: the default ``n_sequence_chars`` of 4 is like Django
327
+ and gives files with names like
336
328
 
337
- .. code-block:: none
329
+ .. code-block:: none
338
330
 
339
- 0001_x.py, 0002_y.py, ...
331
+ 0001_x.py, 0002_y.py, ...
340
332
 
341
- NOTE THAT TO USE A NON-STANDARD ALEMBIC VERSION TABLE, YOU MUST SPECIFY
342
- THAT IN YOUR ``env.py`` (see e.g. CamCOPS).
333
+ NOTE THAT TO USE A NON-STANDARD ALEMBIC VERSION TABLE, YOU MUST SPECIFY
334
+ THAT IN YOUR ``env.py`` (see e.g. CamCOPS).
343
335
 
344
- Args:
345
- alembic_ini_file: filename of Alembic ``alembic.ini`` file
346
- alembic_versions_dir: directory in which you keep your Python scripts,
347
- one per Alembic revision
348
- message: message to be associated with this revision
349
- n_sequence_chars: number of numerical sequence characters to use in the
350
- filename/revision (see above).
336
+ Args:
337
+ alembic_ini_file:
338
+ filename (full path) of Alembic ``alembic.ini`` file
339
+ alembic_versions_dir:
340
+ directory in which you keep your Python scripts, one per Alembic
341
+ revision
342
+ message:
343
+ message to be associated with this revision
344
+ n_sequence_chars:
345
+ number of numerical sequence characters to use in the
346
+ filename/revision (see above).
347
+ db_url:
348
+ Optional database URL to use, by way of override. We achieve this
349
+ via a temporary config file; not ideal.
351
350
  """ # noqa: E501
352
- file_regex = r"\d{" + str(n_sequence_chars) + r"}_\S*\.py$"
353
351
 
352
+ # Calculate current_seq_str, new_seq_str:
353
+ file_regex = r"\d{" + str(n_sequence_chars) + r"}_\S*\.py$"
354
354
  _, _, existing_version_filenames = next(
355
355
  os.walk(alembic_versions_dir), (None, None, [])
356
356
  )
@@ -358,8 +358,8 @@ def create_database_migration_numbered_style(
358
358
  x for x in existing_version_filenames if re.match(file_regex, x)
359
359
  ]
360
360
  log.debug(
361
- "Existing Alembic version script filenames: {!r}",
362
- existing_version_filenames,
361
+ f"Existing Alembic version script filenames: "
362
+ f"{existing_version_filenames!r}"
363
363
  )
364
364
  current_seq_strs = [
365
365
  x[:n_sequence_chars] for x in existing_version_filenames
@@ -374,37 +374,29 @@ def create_database_migration_numbered_style(
374
374
  new_seq_str = str(new_seq_no).zfill(n_sequence_chars)
375
375
 
376
376
  log.info(
377
- """
378
- Generating new revision with Alembic...
379
- Last revision was: {}
380
- New revision will be: {}
381
- [If it fails with "Can't locate revision identified by...", you might need
382
- to DROP the Alembic version table (by default named 'alembic_version', but
383
- you may have elected to change that in your env.py.]
384
- """,
385
- current_seq_str,
386
- new_seq_str,
377
+ f"Generating new revision with Alembic. "
378
+ f"Last revision was: {current_seq_str}. "
379
+ f"New revision will be: {new_seq_str}. "
380
+ f"(If the process fails with \"Can't locate revision identified "
381
+ f'by...", you might need to DROP the Alembic version table; by '
382
+ f"default that is named {DEFAULT_ALEMBIC_VERSION_TABLE!r}, but you "
383
+ f"may have elected to change that in your 'env.py' file.)"
387
384
  )
388
385
 
389
386
  alembic_ini_dir = os.path.dirname(alembic_ini_file)
390
387
  os.chdir(alembic_ini_dir)
391
- cmdargs = [
392
- "alembic",
393
- "-c",
394
- alembic_ini_file,
395
- "revision",
396
- "--autogenerate",
397
- "-m",
398
- message,
399
- "--rev-id",
400
- new_seq_str,
401
- ]
402
- log.info("From directory {!r}, calling: {!r}", alembic_ini_dir, cmdargs)
403
- subprocess.call(cmdargs)
388
+
389
+ # https://github.com/sqlalchemy/alembic/discussions/1089
390
+ namespace = CommandLine().parser.parse_args(["revision", "--autogenerate"])
391
+ config = AlembicConfig(alembic_ini_file, cmd_opts=namespace)
392
+ if db_url:
393
+ config.set_main_option("sqlalchemy.url", db_url)
394
+
395
+ mk_revision(config, message=message, autogenerate=True, rev_id=new_seq_str)
404
396
 
405
397
 
406
398
  def stamp_allowing_unusual_version_table(
407
- config: Config,
399
+ config: AlembicConfig,
408
400
  revision: str,
409
401
  sql: bool = False,
410
402
  tag: str = None,
@@ -417,8 +417,18 @@ def execute_ddl(
417
417
  if sql:
418
418
  ddl = DDL(sql)
419
419
  with engine.connect() as connection:
420
- # DDL doesn't need a COMMIT.
421
420
  connection.execute(ddl)
421
+ # DDL may need a commit for some dialects:
422
+ #
423
+ # Generic (but generic may not be useful)
424
+ # https://stackoverflow.com/questions/730621/do-ddl-statements-always-give-you-an-implicit-commit-or-can-you-get-an-implicit
425
+ # Oracle - autocommitted?
426
+ # https://docs.oracle.com/cd/A97335_02/apps.102/a83723/keyprog6.htm
427
+ # but not Postgres?
428
+ # https://dba.stackexchange.com/questions/340916/why-must-i-commit-after-the-alter-table-ddl-to-make-changes-visible
429
+ # and in SQL Server they are "batched" so not entirely autocommitted
430
+ # https://www.mssqltips.com/sqlservertip/4591/ddl-commands-in-transactions-in-sql-server-versus-oracle/
431
+ connection.commit()
422
432
 
423
433
 
424
434
  # =============================================================================
@@ -31,5 +31,5 @@ For changelog, see changelog.rst
31
31
 
32
32
  """
33
33
 
34
- VERSION_STRING = "2.0.2"
34
+ VERSION_STRING = "2.0.4"
35
35
  # Use semantic versioning: https://semver.org/
@@ -1,13 +1,12 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cardinal-pythonlib
3
- Version: 2.0.2
3
+ Version: 2.0.4
4
4
  Summary: Miscellaneous Python libraries
5
5
  Home-page: https://github.com/RudolfCardinal/pythonlib
6
6
  Author: Rudolf Cardinal
7
7
  Author-email: rudolf@pobox.com
8
8
  License: Apache License 2.0
9
9
  Keywords: cardinal
10
- Platform: UNKNOWN
11
10
  Classifier: Development Status :: 4 - Beta
12
11
  Classifier: Intended Audience :: Developers
13
12
  Classifier: License :: OSI Approved :: Apache Software License
@@ -43,5 +42,3 @@ By Rudolf Cardinal (rudolf@pobox.com)
43
42
  Install with ``pip install cardinal_pythonlib``.
44
43
 
45
44
  Documentation is at https://cardinalpythonlib.readthedocs.io/.
46
-
47
-
@@ -16,4 +16,3 @@ cardinalpythonlib_merge_csv = cardinal_pythonlib.tools.merge_csv:main
16
16
  cardinalpythonlib_pause_process_by_disk_space = cardinal_pythonlib.openxml.pause_process_by_disk_space:main
17
17
  cardinalpythonlib_pdf_to_booklet = cardinal_pythonlib.tools.pdf_to_booklet:main
18
18
  cardinalpythonlib_remove_duplicate_files = cardinal_pythonlib.tools.remove_duplicate_files:main
19
-
@@ -1,4 +1,3 @@
1
- SQLAlchemy<3.0,>=1.4
2
1
  alembic
3
2
  appdirs>=1.4.0
4
3
  arrow>=0.15
@@ -10,8 +9,8 @@ numba
10
9
  numpy<2.0,>=1.20.0
11
10
  openpyxl
12
11
  pandas
13
- pdfminer.six>=20191010
14
12
  pendulum>=2.1.1
13
+ pdfminer.six>=20191010
15
14
  prettytable
16
15
  psutil
17
16
  pygments
@@ -21,5 +20,6 @@ python-dateutil
21
20
  rich-argparse>=0.5.0
22
21
  scipy
23
22
  semantic-version
23
+ SQLAlchemy<3.0,>=1.4
24
24
  sqlparse
25
25
  xlrd>=2.0.0