cardinal-pythonlib 2.0.4__tar.gz → 2.1.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 (203) hide show
  1. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/PKG-INFO +1 -1
  2. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/bulk_email/main.py +1 -1
  3. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/bulk_email/models.py +1 -1
  4. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/django/fields/jsonclassfield.py +1 -1
  5. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/django/function_cache.py +1 -1
  6. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/django/middleware.py +5 -5
  7. {cardinal_pythonlib-2.0.4/cardinal_pythonlib/email → cardinal_pythonlib-2.1.0/cardinal_pythonlib/email_utils}/__init__.py +1 -1
  8. {cardinal_pythonlib-2.0.4/cardinal_pythonlib/email → cardinal_pythonlib-2.1.0/cardinal_pythonlib/email_utils}/mailboxpurge.py +1 -1
  9. {cardinal_pythonlib-2.0.4/cardinal_pythonlib/email → cardinal_pythonlib-2.1.0/cardinal_pythonlib/email_utils}/sendmail.py +1 -1
  10. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/extract_text.py +110 -18
  11. {cardinal_pythonlib-2.0.4/cardinal_pythonlib/json → cardinal_pythonlib-2.1.0/cardinal_pythonlib/json_utils}/__init__.py +1 -1
  12. {cardinal_pythonlib-2.0.4/cardinal_pythonlib/json → cardinal_pythonlib-2.1.0/cardinal_pythonlib/json_utils}/serialize.py +2 -2
  13. {cardinal_pythonlib-2.0.4/cardinal_pythonlib/json → cardinal_pythonlib-2.1.0/cardinal_pythonlib/json_utils}/typing_helpers.py +1 -1
  14. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/module_version.py +0 -3
  15. cardinal_pythonlib-2.0.4/cardinal_pythonlib/profile.py → cardinal_pythonlib-2.1.0/cardinal_pythonlib/profiling.py +1 -1
  16. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/sizeformatter.py +1 -1
  17. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/sqlalchemy/dialect.py +1 -1
  18. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/sqlalchemy/schema.py +1 -0
  19. cardinal_pythonlib-2.1.0/cardinal_pythonlib/tests/__init__.py +27 -0
  20. cardinal_pythonlib-2.1.0/cardinal_pythonlib/tests/datetimefunc_tests.py +485 -0
  21. cardinal_pythonlib-2.1.0/cardinal_pythonlib/tests/dogpile_cache_tests.py +727 -0
  22. cardinal_pythonlib-2.1.0/cardinal_pythonlib/tests/extract_text_tests.py +588 -0
  23. cardinal_pythonlib-2.1.0/cardinal_pythonlib/tests/interval_tests.py +58 -0
  24. cardinal_pythonlib-2.1.0/cardinal_pythonlib/tests/lists_tests.py +45 -0
  25. cardinal_pythonlib-2.1.0/cardinal_pythonlib/tests/pdf_tests.py +215 -0
  26. cardinal_pythonlib-2.1.0/cardinal_pythonlib/tests/rate_limiting_tests.py +71 -0
  27. cardinal_pythonlib-2.1.0/cardinal_pythonlib/tests/rounding_tests.py +250 -0
  28. cardinal_pythonlib-2.1.0/cardinal_pythonlib/tests/rpm_tests.py +193 -0
  29. cardinal_pythonlib-2.1.0/cardinal_pythonlib/tests/sphinxtools_tests.py +81 -0
  30. cardinal_pythonlib-2.1.0/cardinal_pythonlib/tests/spreadsheets_tests.py +51 -0
  31. cardinal_pythonlib-2.1.0/cardinal_pythonlib/tests/subprocess_tests.py +52 -0
  32. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/tools/convert_mdb_to_mysql.py +2 -2
  33. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/tools/explore_clang_format_config.py +5 -1
  34. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/version_string.py +1 -1
  35. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib.egg-info/PKG-INFO +1 -1
  36. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib.egg-info/SOURCES.txt +20 -8
  37. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib.egg-info/entry_points.txt +1 -1
  38. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/setup.cfg +4 -1
  39. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/setup.py +2 -2
  40. cardinal_pythonlib-2.0.4/cardinal_pythonlib/ensure_test_executed_correctly.py +0 -40
  41. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/LICENSE +0 -0
  42. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/README.rst +0 -0
  43. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/__init__.py +0 -0
  44. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/argparse_func.py +0 -0
  45. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/athena_ohdsi.py +0 -0
  46. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/betweendict.py +0 -0
  47. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/buildfunc.py +0 -0
  48. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/bulk_email/__init__.py +0 -0
  49. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/bulk_email/constants.py +0 -0
  50. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/chebi.py +0 -0
  51. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/classes.py +0 -0
  52. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/cmdline.py +0 -0
  53. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/colander_utils.py +0 -0
  54. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/compression.py +0 -0
  55. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/configfiles.py +0 -0
  56. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/contexts.py +0 -0
  57. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/convert.py +0 -0
  58. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/crypto.py +0 -0
  59. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/datamapping.py +0 -0
  60. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/datetimefunc.py +0 -0
  61. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/dbfunc.py +0 -0
  62. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/debugging.py +0 -0
  63. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/deform_utils.py +0 -0
  64. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/dicts.py +0 -0
  65. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/django/__init__.py +0 -0
  66. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/django/admin.py +0 -0
  67. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/django/django_constants.py +0 -0
  68. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/django/fields/__init__.py +0 -0
  69. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/django/fields/helpers.py +0 -0
  70. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/django/fields/isodatetimetz.py +0 -0
  71. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/django/fields/restrictedcontentfile.py +0 -0
  72. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/django/files.py +0 -0
  73. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/django/forms.py +0 -0
  74. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/django/mail.py +0 -0
  75. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/django/reprfunc.py +0 -0
  76. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/django/request_cache.py +0 -0
  77. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/django/serve.py +0 -0
  78. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/django/tools/__init__.py +0 -0
  79. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/django/tools/generate_new_django_secret_key.py +0 -0
  80. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/docker.py +0 -0
  81. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/dogpile_cache.py +0 -0
  82. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/dsp.py +0 -0
  83. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/enumlike.py +0 -0
  84. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/excel.py +0 -0
  85. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/exceptions.py +0 -0
  86. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/file_io.py +0 -0
  87. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/fileops.py +0 -0
  88. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/formatting.py +0 -0
  89. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/getch.py +0 -0
  90. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/hash.py +0 -0
  91. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/httpconst.py +0 -0
  92. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/interval.py +0 -0
  93. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/iterhelp.py +0 -0
  94. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/lang.py +0 -0
  95. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/lists.py +0 -0
  96. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/logs.py +0 -0
  97. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/maths_numpy.py +0 -0
  98. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/maths_py.py +0 -0
  99. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/metaclasses.py +0 -0
  100. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/modules.py +0 -0
  101. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/network.py +0 -0
  102. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/nhs.py +0 -0
  103. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/openxml/__init__.py +0 -0
  104. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/openxml/find_bad_openxml.py +0 -0
  105. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/openxml/find_recovered_openxml.py +0 -0
  106. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/openxml/grep_in_openxml.py +0 -0
  107. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/openxml/pause_process_by_disk_space.py +0 -0
  108. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/parallel.py +0 -0
  109. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/pdf.py +0 -0
  110. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/platformfunc.py +0 -0
  111. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/plot.py +0 -0
  112. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/probability.py +0 -0
  113. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/process.py +0 -0
  114. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/progress.py +0 -0
  115. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/psychiatry/__init__.py +0 -0
  116. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/psychiatry/drugs.py +0 -0
  117. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/psychiatry/mk_r_druglists.py +0 -0
  118. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/psychiatry/rfunc.py +0 -0
  119. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/psychiatry/simhelpers.py +0 -0
  120. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/psychiatry/timeline.py +0 -0
  121. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/psychiatry/treatment_resistant_depression.py +0 -0
  122. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/pyramid/__init__.py +0 -0
  123. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/pyramid/compression.py +0 -0
  124. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/pyramid/constants.py +0 -0
  125. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/pyramid/requests.py +0 -0
  126. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/pyramid/responses.py +0 -0
  127. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/randomness.py +0 -0
  128. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/rate_limiting.py +0 -0
  129. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/regexfunc.py +0 -0
  130. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/register_db_with_odbc.py +0 -0
  131. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/reprfunc.py +0 -0
  132. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/rnc_text.py +0 -0
  133. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/rnc_web.py +0 -0
  134. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/rounding.py +0 -0
  135. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/rpm.py +0 -0
  136. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/run_all_tests.py +0 -0
  137. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/signalfunc.py +0 -0
  138. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/slurm.py +0 -0
  139. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/snomed.py +0 -0
  140. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/sort.py +0 -0
  141. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/source_reformatting.py +0 -0
  142. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/sphinxtools.py +0 -0
  143. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/spreadsheets.py +0 -0
  144. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/sql/__init__.py +0 -0
  145. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/sql/literals.py +0 -0
  146. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/sql/sql_grammar.py +0 -0
  147. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/sql/sql_grammar_factory.py +0 -0
  148. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/sql/sql_grammar_mssql.py +0 -0
  149. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/sql/sql_grammar_mysql.py +0 -0
  150. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/sql/validation.py +0 -0
  151. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/sqlalchemy/__init__.py +0 -0
  152. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/sqlalchemy/alembic_func.py +0 -0
  153. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/sqlalchemy/alembic_ops.py +0 -0
  154. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/sqlalchemy/arrow_types.py +0 -0
  155. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/sqlalchemy/core_query.py +0 -0
  156. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/sqlalchemy/dump.py +0 -0
  157. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/sqlalchemy/engine_func.py +0 -0
  158. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/sqlalchemy/insert_on_duplicate.py +0 -0
  159. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/sqlalchemy/list_types.py +0 -0
  160. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/sqlalchemy/logs.py +0 -0
  161. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/sqlalchemy/merge_db.py +0 -0
  162. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/sqlalchemy/orm_inspect.py +0 -0
  163. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/sqlalchemy/orm_query.py +0 -0
  164. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/sqlalchemy/orm_schema.py +0 -0
  165. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/sqlalchemy/semantic_version_coltype.py +0 -0
  166. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/sqlalchemy/session.py +0 -0
  167. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/sqlalchemy/sqla_version.py +0 -0
  168. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/sqlalchemy/sqlfunc.py +0 -0
  169. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/sqlalchemy/sqlserver.py +0 -0
  170. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/sqlalchemy/table_identity.py +0 -0
  171. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/stringfunc.py +0 -0
  172. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/subproc.py +0 -0
  173. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/sysops.py +0 -0
  174. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/tcpipconst.py +0 -0
  175. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/tee.py +0 -0
  176. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/text.py +0 -0
  177. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/timing.py +0 -0
  178. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/tools/__init__.py +0 -0
  179. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/tools/backup_mysql_database.py +0 -0
  180. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/tools/convert_athena_ohdsi_codes.py +0 -0
  181. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/tools/estimate_mysql_memory_usage.py +0 -0
  182. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/tools/list_all_file_extensions.py +0 -0
  183. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/tools/merge_csv.py +0 -0
  184. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/tools/pdf_to_booklet.py +0 -0
  185. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/tools/remove_duplicate_files.py +0 -0
  186. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/tsv.py +0 -0
  187. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/typetests.py +0 -0
  188. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/typing_helpers.py +0 -0
  189. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/ui.py +0 -0
  190. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/ui_commandline.py +0 -0
  191. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/uriconst.py +0 -0
  192. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/version.py +0 -0
  193. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/winservice.py +0 -0
  194. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/wsgi/__init__.py +0 -0
  195. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/wsgi/cache_mw.py +0 -0
  196. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/wsgi/constants.py +0 -0
  197. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/wsgi/errorreporter_mw.py +0 -0
  198. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/wsgi/headers_mw.py +0 -0
  199. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/wsgi/request_logging_mw.py +0 -0
  200. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib/wsgi/reverse_proxied_mw.py +0 -0
  201. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib.egg-info/dependency_links.txt +0 -0
  202. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib.egg-info/requires.txt +0 -0
  203. {cardinal_pythonlib-2.0.4 → cardinal_pythonlib-2.1.0}/cardinal_pythonlib.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cardinal_pythonlib
3
- Version: 2.0.4
3
+ Version: 2.1.0
4
4
  Summary: Miscellaneous Python libraries
5
5
  Home-page: https://github.com/RudolfCardinal/pythonlib
6
6
  Author: Rudolf Cardinal
@@ -57,7 +57,7 @@ from cardinal_pythonlib.bulk_email.models import (
57
57
  Recipient,
58
58
  SendAttempt,
59
59
  )
60
- from cardinal_pythonlib.email.sendmail import (
60
+ from cardinal_pythonlib.email_utils.sendmail import (
61
61
  CONTENT_TYPE_HTML,
62
62
  CONTENT_TYPE_TEXT,
63
63
  is_email_valid,
@@ -63,7 +63,7 @@ from cardinal_pythonlib.bulk_email.constants import (
63
63
  USERNAME_MAX_LENGTH,
64
64
  )
65
65
  from cardinal_pythonlib.colander_utils import EMAIL_ADDRESS_MAX_LEN
66
- from cardinal_pythonlib.email.sendmail import (
66
+ from cardinal_pythonlib.email_utils.sendmail import (
67
67
  ASCII,
68
68
  CONTENT_TYPE_TEXT,
69
69
  is_email_valid,
@@ -130,7 +130,7 @@ from django.core.exceptions import ValidationError
130
130
  # noinspection PyUnresolvedReferences
131
131
  from django.db.models import TextField
132
132
 
133
- from cardinal_pythonlib.json.serialize import json_decode, json_encode
133
+ from cardinal_pythonlib.json_utils.serialize import json_decode, json_encode
134
134
 
135
135
 
136
136
  # =============================================================================
@@ -36,7 +36,7 @@ from typing import Any, Callable, Dict, Tuple
36
36
  from django.core.cache import cache # default cache
37
37
 
38
38
  from cardinal_pythonlib.logs import get_brace_style_log_with_null_handler
39
- from cardinal_pythonlib.json.serialize import json_encode
39
+ from cardinal_pythonlib.json_utils.serialize import json_encode
40
40
 
41
41
  log = get_brace_style_log_with_null_handler(__name__)
42
42
 
@@ -28,7 +28,7 @@
28
28
 
29
29
  import logging
30
30
  import os
31
- from re import compile
31
+ import re
32
32
  import sys
33
33
  from typing import Optional
34
34
 
@@ -107,9 +107,9 @@ https://onecreativeblog.com/post/59051248/django-login-required-middleware
107
107
  Modified according to: https://djangosnippets.org/snippets/2845/
108
108
  """
109
109
 
110
- # EXEMPT_URLS = [compile(settings.LOGIN_URL.lstrip('/'))]
110
+ # EXEMPT_URLS = [re.compile(settings.LOGIN_URL.lstrip('/'))]
111
111
  # if hasattr(settings, 'LOGIN_EXEMPT_URLS'):
112
- # EXEMPT_URLS += [compile(expr) for expr in settings.LOGIN_EXEMPT_URLS]
112
+ # EXEMPT_URLS += [re.compile(expr) for expr in settings.LOGIN_EXEMPT_URLS]
113
113
  #
114
114
  #
115
115
  # class LoginRequiredMiddleware:
@@ -166,10 +166,10 @@ Modified according to: https://djangosnippets.org/snippets/2845/
166
166
  # 3. RNC; composite of those patterns.
167
167
  # -----------------------------------------------------------------------------
168
168
 
169
- EXEMPT_URLS = [compile(settings.LOGIN_URL.lstrip("/"))]
169
+ EXEMPT_URLS = [re.compile(settings.LOGIN_URL.lstrip("/"))]
170
170
  if hasattr(settings, "LOGIN_EXEMPT_URLS"):
171
171
  EXEMPT_URLS += [
172
- compile(expr.lstrip("/")) for expr in settings.LOGIN_EXEMPT_URLS
172
+ re.compile(expr.lstrip("/")) for expr in settings.LOGIN_EXEMPT_URLS
173
173
  ]
174
174
 
175
175
 
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env python
2
- # cardinal_pythonlib/email/__init__.py
2
+ # cardinal_pythonlib/email_utils/__init__.py
3
3
 
4
4
  """
5
5
  ===============================================================================
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env python
2
- # cardinal_pythonlib/email/mailboxpurge.py
2
+ # cardinal_pythonlib/email_utils/mailboxpurge.py
3
3
 
4
4
  """
5
5
  Remove all binary attachments from email messages
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env python
2
- # cardinal_pythonlib/email/sendmail.py
2
+ # cardinal_pythonlib/email_utils/sendmail.py
3
3
 
4
4
  """
5
5
  ===============================================================================
@@ -77,9 +77,14 @@ See also:
77
77
  # =============================================================================
78
78
 
79
79
  import argparse
80
+ import base64
81
+ from email import policy
82
+ from email.message import EmailMessage
83
+ from email.parser import BytesParser
80
84
  from io import StringIO
81
85
  import io
82
86
  import logging
87
+ from mimetypes import guess_extension
83
88
  import os
84
89
  import re
85
90
  import shutil
@@ -87,6 +92,7 @@ import subprocess
87
92
  import sys
88
93
  import textwrap
89
94
  from typing import (
95
+ Any,
90
96
  BinaryIO,
91
97
  Dict,
92
98
  Generator,
@@ -205,9 +211,9 @@ class TextProcessingConfig(object):
205
211
  plain: bool = False,
206
212
  semiplain: bool = False,
207
213
  docx_in_order: bool = True,
208
- horizontal_char="─",
209
- vertical_char="│",
210
- junction_char="┼",
214
+ horizontal_char: str = "─",
215
+ vertical_char: str = "│",
216
+ junction_char: str = "┼",
211
217
  plain_table_start: str = None,
212
218
  plain_table_end: str = None,
213
219
  plain_table_col_boundary: str = None,
@@ -352,7 +358,7 @@ def get_filelikeobject(filename: str = None, blob: bytes = None) -> BinaryIO:
352
358
  Returns:
353
359
  a :class:`BinaryIO` object
354
360
  """
355
- if not filename and not blob:
361
+ if not filename and blob is None:
356
362
  raise ValueError("no filename and no blob")
357
363
  if filename and blob:
358
364
  raise ValueError("specify either filename or blob")
@@ -367,11 +373,11 @@ def get_file_contents(filename: str = None, blob: bytes = None) -> bytes:
367
373
  """
368
374
  Returns the binary contents of a file, or of a BLOB.
369
375
  """
370
- if not filename and not blob:
376
+ if filename is None and blob is None:
371
377
  raise ValueError("no filename and no blob")
372
378
  if filename and blob:
373
379
  raise ValueError("specify either filename or blob")
374
- if blob:
380
+ if blob is not None:
375
381
  return blob
376
382
  with open(filename, "rb") as f:
377
383
  return f.read()
@@ -445,7 +451,7 @@ def get_file_contents_text(
445
451
  )
446
452
 
447
453
 
448
- def get_cmd_output(*args, encoding: str = SYS_ENCODING) -> str:
454
+ def get_cmd_output(*args: Any, encoding: str = SYS_ENCODING) -> str:
449
455
  """
450
456
  Returns text output of a command.
451
457
  """
@@ -456,7 +462,7 @@ def get_cmd_output(*args, encoding: str = SYS_ENCODING) -> str:
456
462
 
457
463
 
458
464
  def get_cmd_output_from_stdin(
459
- stdint_content_binary: bytes, *args, encoding: str = SYS_ENCODING
465
+ stdint_content_binary: bytes, *args: Any, encoding: str = SYS_ENCODING
460
466
  ) -> str:
461
467
  """
462
468
  Returns text output of a command, passing binary data in via stdin.
@@ -549,17 +555,17 @@ def availability_pdf() -> bool:
549
555
  # -----------------------------------------------------------------------------
550
556
  # In a D.I.Y. fashion
551
557
  # -----------------------------------------------------------------------------
552
- # DOCX specification: http://www.ecma-international.org/news/TC45_current_work/TC45_available_docs.htm # noqa: E501
558
+ # DOCX specification: https://ecma-international.org/publications-and-standards/standards/ecma-376/ # noqa: E501
553
559
 
554
560
  DOCX_HEADER_FILE_REGEX = re.compile("word/header[0-9]*.xml")
555
- DOCX_DOC_FILE = "word/document.xml"
561
+ DOCX_DOCUMENT_FILE_REGEX = re.compile("word/document[0-9]*.xml")
556
562
  DOCX_FOOTER_FILE_REGEX = re.compile("word/footer[0-9]*.xml")
557
563
  DOCX_SCHEMA_URL = (
558
564
  "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
559
565
  )
560
566
 
561
567
 
562
- def docx_qn(tagroot):
568
+ def docx_qn(tagroot: str) -> str:
563
569
  return f"{{{DOCX_SCHEMA_URL}}}{tagroot}"
564
570
 
565
571
 
@@ -595,7 +601,9 @@ def gen_xml_files_from_docx(fp: BinaryIO) -> Iterator[str]:
595
601
  for filename in filelist:
596
602
  if DOCX_HEADER_FILE_REGEX.match(filename):
597
603
  yield z.read(filename).decode("utf8")
598
- yield z.read(DOCX_DOC_FILE)
604
+ for filename in filelist:
605
+ if DOCX_DOCUMENT_FILE_REGEX.match(filename):
606
+ yield z.read(filename).decode("utf8")
599
607
  for filename in filelist:
600
608
  if DOCX_FOOTER_FILE_REGEX.match(filename):
601
609
  yield z.read(filename).decode("utf8")
@@ -624,7 +632,7 @@ def docx_gen_wordwrapped_fragments(
624
632
  """
625
633
  to_wrap = [] # type: List[DocxFragment]
626
634
 
627
- def yield_wrapped():
635
+ def yield_wrapped() -> Generator[str, None, None]:
628
636
  """
629
637
  Yield the word-wrapped stuff to date.
630
638
  """
@@ -1132,9 +1140,24 @@ def convert_html_to_text(
1132
1140
  """
1133
1141
  Converts HTML to text.
1134
1142
  """
1143
+
1144
+ # https://bugs.launchpad.net/beautifulsoup/+bug/2110492
1145
+ # beautifulsoup4==4.13.4 returns "b''" for an empty bytes array
1146
+ # So we just workaround this here:
1147
+ if bytes is not None and len(blob) == 0:
1148
+ return ""
1149
+
1135
1150
  with get_filelikeobject(filename, blob) as fp:
1136
- soup = bs4.BeautifulSoup(fp)
1137
- return soup.get_text()
1151
+ soup = bs4.BeautifulSoup(fp, "html.parser")
1152
+
1153
+ # In the real world we can end up with UTF-16 characters embedded as
1154
+ # numbered entities in Windows-1252 encoded HTML such as
1155
+ # �� "Slightly smiling face". Replacing these here
1156
+ # avoids "UnicodeEncodeError: 'utf-8' codec can't encode characters in
1157
+ # position ... surrogates not allowed".
1158
+ text = soup.get_text().encode(errors="replace").decode()
1159
+
1160
+ return text
1138
1161
 
1139
1162
 
1140
1163
  # =============================================================================
@@ -1152,7 +1175,7 @@ def convert_xml_to_text(
1152
1175
  Converts XML to text.
1153
1176
  """
1154
1177
  with get_filelikeobject(filename, blob) as fp:
1155
- soup = bs4.BeautifulStoneSoup(fp)
1178
+ soup = bs4.BeautifulSoup(fp, features="xml")
1156
1179
  return soup.get_text()
1157
1180
 
1158
1181
 
@@ -1229,6 +1252,74 @@ def availability_doc() -> bool:
1229
1252
  return bool(antiword)
1230
1253
 
1231
1254
 
1255
+ # =============================================================================
1256
+ # EML
1257
+ # =============================================================================
1258
+
1259
+
1260
+ def convert_eml_to_text(
1261
+ filename: str = None,
1262
+ blob: bytes = None,
1263
+ config: TextProcessingConfig = _DEFAULT_CONFIG,
1264
+ ) -> str:
1265
+ email_content_list: list[str] = []
1266
+
1267
+ with get_filelikeobject(filename, blob) as fp:
1268
+ parser = BytesParser(policy=policy.default) # type: ignore[arg-type]
1269
+ message = parser.parse(fp)
1270
+
1271
+ for email_content in _gen_email_content(message, config):
1272
+ if email_content is not None:
1273
+ email_content_list.append(email_content)
1274
+
1275
+ text = "\n".join(email_content_list)
1276
+
1277
+ return text
1278
+
1279
+
1280
+ def _gen_email_content(
1281
+ message: EmailMessage, config: TextProcessingConfig
1282
+ ) -> Generator[Optional[str], None, None]:
1283
+ body = message.get_body(
1284
+ preferencelist=(
1285
+ "html",
1286
+ "plain",
1287
+ )
1288
+ ) # type: ignore[attr-defined]
1289
+ if body is not None:
1290
+ yield _get_email_content(body, config)
1291
+
1292
+ for part in message.iter_attachments(): # type: ignore[attr-defined]
1293
+ yield _get_email_content(part, config)
1294
+
1295
+
1296
+ def _get_email_content(
1297
+ message: EmailMessage,
1298
+ config: TextProcessingConfig,
1299
+ ) -> Optional[str]:
1300
+ content_type = message.get_content_type()
1301
+ ext = guess_extension(content_type)
1302
+
1303
+ if ext is not None and ext in ext_map:
1304
+ content = message.get_content()
1305
+ if isinstance(content, str):
1306
+ charset = "utf-8"
1307
+ content_type_header = message.get("Content-Type")
1308
+ if content_type_header:
1309
+ charset = content_type_header.params.get("charset", "utf-8")
1310
+ blob = content.encode(charset, "replace")
1311
+ elif isinstance(content, EmailMessage):
1312
+ blob = content.as_bytes()
1313
+ if message.get("Content-Transfer-Encoding") == "base64":
1314
+ blob = base64.b64decode(blob)
1315
+ else:
1316
+ blob = content
1317
+
1318
+ return document_to_text(blob=blob, extension=ext, config=config)
1319
+
1320
+ return None
1321
+
1322
+
1232
1323
  # =============================================================================
1233
1324
  # Anything
1234
1325
  # =============================================================================
@@ -1267,7 +1358,7 @@ def availability_anything() -> bool:
1267
1358
  # Decider
1268
1359
  # =============================================================================
1269
1360
 
1270
- ext_map = {
1361
+ ext_map: dict[str, dict[str, Any]] = {
1271
1362
  # Converter functions must be of the form: func(filename, blob, config).
1272
1363
  # Availability must be either a boolean literal or a function that takes no
1273
1364
  # params.
@@ -1276,6 +1367,7 @@ ext_map = {
1276
1367
  ".docm": {CONVERTER: convert_docx_to_text, AVAILABILITY: True},
1277
1368
  ".docx": {CONVERTER: convert_docx_to_text, AVAILABILITY: True},
1278
1369
  ".dot": {CONVERTER: convert_doc_to_text, AVAILABILITY: availability_doc},
1370
+ ".eml": {CONVERTER: convert_eml_to_text, AVAILABILITY: True},
1279
1371
  ".htm": {CONVERTER: convert_html_to_text, AVAILABILITY: True},
1280
1372
  ".html": {CONVERTER: convert_html_to_text, AVAILABILITY: True},
1281
1373
  ".log": {CONVERTER: get_file_contents_text, AVAILABILITY: True},
@@ -1333,7 +1425,7 @@ def document_to_text(
1333
1425
  Raises an exception for malformed arguments, missing files, bad
1334
1426
  filetypes, etc.
1335
1427
  """
1336
- if not filename and not blob:
1428
+ if not filename and blob is None:
1337
1429
  raise ValueError("document_to_text: no filename and no blob")
1338
1430
  if filename and blob:
1339
1431
  raise ValueError("document_to_text: specify either filename or blob")
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env python
2
- # cardinal_pythonlib/json/__init__.py
2
+ # cardinal_pythonlib/json_utils/__init__.py
3
3
 
4
4
  """
5
5
  ===============================================================================
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env python
2
- # cardinal_pythonlib/json/serialize.py
2
+ # cardinal_pythonlib/json_utils/serialize.py
3
3
 
4
4
  """
5
5
  ===============================================================================
@@ -807,7 +807,7 @@ def dict_to_pendulumdate(
807
807
  # noinspection PyTypeChecker
808
808
  dt = pendulum.parse(d["iso"]) # type: pendulum.DateTime
809
809
  # noinspection PyTypeChecker
810
- return dt.date() # type: pendulum.Date
810
+ return dt.date()
811
811
 
812
812
 
813
813
  register_class_for_json(
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env python
2
- # cardinal_pythonlib/json/typing_helpers.py
2
+ # cardinal_pythonlib/json_utils/typing_helpers.py
3
3
 
4
4
  """
5
5
  ===============================================================================
@@ -39,9 +39,6 @@ from importlib.metadata import version # structure for Python 3.8 or higher
39
39
 
40
40
  from semantic_version import Version
41
41
 
42
- # noinspection PyUnresolvedReferences
43
- import cardinal_pythonlib.ensure_test_executed_correctly # noqa: F401
44
-
45
42
 
46
43
  # =============================================================================
47
44
  # Report Python module versions
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env python
2
- # cardinal_pythonlib/profile.py
2
+ # cardinal_pythonlib/profiling.py
3
3
 
4
4
  """
5
5
  ===============================================================================
@@ -69,7 +69,7 @@ SYMBOLS = {
69
69
 
70
70
  def bytes2human(
71
71
  n: Union[int, float],
72
- format: str = "%(value).1f %(symbol)s",
72
+ format: str = "%(value).1f %(symbol)s", # noqa: A002
73
73
  symbols: str = "customary",
74
74
  ) -> str:
75
75
  """
@@ -148,7 +148,7 @@ def get_preparer(
148
148
  """
149
149
  dialect = get_dialect(mixed)
150
150
  # noinspection PyUnresolvedReferences
151
- return dialect.preparer(dialect) # type: IdentifierPreparer
151
+ return dialect.preparer(dialect)
152
152
 
153
153
 
154
154
  def quote_identifier(
@@ -138,6 +138,7 @@ DATABRICKS_SQLCOLTYPE_TO_SQLALCHEMY_GENERIC = {
138
138
  "DECIMAL": Numeric,
139
139
  "SMALLINT": SmallInteger,
140
140
  "STRING": Text,
141
+ "VARCHAR": String,
141
142
  }
142
143
 
143
144
 
@@ -0,0 +1,27 @@
1
+ # cardinal_pythonlib/tests/__init__.py
2
+
3
+ """
4
+ ===============================================================================
5
+
6
+ Original code copyright (C) 2009-2022 Rudolf Cardinal (rudolf@pobox.com).
7
+
8
+ This file is part of cardinal_pythonlib.
9
+
10
+ Licensed under the Apache License, Version 2.0 (the "License");
11
+ you may not use this file except in compliance with the License.
12
+ You may obtain a copy of the License at
13
+
14
+ https://www.apache.org/licenses/LICENSE-2.0
15
+
16
+ Unless required by applicable law or agreed to in writing, software
17
+ distributed under the License is distributed on an "AS IS" BASIS,
18
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19
+ See the License for the specific language governing permissions and
20
+ limitations under the License.
21
+
22
+ ===============================================================================
23
+
24
+ The mere existence of this file makes Python treat the directory as a
25
+ package.
26
+
27
+ """