nautobot 2.2.2__py3-none-any.whl → 2.2.4__py3-none-any.whl

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.

Potentially problematic release.


This version of nautobot might be problematic. Click here for more details.

Files changed (362) hide show
  1. nautobot/apps/jobs.py +2 -0
  2. nautobot/core/api/utils.py +12 -9
  3. nautobot/core/apps/__init__.py +2 -2
  4. nautobot/core/celery/__init__.py +79 -68
  5. nautobot/core/celery/backends.py +9 -1
  6. nautobot/core/celery/control.py +4 -7
  7. nautobot/core/celery/schedulers.py +4 -2
  8. nautobot/core/celery/task.py +78 -5
  9. nautobot/core/graphql/schema.py +2 -1
  10. nautobot/core/jobs/__init__.py +2 -1
  11. nautobot/core/settings.py +6 -4
  12. nautobot/core/settings.yaml +51 -16
  13. nautobot/core/templates/admin/base.html +2 -2
  14. nautobot/core/templates/base_django.html +2 -2
  15. nautobot/core/templates/buttons/export.html +47 -47
  16. nautobot/core/templates/generic/object_list.html +3 -3
  17. nautobot/core/templates/inc/javascript.html +3 -0
  18. nautobot/core/templates/inc/media.html +3 -0
  19. nautobot/core/templates/login.html +2 -2
  20. nautobot/core/templates/nautobot_config.py.j2 +2 -0
  21. nautobot/core/templatetags/helpers.py +66 -9
  22. nautobot/core/testing/__init__.py +6 -1
  23. nautobot/core/testing/api.py +12 -13
  24. nautobot/core/testing/mixins.py +2 -2
  25. nautobot/core/testing/views.py +50 -51
  26. nautobot/core/tests/test_api.py +23 -2
  27. nautobot/core/tests/test_jobs.py +79 -2
  28. nautobot/core/tests/test_templatetags_helpers.py +32 -0
  29. nautobot/core/tests/test_views.py +52 -0
  30. nautobot/core/tests/test_views_utils.py +22 -1
  31. nautobot/core/utils/module_loading.py +89 -0
  32. nautobot/core/views/mixins.py +4 -0
  33. nautobot/core/views/utils.py +3 -2
  34. nautobot/dcim/choices.py +14 -0
  35. nautobot/dcim/forms.py +51 -1
  36. nautobot/dcim/models/device_components.py +9 -5
  37. nautobot/dcim/templates/dcim/location.html +32 -13
  38. nautobot/dcim/templates/dcim/location_migrate_data_to_contact.html +102 -0
  39. nautobot/dcim/tests/test_views.py +376 -55
  40. nautobot/dcim/urls.py +5 -0
  41. nautobot/dcim/views.py +172 -21
  42. nautobot/extras/api/serializers.py +17 -6
  43. nautobot/extras/api/views.py +21 -10
  44. nautobot/extras/constants.py +3 -3
  45. nautobot/extras/datasources/git.py +47 -58
  46. nautobot/extras/forms/forms.py +3 -1
  47. nautobot/extras/jobs.py +79 -146
  48. nautobot/extras/models/datasources.py +0 -2
  49. nautobot/extras/models/jobs.py +36 -18
  50. nautobot/extras/plugins/__init__.py +1 -20
  51. nautobot/extras/signals.py +6 -9
  52. nautobot/extras/test_jobs/__init__.py +8 -0
  53. nautobot/extras/test_jobs/dry_run.py +3 -2
  54. nautobot/extras/test_jobs/fail.py +43 -0
  55. nautobot/extras/test_jobs/ipaddress_vars.py +40 -1
  56. nautobot/extras/test_jobs/jobs_module/__init__.py +5 -0
  57. nautobot/extras/test_jobs/jobs_module/jobs_submodule/__init__.py +1 -0
  58. nautobot/extras/test_jobs/jobs_module/jobs_submodule/jobs.py +6 -0
  59. nautobot/extras/test_jobs/pass.py +40 -0
  60. nautobot/extras/test_jobs/relative_import.py +11 -0
  61. nautobot/extras/tests/test_api.py +3 -0
  62. nautobot/extras/tests/test_context_managers.py +18 -0
  63. nautobot/extras/tests/test_datasources.py +125 -118
  64. nautobot/extras/tests/test_job_variables.py +57 -15
  65. nautobot/extras/tests/test_jobs.py +135 -1
  66. nautobot/extras/tests/test_models.py +26 -19
  67. nautobot/extras/tests/test_plugins.py +1 -3
  68. nautobot/extras/tests/test_views.py +2 -4
  69. nautobot/extras/utils.py +2 -1
  70. nautobot/extras/views.py +82 -116
  71. nautobot/ipam/api/views.py +8 -1
  72. nautobot/ipam/graphql/types.py +11 -0
  73. nautobot/ipam/mixins.py +32 -0
  74. nautobot/ipam/models.py +2 -1
  75. nautobot/ipam/querysets.py +6 -1
  76. nautobot/ipam/tests/test_models.py +82 -0
  77. nautobot/ipam/views.py +6 -6
  78. nautobot/project-static/docs/404.html +107 -51
  79. nautobot/project-static/docs/apps/index.html +107 -51
  80. nautobot/project-static/docs/apps/nautobot-apps.html +107 -51
  81. nautobot/project-static/docs/assets/_mkdocstrings.css +6 -1
  82. nautobot/project-static/docs/assets/extra.css +11 -0
  83. nautobot/project-static/docs/assets/javascripts/bundle.3220b9d7.min.js +29 -0
  84. nautobot/project-static/docs/assets/javascripts/bundle.3220b9d7.min.js.map +7 -0
  85. nautobot/project-static/docs/assets/stylesheets/main.66ac8b77.min.css +1 -0
  86. nautobot/project-static/docs/assets/stylesheets/main.66ac8b77.min.css.map +1 -0
  87. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +107 -51
  88. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +107 -51
  89. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +108 -52
  90. nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +107 -51
  91. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +107 -51
  92. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +107 -51
  93. nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +107 -51
  94. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +107 -51
  95. nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +107 -51
  96. nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +107 -51
  97. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +107 -51
  98. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +107 -51
  99. nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +107 -51
  100. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +287 -262
  101. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +107 -51
  102. nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +107 -51
  103. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +107 -51
  104. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +107 -51
  105. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +107 -51
  106. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +107 -51
  107. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +107 -51
  108. nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +107 -51
  109. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +107 -51
  110. nautobot/project-static/docs/development/apps/api/configuration-view.html +110 -54
  111. nautobot/project-static/docs/development/apps/api/database-backend-config.html +110 -54
  112. nautobot/project-static/docs/development/apps/api/models/django-admin.html +107 -51
  113. nautobot/project-static/docs/development/apps/api/models/global-search.html +110 -54
  114. nautobot/project-static/docs/development/apps/api/models/graphql.html +113 -57
  115. nautobot/project-static/docs/development/apps/api/models/index.html +107 -51
  116. nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +113 -57
  117. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +107 -51
  118. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +110 -54
  119. nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +107 -51
  120. nautobot/project-static/docs/development/apps/api/platform-features/index.html +107 -51
  121. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +110 -54
  122. nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +111 -55
  123. nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +110 -54
  124. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +110 -54
  125. nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +107 -51
  126. nautobot/project-static/docs/development/apps/api/prometheus.html +110 -54
  127. nautobot/project-static/docs/development/apps/api/setup.html +107 -51
  128. nautobot/project-static/docs/development/apps/api/testing.html +113 -57
  129. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +110 -54
  130. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +110 -54
  131. nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +107 -51
  132. nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +107 -51
  133. nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +113 -57
  134. nautobot/project-static/docs/development/apps/api/views/base-template.html +107 -51
  135. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +110 -54
  136. nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +107 -51
  137. nautobot/project-static/docs/development/apps/api/views/help-documentation.html +110 -54
  138. nautobot/project-static/docs/development/apps/api/views/index.html +107 -51
  139. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +113 -57
  140. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +122 -66
  141. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +110 -54
  142. nautobot/project-static/docs/development/apps/api/views/notes.html +110 -54
  143. nautobot/project-static/docs/development/apps/api/views/rest-api.html +107 -51
  144. nautobot/project-static/docs/development/apps/api/views/urls.html +107 -51
  145. nautobot/project-static/docs/development/apps/index.html +128 -72
  146. nautobot/project-static/docs/development/apps/migration/code-updates.html +107 -51
  147. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +107 -51
  148. nautobot/project-static/docs/development/apps/migration/from-v1.html +107 -51
  149. nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +107 -51
  150. nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +107 -51
  151. nautobot/project-static/docs/development/apps/migration/model-updates/global.html +107 -51
  152. nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +107 -51
  153. nautobot/project-static/docs/development/apps/porting-from-netbox.html +110 -54
  154. nautobot/project-static/docs/development/core/application-registry.html +242 -144
  155. nautobot/project-static/docs/development/core/best-practices.html +122 -66
  156. nautobot/project-static/docs/development/core/bootstrap-ui.html +107 -51
  157. nautobot/project-static/docs/development/core/caching.html +107 -51
  158. nautobot/project-static/docs/development/core/controllers.html +107 -51
  159. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +113 -57
  160. nautobot/project-static/docs/development/core/generic-views.html +110 -54
  161. nautobot/project-static/docs/development/core/getting-started.html +135 -79
  162. nautobot/project-static/docs/development/core/homepage.html +110 -54
  163. nautobot/project-static/docs/development/core/index.html +107 -51
  164. nautobot/project-static/docs/development/core/model-checklist.html +156 -52
  165. nautobot/project-static/docs/development/core/model-features.html +108 -52
  166. nautobot/project-static/docs/development/core/natural-keys.html +110 -54
  167. nautobot/project-static/docs/development/core/navigation-menu.html +107 -51
  168. nautobot/project-static/docs/development/core/release-checklist.html +107 -51
  169. nautobot/project-static/docs/development/core/role-internals.html +107 -51
  170. nautobot/project-static/docs/development/core/settings.html +107 -51
  171. nautobot/project-static/docs/development/core/style-guide.html +110 -54
  172. nautobot/project-static/docs/development/core/templates.html +113 -57
  173. nautobot/project-static/docs/development/core/testing.html +125 -69
  174. nautobot/project-static/docs/development/core/user-preferences.html +107 -51
  175. nautobot/project-static/docs/development/index.html +107 -51
  176. nautobot/project-static/docs/development/jobs/index.html +504 -172
  177. nautobot/project-static/docs/development/jobs/migration/from-v1.html +111 -55
  178. nautobot/project-static/docs/docker/index.html +3 -3
  179. nautobot/project-static/docs/index.html +125 -69
  180. nautobot/project-static/docs/installation/selinux-troubleshooting.html +3 -3
  181. nautobot/project-static/docs/objects.inv +0 -0
  182. nautobot/project-static/docs/release-notes/index.html +107 -51
  183. nautobot/project-static/docs/release-notes/version-1.0.html +107 -51
  184. nautobot/project-static/docs/release-notes/version-1.1.html +107 -51
  185. nautobot/project-static/docs/release-notes/version-1.2.html +107 -51
  186. nautobot/project-static/docs/release-notes/version-1.3.html +107 -51
  187. nautobot/project-static/docs/release-notes/version-1.4.html +107 -51
  188. nautobot/project-static/docs/release-notes/version-1.5.html +116 -60
  189. nautobot/project-static/docs/release-notes/version-1.6.html +107 -51
  190. nautobot/project-static/docs/release-notes/version-2.0.html +110 -54
  191. nautobot/project-static/docs/release-notes/version-2.1.html +107 -51
  192. nautobot/project-static/docs/release-notes/version-2.2.html +500 -114
  193. nautobot/project-static/docs/requirements.txt +2 -2
  194. nautobot/project-static/docs/search/search_index.json +1 -1
  195. nautobot/project-static/docs/sitemap.xml +262 -262
  196. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  197. nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +107 -51
  198. nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +107 -51
  199. nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +107 -51
  200. nautobot/project-static/docs/user-guide/administration/configuration/index.html +107 -51
  201. nautobot/project-static/docs/user-guide/administration/configuration/optional-settings.html +251 -164
  202. nautobot/project-static/docs/user-guide/administration/configuration/required-settings.html +113 -57
  203. nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +107 -51
  204. nautobot/project-static/docs/user-guide/administration/guides/caching.html +113 -57
  205. nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +107 -51
  206. nautobot/project-static/docs/user-guide/administration/guides/healthcheck.html +107 -51
  207. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +107 -51
  208. nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +113 -57
  209. nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +107 -51
  210. nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +107 -51
  211. nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +107 -51
  212. nautobot/project-static/docs/user-guide/administration/installation/app-install.html +171 -112
  213. nautobot/project-static/docs/user-guide/administration/installation/docker.html +13 -8626
  214. nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +117 -61
  215. nautobot/project-static/docs/user-guide/administration/installation/health-checks.html +13 -8614
  216. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +252 -165
  217. nautobot/project-static/docs/user-guide/administration/installation/index.html +165 -192
  218. nautobot/project-static/docs/user-guide/administration/installation/install_system.html +411 -691
  219. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +248 -229
  220. nautobot/project-static/docs/user-guide/administration/installation/selinux-troubleshooting.html +13 -8118
  221. nautobot/project-static/docs/user-guide/administration/installation/services.html +350 -240
  222. nautobot/project-static/docs/user-guide/administration/installation-extras/docker.html +8684 -0
  223. nautobot/project-static/docs/user-guide/administration/installation-extras/health-checks.html +8672 -0
  224. nautobot/project-static/docs/user-guide/administration/installation-extras/selinux-troubleshooting.html +8176 -0
  225. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +110 -54
  226. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +110 -54
  227. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +155 -99
  228. nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +107 -51
  229. nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +109 -53
  230. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +107 -51
  231. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +107 -51
  232. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +107 -51
  233. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +107 -51
  234. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +107 -51
  235. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +107 -51
  236. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +117 -58
  237. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +113 -57
  238. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +107 -51
  239. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +107 -51
  240. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +107 -51
  241. nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +107 -51
  242. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +110 -54
  243. nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +107 -51
  244. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +110 -54
  245. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +110 -54
  246. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +110 -54
  247. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +110 -54
  248. nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +107 -51
  249. nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +107 -51
  250. nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +113 -57
  251. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +110 -54
  252. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +110 -54
  253. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +110 -54
  254. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +110 -54
  255. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +116 -60
  256. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +110 -54
  257. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +110 -54
  258. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +119 -63
  259. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +110 -54
  260. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +110 -54
  261. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +113 -57
  262. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +113 -57
  263. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +113 -57
  264. nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +107 -51
  265. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +113 -57
  266. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +107 -51
  267. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +110 -54
  268. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +110 -54
  269. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +107 -51
  270. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +110 -54
  271. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +110 -54
  272. nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +107 -51
  273. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +107 -51
  274. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +107 -51
  275. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +110 -54
  276. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +110 -54
  277. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +110 -54
  278. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +110 -54
  279. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +107 -51
  280. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +113 -57
  281. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +110 -54
  282. nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +110 -54
  283. nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +110 -54
  284. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +125 -69
  285. nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +113 -57
  286. nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +128 -72
  287. nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +110 -54
  288. nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +107 -51
  289. nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +110 -54
  290. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +227 -60
  291. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +107 -51
  292. nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +113 -57
  293. nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +107 -51
  294. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +110 -54
  295. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +107 -51
  296. nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +107 -51
  297. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +107 -51
  298. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +107 -51
  299. nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +113 -57
  300. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +113 -57
  301. nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +107 -51
  302. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +113 -57
  303. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +107 -51
  304. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +107 -51
  305. nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +107 -51
  306. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +107 -51
  307. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +107 -51
  308. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +107 -51
  309. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +107 -51
  310. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +107 -51
  311. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +107 -51
  312. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +110 -54
  313. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +113 -57
  314. nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +107 -51
  315. nautobot/project-static/docs/user-guide/feature-guides/relationships.html +110 -54
  316. nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +107 -51
  317. nautobot/project-static/docs/user-guide/index.html +109 -53
  318. nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +107 -51
  319. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +113 -57
  320. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +128 -72
  321. nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +107 -51
  322. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +125 -69
  323. nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +107 -51
  324. nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +110 -54
  325. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +125 -69
  326. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +110 -54
  327. nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +107 -51
  328. nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +107 -51
  329. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +143 -100
  330. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +113 -57
  331. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +113 -57
  332. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +110 -54
  333. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +123 -67
  334. nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +107 -51
  335. nautobot/project-static/docs/user-guide/platform-functionality/note.html +110 -54
  336. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +116 -60
  337. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +110 -54
  338. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +131 -75
  339. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +149 -93
  340. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +110 -54
  341. nautobot/project-static/docs/user-guide/platform-functionality/role.html +107 -51
  342. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +116 -60
  343. nautobot/project-static/docs/user-guide/platform-functionality/status.html +119 -63
  344. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +110 -54
  345. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +137 -81
  346. nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +110 -54
  347. nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +107 -51
  348. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +110 -54
  349. nautobot/project-static/js/forms.js +18 -11
  350. nautobot/tenancy/views.py +2 -6
  351. nautobot/virtualization/views.py +5 -9
  352. {nautobot-2.2.2.dist-info → nautobot-2.2.4.dist-info}/METADATA +4 -4
  353. {nautobot-2.2.2.dist-info → nautobot-2.2.4.dist-info}/RECORD +357 -348
  354. nautobot/extras/test_jobs/job_variables.py +0 -93
  355. nautobot/project-static/docs/assets/javascripts/bundle.bd41221c.min.js +0 -29
  356. nautobot/project-static/docs/assets/javascripts/bundle.bd41221c.min.js.map +0 -7
  357. nautobot/project-static/docs/assets/stylesheets/main.bcfcd587.min.css +0 -1
  358. nautobot/project-static/docs/assets/stylesheets/main.bcfcd587.min.css.map +0 -1
  359. {nautobot-2.2.2.dist-info → nautobot-2.2.4.dist-info}/LICENSE.txt +0 -0
  360. {nautobot-2.2.2.dist-info → nautobot-2.2.4.dist-info}/NOTICE +0 -0
  361. {nautobot-2.2.2.dist-info → nautobot-2.2.4.dist-info}/WHEEL +0 -0
  362. {nautobot-2.2.2.dist-info → nautobot-2.2.4.dist-info}/entry_points.txt +0 -0
@@ -56,7 +56,7 @@
56
56
  {% if not is_popup %}
57
57
  {% if "BANNER_TOP"|settings_or_config %}
58
58
  <div class="alert alert-info text-center" role="alert">
59
- {{ "BANNER_TOP"|settings_or_config|safe }}
59
+ {{ "BANNER_TOP"|settings_or_config|render_markdown }}
60
60
  </div>
61
61
  {% endif %}
62
62
  {% if settings.MAINTENANCE_MODE %}
@@ -107,7 +107,7 @@
107
107
  <div class="push"></div>
108
108
  {% if "BANNER_BOTTOM"|settings_or_config %}
109
109
  <div class="alert alert-info text-center banner-bottom" role="alert">
110
- {{ "BANNER_BOTTOM"|settings_or_config|safe }}
110
+ {{ "BANNER_BOTTOM"|settings_or_config|render_markdown }}
111
111
  </div>
112
112
  {% endif %}
113
113
  </div>
@@ -16,7 +16,7 @@
16
16
  {% if request.user.is_authenticated %}
17
17
  {% if "BANNER_TOP"|settings_or_config %}
18
18
  <div class="alert alert-info text-center" role="alert">
19
- {{ "BANNER_TOP"|settings_or_config|safe }}
19
+ {{ "BANNER_TOP"|settings_or_config|render_markdown }}
20
20
  </div>
21
21
  {% endif %}
22
22
  {% endif %}
@@ -42,7 +42,7 @@
42
42
  {% if request.user.is_authenticated %}
43
43
  {% if "BANNER_BOTTOM"|settings_or_config %}
44
44
  <div class="alert alert-info text-center banner-bottom" role="alert">
45
- {{ "BANNER_BOTTOM"|settings_or_config|safe }}
45
+ {{ "BANNER_BOTTOM"|settings_or_config|render_markdown }}
46
46
  </div>
47
47
  {% endif %}
48
48
  {% endif %}
@@ -1,60 +1,60 @@
1
1
  {% if export_url %}
2
2
  {% if export_templates or include_yaml_option %}
3
- <form style="display: inline-block" action="{{ export_url }}" method="post">
4
- {% csrf_token %}
5
- <input type="hidden" name="content_type" value="{{ content_type.pk }}">
6
- <input type="hidden" name="query_string" value="{{ query_string }}">
7
- <input type="hidden" name="export_format"
8
- value="{% if include_yaml_option %}yaml{% else %}csv{% endif %}">
9
- <input type="hidden" name="_schedule_type" value="immediately">
10
- <div class="btn-group">
11
- <button type="submit" class="btn btn-success">
12
- <span class="mdi mdi-database-export" aria-hidden="true"></span>
13
- Export
14
- </button>
15
- <button type="button" class="btn btn-success dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
16
- <span class="caret"></span>
17
- <span class="sr-only">Toggle Dropdown</span>
18
- </button>
19
- <ul class="dropdown-menu dropdown-menu-right">
20
- {% if include_yaml_option %}
21
- <li>
22
- <button type="submit" class="btn btn-link">YAML format</button>
23
- </li>
3
+ <div class="btn-group">
4
+ <button type="submit" class="btn btn-success" form="export_default">
5
+ <span class="mdi mdi-database-export" aria-hidden="true"></span>
6
+ Export
7
+ </button>
8
+ <form id="export_default" style="display: inline-block" action="{{ export_url }}" method="post">
9
+ {% csrf_token %}
10
+ <input type="hidden" name="content_type" value="{{ content_type.pk }}">
11
+ <input type="hidden" name="query_string" value="{{ query_string }}">
12
+ <input type="hidden" name="export_format"
13
+ value="{% if include_yaml_option %}yaml{% else %}csv{% endif %}">
14
+ <input type="hidden" name="_schedule_type" value="immediately">
15
+ </form>
16
+ <button type="button" class="btn btn-success dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
17
+ <span class="caret"></span>
18
+ <span class="sr-only">Toggle Dropdown</span>
19
+ </button>
20
+ <ul class="dropdown-menu dropdown-menu-right">
21
+ {% if include_yaml_option %}
22
+ <li>
23
+ <button type="submit" class="btn btn-link" form="export_default">YAML format</button>
24
+ </li>
25
+ <li>
26
+ <form action="{{ export_url }}" method="post">
27
+ {% csrf_token %}
28
+ <input type="hidden" name="content_type" value="{{ content_type.pk }}">
29
+ <input type="hidden" name="query_string" value="{{ query_string }}">
30
+ <input type="hidden" name="_schedule_type" value="immediately">
31
+ <button type="submit" class="btn btn-link">CSV format</button>
32
+ </form>
33
+ </li>
34
+ {% else %}
35
+ <li>
36
+ <button type="submit" class="btn btn-link" form="export_default">CSV format</button>
37
+ </li>
38
+ {% endif %}
39
+ {% if export_templates %}
40
+ <li class="divider"></li>
41
+ {% for et in export_templates %}
24
42
  <li>
25
43
  <form action="{{ export_url }}" method="post">
26
44
  {% csrf_token %}
27
45
  <input type="hidden" name="content_type" value="{{ content_type.pk }}">
46
+ <input type="hidden" name="export_template" value="{{ et.pk }}">
28
47
  <input type="hidden" name="query_string" value="{{ query_string }}">
29
48
  <input type="hidden" name="_schedule_type" value="immediately">
30
- <button type="submit" class="btn btn-link">CSV format</button>
49
+ <button type="submit" class="btn btn-link"
50
+ {% if et.description %}title="{{ et.description }}"{% endif %}
51
+ >{{ et.name }}</button>
31
52
  </form>
32
53
  </li>
33
- {% else %}
34
- <li>
35
- <button type="submit" class="btn btn-link">CSV format</button>
36
- </li>
37
- {% endif %}
38
- {% if export_templates %}
39
- <li class="divider"></li>
40
- {% for et in export_templates %}
41
- <li>
42
- <form action="{{ export_url }}" method="post">
43
- {% csrf_token %}
44
- <input type="hidden" name="content_type" value="{{ content_type.pk }}">
45
- <input type="hidden" name="export_template" value="{{ et.pk }}">
46
- <input type="hidden" name="query_string" value="{{ query_string }}">
47
- <input type="hidden" name="_schedule_type" value="immediately">
48
- <button type="submit" class="btn btn-link"
49
- {% if et.description %}title="{{ et.description }}"{% endif %}
50
- >{{ et.name }}</button>
51
- </form>
52
- </li>
53
- {% endfor %}
54
- {% endif %}
55
- </ul>
56
- </div>
57
- </form>
54
+ {% endfor %}
55
+ {% endif %}
56
+ </ul>
57
+ </div>
58
58
  {% else %}
59
59
  <form style="display: inline-block" action="{{ export_url }}" method="post">
60
60
  {% csrf_token %}
@@ -74,7 +74,7 @@
74
74
  class="remove-filter-param"
75
75
  title="Remove all items"
76
76
  data-field-type="parent"
77
- data-field-value={{ field.name }}
77
+ data-field-value="{{ field.name }}"
78
78
  >×</span>
79
79
  <ul class="filter-selection-rendered">
80
80
  {% for value in field.values %}
@@ -85,8 +85,8 @@
85
85
  <span
86
86
  class="filter-selection-choice-remove remove-filter-param"
87
87
  data-field-type="child"
88
- data-field-parent={{ field.name }}
89
- data-field-value={{ value.name }}
88
+ data-field-parent="{{ field.name }}"
89
+ data-field-value="{{ value.name }}"
90
90
  >×</span>{{ value.display }}
91
91
  </li>
92
92
  {% endfor %}
@@ -40,3 +40,6 @@
40
40
  hljs.configure({ cssSelector: '.language-graphql, .language-json, .language-xml, .language-yaml' });
41
41
  hljs.highlightAll();
42
42
  </script>
43
+ {% if settings.BRANDING_FILEPATHS.javascript %}
44
+ <script src="{% custom_branding_or_static 'javascript' None %}"></script>
45
+ {% endif %}
@@ -34,6 +34,9 @@
34
34
  <link rel="stylesheet" id="base-theme"
35
35
  href="{% versioned_static 'css/base.css' %}"
36
36
  onerror="window.location='{% url 'media_failure' %}?filename=css/base.css'">
37
+ {% if settings.BRANDING_FILEPATHS.css %}
38
+ <link rel="stylesheet" id="custom-css" href="{% custom_branding_or_static 'css' None %}">
39
+ {% endif %}
37
40
  <link rel="apple-touch-icon" sizes="180x180" href="{% custom_branding_or_static 'icon_180' 'img/nautobot_icon_180x180.png' %}">
38
41
  <link rel="icon" type="image/png" sizes="32x32" href="{% custom_branding_or_static 'icon_32' 'img/nautobot_icon_32x32.png' %}">
39
42
  <link rel="icon" type="image/png" sizes="16x16" href="{% custom_branding_or_static 'icon_16' 'img/nautobot_icon_16x16.png' %}">
@@ -53,8 +53,8 @@
53
53
  <div class="row" style="margin-top: {% if 'BANNER_LOGIN'|settings_or_config %}100{% else %}150{% endif %}px;">
54
54
  <div class="col-sm-4 col-sm-offset-4">
55
55
  {% if "BANNER_LOGIN"|settings_or_config %}
56
- <div style="margin-bottom: 25px">
57
- {{ "BANNER_LOGIN"|settings_or_config|safe }}
56
+ <div class="alert alert-info text-center" role="alert">
57
+ {{ "BANNER_LOGIN"|settings_or_config|render_markdown }}
58
58
  </div>
59
59
  {% endif %}
60
60
  {% if form.non_field_errors %}
@@ -248,6 +248,8 @@ SECRET_KEY = os.getenv("NAUTOBOT_SECRET_KEY", "{{ secret_key }}")
248
248
  # "NAUTOBOT_BRANDING_FILEPATHS_HEADER_BULLET", None
249
249
  # ), # bullet image used for various view headers
250
250
  # "nav_bullet": os.getenv("NAUTOBOT_BRANDING_FILEPATHS_NAV_BULLET", None), # bullet image used for nav menu headers
251
+ # "css": os.getenv("NAUTOBOT_BRANDING_FILEPATHS_CSS", None), # Custom global CSS
252
+ # "javascript": os.getenv("NAUTOBOT_BRANDING_FILEPATHS_JAVASCRIPT", None), # Custom global JavaScript
251
253
  # }
252
254
 
253
255
  # Prepended to CSV, YAML and export template filenames (i.e. `nautobot_device.yml`)
@@ -8,7 +8,7 @@ from django.conf import settings
8
8
  from django.contrib.staticfiles.finders import find
9
9
  from django.templatetags.static import static, StaticNode
10
10
  from django.urls import NoReverseMatch, reverse
11
- from django.utils.html import format_html
11
+ from django.utils.html import format_html, format_html_join
12
12
  from django.utils.safestring import mark_safe
13
13
  from django.utils.text import slugify as django_slugify
14
14
  from django_jinja import library
@@ -71,14 +71,7 @@ def hyperlinked_object(value, field="display"):
71
71
  >>> hyperlinked_object(location, "name")
72
72
  '<a href="/dcim/locations/leaf/">Leaf</a>'
73
73
  """
74
- if value is None:
75
- return placeholder(value)
76
- display = getattr(value, field) if hasattr(value, field) else str(value)
77
- if hasattr(value, "get_absolute_url"):
78
- if hasattr(value, "description") and value.description:
79
- return format_html('<a href="{}" title="{}">{}</a>', value.get_absolute_url(), value.description, display)
80
- return format_html('<a href="{}">{}</a>', value.get_absolute_url(), display)
81
- return format_html("{}", display)
74
+ return _build_hyperlink(value, field)
82
75
 
83
76
 
84
77
  @library.filter()
@@ -822,3 +815,67 @@ def queryset_to_pks(obj):
822
815
  result = list(obj.values_list("pk", flat=True)) if obj else []
823
816
  result = [str(entry) for entry in result]
824
817
  return ",".join(result)
818
+
819
+
820
+ @library.filter()
821
+ @register.filter()
822
+ def hyperlinked_object_target_new_tab(value, field="display"):
823
+ """Render and link to a Django model instance, if any, or render a placeholder if not.
824
+
825
+ Similar to the hyperlinked_object filter, but passes attributes needed to open the link in new tab.
826
+
827
+ Uses the specified object field if available, otherwise uses the string representation of the object.
828
+ If the object defines `get_absolute_url()` this will be used to hyperlink the displayed object;
829
+ additionally if there is an `object.description` this will be used as the title of the hyperlink.
830
+
831
+ Args:
832
+ value (Union[django.db.models.Model, None]): Instance of a Django model or None.
833
+ field (Optional[str]): Name of the field to use for the display value. Defaults to "display".
834
+
835
+ Returns:
836
+ (str): String representation of the value (hyperlinked if it defines get_absolute_url()) or a placeholder.
837
+
838
+ Examples:
839
+ >>> hyperlinked_object_target_new_tab(device)
840
+ '<a href="/dcim/devices/3faafe8c-bdd6-4317-88dc-f791e6988caa/" target="_blank" rel="noreferrer">Device 1</a>'
841
+ >>> hyperlinked_object_target_new_tab(device_role)
842
+ '<a href="/dcim/device-roles/router/" title="Devices that are routers, not switches" target="_blank" rel="noreferrer">Router</a>'
843
+ >>> hyperlinked_object_target_new_tab(None)
844
+ '<span class="text-muted">&mdash;</span>'
845
+ >>> hyperlinked_object_target_new_tab("Hello")
846
+ 'Hello'
847
+ >>> hyperlinked_object_target_new_tab(location)
848
+ '<a href="/dcim/locations/leaf/" target="_blank" rel="noreferrer">Root → Intermediate → Leaf</a>'
849
+ >>> hyperlinked_object_target_new_tab(location, "name")
850
+ '<a href="/dcim/locations/leaf/" target="_blank" rel="noreferrer">Leaf</a>'
851
+ """
852
+ return _build_hyperlink(value, field, target="_blank", rel="noreferrer")
853
+
854
+
855
+ def _build_hyperlink(value, field="", target="", rel=""):
856
+ """Internal function used by filters to build hyperlinks.
857
+
858
+ Args:
859
+ value (Union[django.db.models.Model, None]): Instance of a Django model or None.
860
+ field (Optional[str]): Name of the field to use for the display value. Defaults to "display".
861
+ target (Optional[str]): Location to open the linked document. Defaults to "" which is _self.
862
+ rel (Optional[str]): Relationship between current document and linked document. Defaults to "".
863
+
864
+ Returns:
865
+ (str): String representation of the value (hyperlinked if it defines get_absolute_url()) or a placeholder.
866
+ """
867
+ if value is None:
868
+ return placeholder(value)
869
+
870
+ attributes = {}
871
+ display = getattr(value, field) if hasattr(value, field) else str(value)
872
+ if hasattr(value, "get_absolute_url"):
873
+ attributes["href"] = value.get_absolute_url()
874
+ if hasattr(value, "description") and value.description:
875
+ attributes["title"] = value.description
876
+ if target:
877
+ attributes["target"] = target
878
+ if rel:
879
+ attributes["rel"] = rel
880
+ return format_html("<a {}>{}</a>", format_html_join(" ", '{}="{}"', attributes.items()), display)
881
+ return format_html("{}", display)
@@ -102,7 +102,12 @@ def get_job_class_and_model(module, name, source="local"):
102
102
  (JobClassInfo): Named 2-tuple of (job_class, job_model)
103
103
  """
104
104
  job_class = get_job(f"{module}.{name}")
105
- job_model = Job.objects.get(module_name=module, job_class_name=name)
105
+ try:
106
+ job_model = Job.objects.get(module_name=module, job_class_name=name)
107
+ except Job.DoesNotExist:
108
+ raise RuntimeError(
109
+ f"Job database record for {module}.{name} not found. Known jobs are: {list(Job.objects.all())}"
110
+ )
106
111
  job_model.enabled = True
107
112
  job_model.validated_save()
108
113
  return JobClassInfo(job_class, job_model)
@@ -13,12 +13,11 @@ from rest_framework import status
13
13
  from rest_framework.relations import ManyRelatedField
14
14
  from rest_framework.test import APITransactionTestCase as _APITransactionTestCase
15
15
 
16
- from nautobot.core import testing
17
16
  from nautobot.core.api.utils import get_serializer_for_model
18
17
  from nautobot.core.models import fields as core_fields
19
18
  from nautobot.core.models.tree_queries import TreeModel
20
19
  from nautobot.core.templatetags.helpers import bettertitle
21
- from nautobot.core.testing import mixins, views
20
+ from nautobot.core.testing import mixins, utils, views
22
21
  from nautobot.core.utils import lookup
23
22
  from nautobot.core.utils.data import is_uuid
24
23
  from nautobot.extras import choices as extras_choices, models as extras_models, registry
@@ -111,7 +110,7 @@ class APIViewTestCases:
111
110
  self.model._meta.model_name,
112
111
  ) in settings.EXEMPT_EXCLUDE_MODELS:
113
112
  # Models listed in EXEMPT_EXCLUDE_MODELS should not be accessible to anonymous users
114
- with testing.disable_warnings("django.request"):
113
+ with utils.disable_warnings("django.request"):
115
114
  self.assertHttpStatus(self.client.get(url, **self.header), status.HTTP_403_FORBIDDEN)
116
115
  else:
117
116
  response = self.client.get(url, **self.header)
@@ -125,7 +124,7 @@ class APIViewTestCases:
125
124
  url = self._get_detail_url(self._get_queryset().first())
126
125
 
127
126
  # Try GET without permission
128
- with testing.disable_warnings("django.request"):
127
+ with utils.disable_warnings("django.request"):
129
128
  self.assertHttpStatus(self.client.get(url, **self.header), status.HTTP_403_FORBIDDEN)
130
129
 
131
130
  @override_settings(EXEMPT_VIEW_PERMISSIONS=[])
@@ -303,7 +302,7 @@ class APIViewTestCases:
303
302
  self.model._meta.model_name,
304
303
  ) in settings.EXEMPT_EXCLUDE_MODELS:
305
304
  # Models listed in EXEMPT_EXCLUDE_MODELS should not be accessible to anonymous users
306
- with testing.disable_warnings("django.request"):
305
+ with utils.disable_warnings("django.request"):
307
306
  self.assertHttpStatus(self.client.get(url, **self.header), status.HTTP_403_FORBIDDEN)
308
307
  else:
309
308
  # TODO(Glenn): if we're passing **self.header, we are *by definition* **NOT** anonymous!!
@@ -389,7 +388,7 @@ class APIViewTestCases:
389
388
  url = self._get_list_url()
390
389
 
391
390
  # Try GET without permission
392
- with testing.disable_warnings("django.request"):
391
+ with utils.disable_warnings("django.request"):
393
392
  self.assertHttpStatus(self.client.get(url, **self.header), status.HTTP_403_FORBIDDEN)
394
393
 
395
394
  @override_settings(EXEMPT_VIEW_PERMISSIONS=[])
@@ -490,7 +489,7 @@ class APIViewTestCases:
490
489
  GET a list of objects with an unknown filter parameter and strict filtering, expect a 400 response.
491
490
  """
492
491
  self.add_permissions(f"{self.model._meta.app_label}.view_{self.model._meta.model_name}")
493
- with testing.disable_warnings("django.request"):
492
+ with utils.disable_warnings("django.request"):
494
493
  response = self.client.get(f"{self._get_list_url()}?ice_cream_flavor=rocky-road", **self.header)
495
494
  self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST)
496
495
  self.assertIsInstance(response.data, dict)
@@ -606,7 +605,7 @@ class APIViewTestCases:
606
605
  url = self._get_list_url()
607
606
 
608
607
  # Try POST without permission
609
- with testing.disable_warnings("django.request"):
608
+ with utils.disable_warnings("django.request"):
610
609
  response = self.client.post(url, self.create_data[0], format="json", **self.header)
611
610
  self.assertHttpStatus(response, status.HTTP_403_FORBIDDEN)
612
611
 
@@ -679,7 +678,7 @@ class APIViewTestCases:
679
678
  instance = self.get_deletable_object()
680
679
  else:
681
680
  # try to do it ourselves
682
- instance = testing.get_deletable_objects(self.model, self._get_queryset()).first()
681
+ instance = utils.get_deletable_objects(self.model, self._get_queryset()).first()
683
682
  if instance is None:
684
683
  self.fail("Couldn't find a single deletable object!")
685
684
 
@@ -776,7 +775,7 @@ class APIViewTestCases:
776
775
  update_data = self.update_data or getattr(self, "create_data")[0]
777
776
 
778
777
  # Try PATCH without permission
779
- with testing.disable_warnings("django.request"):
778
+ with utils.disable_warnings("django.request"):
780
779
  response = self.client.patch(url, update_data, format="json", **self.header)
781
780
  self.assertHttpStatus(response, status.HTTP_403_FORBIDDEN)
782
781
 
@@ -983,7 +982,7 @@ class APIViewTestCases:
983
982
  For some models this may just be any random object, but when we have FKs with `on_delete=models.PROTECT`
984
983
  (as is often the case) we need to find or create an instance that doesn't have such entanglements.
985
984
  """
986
- instance = testing.get_deletable_objects(self.model, self._get_queryset()).first()
985
+ instance = utils.get_deletable_objects(self.model, self._get_queryset()).first()
987
986
  if instance is None:
988
987
  self.fail("Couldn't find a single deletable object!")
989
988
  return instance
@@ -995,7 +994,7 @@ class APIViewTestCases:
995
994
  For some models this may just be any random objects, but when we have FKs with `on_delete=models.PROTECT`
996
995
  (as is often the case) we need to find or create an instance that doesn't have such entanglements.
997
996
  """
998
- instances = testing.get_deletable_objects(self.model, self._get_queryset()).values_list("pk", flat=True)[:3]
997
+ instances = utils.get_deletable_objects(self.model, self._get_queryset()).values_list("pk", flat=True)[:3]
999
998
  if len(instances) < 3:
1000
999
  self.fail(f"Couldn't find 3 deletable objects, only found {len(instances)}!")
1001
1000
  return instances
@@ -1007,7 +1006,7 @@ class APIViewTestCases:
1007
1006
  url = self._get_detail_url(self.get_deletable_object())
1008
1007
 
1009
1008
  # Try DELETE without permission
1010
- with testing.disable_warnings("django.request"):
1009
+ with utils.disable_warnings("django.request"):
1011
1010
  response = self.client.delete(url, **self.header)
1012
1011
  self.assertHttpStatus(response, status.HTTP_403_FORBIDDEN)
1013
1012
 
@@ -11,8 +11,8 @@ from django.forms.models import model_to_dict
11
11
  from netaddr import IPNetwork
12
12
  from rest_framework.test import APIClient, APIRequestFactory
13
13
 
14
- from nautobot.core import testing
15
14
  from nautobot.core.models import fields as core_fields
15
+ from nautobot.core.testing import utils
16
16
  from nautobot.core.utils import permissions
17
17
  from nautobot.extras import management, models as extras_models
18
18
  from nautobot.users import models as users_models
@@ -169,7 +169,7 @@ class NautobotTestCaseMixin:
169
169
  # REST API response; pass the response data through directly
170
170
  err_message += f"\n{response.data}"
171
171
  # Attempt to extract form validation errors from the response HTML
172
- form_errors = testing.extract_form_failures(response.content.decode(response.charset))
172
+ form_errors = utils.extract_form_failures(response.content.decode(response.charset))
173
173
  err_message += "\n" + str(form_errors or response.content.decode(response.charset) or "No data")
174
174
  if msg:
175
175
  err_message = f"{msg}\n{err_message}"