dipex 5.2.0__tar.gz → 5.3.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 (169) hide show
  1. {dipex-5.2.0 → dipex-5.3.0}/PKG-INFO +1 -1
  2. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/sdlon/config.py +3 -0
  3. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/sdlon/date_utils.py +2 -1
  4. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/sdlon/fix_departments.py +64 -80
  5. dipex-5.3.0/integrations/SD_Lon/sdlon/log.py +65 -0
  6. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/sdlon/main.py +2 -2
  7. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/sdlon/sd_changed_at.py +148 -148
  8. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/sdlon/sd_common.py +2 -2
  9. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/sdlon/sd_importer.py +5 -23
  10. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/sdlon/skip.py +2 -3
  11. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/sdlon/sync_job_id.py +3 -18
  12. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/tests/test_config.py +1 -0
  13. dipex-5.3.0/integrations/SD_Lon/tests/test_log.py +12 -0
  14. {dipex-5.2.0 → dipex-5.3.0}/pyproject.toml +1 -1
  15. {dipex-5.2.0 → dipex-5.3.0}/exporters/sql_export/__init__.py +0 -0
  16. {dipex-5.2.0 → dipex-5.3.0}/exporters/sql_export/gql_lora_cache_async.py +0 -0
  17. {dipex-5.2.0 → dipex-5.3.0}/exporters/sql_export/lc_for_jobs_db.py +0 -0
  18. {dipex-5.2.0 → dipex-5.3.0}/exporters/sql_export/lora_cache.py +0 -0
  19. {dipex-5.2.0 → dipex-5.3.0}/exporters/sql_export/lora_gql_equivalence_tester.py +0 -0
  20. {dipex-5.2.0 → dipex-5.3.0}/exporters/sql_export/main.py +0 -0
  21. {dipex-5.2.0 → dipex-5.3.0}/exporters/sql_export/old_lora_cache.py +0 -0
  22. {dipex-5.2.0 → dipex-5.3.0}/exporters/sql_export/sql_export.py +0 -0
  23. {dipex-5.2.0 → dipex-5.3.0}/exporters/sql_export/sql_table_defs.py +0 -0
  24. {dipex-5.2.0 → dipex-5.3.0}/exporters/sql_export/sql_url.py +0 -0
  25. {dipex-5.2.0 → dipex-5.3.0}/exporters/sql_export/trigger.py +0 -0
  26. {dipex-5.2.0 → dipex-5.3.0}/exporters/utils/priority_by_class.py +0 -0
  27. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/sdlon/__init__.py +0 -0
  28. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/sdlon/employees.py +0 -0
  29. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/sdlon/engagement.py +0 -0
  30. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/sdlon/exceptions.py +0 -0
  31. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/sdlon/graphql.py +0 -0
  32. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/sdlon/it_systems.py +0 -0
  33. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/sdlon/models.py +0 -0
  34. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/sdlon/scripts/__init__.py +0 -0
  35. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/sdlon/scripts/fix_monthly_hourly_divide.py +0 -0
  36. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/sdlon/scripts/fix_status8.py +0 -0
  37. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/sdlon/scripts/generate_org_unit_level_uuid.py +0 -0
  38. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/sdlon/sd_changed_at_redo.py +0 -0
  39. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/sdlon/sd_cli.py +0 -0
  40. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/sdlon/sd_fixup.py +0 -0
  41. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/sdlon/sd_log_analyzer.py +0 -0
  42. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/sdlon/sd_payloads.py +0 -0
  43. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/sdlon/sd_to_pydantic.py +0 -0
  44. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/sdlon/test_mo_against_sd.py +0 -0
  45. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/sdlon/test_sd_connectivity.py +0 -0
  46. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/sdtool/__init__.py +0 -0
  47. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/sdtool/config.py +0 -0
  48. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/sdtool/main.py +0 -0
  49. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/tests/__init__.py +0 -0
  50. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/tests/fixtures.py +0 -0
  51. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/tests/org_manipulations.py +0 -0
  52. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/tests/sdtool/__init__.py +0 -0
  53. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/tests/sdtool/test_app.py +0 -0
  54. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/tests/sdtool/test_config.py +0 -0
  55. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/tests/sdtool/utils.py +0 -0
  56. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/tests/test_date_utils.py +0 -0
  57. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/tests/test_employee.py +0 -0
  58. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/tests/test_engagement.py +0 -0
  59. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/tests/test_fix_departments.py +0 -0
  60. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/tests/test_graphql.py +0 -0
  61. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/tests/test_it_systems.py +0 -0
  62. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/tests/test_main.py +0 -0
  63. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/tests/test_sd_changed_at.py +0 -0
  64. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/tests/test_sd_common.py +0 -0
  65. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/tests/test_sd_importer.py +0 -0
  66. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/tests/test_sd_log_analyzer.py +0 -0
  67. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/tests/test_sd_to_pydantic.py +0 -0
  68. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/tests/test_skip.py +0 -0
  69. {dipex-5.2.0 → dipex-5.3.0}/integrations/SD_Lon/tests/test_sync_job_id.py +0 -0
  70. {dipex-5.2.0 → dipex-5.3.0}/integrations/__init__.py +0 -0
  71. {dipex-5.2.0 → dipex-5.3.0}/integrations/aarhus/config.py +0 -0
  72. {dipex-5.2.0 → dipex-5.3.0}/integrations/aarhus/dar_helper.py +0 -0
  73. {dipex-5.2.0 → dipex-5.3.0}/integrations/aarhus/initial.py +0 -0
  74. {dipex-5.2.0 → dipex-5.3.0}/integrations/aarhus/initial_classes.py +0 -0
  75. {dipex-5.2.0 → dipex-5.3.0}/integrations/aarhus/los_files.py +0 -0
  76. {dipex-5.2.0 → dipex-5.3.0}/integrations/aarhus/los_import.py +0 -0
  77. {dipex-5.2.0 → dipex-5.3.0}/integrations/aarhus/los_leder.py +0 -0
  78. {dipex-5.2.0 → dipex-5.3.0}/integrations/aarhus/los_org.py +0 -0
  79. {dipex-5.2.0 → dipex-5.3.0}/integrations/aarhus/los_pers.py +0 -0
  80. {dipex-5.2.0 → dipex-5.3.0}/integrations/aarhus/los_stam.py +0 -0
  81. {dipex-5.2.0 → dipex-5.3.0}/integrations/aarhus/payloads.py +0 -0
  82. {dipex-5.2.0 → dipex-5.3.0}/integrations/aarhus/tests/__init__.py +0 -0
  83. {dipex-5.2.0 → dipex-5.3.0}/integrations/aarhus/tests/conftest.py +0 -0
  84. {dipex-5.2.0 → dipex-5.3.0}/integrations/aarhus/tests/helpers.py +0 -0
  85. {dipex-5.2.0 → dipex-5.3.0}/integrations/aarhus/tests/strategies.py +0 -0
  86. {dipex-5.2.0 → dipex-5.3.0}/integrations/aarhus/tests/test_config.py +0 -0
  87. {dipex-5.2.0 → dipex-5.3.0}/integrations/aarhus/tests/test_initial.py +0 -0
  88. {dipex-5.2.0 → dipex-5.3.0}/integrations/aarhus/tests/test_los_files.py +0 -0
  89. {dipex-5.2.0 → dipex-5.3.0}/integrations/aarhus/tests/test_los_import.py +0 -0
  90. {dipex-5.2.0 → dipex-5.3.0}/integrations/aarhus/tests/test_los_leder.py +0 -0
  91. {dipex-5.2.0 → dipex-5.3.0}/integrations/aarhus/tests/test_los_org.py +0 -0
  92. {dipex-5.2.0 → dipex-5.3.0}/integrations/aarhus/tests/test_los_pers.py +0 -0
  93. {dipex-5.2.0 → dipex-5.3.0}/integrations/aarhus/tests/test_los_stam.py +0 -0
  94. {dipex-5.2.0 → dipex-5.3.0}/integrations/aarhus/tests/test_payloads.py +0 -0
  95. {dipex-5.2.0 → dipex-5.3.0}/integrations/aarhus/tests/test_util.py +0 -0
  96. {dipex-5.2.0 → dipex-5.3.0}/integrations/aarhus/util.py +0 -0
  97. {dipex-5.2.0 → dipex-5.3.0}/integrations/aarhus/uuids.py +0 -0
  98. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/__init__.py +0 -0
  99. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/ad_common.py +0 -0
  100. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/ad_exceptions.py +0 -0
  101. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/ad_fix_enddate.py +0 -0
  102. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/ad_jinja_filters.py +0 -0
  103. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/ad_life_cycle.py +0 -0
  104. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/ad_logger.py +0 -0
  105. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/ad_reader.py +0 -0
  106. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/ad_sync.py +0 -0
  107. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/ad_template_engine.py +0 -0
  108. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/ad_templates.py +0 -0
  109. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/ad_writer.py +0 -0
  110. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/import_ad_group_into_mo.py +0 -0
  111. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/mo_to_ad_sync.py +0 -0
  112. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/payloads.py +0 -0
  113. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/read_ad_conf_settings.py +0 -0
  114. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/sync_mo_uuid_to_ad.py +0 -0
  115. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/test_connectivity.py +0 -0
  116. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/tests/__init__.py +0 -0
  117. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/tests/mocks.py +0 -0
  118. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/tests/name_simulator.py +0 -0
  119. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/tests/test_ad_common.py +0 -0
  120. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/tests/test_ad_fix_enddate.py +0 -0
  121. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/tests/test_ad_jinja_filters.py +0 -0
  122. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/tests/test_ad_life_cycle.py +0 -0
  123. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/tests/test_ad_logger.py +0 -0
  124. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/tests/test_ad_reader.py +0 -0
  125. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/tests/test_ad_sync.py +0 -0
  126. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/tests/test_ad_writer.py +0 -0
  127. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/tests/test_dot_mapping.py +0 -0
  128. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/tests/test_first_included.py +0 -0
  129. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/tests/test_import_ad_group_into_mo.py +0 -0
  130. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/tests/test_location_element.py +0 -0
  131. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/tests/test_mo_data_source.py +0 -0
  132. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/tests/test_mo_to_ad_sync.py +0 -0
  133. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/tests/test_morestsource.py +0 -0
  134. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/tests/test_read_ad_conf_settings.py +0 -0
  135. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/tests/test_recursive_dict_update.py +0 -0
  136. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/tests/test_sync_mo_uuid_to_ad.py +0 -0
  137. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/tests/test_usernames.py +0 -0
  138. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/tests/test_utils.py +0 -0
  139. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/user_names.py +0 -0
  140. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/username_rules/method_2.py +0 -0
  141. {dipex-5.2.0 → dipex-5.3.0}/integrations/ad_integration/utils.py +0 -0
  142. {dipex-5.2.0 → dipex-5.3.0}/integrations/calculate_primary/__init__.py +0 -0
  143. {dipex-5.2.0 → dipex-5.3.0}/integrations/calculate_primary/calculate_primary.py +0 -0
  144. {dipex-5.2.0 → dipex-5.3.0}/integrations/calculate_primary/common.py +0 -0
  145. {dipex-5.2.0 → dipex-5.3.0}/integrations/calculate_primary/default.py +0 -0
  146. {dipex-5.2.0 → dipex-5.3.0}/integrations/calculate_primary/opus.py +0 -0
  147. {dipex-5.2.0 → dipex-5.3.0}/integrations/calculate_primary/sd.py +0 -0
  148. {dipex-5.2.0 → dipex-5.3.0}/integrations/calculate_primary/tests/__init__.py +0 -0
  149. {dipex-5.2.0 → dipex-5.3.0}/integrations/calculate_primary/tests/test_primary.py +0 -0
  150. {dipex-5.2.0 → dipex-5.3.0}/integrations/cpr_mapper.py +0 -0
  151. {dipex-5.2.0 → dipex-5.3.0}/integrations/dawa_helper.py +0 -0
  152. {dipex-5.2.0 → dipex-5.3.0}/integrations/kle/__init__.py +0 -0
  153. {dipex-5.2.0 → dipex-5.3.0}/integrations/kle/kle_import.py +0 -0
  154. {dipex-5.2.0 → dipex-5.3.0}/integrations/kle/kle_import_export.py +0 -0
  155. {dipex-5.2.0 → dipex-5.3.0}/integrations/kle/kle_xlsx.py +0 -0
  156. {dipex-5.2.0 → dipex-5.3.0}/integrations/kle/payloads.py +0 -0
  157. {dipex-5.2.0 → dipex-5.3.0}/integrations/opus/clear_and_import_opus.py +0 -0
  158. {dipex-5.2.0 → dipex-5.3.0}/integrations/opus/opus_diff_import.py +0 -0
  159. {dipex-5.2.0 → dipex-5.3.0}/integrations/opus/opus_exceptions.py +0 -0
  160. {dipex-5.2.0 → dipex-5.3.0}/integrations/opus/opus_file_reader.py +0 -0
  161. {dipex-5.2.0 → dipex-5.3.0}/integrations/opus/opus_helpers.py +0 -0
  162. {dipex-5.2.0 → dipex-5.3.0}/integrations/opus/opus_reimport_one.py +0 -0
  163. {dipex-5.2.0 → dipex-5.3.0}/integrations/opus/org_tree_print/main.py +0 -0
  164. {dipex-5.2.0 → dipex-5.3.0}/integrations/opus/payloads.py +0 -0
  165. {dipex-5.2.0 → dipex-5.3.0}/integrations/opus/tests/test_opus_diff_import.py +0 -0
  166. {dipex-5.2.0 → dipex-5.3.0}/integrations/opus/tests/test_opus_file_reader.py +0 -0
  167. {dipex-5.2.0 → dipex-5.3.0}/integrations/opus/tests/test_opus_helpers.py +0 -0
  168. {dipex-5.2.0 → dipex-5.3.0}/integrations/rundb/db_overview.py +0 -0
  169. {dipex-5.2.0 → dipex-5.3.0}/integrations/rundb/tests/test_db_overview.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: DIPEX
3
- Version: 5.2.0
3
+ Version: 5.3.0
4
4
  Summary: OS2mo-data-import-and-export
5
5
  Home-page: https://magenta.dk/
6
6
  License: MPL-2.0
@@ -24,6 +24,7 @@ from pydantic import UUID4
24
24
  from ra_utils.load_settings import load_settings
25
25
  from ra_utils.job_settings import JobSettings
26
26
 
27
+ from .log import LogLevel
27
28
  from .models import JobFunction
28
29
 
29
30
 
@@ -63,6 +64,8 @@ class CommonSettings(BaseSettings): # type: ignore
63
64
  "/opt/dipex/os2mo-data-import-and-export/settings/cpr_uuid_map.csv"
64
65
  )
65
66
 
67
+ log_level: LogLevel = LogLevel.DEBUG
68
+
66
69
  job_settings: JobSettings = JobSettings()
67
70
 
68
71
 
@@ -14,6 +14,7 @@ from typing import Tuple
14
14
  from more_itertools import pairwise
15
15
  from more_itertools import tabulate
16
16
 
17
+ from .log import get_logger
17
18
  from .sd_common import EmploymentStatus
18
19
 
19
20
  # TODO: move constants elsewhere
@@ -24,7 +25,7 @@ MO_INFINITY = None
24
25
  SD_INFINITY: str = "9999-12-31"
25
26
  DATE_REGEX_STR = "[0-9]{4}-(0[1-9]|1[0-2])-([0-2][0-9]|3[0-1])"
26
27
 
27
- logger = logging.getLogger("sdImport")
28
+ logger = get_logger()
28
29
 
29
30
 
30
31
  def date_to_datetime(d: date) -> datetime:
@@ -1,7 +1,5 @@
1
1
  import datetime
2
2
  import json
3
- import logging
4
- import sys
5
3
  from typing import Any
6
4
  from typing import Optional
7
5
  from typing import List
@@ -22,28 +20,13 @@ from . import sd_payloads
22
20
  from .config import ChangedAtSettings
23
21
  from .config import get_changed_at_settings
24
22
  from .exceptions import NoCurrentValdityException
23
+ from .log import get_logger
24
+ from .log import setup_logging
25
25
  from .sd_common import mora_assert
26
26
  from .sd_common import sd_lookup
27
27
 
28
28
 
29
- LOG_LEVEL = logging.DEBUG
30
-
31
- logger = logging.getLogger("fixDepartments")
32
-
33
-
34
- def setup_logging():
35
- detail_logging = ("sdCommon", "fixDepartments")
36
- for name in logging.root.manager.loggerDict:
37
- if name in detail_logging:
38
- logging.getLogger(name).setLevel(LOG_LEVEL)
39
- else:
40
- logging.getLogger(name).setLevel(logging.ERROR)
41
-
42
- logging.basicConfig(
43
- format="%(levelname)s %(asctime)s %(name)s %(message)s",
44
- level=LOG_LEVEL,
45
- stream=sys.stdout,
46
- )
29
+ logger = get_logger()
47
30
 
48
31
 
49
32
  class FixDepartments:
@@ -61,12 +44,10 @@ class FixDepartments:
61
44
  try:
62
45
  self.org_uuid = self.helper.read_organisation()
63
46
  except requests.exceptions.RequestException as e:
64
- logger.error(e)
65
- print(e)
47
+ logger.error("Problem getting the MO organization", err=e)
66
48
  exit()
67
49
  except json.decoder.JSONDecodeError as e:
68
- logger.error(e)
69
- print(e)
50
+ logger.error("Problem decoding response JSON", err=e)
70
51
  exit()
71
52
 
72
53
  logger.info("Read org_unit types")
@@ -115,7 +96,7 @@ class FixDepartments:
115
96
  parent_uuid: The parent UUID of the department in SD
116
97
  """
117
98
  logger.info(
118
- f"""Create department with SD UUID: {department["DepartmentUUIDIdentifier"]}"""
99
+ "Create department", sd_dep_uuid=department["DepartmentUUIDIdentifier"]
119
100
  )
120
101
 
121
102
  effective_parent_uuid = (
@@ -126,21 +107,18 @@ class FixDepartments:
126
107
  if unit_level["user_key"] == department["DepartmentLevelIdentifier"]:
127
108
  unit_level_uuid = unit_level["uuid"]
128
109
 
129
- logger.debug("SD department info to create from: {}".format(department))
110
+ logger.debug("SD department", department=department)
130
111
  payload = sd_payloads.create_single_org_unit(
131
112
  department=department,
132
113
  unit_type=self.unit_type["uuid"],
133
114
  unit_level=unit_level_uuid,
134
115
  parent=effective_parent_uuid,
135
116
  )
136
- logger.debug("Create department MO payload: {}".format(payload))
137
- if self.dry_run:
138
- print("Dry-run (ou/create): ", payload)
139
- return None
140
- response = self.helper._mo_post("ou/create", payload)
141
- response.raise_for_status()
142
- logger.info("Created unit {}".format(department["DepartmentIdentifier"]))
143
- logger.debug("Create response status: {}".format(response.status_code))
117
+ logger.debug("Create MO department (ou/create)", payload=payload)
118
+ if not self.dry_run:
119
+ response = self.helper._mo_post("ou/create", payload)
120
+ response.raise_for_status()
121
+ logger.info("Created unit")
144
122
 
145
123
  def _create_org_unit_if_missing_in_mo(
146
124
  self, department: OrderedDict, parent_uuid: Optional[str]
@@ -191,14 +169,15 @@ class FixDepartments:
191
169
  if unit_level["user_key"] == department_level_identifier:
192
170
  unit_level_uuid = unit_level["uuid"]
193
171
  if unit_level_uuid is None:
194
- msg = "Unknown department level {}!!"
195
- logger.error(msg.format(department_level_identifier))
196
- raise Exception(msg.format(department_level_identifier))
172
+ logger.exception(
173
+ "Unknown department level!!",
174
+ department_level_identifier=department_level_identifier,
175
+ )
176
+ raise Exception("Unknown department level!!")
197
177
 
198
178
  parent = parent_uuid if parent_uuid is not None else self.org_uuid
199
179
 
200
- msg = "Unit parent at {} is {}"
201
- logger.info(msg.format(from_date, parent))
180
+ logger.info("Unit parent at from_date", from_date=from_date, parent_uuid=parent)
202
181
 
203
182
  payload = sd_payloads.edit_org_unit(
204
183
  user_key=shortname,
@@ -210,16 +189,14 @@ class FixDepartments:
210
189
  from_date=from_date,
211
190
  to_date=to_date,
212
191
  )
213
- logger.debug("Edit payload to fix unit: {}".format(payload))
214
- if self.dry_run:
215
- print("Dry-run (details/edit): ", payload)
216
- return None
217
- response = self.helper._mo_post("details/edit", payload)
218
- logger.debug("Edit response status: {}".format(response.status_code))
219
- if response.status_code == 400:
220
- assert response.text.find("raise to a new registration") > 0
221
- else:
222
- response.raise_for_status()
192
+ logger.debug("Edit payload to fix unit (details/edit)", payload=payload)
193
+ if not self.dry_run:
194
+ response = self.helper._mo_post("details/edit", payload)
195
+ logger.debug("Edit response status: {}".format(response.status_code))
196
+ if response.status_code == 400:
197
+ assert response.text.find("raise to a new registration") > 0
198
+ else:
199
+ response.raise_for_status()
223
200
 
224
201
  def fix_department(self, unit_uuid: str, validity_date: datetime.date) -> None:
225
202
  """
@@ -228,8 +205,7 @@ class FixDepartments:
228
205
  :param validity_date: The validity date to read the department info from SD.
229
206
  """
230
207
 
231
- msg = "Set department {} to state as of {}"
232
- logger.info(msg.format(unit_uuid, validity_date))
208
+ logger.info("Fix department", unit_uuid=unit_uuid, validity_date=validity_date)
233
209
  validity = {
234
210
  "from_date": validity_date.strftime("%d.%m.%Y"),
235
211
  "to_date": datetime_to_sd_date(parse_datetime(SD_INFINITY)),
@@ -318,8 +294,11 @@ class FixDepartments:
318
294
  relevant_engagement = mo_eng
319
295
 
320
296
  if relevant_engagement is None:
321
- msg = "Fruitlessly searched for {} in {}".format(job_id, mo_engagements)
322
- logger.info(msg)
297
+ logger.info(
298
+ "Fruitlessly searched for employment_id in MO engagements",
299
+ employment_id=job_id,
300
+ mo_engagements=mo_engagements,
301
+ )
323
302
  return relevant_engagement
324
303
 
325
304
  def _read_department_engagements(self, unit_uuid, validity_date):
@@ -341,8 +320,9 @@ class FixDepartments:
341
320
  }
342
321
  department = self.get_department(sd_validity, uuid=unit_uuid)[0]
343
322
  if not department["DepartmentLevelIdentifier"] in too_deep:
344
- msg = "{} regnes ikke som et SD afdelingsniveau"
345
- logger.info(msg.format(unit_uuid))
323
+ logger.info(
324
+ "Enhed regnes ikke som et SD afdelingsniveau", unit_uuid=unit_uuid
325
+ )
346
326
  return {}
347
327
 
348
328
  params = {
@@ -359,7 +339,7 @@ class FixDepartments:
359
339
  time_deltas = [0, 90, 365]
360
340
 
361
341
  all_people = {}
362
- logger.debug("Perform GetEmployments, time_delas: {}".format(time_deltas))
342
+ logger.debug("Perform GetEmployments", time_deltas=time_deltas)
363
343
  for time_delta in time_deltas:
364
344
  effective_date = validity_date + datetime.timedelta(days=time_delta)
365
345
  params["EffectiveDate"] = (effective_date.strftime("%d.%m.%Y"),)
@@ -375,7 +355,7 @@ class FixDepartments:
375
355
  cpr = person["PersonCivilRegistrationIdentifier"]
376
356
  if cpr not in all_people:
377
357
  all_people[cpr] = person
378
- logger.debug("Department engagements: {}".format(all_people.keys()))
358
+ logger.debug("Department engagements", all_people=all_people.keys())
379
359
  return all_people
380
360
 
381
361
  def fix_NY_logic(self, unit_uuid, validity_date):
@@ -397,9 +377,9 @@ class FixDepartments:
397
377
  mo_unit = self.helper.read_ou(unit_uuid)
398
378
  while mo_unit["org_unit_level"]["user_key"] in too_deep:
399
379
  mo_unit = mo_unit["parent"]
400
- logger.debug("Parent unit: {}".format(mo_unit["uuid"]))
380
+ logger.debug("Parent unit", parent_uuid=mo_unit["uuid"])
401
381
  destination_unit = mo_unit["uuid"]
402
- logger.debug("Destination found: {}".format(destination_unit))
382
+ logger.debug("Destination found", destination_unit=destination_unit)
403
383
 
404
384
  all_people = self._read_department_engagements(unit_uuid, validity_date)
405
385
 
@@ -414,9 +394,7 @@ class FixDepartments:
414
394
 
415
395
  for employment in person["Employment"]:
416
396
  job_id = employment["EmploymentIdentifier"]
417
- msg = "Checking job-id: {}"
418
- print(msg.format(job_id))
419
- logger.info(msg.format(job_id))
397
+ logger.info("Checking job-id", employment_id=job_id)
420
398
  sd_uuid = employment["EmploymentDepartment"]["DepartmentUUIDIdentifier"]
421
399
  if not sd_uuid == unit_uuid:
422
400
  # This employment is not from the current department,
@@ -426,8 +404,9 @@ class FixDepartments:
426
404
 
427
405
  mo_person = self.helper.read_user(user_cpr=cpr, org_uuid=self.org_uuid)
428
406
  if mo_person is None:
429
- msg = "MO person is None for job_id: {}"
430
- logger.warning(msg.format(job_id))
407
+ logger.warning(
408
+ "MO person is None for employment_id", employment_id=job_id
409
+ )
431
410
  continue
432
411
 
433
412
  mo_engagements = self.helper.read_user_engagement(
@@ -438,8 +417,11 @@ class FixDepartments:
438
417
  # future rows.
439
418
  mo_engagement = self._find_engagement(mo_engagements, job_id)
440
419
  if mo_engagement is None:
441
- msg = "MO engagement is None for job_id: {}, user_uuid: {}"
442
- logger.warning(msg.format(job_id, mo_person["uuid"]))
420
+ logger.warning(
421
+ "MO engagement is None",
422
+ employment_id=job_id,
423
+ mo_person_uuid=mo_person["uuid"],
424
+ )
443
425
  continue
444
426
  for eng in mo_engagements:
445
427
  if not eng["uuid"] == mo_engagement["uuid"]:
@@ -460,12 +442,12 @@ class FixDepartments:
460
442
  "validity": eng["validity"],
461
443
  }
462
444
  payload = sd_payloads.engagement(data, mo_engagement)
463
- logger.debug("Move engagement payload: {}".format(payload))
464
- if self.dry_run:
465
- print("Dry-run (details/edit): ", payload)
466
- return
467
- response = self.helper._mo_post("details/edit", payload)
468
- mora_assert(response)
445
+ logger.debug(
446
+ "Move engagement payload (details/edit)", payload=payload
447
+ )
448
+ if not self.dry_run:
449
+ response = self.helper._mo_post("details/edit", payload)
450
+ mora_assert(response)
469
451
 
470
452
  def get_parent(self, unit_uuid, validity_date) -> Optional[str]:
471
453
  """
@@ -489,8 +471,11 @@ class FixDepartments:
489
471
  "GetDepartmentParent20190701", settings=self.settings, params=params
490
472
  )
491
473
  if "DepartmentParent" not in parent_response:
492
- msg = "No parent for {} found at validity: {}"
493
- logger.error(msg.format(unit_uuid, validity_date))
474
+ logger.error(
475
+ "No parent found at this date",
476
+ unit_uuid=unit_uuid,
477
+ validity_date=validity_date,
478
+ )
494
479
  raise NoCurrentValdityException()
495
480
  parent = parent_response["DepartmentParent"]["DepartmentUUIDIdentifier"]
496
481
  if parent == self.institution_uuid:
@@ -528,8 +513,7 @@ class FixDepartments:
528
513
  uuid = department["DepartmentUUIDIdentifier"]
529
514
  department_branch.append((shortname, uuid))
530
515
  current_uuid = self.get_parent(current_uuid, validity_date=validity_date)
531
- msg = "Department: {}, uuid: {}, level: {}"
532
- logger.debug(msg.format(shortname, uuid, level))
516
+ logger.debug("Department", shortname=shortname, uuid=uuid, level=level)
533
517
  return department_branch
534
518
 
535
519
  def sd_uuid_from_short_code(self, validity_date, shortname):
@@ -543,17 +527,17 @@ class FixDepartments:
543
527
 
544
528
  def unit_fixer(ou_uuid: UUID):
545
529
  """Sync SD department information to MO."""
546
- setup_logging()
547
-
548
530
  settings = get_changed_at_settings()
531
+ setup_logging(settings.log_level)
532
+
549
533
  unit_fixer = FixDepartments(settings)
550
534
 
551
535
  today = datetime.datetime.today().date()
552
536
 
553
- logger.info(f"Calling fix_departments on {str(ou_uuid)}")
537
+ logger.info("Calling fix_departments", ou_uuid=ou_uuid)
554
538
  unit_fixer.fix_department(str(ou_uuid), today)
555
539
 
556
- logger.info(f"Calling fix_NY_logic on {str(ou_uuid)}")
540
+ logger.info("Calling fix_NY_logic", ou_uuid=ou_uuid)
557
541
  unit_fixer.fix_NY_logic(str(ou_uuid), today)
558
542
 
559
543
  logger.info("unit_fixer done!")
@@ -0,0 +1,65 @@
1
+ import logging.config
2
+ import re
3
+ from enum import Enum
4
+ from uuid import uuid4
5
+
6
+ import structlog
7
+
8
+
9
+ CPR_REGEX = re.compile("[0-9]{10}")
10
+
11
+ # Unique log context for this application
12
+ APP_LOG_CONTEXT = uuid4()
13
+
14
+
15
+ class LogLevel(str, Enum):
16
+ DEBUG = "DEBUG"
17
+ INFO = "INFO"
18
+ WARNING = "WARNING"
19
+ ERROR = "ERROR"
20
+ CRITICAL = "CRITICAL"
21
+
22
+
23
+ def anonymize_cpr(cpr: str) -> str:
24
+ assert CPR_REGEX.match(cpr)
25
+ return cpr[:6] + "xxxx"
26
+
27
+
28
+ def log_filter(logger, method_name, event_dict):
29
+ # Only log from our application log context
30
+ if event_dict.get("log_context") == APP_LOG_CONTEXT:
31
+ return event_dict
32
+ raise structlog.DropEvent
33
+
34
+
35
+ def get_logger():
36
+ """
37
+ Use this function to get a logger instead of using structlog.get_logger() directly
38
+ """
39
+ return structlog.get_logger().bind(log_context=APP_LOG_CONTEXT)
40
+
41
+
42
+ def setup_logging(log_level: LogLevel) -> None:
43
+ log_level_value = logging.getLevelName(log_level.value)
44
+
45
+ # Disable logging from imported modules that use Pythons stdlib logging
46
+ logging.config.dictConfig(
47
+ {
48
+ "version": 1,
49
+ "disable_existing_loggers": True, # This line does not really seem to work
50
+ "root": {"level": logging.CRITICAL + 1},
51
+ }
52
+ )
53
+
54
+ structlog.configure(
55
+ processors=[
56
+ log_filter,
57
+ structlog.contextvars.merge_contextvars,
58
+ structlog.processors.add_log_level,
59
+ structlog.processors.StackInfoRenderer(),
60
+ structlog.dev.set_exc_info,
61
+ structlog.processors.TimeStamper(),
62
+ structlog.dev.ConsoleRenderer(),
63
+ ],
64
+ wrapper_class=structlog.make_filtering_bound_logger(log_level_value),
65
+ )
@@ -6,7 +6,6 @@ from contextlib import contextmanager
6
6
  from functools import partial
7
7
  from uuid import UUID
8
8
 
9
- import structlog
10
9
  from fastapi import FastAPI
11
10
  from fastapi import Request
12
11
  from fastapi import Response
@@ -18,10 +17,11 @@ from starlette.status import HTTP_500_INTERNAL_SERVER_ERROR
18
17
 
19
18
  from .config import get_changed_at_settings
20
19
  from .fix_departments import FixDepartments
20
+ from .log import get_logger
21
21
  from .sd_changed_at import changed_at
22
22
 
23
23
 
24
- logger = structlog.get_logger(__name__)
24
+ logger = get_logger()
25
25
 
26
26
 
27
27
  class State(enum.Enum):