public ScriptResult Execute(
            string code,
            string[] scriptArgs,
            AssemblyReferences references,
            IEnumerable<string> namespaces,
            ScriptPackSession scriptPackSession)
        {
            Guard.AgainstNullArgument("references", references);
            Guard.AgainstNullArgument("scriptPackSession", scriptPackSession);

            references = references.Union(scriptPackSession.References);

            SessionState<Evaluator> sessionState;
            var isFirstExecution = !scriptPackSession.State.ContainsKey(SessionKey);

            if (isFirstExecution)
            {
                code = code.DefineTrace();
                _log.Debug("Creating session");
                var context = new CompilerContext(
                    new CompilerSettings { AssemblyReferences = references.Paths.ToList() },
                    new ConsoleReportPrinter());

                var evaluator = new Evaluator(context);
                var allNamespaces = namespaces.Union(scriptPackSession.Namespaces).Distinct();

                var host = _scriptHostFactory.CreateScriptHost(
                    new ScriptPackManager(scriptPackSession.Contexts), scriptArgs);

                MonoHost.SetHost((ScriptHost)host);
                ScriptLibraryWrapper.SetHost(host);

                evaluator.ReferenceAssembly(typeof(MonoHost).Assembly);
                evaluator.InteractiveBaseClass = typeof(MonoHost);

                sessionState = new SessionState<Evaluator>
                {
                    References = references,
                    Namespaces = new HashSet<string>(),
                    Session = evaluator,
                };

                ImportNamespaces(allNamespaces, sessionState);
                scriptPackSession.State[SessionKey] = sessionState;
            }
            else
            {
                _log.Debug("Reusing existing session");
                sessionState = (SessionState<Evaluator>)scriptPackSession.State[SessionKey];

                var newReferences = sessionState.References == null
                    ? references
                    : references.Except(sessionState.References);

                foreach (var reference in newReferences.Paths)
                {
                    _log.DebugFormat("Adding reference to {0}", reference);
                    sessionState.Session.LoadAssembly(reference);
                }

                sessionState.References = references;

                var newNamespaces = sessionState.Namespaces == null
                    ? namespaces
                    : namespaces.Except(sessionState.Namespaces);

                ImportNamespaces(newNamespaces, sessionState);
            }

            _log.Debug("Starting execution");
            var result = Execute(code, sessionState.Session);
            _log.Debug("Finished execution");

            return result;
        }
        public ScriptResult Execute(
            string code,
            string[] scriptArgs,
            AssemblyReferences references,
            IEnumerable<string> namespaces,
            ScriptPackSession scriptPackSession)
        {
            Guard.AgainstNullArgument("scriptPackSession", scriptPackSession);
            Guard.AgainstNullArgument("references", references);

            _log.Debug("Starting to create execution components");
            _log.Debug("Creating script host");

            var executionReferences = references.Union(scriptPackSession.References);

            SessionState<Session> sessionState;

            var isFirstExecution = !scriptPackSession.State.ContainsKey(SessionKey);

            if (isFirstExecution)
            {
                code = code.DefineTrace();
                var host = _scriptHostFactory.CreateScriptHost(
                    new ScriptPackManager(scriptPackSession.Contexts), scriptArgs);

                ScriptLibraryWrapper.SetHost(host);
                _log.Debug("Creating session");

                var hostType = host.GetType();
                ScriptEngine.AddReference(hostType.Assembly);
                var session = ScriptEngine.CreateSession(host, hostType);
                var allNamespaces = namespaces.Union(scriptPackSession.Namespaces).Distinct();

                foreach (var reference in executionReferences.Paths)
                {
                    _log.DebugFormat("Adding reference to {0}", reference);
                    session.AddReference(reference);
                }

                foreach (var assembly in executionReferences.Assemblies)
                {
                    _log.DebugFormat("Adding reference to {0}", assembly.FullName);
                    session.AddReference(assembly);
                }

                foreach (var @namespace in allNamespaces)
                {
                    _log.DebugFormat("Importing namespace {0}", @namespace);
                    session.ImportNamespace(@namespace);
                }

                sessionState = new SessionState<Session>
                {
                    References = executionReferences,
                    Session = session,
                    Namespaces = new HashSet<string>(allNamespaces)
                };
                
                scriptPackSession.State[SessionKey] = sessionState;
            }
            else
            {
                _log.Debug("Reusing existing session");
                sessionState = (SessionState<Session>)scriptPackSession.State[SessionKey];

                if (sessionState.References == null)
                {
                    sessionState.References = new AssemblyReferences();
                }

                if (sessionState.Namespaces == null)
                {
                    sessionState.Namespaces = new HashSet<string>();
                }

                var newReferences = executionReferences.Except(sessionState.References);

                foreach (var reference in newReferences.Paths)
                {
                    _log.DebugFormat("Adding reference to {0}", reference);
                    sessionState.Session.AddReference(reference);
                    sessionState.References = sessionState.References.Union(new[] { reference });
                }

                foreach (var assembly in newReferences.Assemblies)
                {
                    _log.DebugFormat("Adding reference to {0}", assembly.FullName);
                    sessionState.Session.AddReference(assembly);
                    sessionState.References = sessionState.References.Union(new[] { assembly });
                }

                var newNamespaces = namespaces.Except(sessionState.Namespaces);

                foreach (var @namespace in newNamespaces)
                {
                    _log.DebugFormat("Importing namespace {0}", @namespace);
                    sessionState.Session.ImportNamespace(@namespace);
                    sessionState.Namespaces.Add(@namespace);
                }
            }

            _log.Debug("Starting execution");

            var result = Execute(code, sessionState.Session);

            if (result.InvalidNamespaces.Any())
            {
                var pendingNamespacesField = sessionState.Session.GetType().GetField(
                    "pendingNamespaces",
                    System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);

                if (pendingNamespacesField != null)
                {
                    var pendingNamespacesValue = (ReadOnlyArray<string>)pendingNamespacesField
                        .GetValue(sessionState.Session);

                    //no need to check this for null as ReadOnlyArray is a value type
                    if (pendingNamespacesValue.Any())
                    {
                        var fixedNamespaces = pendingNamespacesValue.ToList();

                        foreach (var @namespace in result.InvalidNamespaces)
                        {
                            sessionState.Namespaces.Remove(@namespace);
                            fixedNamespaces.Remove(@namespace);
                        }
                        pendingNamespacesField.SetValue(
                            sessionState.Session, ReadOnlyArray<string>.CreateFrom(fixedNamespaces));
                    }
                }
            }

            _log.Debug("Finished execution");
            return result;
        }
        public ScriptResult Execute(string code, string[] scriptArgs, AssemblyReferences references, IEnumerable<string> namespaces, ScriptPackSession scriptPackSession)
        {
            if (scriptPackSession == null)
            {
                throw new ArgumentNullException("scriptPackSession");
            }

            if (references == null)
            {
                throw new ArgumentNullException("references");
            }

            _log.Debug("Starting to create execution components");
            _log.Debug("Creating script host");

            var executionReferences = new AssemblyReferences(references.Assemblies, references.Paths);
            executionReferences.Union(scriptPackSession.References);

            ScriptResult scriptResult;
            SessionState<ScriptState> sessionState;

            var isFirstExecution = !scriptPackSession.State.ContainsKey(SessionKey);

            if (isFirstExecution)
            {
                var host = _scriptHostFactory.CreateScriptHost(
                    new ScriptPackManager(scriptPackSession.Contexts), scriptArgs);

                ScriptLibraryWrapper.SetHost(host);
                _log.Debug("Creating session");

                var hostType = host.GetType();

                ScriptOptions = ScriptOptions.AddReferences(hostType.Assembly);

                var allNamespaces = namespaces.Union(scriptPackSession.Namespaces).Distinct();

                foreach (var reference in executionReferences.Paths)
                {
                    _log.DebugFormat("Adding reference to {0}", reference);
                    ScriptOptions = ScriptOptions.AddReferences(reference);
                }

                foreach (var assembly in executionReferences.Assemblies)
                {
                    _log.DebugFormat("Adding reference to {0}", assembly.FullName);
                    ScriptOptions = ScriptOptions.AddReferences(assembly);
                }

                foreach (var @namespace in allNamespaces)
                {
                    _log.DebugFormat("Importing namespace {0}", @namespace);
                    ScriptOptions = ScriptOptions.AddNamespaces(@namespace);
                }

                sessionState = new SessionState<ScriptState> { References = executionReferences, Namespaces = new HashSet<string>(allNamespaces) };
                scriptPackSession.State[SessionKey] = sessionState;

                scriptResult = Execute(code, host, sessionState);
            }
            else
            {
                _log.Debug("Reusing existing session");
                sessionState = (SessionState<ScriptState>)scriptPackSession.State[SessionKey];

                if (sessionState.References == null)
                {
                    sessionState.References = new AssemblyReferences();
                }

                if (sessionState.Namespaces == null)
                {
                    sessionState.Namespaces = new HashSet<string>();
                }

                var newReferences = executionReferences.Except(sessionState.References);

                foreach (var reference in newReferences.Paths)
                {
                    _log.DebugFormat("Adding reference to {0}", reference);
                    ScriptOptions = ScriptOptions.AddReferences(reference);
                    sessionState.References = sessionState.References.Union(new[] { reference });
                }

                foreach (var assembly in newReferences.Assemblies)
                {
                    _log.DebugFormat("Adding reference to {0}", assembly.FullName);
                    ScriptOptions = ScriptOptions.AddReferences(assembly);
                    sessionState.References = sessionState.References.Union(new[] { assembly });
                }

                var newNamespaces = namespaces.Except(sessionState.Namespaces);

                foreach (var @namespace in newNamespaces)
                {
                    _log.DebugFormat("Importing namespace {0}", @namespace);
                    ScriptOptions = ScriptOptions.AddNamespaces(@namespace);
                    sessionState.Namespaces.Add(@namespace);
                }

                if (string.IsNullOrWhiteSpace(code))
                {
                    return ScriptResult.Empty;
                }

                scriptResult = Execute(code, sessionState.Session, sessionState);
            }

            return scriptResult;

            //todo handle namespace failures
            //https://github.com/dotnet/roslyn/issues/1012
        }
        public ScriptResult Execute(string code, string[] scriptArgs, AssemblyReferences references,
            IEnumerable<string> namespaces,
            ScriptPackSession scriptPackSession)
        {
            if (scriptPackSession == null)
            {
                throw new ArgumentNullException("scriptPackSession");
            }

            if (references == null)
            {
                throw new ArgumentNullException("references");
            }

            var executionReferences = new AssemblyReferences(references.Assemblies, references.Paths);
            executionReferences.Union(scriptPackSession.References);

            var allNamespaces = namespaces.Union(scriptPackSession.Namespaces).Distinct();
            var host = _scriptHostFactory.CreateScriptHost(new ScriptPackManager(scriptPackSession.Contexts), scriptArgs) as ScriptHost;

            var runtimeSetup = new ScriptRuntimeSetup();
            runtimeSetup.LanguageSetups.Add(Python.CreateLanguageSetup(null));

            var runtime = new ScriptRuntime(runtimeSetup);
            var python = Python.GetEngine(runtime);
            python.Runtime.LoadAssembly(typeof(IScriptHost).Assembly);
            python.Runtime.LoadAssembly(typeof(object).Assembly);
            python.Runtime.LoadAssembly(typeof(ExpandoObject).Assembly);

            var currentAssemblies = AppDomain.CurrentDomain.GetAssemblies().Where(x => !x.IsDynamic);

            foreach (var reference in executionReferences.Paths)
            {
                var loadedAssembly =
                    currentAssemblies.FirstOrDefault(
                        x => String.Equals(x.Location, reference, StringComparison.InvariantCultureIgnoreCase));
                if (loadedAssembly != null)
                {
                    python.Runtime.LoadAssembly(loadedAssembly);
                }
                else
                {
                    try
                    {
                        var assembly = reference.ToLowerInvariant().EndsWith("dll") ? Assembly.LoadFrom(reference) : Assembly.LoadWithPartialName(reference);
                        if (assembly != null)
                        {
                            python.Runtime.LoadAssembly(assembly);
                        }
                    }
                    catch (Exception e)
                    {
                        _logger.Warn("Invalid path reference: " + reference);
                    }
                }
            }

            foreach (var assembly in executionReferences.Assemblies)
            {
                python.Runtime.LoadAssembly(assembly);
            }

            foreach (var @namespace in allNamespaces)
            {
                code = "from " + @namespace + " import *" + Environment.NewLine + code;
            }

            var scope = python.CreateScope();
            scope.SetVariable("scriptcs", host);

            try
            {
                var result = python.Execute(code, scope);
                return new ScriptResult(result);
            }
            catch (NotSupportedException e)
            {
                return new ScriptResult(compilationException: e);
            }
            catch (Exception e)
            {
                return new ScriptResult(executionException: e);
            }
        }