예제 #1
0
        public void error_cell_outputs_are_serialized()
        {
            var cells = new List <InteractiveDocumentElement>()
            {
                new InteractiveDocumentElement("csharp", "//", new[]
                {
                    new ErrorElement("e-name", "e-value", new[] { "at func1()", "at func2()" })
                })
            };
            var notebook   = new InteractiveDocument(cells);
            var serialized = SerializeJupyter(notebook, "\n");
            var jupyter    = JToken.Parse(serialized);

            jupyter["cells"]
            .Should()
            .ContainSingleItem()
            .Which["outputs"]
            .Should()
            .ContainSingleItem()
            .Which
            .Should()
            .BeEquivalentTo(JToken.Parse(JsonConvert.SerializeObject(
                                             new
            {
                output_type = "error",
                ename       = "e-name",
                evalue      = "e-value",
                traceback   = new[]
                {
                    "at func1()",
                    "at func2()"
                }
            }
                                             )));
        }
예제 #2
0
        public async Task parser_can_parse_teacher_notebook_with_two_challenges_with_all_components_defined()
        {
            InteractiveDocument document = await ReadDibAsync("forParsing1.dib");

            NotebookLessonParser.Parse(document, out var lesson, out var challenges);

            lesson.Setup.Select(sc => sc.Code).Join("\r\n").Should().ContainAll("lessonSetupCell1", "lessonSetupCell2");

            challenges[0].Name.Should().Be("Challenge1Name");

            challenges[0].Setup.Select(sc => sc.Code).Join("\r\n")
            .Should().ContainAll("challenge1SetupCell1", "challenge1SetupCell2");

            challenges[0].EnvironmentSetup.Select(sc => sc.Code).Join("\r\n")
            .Should().ContainAll("challenge1EnvironmentSetupCell1", "challenge1EnvironmentSetupCell2");

            challenges[0].Contents.Select(sec => sec.Code).Join("\r\n")
            .Should().ContainAll("challenge1QuestionCell1", "challenge1QuestionCell2");

            challenges[1].Name.Should().Be("Challenge2Name");

            challenges[1].Setup.Select(sc => sc.Code).Join("\r\n")
            .Should().ContainAll("challenge2SetupCell1", "challenge2SetupCell2");

            challenges[1].EnvironmentSetup.Select(sc => sc.Code).Join("\r\n")
            .Should().ContainAll("challenge2EnvironmentSetupCell1", "challenge2EnvironmentSetupCell2");

            challenges[1].Contents.Select(sec => sec.Code).Join("\r\n")
            .Should().ContainAll("challenge2QuestionCell1", "challenge2QuestionCell2");
        }
예제 #3
0
        public void text_cell_outputs_are_serialized()
        {
            var cells = new List <InteractiveDocumentElement>()
            {
                new InteractiveDocumentElement("csharp", "//", new[]
                {
                    new TextElement("this is text")
                })
            };
            var notebook   = new InteractiveDocument(cells);
            var serialized = SerializeJupyter(notebook, "\n");
            var jupyter    = JToken.Parse(serialized);

            jupyter["cells"]
            .Should()
            .ContainSingleItem()
            .Which["outputs"]
            .Should()
            .ContainSingleItem()
            .Which
            .Should()
            .BeEquivalentTo(JToken.Parse(JsonConvert.SerializeObject(
                                             new
            {
                output_type = "stream",
                name        = "stdout",
                text        = "this is text"
            }
                                             )));
        }
예제 #4
0
        public void serialized_code_cells_have_appropriate_shape()
        {
            var cells = new List <InteractiveDocumentElement>()
            {
                new InteractiveDocumentElement("csharp", "//")
            };
            var notebook   = new InteractiveDocument(cells);
            var serialized = SerializeJupyter(notebook, "\n");
            var jupyter    = JToken.Parse(serialized);

            jupyter["cells"]
            .Should()
            .ContainSingleItem()
            .Which
            .Should()
            .BeEquivalentTo(JToken.Parse(JsonConvert.SerializeObject(
                                             new
            {
                cell_type       = "code",
                execution_count = 1,
                metadata        = new
                {
                    dotnet_interactive = new
                    {
                        language = "csharp"
                    }
                },
                source = new[]
                {
                    "//"
                },
                outputs = Array.Empty <object>()
            }
                                             )));
        }
예제 #5
0
        public void serialized_markdown_cells_have_appropriate_shape()
        {
            var cells = new List <InteractiveDocumentElement>()
            {
                new InteractiveDocumentElement("markdown", "This is `markdown`.\nThis is more `markdown`.")
            };
            var notebook   = new InteractiveDocument(cells);
            var serialized = SerializeJupyter(notebook, "\n");
            var jupyter    = JToken.Parse(serialized);

            jupyter["cells"]
            .Should()
            .ContainSingleItem()
            .Which
            .Should()
            .BeEquivalentTo(JToken.Parse(JsonConvert.SerializeObject(
                                             new
            {
                cell_type = "markdown",
                metadata  = new { },
                source    = new[]
                {
                    "This is `markdown`.\n",
                    "This is more `markdown`.",
                }
            }
                                             )));
        }
예제 #6
0
        public void serialized_code_cells_with_non_default_jupyter_kernel_language_have_language_metadata_and_no_language_specifier()
        {
            var cells = new List <InteractiveDocumentElement>()
            {
                new InteractiveDocumentElement("fsharp", "let x = 1")
            };
            var notebook   = new InteractiveDocument(cells);
            var serialized = SerializeJupyter(notebook, "\n");
            var jupyter    = JToken.Parse(serialized);

            jupyter["cells"][0]
            .Should()
            .BeEquivalentTo(JToken.Parse(JsonConvert.SerializeObject(new
            {
                cell_type       = "code",
                execution_count = 1,
                metadata        = new
                {
                    dotnet_interactive = new
                    {
                        language = "fsharp"
                    }
                },
                source = new[]
                {
                    "let x = 1"
                },
                outputs = new object[] { }
            })));
        }
예제 #7
0
        public void serialized_notebook_has_appropriate_metadata()
        {
            var notebook   = new InteractiveDocument(new List <InteractiveDocumentElement>());
            var serialized = SerializeJupyter(notebook, "\n");
            var jupyter    = JToken.Parse(serialized);

            using var _ = new AssertionScope();
            jupyter["metadata"]
            .Should()
            .BeEquivalentTo(JToken.Parse(JsonConvert.SerializeObject(new
            {
                kernelspec = new
                {
                    display_name = ".NET (C#)",
                    language     = "C#",
                    name         = ".net-csharp"
                },
                language_info = new
                {
                    file_extension = ".cs",
                    mimetype       = "text/x-csharp",
                    name           = "C#",
                    pygments_lexer = "csharp",
                    version        = "8.0"
                }
            })));
            jupyter["nbformat"]
            .ToObject <int>()
            .Should()
            .Be(4);
            jupyter["nbformat_minor"]
            .ToObject <int>()
            .Should()
            .Be(4);
        }
예제 #8
0
        public void multiple_cells_are_serialized_with_appropriate_separators(string newline)
        {
            var cells = new[]
            {
                new InteractiveDocumentElement("csharp", $"// C# line 1{newline}// C# line 2"),
                new InteractiveDocumentElement("fsharp", $"// F# line 1{newline}// F# line 2"),
                new InteractiveDocumentElement("markdown", "This is `markdown`.")
            };
            var notebook      = new InteractiveDocument(cells);
            var serialized    = SerializeDib(notebook, newline);
            var expectedLines = new[]
            {
                "#!csharp",
                "",
                "// C# line 1",
                "// C# line 2",
                "",
                "#!fsharp",
                "",
                "// F# line 1",
                "// F# line 2",
                "",
                "#!markdown",
                "",
                "This is `markdown`.",
                ""
            };
            var expected = string.Join(newline, expectedLines);

            serialized
            .Should()
            .Be(expected);
        }
예제 #9
0
        public async Task duplicate_challenge_name_causes_parser_to_throw_exception()
        {
            InteractiveDocument document = await ReadDibAsync("forParsing2DuplicateChallengeName.dib");

            Action parsingDuplicateChallengeName = () => NotebookLessonParser.Parse(document, out var _, out var _);

            parsingDuplicateChallengeName
            .Should().Throw <ArgumentException>()
            .Which.Message.Should().Contain("conflicts");
        }
예제 #10
0
        public async Task notebook_with_no_challenge_causes_parser_to_throw_exception()
        {
            InteractiveDocument document = await ReadDibAsync("noChallenge.dib");

            Action parsingDuplicateChallengeName = () => NotebookLessonParser.Parse(document, out var _, out var _);

            parsingDuplicateChallengeName
            .Should().Throw <ArgumentException>()
            .Which.Message.Should().Contain("This lesson has no challenges");
        }
예제 #11
0
        public async Task a_challenge_with_no_question_causes_parser_to_throw_exception()
        {
            InteractiveDocument document = await ReadDibAsync("challengeWithNoQuestion.dib");

            Action parsingDuplicateChallengeName = () => NotebookLessonParser.Parse(document, out var _, out var _);

            parsingDuplicateChallengeName
            .Should().Throw <ArgumentException>()
            .Which.Message.Should().Contain("empty question");
        }
예제 #12
0
        public void serialized_code_cells_with_default_jupyter_kernel_language_dont_have_language_specifier()
        {
            var cells = new List <InteractiveDocumentElement>()
            {
                new InteractiveDocumentElement("csharp", "var x = 1;")
            };
            var notebook   = new InteractiveDocument(cells);
            var serialized = SerializeJupyter(notebook, "\n");
            var jupyter    = JToken.Parse(serialized);

            jupyter["cells"][0]["source"]
            .Should()
            .BeEquivalentTo(JToken.Parse(JsonConvert.SerializeObject(new object[]
            {
                "var x = 1;"
            })));
        }
예제 #13
0
        public void code_cells_with_multi_line_text_are_serialized_as_an_array()
        {
            var cells = new List <InteractiveDocumentElement>()
            {
                new InteractiveDocumentElement("csharp", "var x = 1;\nvar y = 2;")
            };
            var notebook   = new InteractiveDocument(cells);
            var serialized = SerializeJupyter(notebook, "\n");
            var jupyter    = JToken.Parse(serialized);

            jupyter["cells"][0]["source"]
            .Should()
            .BeEquivalentTo(JToken.Parse(JsonConvert.SerializeObject(new object[]
            {
                "var x = 1;\n",
                "var y = 2;"
            })));
        }
예제 #14
0
        public void serialize_entire_file_to_verify_indention()
        {
            var configuration = new Configuration()
                                .UsingExtension("json")
                                .SetInteractive(Debugger.IsAttached);
            var cells = new List <InteractiveDocumentElement>()
            {
                new InteractiveDocumentElement("csharp", "// this is csharp", new[]
                {
                    new DisplayElement(new Dictionary <string, object>()
                    {
                        { "text/html", "this is html" }
                    })
                }),
                new InteractiveDocumentElement("markdown", "This is `markdown`.")
            };
            var notebook = new InteractiveDocument(cells);
            var json     = SerializeJupyter(notebook, "\n");

            this.Assent(json, configuration);
        }
예제 #15
0
        public void extra_blank_lines_are_removed_from_beginning_and_end_on_save()
        {
            var cells = new[]
            {
                new InteractiveDocumentElement("csharp", "\n\n\n\n// this is csharp\n\n\n")
            };
            var notebook      = new InteractiveDocument(cells);
            var serialized    = SerializeDib(notebook, "\n");
            var expectedLines = new[]
            {
                "#!csharp",
                "",
                "// this is csharp",
                ""
            };
            var expected = string.Join("\n", expectedLines);

            serialized
            .Should()
            .Be(expected);
        }
예제 #16
0
        public void empty_cells_are_not_serialized()
        {
            var cells = new[]
            {
                new InteractiveDocumentElement("csharp", ""),
                new InteractiveDocumentElement("fsharp", "// this is fsharp"),
                new InteractiveDocumentElement("csharp", "")
            };
            var notebook      = new InteractiveDocument(cells);
            var serialized    = SerializeDib(notebook, "\n");
            var expectedLines = new[]
            {
                "#!fsharp",
                "",
                "// this is fsharp",
                ""
            };
            var expected = string.Join("\n", expectedLines);

            serialized
            .Should()
            .Be(expected);
        }
예제 #17
0
        public void rich_cell_outputs_are_serialized()
        {
            var cells = new List <InteractiveDocumentElement>()
            {
                new InteractiveDocumentElement("csharp", "//", new[]
                {
                    new DisplayElement(new Dictionary <string, object>
                    {
                        { "text/html", "this is html" }
                    })
                })
            };
            var notebook   = new InteractiveDocument(cells);
            var serialized = SerializeJupyter(notebook, "\n");
            var jupyter    = JToken.Parse(serialized);

            jupyter["cells"]
            .Should()
            .ContainSingleItem()
            .Which["outputs"]
            .Should()
            .ContainSingleItem()
            .Which
            .Should()
            .BeEquivalentTo(JToken.Parse(JsonConvert.SerializeObject(
                                             new
            {
                output_type = "execute_result",
                data        = new Dictionary <string, string>()
                {
                    { "text/html", "this is html" }
                },
                execution_count = 1,
                metadata        = new { }
            }
                                             )));
        }
예제 #18
0
 public NotebookSerializeRequest(string id, DocumentSerializationType serializationType, string defaultLanguage, string newLine, InteractiveDocument document)
     : base(id, serializationType, defaultLanguage)
 {
     NewLine  = newLine ?? throw new ArgumentNullException(nameof(newLine));
     Document = document ?? throw new ArgumentNullException(nameof(document));
 }
예제 #19
0
 public string SerializeDib(InteractiveDocument interactive, string newLine)
 {
     return(interactive.ToCodeSubmissionContent(newLine));
 }
        public override NotebookParseOrSerializeRequest Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            EnsureStartObject(reader, typeToConvert);

            RequestType?type = null;
            string      id   = null;
            DocumentSerializationType?serializationType = null;
            string defaultLanguage = null;

            byte[] rawData = null;
            string newLine = null;
            InteractiveDocument document = null;

            while (reader.Read())
            {
                if (reader.TokenType == JsonTokenType.PropertyName)
                {
                    switch (reader.GetString())
                    {
                    case "type":
                        if (reader.Read() && reader.TokenType == JsonTokenType.String)
                        {
                            type = JsonSerializer.Deserialize <RequestType>(ref reader, options);
                        }
                        break;

                    case "id":
                        if (reader.Read() && reader.TokenType == JsonTokenType.String)
                        {
                            id = reader.GetString();
                        }
                        break;

                    case "serializationType":
                        if (reader.Read() && reader.TokenType == JsonTokenType.String)
                        {
                            serializationType = JsonSerializer.Deserialize <DocumentSerializationType>(ref reader, options);
                        }
                        break;

                    case "defaultLanguage":
                        if (reader.Read() && reader.TokenType == JsonTokenType.String)
                        {
                            defaultLanguage = reader.GetString();
                        }
                        break;

                    case "rawData":
                        if (reader.Read() && reader.TokenType == JsonTokenType.String)
                        {
                            rawData = JsonSerializer.Deserialize <byte[]>(ref reader, options);
                        }
                        break;

                    case "newLine":
                        if (reader.Read() && reader.TokenType == JsonTokenType.String)
                        {
                            newLine = reader.GetString();
                        }
                        break;

                    case "document":
                        if (reader.Read() && reader.TokenType == JsonTokenType.StartObject)
                        {
                            document = JsonSerializer.Deserialize <InteractiveDocument>(ref reader, options);
                        }
                        break;
                    }
                }
                else if (reader.TokenType == JsonTokenType.EndObject)
                {
                    if (type is null ||
                        id is null ||
                        serializationType is null ||
                        defaultLanguage is null)
                    {
                        throw new JsonException("Missing properties on request object");
                    }

                    switch (type.GetValueOrDefault())
                    {
                    case RequestType.Parse:
                        if (rawData is null)
                        {
                            throw new JsonException($"Missing property for {nameof(NotebookParseRequest)}");
                        }

                        return(new NotebookParseRequest(id, serializationType.GetValueOrDefault(), defaultLanguage, rawData));

                    case RequestType.Serialize:
                        if (newLine is null ||
                            document is null)
                        {
                            throw new JsonException($"Missing property for {nameof(NotebookSerializeRequest)}");
                        }

                        return(new NotebookSerializeRequest(id, serializationType.GetValueOrDefault(), defaultLanguage, newLine, document));

                    default:
                        throw new JsonException($"Unsupported request type '{type}'");
                    }
                }
            }

            throw new JsonException($"Cannot deserialize {typeToConvert.Name}");
        }
예제 #21
0
 public NotebookParseResponse(string id, InteractiveDocument document)
     : base(id)
 {
     Document = document ?? throw new ArgumentNullException(nameof(document));
 }
예제 #22
0
        public override NotebookParserServerResponse Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            EnsureStartObject(reader, typeToConvert);

            string id = null;
            InteractiveDocument document = null;

            byte[] rawData      = null;
            string errorMessage = null;

            while (reader.Read())
            {
                if (reader.TokenType == JsonTokenType.PropertyName)
                {
                    switch (reader.GetString())
                    {
                    case "id":
                        if (reader.Read() && reader.TokenType == JsonTokenType.String)
                        {
                            id = reader.GetString();
                        }
                        break;

                    case "document":
                        if (reader.Read() && reader.TokenType == JsonTokenType.StartObject)
                        {
                            document = JsonSerializer.Deserialize <InteractiveDocument>(ref reader, options);
                        }
                        break;

                    case "rawData":
                        if (reader.Read() && reader.TokenType == JsonTokenType.String)
                        {
                            rawData = JsonSerializer.Deserialize <byte[]>(ref reader, options);
                        }
                        break;

                    case "errorMessage":
                        if (reader.Read() && reader.TokenType == JsonTokenType.String)
                        {
                            errorMessage = reader.GetString();
                        }
                        break;
                    }
                }
                else if (reader.TokenType == JsonTokenType.EndObject)
                {
                    if (id is null)
                    {
                        throw new JsonException("Missing properties on response object");
                    }

                    if (document is not null)
                    {
                        return(new NotebookParseResponse(id, document));
                    }

                    if (rawData is not null)
                    {
                        return(new NotebookSerializeResponse(id, rawData));
                    }

                    if (errorMessage is not null)
                    {
                        return(new NotebookErrorResponse(id, errorMessage));
                    }

                    throw new JsonException($"Cannot deserialize {typeToConvert.Name} due to missing properties");
                }
            }

            throw new JsonException($"Cannot deserialize {typeToConvert.Name}");
        }
예제 #23
0
        public static CompositeKernel UseProgressiveLearning(
            this CompositeKernel kernel,
            HttpClient httpClient = null)
        {
            kernel.Bootstrapping();

            var fromUrlOption = new Option <Uri>(
                "--from-url",
                "Specify lesson source URL");

            var fromFileOption = new Option <FileInfo>(
                "--from-file",
                description: "Specify lesson source file",
                parseArgument: result =>
            {
                var filePath      = result.Tokens.Single().Value;
                var fromUrlResult = result.FindResultFor(fromUrlOption);
                if (fromUrlResult is not null)
                {
                    result.ErrorMessage = $"The {fromUrlResult.Token.Value} and {(result.Parent as OptionResult).Token.Value} options cannot be used together";
                    return(null);
                }

                if (!File.Exists(filePath))
                {
                    result.ErrorMessage = Resources.Instance.FileDoesNotExist(filePath);
                    return(null);
                }

                return(new FileInfo(filePath));
            });

            var startCommand = new Command("#!start-lesson")
            {
                fromFileOption,
                fromUrlOption
            };

            startCommand.Handler = CommandHandler.Create <Uri, FileInfo, KernelInvocationContext>(StartCommandHandler);

            kernel.AddDirective(startCommand);

            return(kernel);

            async Task StartCommandHandler(Uri fromUrl, FileInfo fromFile, KernelInvocationContext context)
            {
                InteractiveDocument document = fromFile switch
                {
                    { } => await NotebookLessonParser.ReadFileAsInteractiveDocument(fromFile, kernel),
                    _ => await NotebookLessonParser.LoadNotebookFromUrl(fromUrl, httpClient)
                };

                NotebookLessonParser.Parse(document, out var lessonDefinition, out var challengeDefinitions);

                var challenges = challengeDefinitions.Select(b => b.ToChallenge()).ToList();

                challenges.SetDefaultProgressionHandlers();
                Lesson.From(lessonDefinition);
                Lesson.SetChallengeLookup(queryName => { return(challenges.FirstOrDefault(c => c.Name == queryName)); });

                await kernel.StartLesson();

                await Lesson.StartChallengeAsync(challenges.First());

                await kernel.InitializeChallenge(Lesson.CurrentChallenge);
            }
예제 #24
0
 public string SerializeJupyter(InteractiveDocument interactive, string newLine)
 {
     return(interactive.ToJupyterNotebookContent(newLine));
 }