mage-ai 0.8.4__py3-none-any.whl → 0.8.6__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 mage-ai might be problematic. Click here for more details.

Files changed (94) hide show
  1. mage_ai/api/policies/BlockPolicy.py +2 -0
  2. mage_ai/api/policies/PipelinePolicy.py +1 -0
  3. mage_ai/api/presenters/BlockPresenter.py +1 -0
  4. mage_ai/api/presenters/OutputPresenter.py +1 -0
  5. mage_ai/api/presenters/PipelinePresenter.py +6 -1
  6. mage_ai/data_preparation/models/block/__init__.py +18 -4
  7. mage_ai/data_preparation/models/block/dbt/__init__.py +50 -1
  8. mage_ai/data_preparation/models/block/dbt/utils/__init__.py +136 -60
  9. mage_ai/data_preparation/models/block/utils.py +2 -1
  10. mage_ai/data_preparation/models/pipeline.py +5 -3
  11. mage_ai/data_preparation/repo_manager.py +1 -1
  12. mage_ai/data_preparation/storage/local_storage.py +1 -1
  13. mage_ai/data_preparation/templates/custom/python/default.jinja +1 -1
  14. mage_ai/data_preparation/templates/data_exporters/default.jinja +2 -4
  15. mage_ai/data_preparation/templates/data_exporters/pyspark/default.jinja +2 -2
  16. mage_ai/data_preparation/templates/data_loaders/api.py +1 -1
  17. mage_ai/data_preparation/templates/data_loaders/default.jinja +1 -1
  18. mage_ai/data_preparation/templates/data_loaders/file.py +1 -0
  19. mage_ai/data_preparation/templates/data_loaders/pyspark/default.jinja +1 -1
  20. mage_ai/data_preparation/templates/testable.jinja +2 -2
  21. mage_ai/data_preparation/templates/transformers/data_warehouse_transformer.jinja +2 -0
  22. mage_ai/data_preparation/templates/transformers/default.jinja +4 -6
  23. mage_ai/data_preparation/templates/transformers/default_pyspark.jinja +4 -4
  24. mage_ai/data_preparation/templates/transformers/transformer_actions/action.jinja +2 -0
  25. mage_ai/io/base.py +11 -1
  26. mage_ai/io/postgres.py +10 -5
  27. mage_ai/server/constants.py +1 -1
  28. mage_ai/server/frontend_dist/404.html +2 -2
  29. mage_ai/server/frontend_dist/404.html.html +2 -2
  30. mage_ai/server/frontend_dist/_next/static/chunks/{2249-84de2142241f4925.js → 2249-70929b8c547bbc18.js} +1 -1
  31. mage_ai/server/frontend_dist/_next/static/chunks/4846-58b7e138009c98a2.js +1 -0
  32. mage_ai/server/frontend_dist/_next/static/chunks/{5944-9488f2ddf3543b08.js → 5944-757b7898608a65e1.js} +1 -1
  33. mage_ai/server/frontend_dist/_next/static/chunks/{6641-fb7a8be8444f2dd4.js → 6641-a0ed2bd8f5dc777b.js} +1 -1
  34. mage_ai/server/frontend_dist/_next/static/chunks/8961-7a2143c4424c9217.js +1 -0
  35. mage_ai/server/frontend_dist/_next/static/chunks/{9140-836abb2721055e82.js → 9140-6f67e0879394373d.js} +1 -1
  36. mage_ai/server/frontend_dist/_next/static/chunks/9898-51ca6a904b7a2382.js +1 -0
  37. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills-a1e8869ed201ce7e.js +1 -0
  38. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-0678cf63c79072a7.js +1 -0
  39. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/logs-5ccc75887776efb0.js +1 -0
  40. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors/{block-runs-a6dbd67285ecc5a5.js → block-runs-8f23f7ca9efcb069.js} +1 -1
  41. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/syncs-d2bbafbb5b2c09e7.js +1 -0
  42. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers-b0b91245d3299bdf.js +1 -0
  43. mage_ai/server/frontend_dist/_next/static/chunks/pages/terminal-5d7c45bb058a3f20.js +1 -0
  44. mage_ai/server/frontend_dist/_next/static/chunks/pages/{triggers-dbce4f85a95ea336.js → triggers-e0172c422c95eda9.js} +1 -1
  45. mage_ai/server/frontend_dist/_next/static/{0jln56azuIZflrR1CXt9U → okm8eXXn0kUptL5A1B7a6}/_buildManifest.js +1 -1
  46. mage_ai/server/frontend_dist/index.html +2 -2
  47. mage_ai/server/frontend_dist/manage.html +2 -2
  48. mage_ai/server/frontend_dist/pipeline-runs.html +2 -2
  49. mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills/[...slug].html +2 -2
  50. mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills.html +2 -2
  51. mage_ai/server/frontend_dist/pipelines/[pipeline]/edit.html +2 -2
  52. mage_ai/server/frontend_dist/pipelines/[pipeline]/logs.html +2 -2
  53. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runs.html +2 -2
  54. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runtime.html +2 -2
  55. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors.html +2 -2
  56. mage_ai/server/frontend_dist/pipelines/[pipeline]/runs/[run].html +2 -2
  57. mage_ai/server/frontend_dist/pipelines/[pipeline]/runs.html +2 -2
  58. mage_ai/server/frontend_dist/pipelines/[pipeline]/syncs.html +2 -2
  59. mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers/[...slug].html +2 -2
  60. mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers.html +2 -2
  61. mage_ai/server/frontend_dist/pipelines/[pipeline].html +2 -2
  62. mage_ai/server/frontend_dist/pipelines.html +2 -2
  63. mage_ai/server/frontend_dist/settings/account/profile.html +2 -2
  64. mage_ai/server/frontend_dist/settings/workspace/preferences.html +2 -2
  65. mage_ai/server/frontend_dist/settings/workspace/users.html +2 -2
  66. mage_ai/server/frontend_dist/settings.html +2 -2
  67. mage_ai/server/frontend_dist/sign-in.html +13 -13
  68. mage_ai/server/frontend_dist/terminal.html +2 -2
  69. mage_ai/server/frontend_dist/test.html +2 -2
  70. mage_ai/server/frontend_dist/triggers.html +2 -2
  71. mage_ai/server/server.py +1 -0
  72. mage_ai/server/utils/output_display.py +7 -0
  73. mage_ai/server/websocket_server.py +2 -2
  74. mage_ai/services/datadog/__init__.py +123 -0
  75. mage_ai/tests/data_preparation/test_templates.py +34 -86
  76. mage_ai/tests/services/datadog/__init__.py +0 -0
  77. mage_ai/tests/services/datadog/test_datadog.py +69 -0
  78. {mage_ai-0.8.4.dist-info → mage_ai-0.8.6.dist-info}/METADATA +2 -1
  79. {mage_ai-0.8.4.dist-info → mage_ai-0.8.6.dist-info}/RECORD +85 -82
  80. mage_ai/server/frontend_dist/_next/static/chunks/4846-64f9afc02d45293c.js +0 -1
  81. mage_ai/server/frontend_dist/_next/static/chunks/8961-e25997bc088e0d19.js +0 -1
  82. mage_ai/server/frontend_dist/_next/static/chunks/9898-91c6384c9bd33ca7.js +0 -1
  83. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills-688184bd8b4d4f5c.js +0 -1
  84. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-c6dfcc4f231cfa5a.js +0 -1
  85. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/logs-abce05c25bee218d.js +0 -1
  86. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/syncs-a056c0e384d39c9b.js +0 -1
  87. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers-6a8545f96cc7b8f2.js +0 -1
  88. mage_ai/server/frontend_dist/_next/static/chunks/pages/terminal-1734d248ec2b6c24.js +0 -1
  89. /mage_ai/server/frontend_dist/_next/static/{0jln56azuIZflrR1CXt9U → okm8eXXn0kUptL5A1B7a6}/_middlewareManifest.js +0 -0
  90. /mage_ai/server/frontend_dist/_next/static/{0jln56azuIZflrR1CXt9U → okm8eXXn0kUptL5A1B7a6}/_ssgManifest.js +0 -0
  91. {mage_ai-0.8.4.dist-info → mage_ai-0.8.6.dist-info}/LICENSE +0 -0
  92. {mage_ai-0.8.4.dist-info → mage_ai-0.8.6.dist-info}/WHEEL +0 -0
  93. {mage_ai-0.8.4.dist-info → mage_ai-0.8.6.dist-info}/entry_points.txt +0 -0
  94. {mage_ai-0.8.4.dist-info → mage_ai-0.8.6.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,4 @@
1
- <!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta content="width=device-width, initial-scale=1.0, maximum-scale=5.0, user-scalable=0" name="viewport"/><title>Triggers | Mage</title><meta name="next-head-count" content="3"/><link href="/favicon.ico" rel="icon"/><link rel="preload" href="/_next/static/css/d1e8e64d0b07af2f.css" as="style"/><link rel="stylesheet" href="/_next/static/css/d1e8e64d0b07af2f.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-5cd94c89d3acac5f.js"></script><script src="/_next/static/chunks/webpack-bc5e4eb2c1ff587c.js" defer=""></script><script src="/_next/static/chunks/framework-7c365855dab1bf41.js" defer=""></script><script src="/_next/static/chunks/main-bb0dd5375146d7fd.js" defer=""></script><script src="/_next/static/chunks/pages/_app-0aed65f2e085822e.js" defer=""></script><script src="/_next/static/chunks/3850-6395783d820def1c.js" defer=""></script><script src="/_next/static/chunks/9767-599ba5464d0bf65a.js" defer=""></script><script src="/_next/static/chunks/6579-0bf2380344587a96.js" defer=""></script><script src="/_next/static/chunks/434-69ddfacd3e93f2db.js" defer=""></script><script src="/_next/static/chunks/9898-91c6384c9bd33ca7.js" defer=""></script><script src="/_next/static/chunks/pages/triggers-dbce4f85a95ea336.js" defer=""></script><script src="/_next/static/0jln56azuIZflrR1CXt9U/_buildManifest.js" defer=""></script><script src="/_next/static/0jln56azuIZflrR1CXt9U/_ssgManifest.js" defer=""></script><script src="/_next/static/0jln56azuIZflrR1CXt9U/_middlewareManifest.js" defer=""></script><style data-styled="" data-styled-version="5.3.6">html{-webkit-box-sizing:border-box;box-sizing:border-box;-ms-overflow-style:scrollbar;}/*!sc*/
1
+ <!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta content="width=device-width, initial-scale=1.0, maximum-scale=5.0, user-scalable=0" name="viewport"/><title>Triggers | Mage</title><meta name="next-head-count" content="3"/><link href="/favicon.ico" rel="icon"/><link rel="preload" href="/_next/static/css/d1e8e64d0b07af2f.css" as="style"/><link rel="stylesheet" href="/_next/static/css/d1e8e64d0b07af2f.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-5cd94c89d3acac5f.js"></script><script src="/_next/static/chunks/webpack-bc5e4eb2c1ff587c.js" defer=""></script><script src="/_next/static/chunks/framework-7c365855dab1bf41.js" defer=""></script><script src="/_next/static/chunks/main-bb0dd5375146d7fd.js" defer=""></script><script src="/_next/static/chunks/pages/_app-0aed65f2e085822e.js" defer=""></script><script src="/_next/static/chunks/3850-6395783d820def1c.js" defer=""></script><script src="/_next/static/chunks/9767-599ba5464d0bf65a.js" defer=""></script><script src="/_next/static/chunks/6579-0bf2380344587a96.js" defer=""></script><script src="/_next/static/chunks/434-69ddfacd3e93f2db.js" defer=""></script><script src="/_next/static/chunks/9898-51ca6a904b7a2382.js" defer=""></script><script src="/_next/static/chunks/pages/triggers-e0172c422c95eda9.js" defer=""></script><script src="/_next/static/okm8eXXn0kUptL5A1B7a6/_buildManifest.js" defer=""></script><script src="/_next/static/okm8eXXn0kUptL5A1B7a6/_ssgManifest.js" defer=""></script><script src="/_next/static/okm8eXXn0kUptL5A1B7a6/_middlewareManifest.js" defer=""></script><style data-styled="" data-styled-version="5.3.6">html{-webkit-box-sizing:border-box;box-sizing:border-box;-ms-overflow-style:scrollbar;}/*!sc*/
2
2
  *,*::before,*::after{-webkit-box-sizing:inherit;box-sizing:inherit;}/*!sc*/
3
3
  data-styled.g4[id="sc-global-czSCUT1"]{content:"sc-global-czSCUT1,"}/*!sc*/
4
4
  .kOVcuR .Toastify__toast-container{margin-top:24px;padding:0 !important;width:500px !important;}/*!sc*/
@@ -17,4 +17,4 @@ data-styled.g72[id="indexstyle__HeaderStyle-sc-1bk8irg-0"]{content:"gbXfes,"}/*!
17
17
  data-styled.g74[id="indexstyle__ContainerStyle-sc-ecogjt-0"]{content:"ijwRXz,"}/*!sc*/
18
18
  .jMqDRN{padding:16px;background-color:#232429;border-right:1px solid #1C1C1C;}/*!sc*/
19
19
  data-styled.g75[id="indexstyle__VerticalNavigationStyle-sc-ecogjt-1"]{content:"jMqDRN,"}/*!sc*/
20
- </style></head><body><div id="__next"><div class="" style="position:fixed;top:0;left:0;height:2px;background:transparent;z-index:99999999999;width:100%"><div class="" style="height:100%;background:#FF144D;transition:all 500ms ease;width:0%"><div style="box-shadow:0 0 10px #FF144D, 0 0 10px #FF144D;width:5%;opacity:1;position:absolute;height:100%;transition:all 500ms ease;transform:rotate(3deg) translate(0px, -4px);left:-10rem"></div></div></div><div class="indexstyle__HeaderStyle-sc-1bk8irg-0 gbXfes"><div></div></div><div class="indexstyle__ContainerStyle-sc-ecogjt-0 ijwRXz"><div class="indexstyle__VerticalNavigationStyle-sc-ecogjt-1 jMqDRN"><div></div></div><div class="Flex-sc-sgfnl9-0 dKQluW"><div></div></div></div><div></div><div></div><div class="ToastWrapper-sc-1a33ph1-0 kOVcuR"><div class="Toastify"></div></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{"auth":{"decodedToken":{"expires":0,"token":null}}},"currentTheme":{"accent":{"alert":"#F6540B","blue":"#4877FF","blueLight":"rgba(72, 119, 255, 0.5)","contentDefaultTransparent":"rgba(174, 174, 174, 0.5)","cyan":"#65E3FF","cyanTransparent":"rgba(101, 227, 255, 0.12)","dbt":"#fc6949","dbtLight":"rgba(252, 105, 73, 0.5)","info":"#00ABFF","infoTransparent":"rgba(0, 171, 255, 0.5)","negative":"#FF1E59","negativeTransparent":"rgba(255, 30, 89, 0.3)","pink":"#FF4FF8","pinkLight":"#FFB9FC","positive":"#00A81A","primaryTransparent":"rgba(155, 108, 167, 0.5)","purple":"#7D55EC","purpleLight":"rgba(125, 85, 236, 0.5)","teal":"#00B4CC","tealLight":"rgba(0, 180, 204, 0.5)","warning":"#DD9900","warningTransparent":"rgba(221, 153, 0, 0.5)","yellow":"#FFCC19","yellowLight":"rgba(255, 204, 25, 0.5)"},"background":{"chartBlock":"#2E3036","codeArea":"#1E1F24","codeTextarea":"#000000","content":"#1B1C20","danger":"#FFD0DB","dark":"#B1B8C3","header":"#1B1B1B","menu":"#0F4CFF","muted":"#F9FAFC","navigation":"#EDEDED","output":"#2E3036","page":"#1E1F24","panel":"#232429","popup":"#27292E","row":"#2C2C2C","row2":"#51535C","scrollbarThumb":"rgba(100, 100, 100, 0.5)","scrollbarThumbHover":"rgba(255, 255, 255, 0.3)","scrollbarTrack":"#2E3036","success":"#8ADE00","table":"#292A2F"},"borders":{"contrast":"#FFFFFF","danger":"#FF144D","dark":"#000000","info":"#FFCC19","light":"#2F3034","medium":"#1C1C1C","success":"#2FCB52"},"brand":{"earth100":"#C6EEDB","earth200":"#9DDFBF","earth300":"#6BBF96","earth400":"#37A46F","earth400Transparent":"rgba(55, 164, 111, 0.4)","earth500":"#00954C","energy100":"#FFF4BA","energy200":"#FFED92","energy300":"#FFE662","energy400":"#FFDA19","energy400Transparent":"rgba(255, 218, 25, 0.04)","energy500":"#F6C000","fire100":"#FFD7E0","fire200":"#FFA3B9","fire300":"#FF547D","fire400":"#FF144D","fire400Transparent":"rgba(255, 20, 77, 0.4)","fire500":"#EB0032","stone100":"#F3E6D7","stone200":"#E3D4C2","stone400":"#BFA78B","stone500":"#AF8859","water100":"#BDCEFF","water200":"#81A1FF","water300":"#517DFF","water400":"#2A60FE","water400Transparent":"rgba(42, 96, 254, 0.4)","water500":"#0F4CFF","wind100":"#EEEAFF","wind200":"#CCC1F4","wind300":"#A698DD","wind400":"#6B50D7","wind400SuperTransparent":"rgba(107, 80, 215, 0.12)","wind400Transparent":"rgba(107, 80, 215, 0.4)","wind500":"#4E32BC"},"chart":{"backgroundPrimary":"#7D55EC","backgroundSecondary":"#FF144D","backgroundTertiary":"#86E2FF","button1":"#4877FF","button2":"#FFCC19","button3":"#8ADE00","button4":"#FF4FF8","button5":"#B98D95","lines":"#9B6CA7","primary":"#6B50D7","secondary":"#FF144D","tertiary":"#2A60FE"},"content":{"active":"#FFFFFF","default":"#AEAEAE","disabled":"rgba(255, 255, 255, 0.3)","inverted":"#2C2C2C","muted":"#787A85"},"elevation":{"visualizationAccent":"#996CFF","visualizationAccentAlt":"#C1ACF7"},"feature":{"active":"rgba(250, 248, 254, 0.14)","disabled":"rgba(201, 206, 218, 0.12)"},"icons":{"neutral":"#787878"},"interactive":{"activeBorder":"#060606","checked":"#060606","dangerBorder":"#FF144D","defaultBackground":"#36383F","defaultBorder":"#1C1C1C","disabledBorder":"#B1B8C3","focusBackground":"#B1B8C3","focusBorder":"#86E2FF","hoverBackground":"#4E4E4E","hoverBorder":"#B9BFCA","hoverOverlay":"rgba(255, 255, 255, 0.1)","linkPrimary":"#1752FF","linkPrimaryHover":"#4877FF","linkSecondary":"#6B50D7","linkSecondaryDisabled":"#C4B9EF","rowHoverBackground":"rgba(0, 0, 0, 0.1)"},"loader":{"color":"#EB0032","colorInverted":"#8ADE00"},"logo":{"color":"#FFFFFF"},"monotone":{"black":"#060606","blackTransparent":"rgba(0, 0, 0, 0.6)","gray":"#B1B8C3","grey100":"#F2F2F2","grey200":"#D5D7DC","grey300":"#B4B8C0","grey400":"#70747C","grey500":"#51535C","purple":"#6B50D7","white":"#FFFFFF"},"neutral":{"n100":"#E7E8EA","n200":"#D8DADE","n300":"#CBCCD0","n400":"#BCBEC4","n500":"#AEB0B6"},"progress":{"negative":"#FF144D","positive":"#6B50D7"},"shadow":{"base":"12px 40px 120px rgba(106, 117, 139, 0.4)","menu":"4px 10px 20px rgba(6, 6, 6, 0.12)","popup":"10px 20px 40px rgba(0, 0, 0, 0.2)","small":"0px, 4px, rgba(0, 0, 0, 0.25)","window":"0px 10px 60px rgba(0, 0, 0, 0.7)"},"status":{"negative":"#FF144D","positive":"#24B400"},"text":{"fileBrowser":"#787A85"}}},"page":"/triggers","query":{},"buildId":"0jln56azuIZflrR1CXt9U","nextExport":true,"isFallback":false,"gip":true,"appGip":true,"scriptLoader":[]}</script></body></html>
20
+ </style></head><body><div id="__next"><div class="" style="position:fixed;top:0;left:0;height:2px;background:transparent;z-index:99999999999;width:100%"><div class="" style="height:100%;background:#FF144D;transition:all 500ms ease;width:0%"><div style="box-shadow:0 0 10px #FF144D, 0 0 10px #FF144D;width:5%;opacity:1;position:absolute;height:100%;transition:all 500ms ease;transform:rotate(3deg) translate(0px, -4px);left:-10rem"></div></div></div><div class="indexstyle__HeaderStyle-sc-1bk8irg-0 gbXfes"><div></div></div><div class="indexstyle__ContainerStyle-sc-ecogjt-0 ijwRXz"><div class="indexstyle__VerticalNavigationStyle-sc-ecogjt-1 jMqDRN"><div></div></div><div class="Flex-sc-sgfnl9-0 dKQluW"><div></div></div></div><div></div><div></div><div class="ToastWrapper-sc-1a33ph1-0 kOVcuR"><div class="Toastify"></div></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{"auth":{"decodedToken":{"expires":0,"token":null}}},"currentTheme":{"accent":{"alert":"#F6540B","blue":"#4877FF","blueLight":"rgba(72, 119, 255, 0.5)","contentDefaultTransparent":"rgba(174, 174, 174, 0.5)","cyan":"#65E3FF","cyanTransparent":"rgba(101, 227, 255, 0.12)","dbt":"#fc6949","dbtLight":"rgba(252, 105, 73, 0.5)","info":"#00ABFF","infoTransparent":"rgba(0, 171, 255, 0.5)","negative":"#FF1E59","negativeTransparent":"rgba(255, 30, 89, 0.3)","pink":"#FF4FF8","pinkLight":"#FFB9FC","positive":"#00A81A","primaryTransparent":"rgba(155, 108, 167, 0.5)","purple":"#7D55EC","purpleLight":"rgba(125, 85, 236, 0.5)","teal":"#00B4CC","tealLight":"rgba(0, 180, 204, 0.5)","warning":"#DD9900","warningTransparent":"rgba(221, 153, 0, 0.5)","yellow":"#FFCC19","yellowLight":"rgba(255, 204, 25, 0.5)"},"background":{"chartBlock":"#2E3036","codeArea":"#1E1F24","codeTextarea":"#000000","content":"#1B1C20","danger":"#FFD0DB","dark":"#B1B8C3","header":"#1B1B1B","menu":"#0F4CFF","muted":"#F9FAFC","navigation":"#EDEDED","output":"#2E3036","page":"#1E1F24","panel":"#232429","popup":"#27292E","row":"#2C2C2C","row2":"#51535C","scrollbarThumb":"rgba(100, 100, 100, 0.5)","scrollbarThumbHover":"rgba(255, 255, 255, 0.3)","scrollbarTrack":"#2E3036","success":"#8ADE00","table":"#292A2F"},"borders":{"contrast":"#FFFFFF","danger":"#FF144D","dark":"#000000","info":"#FFCC19","light":"#2F3034","medium":"#1C1C1C","success":"#2FCB52"},"brand":{"earth100":"#C6EEDB","earth200":"#9DDFBF","earth300":"#6BBF96","earth400":"#37A46F","earth400Transparent":"rgba(55, 164, 111, 0.4)","earth500":"#00954C","energy100":"#FFF4BA","energy200":"#FFED92","energy300":"#FFE662","energy400":"#FFDA19","energy400Transparent":"rgba(255, 218, 25, 0.04)","energy500":"#F6C000","fire100":"#FFD7E0","fire200":"#FFA3B9","fire300":"#FF547D","fire400":"#FF144D","fire400Transparent":"rgba(255, 20, 77, 0.4)","fire500":"#EB0032","stone100":"#F3E6D7","stone200":"#E3D4C2","stone400":"#BFA78B","stone500":"#AF8859","water100":"#BDCEFF","water200":"#81A1FF","water300":"#517DFF","water400":"#2A60FE","water400Transparent":"rgba(42, 96, 254, 0.4)","water500":"#0F4CFF","wind100":"#EEEAFF","wind200":"#CCC1F4","wind300":"#A698DD","wind400":"#6B50D7","wind400SuperTransparent":"rgba(107, 80, 215, 0.12)","wind400Transparent":"rgba(107, 80, 215, 0.4)","wind500":"#4E32BC"},"chart":{"backgroundPrimary":"#7D55EC","backgroundSecondary":"#FF144D","backgroundTertiary":"#86E2FF","button1":"#4877FF","button2":"#FFCC19","button3":"#8ADE00","button4":"#FF4FF8","button5":"#B98D95","lines":"#9B6CA7","primary":"#6B50D7","secondary":"#FF144D","tertiary":"#2A60FE"},"content":{"active":"#FFFFFF","default":"#AEAEAE","disabled":"rgba(255, 255, 255, 0.3)","inverted":"#2C2C2C","muted":"#787A85"},"elevation":{"visualizationAccent":"#996CFF","visualizationAccentAlt":"#C1ACF7"},"feature":{"active":"rgba(250, 248, 254, 0.14)","disabled":"rgba(201, 206, 218, 0.12)"},"icons":{"neutral":"#787878"},"interactive":{"activeBorder":"#060606","checked":"#060606","dangerBorder":"#FF144D","defaultBackground":"#36383F","defaultBorder":"#1C1C1C","disabledBorder":"#B1B8C3","focusBackground":"#B1B8C3","focusBorder":"#86E2FF","hoverBackground":"#4E4E4E","hoverBorder":"#B9BFCA","hoverOverlay":"rgba(255, 255, 255, 0.1)","linkPrimary":"#1752FF","linkPrimaryHover":"#4877FF","linkSecondary":"#6B50D7","linkSecondaryDisabled":"#C4B9EF","rowHoverBackground":"rgba(0, 0, 0, 0.1)"},"loader":{"color":"#EB0032","colorInverted":"#8ADE00"},"logo":{"color":"#FFFFFF"},"monotone":{"black":"#060606","blackTransparent":"rgba(0, 0, 0, 0.6)","gray":"#B1B8C3","grey100":"#F2F2F2","grey200":"#D5D7DC","grey300":"#B4B8C0","grey400":"#70747C","grey500":"#51535C","purple":"#6B50D7","white":"#FFFFFF"},"neutral":{"n100":"#E7E8EA","n200":"#D8DADE","n300":"#CBCCD0","n400":"#BCBEC4","n500":"#AEB0B6"},"progress":{"negative":"#FF144D","positive":"#6B50D7"},"shadow":{"base":"12px 40px 120px rgba(106, 117, 139, 0.4)","menu":"4px 10px 20px rgba(6, 6, 6, 0.12)","popup":"10px 20px 40px rgba(0, 0, 0, 0.2)","small":"0px, 4px, rgba(0, 0, 0, 0.25)","window":"0px 10px 60px rgba(0, 0, 0, 0.7)"},"status":{"negative":"#FF144D","positive":"#24B400"},"text":{"fileBrowser":"#787A85"}}},"page":"/triggers","query":{},"buildId":"okm8eXXn0kUptL5A1B7a6","nextExport":true,"isFallback":false,"gip":true,"appGip":true,"scriptLoader":[]}</script></body></html>
mage_ai/server/server.py CHANGED
@@ -148,6 +148,7 @@ def make_app():
148
148
  (r'/pipelines', MainPageHandler),
149
149
  (r'/pipelines/(.*)', MainPageHandler),
150
150
  (r'/pipeline-runs', PipelineRunsPageHandler),
151
+ (r'/settings', MainPageHandler),
151
152
  (r'/sign-in', MainPageHandler),
152
153
  (r'/terminal', MainPageHandler),
153
154
  (r'/manage', ManagePageHandler),
@@ -6,6 +6,7 @@ from mage_ai.data_preparation.models.constants import (
6
6
  from mage_ai.server.kernels import KernelName
7
7
  from mage_ai.shared.code import is_pyspark_code
8
8
  from typing import Dict, List
9
+ import json
9
10
  import re
10
11
 
11
12
 
@@ -226,9 +227,12 @@ def add_execution_code(
226
227
  run_upstream: bool = False,
227
228
  update_status: bool = True,
228
229
  widget: bool = False,
230
+ run_settings: Dict = None,
229
231
  ) -> str:
230
232
  escaped_code = code.replace("'''", "\"\"\"")
231
233
 
234
+ run_settings_json = json.dumps(run_settings or {})
235
+
232
236
  magic_header = ''
233
237
  spark_session_init = ''
234
238
  if kernel_name == KernelName.PYSPARK:
@@ -252,8 +256,10 @@ from mage_ai.data_preparation.repo_manager import get_repo_path
252
256
  from mage_ai.orchestration.db import db_connection
253
257
  from mage_ai.shared.array import find
254
258
  import datetime
259
+ import json
255
260
  import pandas as pd
256
261
 
262
+
257
263
  db_connection.start_session()
258
264
  {spark_session_init}
259
265
 
@@ -285,6 +291,7 @@ def execute_custom_code():
285
291
  custom_code=code,
286
292
  global_vars=global_vars,
287
293
  analyze_outputs={analyze_outputs},
294
+ run_settings=json.loads('{run_settings_json}'),
288
295
  update_status={update_status},
289
296
  test_execution=True,
290
297
  )
@@ -175,8 +175,6 @@ class WebSocketServer(tornado.websocket.WebSocketHandler):
175
175
  oauth_token.user and \
176
176
  has_at_least_editor_role(oauth_token.user)
177
177
 
178
- print('WTFFFFFFFFFFFFFFFFFFFFFF', has_at_least_editor_role(oauth_token.user))
179
-
180
178
  if not valid:
181
179
  return self.send_message(
182
180
  dict(
@@ -299,6 +297,7 @@ class WebSocketServer(tornado.websocket.WebSocketHandler):
299
297
  run_downstream = message.get('run_downstream')
300
298
  run_tests = message.get('run_tests')
301
299
  run_upstream = message.get('run_upstream')
300
+ run_settings = message.get('run_settings')
302
301
 
303
302
  pipeline_uuid = pipeline.uuid
304
303
 
@@ -344,6 +343,7 @@ class WebSocketServer(tornado.websocket.WebSocketHandler):
344
343
  run_upstream=run_upstream,
345
344
  update_status=False if remote_execution else True,
346
345
  widget=widget,
346
+ run_settings=run_settings,
347
347
  )
348
348
 
349
349
  msg_id = client.execute(add_internal_output_info(code))
@@ -0,0 +1,123 @@
1
+ from datadog import initialize, api, statsd
2
+ from datetime import datetime
3
+ import os
4
+ import time
5
+
6
+ options = {
7
+ 'api_key': os.getenv('DD_API_KEY'),
8
+ 'app_key': os.getenv('DD_APP_KEY'),
9
+ }
10
+
11
+ initialize(**options)
12
+
13
+
14
+ def create_event(title, text, tags={}):
15
+ return api.Event.create(
16
+ title=title,
17
+ text=text,
18
+ tags=tags,
19
+ )
20
+
21
+
22
+ def gauge(metric, value, host='mage', tags={}):
23
+ return api.Metric.send(
24
+ host=host,
25
+ metric=metric,
26
+ points=[
27
+ (datetime.utcnow().timestamp(), value),
28
+ ],
29
+ tags=tags,
30
+ type='gauge',
31
+ )
32
+
33
+
34
+ def increment(metric, tags={}, value=1):
35
+ return create_metrics([
36
+ (metric, value, tags),
37
+ ])
38
+
39
+
40
+ def create_metrics(metrics, host='mage', metric_type='count'):
41
+ # Format of argument
42
+ # metrics = [
43
+ # ('metric', 'value', 'tags'),
44
+ # ]
45
+ arr = [{
46
+ 'host': host,
47
+ 'metric': t[0],
48
+ 'points': t[1],
49
+ 'tags': t[2] if len(t) == 3 else {},
50
+ 'type': metric_type,
51
+ } for t in metrics]
52
+ return api.Metric.send(metrics=arr)
53
+
54
+
55
+ def create_metric(metric, value, host='mage', tags={}):
56
+ return api.Metric.send(
57
+ host=host,
58
+ metric=metric,
59
+ points=[
60
+ (datetime.utcnow().timestamp(), value),
61
+ ],
62
+ tags=tags,
63
+ type='count',
64
+ )
65
+
66
+
67
+ def histogram(metric, value, host='mage', tags={}):
68
+ return api.Metric.send(
69
+ host=host,
70
+ metric=metric,
71
+ points=[
72
+ (datetime.utcnow().timestamp(), value),
73
+ ],
74
+ tags=tags,
75
+ type='histogram',
76
+ )
77
+
78
+
79
+ def timing(metric, value, host='mage', tags={}):
80
+ return api.Metric.send(
81
+ host=host,
82
+ metric=metric,
83
+ points=[
84
+ (datetime.utcnow().timestamp(), value),
85
+ ],
86
+ tags=tags,
87
+ type='timer',
88
+ )
89
+
90
+
91
+ class timed_decorator(object):
92
+ """
93
+ @timed_decorator('metric.metric', tags={ 'key': 'value' })
94
+ """
95
+ def __init__(self, metric, tags={}):
96
+ self.metric = metric
97
+ self.tags = tags
98
+
99
+ def __call__(self, f):
100
+ def wrapped_f(*args):
101
+ with statsd.timed(self.metric, tags=self.tags):
102
+ return f(*args)
103
+ return wrapped_f
104
+
105
+
106
+ class timer(object):
107
+ """
108
+ with timer('metric.metric', tags={ 'key': 'value' }):
109
+ function()
110
+ """
111
+ def __init__(self, metric, tags={}):
112
+ self.metric = metric
113
+ self.start = None
114
+ self.tags = tags
115
+
116
+ def __enter__(self):
117
+ self.start = time.time()
118
+
119
+ def __exit__(self, type, value, traceback):
120
+ # Must convert to milliseconds, see details in
121
+ # https://statsd.readthedocs.io/en/v3.1/timing.html
122
+ dt = int((time.time() - self.start) * 1000)
123
+ return timing(self.metric, dt, tags=self.tags)
@@ -36,8 +36,6 @@ class TemplateTest(TestCase):
36
36
  expected_string = """from mage_ai.data_cleaner.transformer_actions.base import BaseAction
37
37
  from mage_ai.data_cleaner.transformer_actions.constants import ActionType, Axis
38
38
  from mage_ai.data_cleaner.transformer_actions.utils import build_transformer_action
39
- from pandas import DataFrame
40
-
41
39
  if 'transformer' not in globals():
42
40
  from mage_ai.data_preparation.decorators import transformer
43
41
  if 'test' not in globals():
@@ -80,11 +78,11 @@ def remove_rows_with_missing_entries(df: DataFrame, *args, **kwargs) -> DataFram
80
78
 
81
79
 
82
80
  @test
83
- def test_output(df, *args) -> None:
81
+ def test_output(output, *args) -> None:
84
82
  \"\"\"
85
83
  Template code for testing the output of the block.
86
84
  \"\"\"
87
- assert df is not None, 'The output is undefined'
85
+ assert output is not None, 'The output is undefined'
88
86
  """
89
87
  new_string = build_template_from_suggestion(suggestion)
90
88
  self.assertEqual(expected_string, new_string)
@@ -102,7 +100,7 @@ def load_data(*args, **kwargs):
102
100
  Template code for loading data from any source.
103
101
 
104
102
  Returns:
105
- Anything
103
+ Anything (e.g. data frame, dictionary, array, int, str, etc.)
106
104
  \"\"\"
107
105
  # Specify your data loading logic here
108
106
 
@@ -110,11 +108,11 @@ def load_data(*args, **kwargs):
110
108
 
111
109
 
112
110
  @test
113
- def test_output(df, *args) -> None:
111
+ def test_output(output, *args) -> None:
114
112
  \"\"\"
115
113
  Template code for testing the output of the block.
116
114
  \"\"\"
117
- assert df is not None, 'The output is undefined'
115
+ assert output is not None, 'The output is undefined'
118
116
  """
119
117
 
120
118
  config1 = {'data_source': 'default'}
@@ -153,11 +151,11 @@ def load_data_from_redshift(*args, **kwargs):
153
151
 
154
152
 
155
153
  @test
156
- def test_output(df, *args) -> None:
154
+ def test_output(output, *args) -> None:
157
155
  \"\"\"
158
156
  Template code for testing the output of the block.
159
157
  \"\"\"
160
- assert df is not None, 'The output is undefined'
158
+ assert output is not None, 'The output is undefined'
161
159
  """
162
160
  s3_template = """from mage_ai.data_preparation.repo_manager import get_repo_path
163
161
  from mage_ai.io.config import ConfigFileLoader
@@ -190,11 +188,11 @@ def load_from_s3_bucket(*args, **kwargs):
190
188
 
191
189
 
192
190
  @test
193
- def test_output(df, *args) -> None:
191
+ def test_output(output, *args) -> None:
194
192
  \"\"\"
195
193
  Template code for testing the output of the block.
196
194
  \"\"\"
197
- assert df is not None, 'The output is undefined'
195
+ assert output is not None, 'The output is undefined'
198
196
  """
199
197
 
200
198
  config1 = {'data_source': DataSource.REDSHIFT}
@@ -220,17 +218,17 @@ def load_data_from_api(*args, **kwargs):
220
218
  Template for loading data from API
221
219
  \"\"\"
222
220
  url = ''
223
-
224
221
  response = requests.get(url)
222
+
225
223
  return pd.read_csv(io.StringIO(response.text), sep=',')
226
224
 
227
225
 
228
226
  @test
229
- def test_output(df, *args) -> None:
227
+ def test_output(output, *args) -> None:
230
228
  \"\"\"
231
229
  Template code for testing the output of the block.
232
230
  \"\"\"
233
- assert df is not None, 'The output is undefined'
231
+ assert output is not None, 'The output is undefined'
234
232
  """
235
233
  config = {'data_source': DataSource.API}
236
234
  api_template = fetch_template_source(BlockType.DATA_LOADER, config)
@@ -268,16 +266,14 @@ consumer_group: unique_consumer_group
268
266
  self.assertEqual(kafka_template, new_kafka_template)
269
267
 
270
268
  def test_template_generation_transformer_default(self):
271
- expected_template = """from pandas import DataFrame
272
-
273
- if 'transformer' not in globals():
269
+ expected_template = """if 'transformer' not in globals():
274
270
  from mage_ai.data_preparation.decorators import transformer
275
271
  if 'test' not in globals():
276
272
  from mage_ai.data_preparation.decorators import test
277
273
 
278
274
 
279
275
  @transformer
280
- def transform_df(df: DataFrame, *args, **kwargs) -> DataFrame:
276
+ def transform(*args, **kwargs):
281
277
  \"\"\"
282
278
  Template code for a transformer block.
283
279
 
@@ -285,68 +281,22 @@ def transform_df(df: DataFrame, *args, **kwargs) -> DataFrame:
285
281
  There should be one parameter for each output variable from each parent block.
286
282
 
287
283
  Args:
288
- df (DataFrame): Data frame from parent block.
284
+ args: The input variables from upstream blocks
289
285
 
290
286
  Returns:
291
- DataFrame: Transformed data frame
287
+ Anything (e.g. data frame, dictionary, array, int, str, etc.)
292
288
  \"\"\"
293
289
  # Specify your transformation logic here
294
290
 
295
- return df
296
-
297
-
298
- @test
299
- def test_output(df, *args) -> None:
300
- \"\"\"
301
- Template code for testing the output of the block.
302
- \"\"\"
303
- assert df is not None, 'The output is undefined'
304
- """
305
-
306
- config1 = {'action_type': 'custom'}
307
- config2 = {'axis': 'row'}
308
- config3 = {}
309
- new_template1 = fetch_template_source(BlockType.TRANSFORMER, config1)
310
- new_template2 = fetch_template_source(BlockType.TRANSFORMER, config2)
311
- new_template3 = fetch_template_source(BlockType.TRANSFORMER, config3)
312
- self.assertEqual(expected_template, new_template1)
313
- self.assertEqual(expected_template, new_template2)
314
- self.assertEqual(expected_template, new_template3)
315
-
316
- def test_template_generation_transformer_action_default(self):
317
- expected_template = """from pandas import DataFrame
318
-
319
- if 'transformer' not in globals():
320
- from mage_ai.data_preparation.decorators import transformer
321
- if 'test' not in globals():
322
- from mage_ai.data_preparation.decorators import test
323
-
324
-
325
- @transformer
326
- def transform_df(df: DataFrame, *args, **kwargs) -> DataFrame:
327
- \"\"\"
328
- Template code for a transformer block.
329
-
330
- Add more parameters to this function if this block has multiple parent blocks.
331
- There should be one parameter for each output variable from each parent block.
332
-
333
- Args:
334
- df (DataFrame): Data frame from parent block.
335
-
336
- Returns:
337
- DataFrame: Transformed data frame
338
- \"\"\"
339
- # Specify your transformation logic here
340
-
341
- return df
291
+ return {}
342
292
 
343
293
 
344
294
  @test
345
- def test_output(df, *args) -> None:
295
+ def test_output(output, *args) -> None:
346
296
  \"\"\"
347
297
  Template code for testing the output of the block.
348
298
  \"\"\"
349
- assert df is not None, 'The output is undefined'
299
+ assert output is not None, 'The output is undefined'
350
300
  """
351
301
 
352
302
  config1 = {'action_type': 'custom'}
@@ -389,11 +339,11 @@ def execute_transformer_action(df: DataFrame, *args, **kwargs) -> DataFrame:
389
339
 
390
340
 
391
341
  @test
392
- def test_output(df, *args) -> None:
342
+ def test_output(output, *args) -> None:
393
343
  \"\"\"
394
344
  Template code for testing the output of the block.
395
345
  \"\"\"
396
- assert df is not None, 'The output is undefined'
346
+ assert output is not None, 'The output is undefined'
397
347
  """
398
348
 
399
349
  config = {'action_type': ActionType.CLEAN_COLUMN_NAME, 'axis': Axis.COLUMN}
@@ -430,11 +380,11 @@ def execute_transformer_action(df: DataFrame, *args, **kwargs) -> DataFrame:
430
380
 
431
381
 
432
382
  @test
433
- def test_output(df, *args) -> None:
383
+ def test_output(output, *args) -> None:
434
384
  \"\"\"
435
385
  Template code for testing the output of the block.
436
386
  \"\"\"
437
- assert df is not None, 'The output is undefined'
387
+ assert output is not None, 'The output is undefined'
438
388
  """
439
389
 
440
390
  config = {'action_type': ActionType.FILTER, 'axis': Axis.ROW}
@@ -472,11 +422,11 @@ def execute_transformer_action(df: DataFrame, *args, **kwargs) -> DataFrame:
472
422
 
473
423
 
474
424
  @test
475
- def test_output(df, *args) -> None:
425
+ def test_output(output, *args) -> None:
476
426
  \"\"\"
477
427
  Template code for testing the output of the block.
478
428
  \"\"\"
479
- assert df is not None, 'The output is undefined'
429
+ assert output is not None, 'The output is undefined'
480
430
  """
481
431
 
482
432
  config = {'action_type': ActionType.REFORMAT, 'axis': Axis.COLUMN}
@@ -519,11 +469,11 @@ def execute_transformer_action(df: DataFrame, *args, **kwargs) -> DataFrame:
519
469
 
520
470
 
521
471
  @test
522
- def test_output(df, *args) -> None:
472
+ def test_output(output, *args) -> None:
523
473
  \"\"\"
524
474
  Template code for testing the output of the block.
525
475
  \"\"\"
526
- assert df is not None, 'The output is undefined'
476
+ assert output is not None, 'The output is undefined'
527
477
  """
528
478
 
529
479
  config = {'action_type': ActionType.FIRST, 'axis': Axis.COLUMN}
@@ -531,19 +481,17 @@ def test_output(df, *args) -> None:
531
481
  self.assertEqual(expected_template, new_template)
532
482
 
533
483
  def test_template_generation_data_exporter_default(self):
534
- expected_template = """from pandas import DataFrame
535
-
536
- if 'data_exporter' not in globals():
484
+ expected_template = """if 'data_exporter' not in globals():
537
485
  from mage_ai.data_preparation.decorators import data_exporter
538
486
 
539
487
 
540
488
  @data_exporter
541
- def export_data(df: DataFrame, **kwargs):
489
+ def export_data(*args, **kwargs):
542
490
  \"\"\"
543
491
  Exports data to some source
544
492
 
545
493
  Args:
546
- df (DataFrame): Data frame to export to
494
+ args: The input variables from upstream blocks
547
495
 
548
496
  Output (optional):
549
497
  Optionally return any object and it'll be logged and
@@ -690,11 +638,11 @@ def transform_in_postgres(*args, **kwargs) -> DataFrame:
690
638
 
691
639
 
692
640
  @test
693
- def test_output(df, *args) -> None:
641
+ def test_output(output, *args) -> None:
694
642
  \"\"\"
695
643
  Template code for testing the output of the block.
696
644
  \"\"\"
697
- assert df is not None, 'The output is undefined'
645
+ assert output is not None, 'The output is undefined'
698
646
  """
699
647
 
700
648
  bigquery_template = """from mage_ai.data_preparation.repo_manager import get_repo_path
@@ -732,11 +680,11 @@ def transform_in_bigquery(*args, **kwargs) -> DataFrame:
732
680
 
733
681
 
734
682
  @test
735
- def test_output(df, *args) -> None:
683
+ def test_output(output, *args) -> None:
736
684
  \"\"\"
737
685
  Template code for testing the output of the block.
738
686
  \"\"\"
739
- assert df is not None, 'The output is undefined'
687
+ assert output is not None, 'The output is undefined'
740
688
  """
741
689
 
742
690
  config1 = {'data_source': DataSource.POSTGRES}
File without changes
@@ -0,0 +1,69 @@
1
+ from datetime import datetime
2
+ from mage_ai.services import datadog as dd
3
+ from mage_ai.tests.base_test import TestCase
4
+ from unittest.mock import Mock, patch
5
+
6
+ TEST_METRIC = 'mage.test'
7
+ TAGS = dict(tag1='tag')
8
+
9
+
10
+ class DatadogTests(TestCase):
11
+ @patch('datadog.api.Event.create')
12
+ def test_create_event(self, mock_event):
13
+ event_name = 'event name'
14
+ event_text = 'event text'
15
+ dd.create_event(event_name, event_text, tags=TAGS)
16
+ mock_event.assert_called_with(title=event_name, text=event_text, tags=TAGS)
17
+
18
+ @patch('datadog.api.Metric.send')
19
+ @patch('mage_ai.services.datadog.datetime')
20
+ def test_gauge(self, mock_dt, mock_metric):
21
+ dt = datetime(2023, 1, 1)
22
+ mock_dt.utcnow = Mock(return_value=dt)
23
+ dd.gauge(TEST_METRIC, 5, tags=TAGS)
24
+ mock_metric.assert_called_with(
25
+ host='mage',
26
+ metric=TEST_METRIC,
27
+ points=[(dt.timestamp(), 5)],
28
+ tags=TAGS,
29
+ type='gauge'
30
+ )
31
+
32
+ @patch('datadog.api.Metric.send')
33
+ def test_increment(self, mock_metric):
34
+ dd.increment(TEST_METRIC, tags=TAGS)
35
+ mock_metric.assert_called_with(metrics=[{
36
+ 'host': 'mage',
37
+ 'metric': TEST_METRIC,
38
+ 'points': 1,
39
+ 'tags': TAGS,
40
+ 'type': 'count'
41
+ }])
42
+
43
+ @patch('datadog.api.Metric.send')
44
+ @patch('mage_ai.services.datadog.datetime')
45
+ def test_histogram(self, mock_dt, mock_metric):
46
+ dt = datetime(2023, 1, 1)
47
+ mock_dt.utcnow = Mock(return_value=dt)
48
+ dd.histogram(TEST_METRIC, 3, tags=TAGS)
49
+ mock_metric.assert_called_with(
50
+ host='mage',
51
+ metric=TEST_METRIC,
52
+ points=[(dt.timestamp(), 3)],
53
+ tags=TAGS,
54
+ type='histogram'
55
+ )
56
+
57
+ @patch('datadog.api.Metric.send')
58
+ @patch('mage_ai.services.datadog.datetime')
59
+ def test_timing(self, mock_dt, mock_metric):
60
+ dt = datetime(2023, 1, 1)
61
+ mock_dt.utcnow = Mock(return_value=dt)
62
+ dd.timing(TEST_METRIC, 100, tags=TAGS)
63
+ mock_metric.assert_called_with(
64
+ host='mage',
65
+ metric=TEST_METRIC,
66
+ points=[(dt.timestamp(), 100)],
67
+ tags=TAGS,
68
+ type='timer'
69
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mage-ai
3
- Version: 0.8.4
3
+ Version: 0.8.6
4
4
  Summary: Mage is a tool for building and deploying data pipelines.
5
5
  Home-page: https://github.com/mage-ai/mage-ai
6
6
  Author: Mage
@@ -20,6 +20,7 @@ Requires-Dist: bcrypt (==4.0.1)
20
20
  Requires-Dist: croniter (==1.3.7)
21
21
  Requires-Dist: cryptography (==36.0.2)
22
22
  Requires-Dist: dask (>=2022.2.0)
23
+ Requires-Dist: datadog (==0.44.0)
23
24
  Requires-Dist: freezegun (==1.2.2)
24
25
  Requires-Dist: httpx (==0.23.1)
25
26
  Requires-Dist: inflection (==0.5.1)