Repository: nteract/papermill

Issue:
Update C# translator to support dotnet-interactive, include .net-fsharp and .net-powershell kernels
In the most recent preview of .NET's support for Jupyter ([.NET Interactive](https://github.com/dotnet/interactive)), we changed the name of the executable from `dotnet-try` to `dotnet-interactive`, which now supports three .NET languages: C#, F#, and PowerShell: https://devblogs.microsoft.com/dotnet/net-interactive-is-here-net-notebooks-preview-2/ 

@lobrien added support for `dotnet-try` in #448, which should be updated to the new tool, and translators added for the additional languages.


Discussion:
haresudhan: Sure @MSeal . I didn't know where to add them. Thanks for the info. I will add them. 
codecov[bot]: # [Codecov](https://codecov.io/gh/nteract/papermill/pull/528?src=pr&el=h1) Report
> Merging [#528](https://codecov.io/gh/nteract/papermill/pull/528?src=pr&el=desc) into [main](https://codecov.io/gh/nteract/papermill/commit/83f1d5d7467272dbdd0b259291e431900cfccfba&el=desc) will **increase** coverage by `0.20%`.
> The diff coverage is `100.00%`.



```diff
@@            Coverage Diff             @@
##             main     #528      +/-   ##
==========================================
+ Coverage   91.57%   91.77%   +0.20%     
==========================================
  Files          14       14              
  Lines        1258     1289      +31     
==========================================
+ Hits         1152     1183      +31     
  Misses        106      106              
```


Patch:
diff --git a/papermill/translators.py b/papermill/translators.py
index 137897a..18b62a7 100644
--- a/papermill/translators.py
+++ b/papermill/translators.py
@@ -368,6 +368,57 @@ class FSharpTranslator(Translator):
         return 'let {} = {}'.format(name, str_val)
 
 
+class PowershellTranslator(Translator):
+    @classmethod
+    def translate_escaped_str(cls, str_val):
+        """Translate a string to an escaped Matlab string"""
+        if isinstance(str_val, str):
+            str_val = str_val.encode('unicode_escape')
+            if sys.version_info >= (3, 0):
+                str_val = str_val.decode('utf-8')
+            str_val = str_val.replace('"', '`"')
+        return '"{}"'.format(str_val)
+
+    @classmethod
+    def translate_float(cls, val):
+        if math.isfinite(val):
+            return cls.translate_raw_str(val)
+        elif math.isnan(val):
+            return "[double]::NaN"
+        elif val < 0:
+            return "[double]::NegativeInfinity"
+        else:
+            return "[double]::PositiveInfinity"
+
+    @classmethod
+    def translate_none(cls, val):
+        return '$Null'
+
+    @classmethod
+    def translate_bool(cls, val):
+        return '$True' if val else '$False'
+
+    @classmethod
+    def translate_dict(cls, val):
+        kvps = '\n '.join(
+            ["{} = {}".format(cls.translate_str(k), cls.translate(v)) for k, v in val.items()]
+        )
+        return '@{{{}}}'.format(kvps)
+
+    @classmethod
+    def translate_list(cls, val):
+        escaped = ', '.join([cls.translate(v) for v in val])
+        return '@({})'.format(escaped)
+
+    @classmethod
+    def comment(cls, cmt_str):
+        return '# {}'.format(cmt_str).strip()
+
+    @classmethod
+    def assign(cls, name, str_val):
+        return '${} = {}'.format(name, str_val)
+
+
 # Instantiate a PapermillIO instance and register Handlers.
 papermill_translators = PapermillTranslators()
 papermill_translators.register("python", PythonTranslator)
@@ -377,6 +428,7 @@ papermill_translators.register("julia", JuliaTranslator)
 papermill_translators.register("matlab", MatlabTranslator)
 papermill_translators.register(".net-csharp", CSharpTranslator)
 papermill_translators.register(".net-fsharp", FSharpTranslator)
+papermill_translators.register(".net-powershell", PowershellTranslator)
 
 
 def translate_parameters(kernel_name, language, parameters, comment='Parameters'):


Test patch:
diff --git a/papermill/tests/test_translators.py b/papermill/tests/test_translators.py
index c3c584b..a67d030 100644
--- a/papermill/tests/test_translators.py
+++ b/papermill/tests/test_translators.py
@@ -245,6 +245,71 @@ def test_translate_codify_csharp(parameters, expected):
     assert translators.CSharpTranslator.codify(parameters) == expected
 
 
+# Powershell section
+@pytest.mark.parametrize(
+    "test_input,expected",
+    [
+        ("foo", '"foo"'),
+        ('{"foo": "bar"}', '"{`"foo`": `"bar`"}"'),
+        ({"foo": "bar"}, '@{"foo" = "bar"}'),
+        ({"foo": '"bar"'}, '@{"foo" = "`"bar`""}'),
+        ({"foo": ["bar"]}, '@{"foo" = @("bar")}'),
+        ({"foo": {"bar": "baz"}}, '@{"foo" = @{"bar" = "baz"}}'),
+        ({"foo": {"bar": '"baz"'}}, '@{"foo" = @{"bar" = "`"baz`""}}'),
+        (["foo"], '@("foo")'),
+        (["foo", '"bar"'], '@("foo", "`"bar`"")'),
+        ([{"foo": "bar"}], '@(@{"foo" = "bar"})'),
+        ([{"foo": '"bar"'}], '@(@{"foo" = "`"bar`""})'),
+        (12345, '12345'),
+        (-54321, '-54321'),
+        (1.2345, '1.2345'),
+        (-5432.1, '-5432.1'),
+        (float('nan'), "[double]::NaN"),
+        (float('-inf'), "[double]::NegativeInfinity"),
+        (float('inf'), "[double]::PositiveInfinity"),
+        (True, '$True'),
+        (False, '$False'),
+        (None, '$Null'),
+    ],
+)
+def test_translate_type_powershell(test_input, expected):
+    assert translators.PowershellTranslator.translate(test_input) == expected
+
+
+@pytest.mark.parametrize(
+    "parameters,expected",
+    [
+        ({"foo": "bar"}, '# Parameters\n$foo = "bar"\n'),
+        ({"foo": True}, '# Parameters\n$foo = $True\n'),
+        ({"foo": 5}, '# Parameters\n$foo = 5\n'),
+        ({"foo": 1.1}, '# Parameters\n$foo = 1.1\n'),
+        ({"foo": ['bar', 'baz']}, '# Parameters\n$foo = @("bar", "baz")\n'),
+        ({"foo": {'bar': 'baz'}}, '# Parameters\n$foo = @{"bar" = "baz"}\n'),
+        (
+            OrderedDict([['foo', 'bar'], ['baz', ['buz']]]),
+            '# Parameters\n$foo = "bar"\n$baz = @("buz")\n',
+        ),
+    ],
+)
+def test_translate_codify_powershell(parameters, expected):
+    assert translators.PowershellTranslator.codify(parameters) == expected
+
+
+@pytest.mark.parametrize(
+    "input_name,input_value,expected",
+    [("foo", '""', '$foo = ""'), ("foo", '"bar"', '$foo = "bar"')],
+)
+def test_translate_assign_powershell(input_name, input_value, expected):
+    assert translators.PowershellTranslator.assign(input_name, input_value) == expected
+
+
+@pytest.mark.parametrize(
+    "test_input,expected", [("", '#'), ("foo", '# foo'), ("['best effort']", "# ['best effort']")]
+)
+def test_translate_comment_powershell(test_input, expected):
+    assert translators.PowershellTranslator.comment(test_input) == expected
+
+
 # F# section
 @pytest.mark.parametrize(
     "test_input,expected",