Пример #1
0
        public DerivedInterpreterFactory(
            PythonInterpreterFactoryWithDatabase baseFactory,
            InterpreterFactoryCreationOptions options
        ) : base(
                options.Id,
                options.Description,
                new InterpreterConfiguration(
                    options.PrefixPath,
                    options.InterpreterPath,
                    options.WindowInterpreterPath,
                    options.LibraryPath,
                    options.PathEnvironmentVariableName,
                    options.Architecture,
                    options.LanguageVersion,
                    InterpreterUIMode.CannotBeDefault | InterpreterUIMode.CannotBeConfigured
                ),
                options.WatchLibraryForNewModules
        ) {
            if (baseFactory.Configuration.Version != options.LanguageVersion) {
                throw new ArgumentException("Language versions do not match", "options");
            }

            _base = baseFactory;
            _base.IsCurrentChanged += Base_IsCurrentChanged;
            _base.NewDatabaseAvailable += Base_NewDatabaseAvailable;

            _description = options.Description;

            if (Volatile.Read(ref _deferRefreshIsCurrent)) {
                // This rare race condition is due to a design flaw that is in
                // shipped public API and cannot be fixed without breaking
                // compatibility with 3rd parties.
                RefreshIsCurrent();
            }
        }
Пример #2
0
        /// <summary>
        /// Creates a new interpreter factory with the specified options. This
        /// interpreter always includes a cached completion database.
        /// </summary>
        public static PythonInterpreterFactoryWithDatabase CreateInterpreterFactory(InterpreterConfiguration configuration, InterpreterFactoryCreationOptions options = null) {
            options = options?.Clone() ?? new InterpreterFactoryCreationOptions();

            if (string.IsNullOrEmpty(options.DatabasePath)) {
                options.DatabasePath = Path.Combine(
                    PythonTypeDatabase.CompletionDatabasePath,
                    GetRelativePathForConfigurationId(configuration.Id)
                );
            }

            var fact = new CPythonInterpreterFactory(configuration, options);
            if (options.WatchFileSystem) {
                fact.BeginRefreshIsCurrent();
            }
            return fact;
        }
Пример #3
0
        public DerivedInterpreterFactory(
            PythonInterpreterFactoryWithDatabase baseFactory,
            InterpreterConfiguration config,
            InterpreterFactoryCreationOptions options
            )
            : base(config, options.WatchLibraryForNewModules)
        {
            _base = baseFactory;
            _base.IsCurrentChanged += Base_IsCurrentChanged;
            _base.NewDatabaseAvailable += Base_NewDatabaseAvailable;

            if (Volatile.Read(ref _deferRefreshIsCurrent)) {
                // This rare race condition is due to a design flaw that is in
                // shipped public API and cannot be fixed without breaking
                // compatibility with 3rd parties.
                RefreshIsCurrent();
            }
        }
Пример #4
0
        /// <summary>
        /// Creates a new interpreter factory with the specified options. This
        /// interpreter always includes a cached completion database.
        /// </summary>
        public static PythonInterpreterFactoryWithDatabase CreateInterpreterFactory(InterpreterFactoryCreationOptions options) {
            var ver = options.LanguageVersion ?? new Version(2, 7);
            var description = options.Description ?? string.Format("Unknown Python {0}", ver);
            var prefixPath = options.PrefixPath;
            if (string.IsNullOrEmpty(prefixPath) && !string.IsNullOrEmpty(options.InterpreterPath)) {
                prefixPath = Path.GetDirectoryName(options.InterpreterPath);
            }

            return new CPythonInterpreterFactory(
                ver,
                (options.Id == default(Guid)) ? Guid.NewGuid() : options.Id,
                description,
                prefixPath ?? string.Empty,
                options.InterpreterPath ?? string.Empty,
                options.WindowInterpreterPath ?? string.Empty,
                options.LibraryPath ?? string.Empty,
                options.PathEnvironmentVariableName ?? "PYTHONPATH",
                options.Architecture,
                options.WatchLibraryForNewModules
            );
        }
Пример #5
0
        public static InterpreterFactoryCreationOptions FindInterpreterOptions(
            string prefixPath,
            IInterpreterOptionsService service,
            IPythonInterpreterFactory baseInterpreter = null
        ) {
            var result = new InterpreterFactoryCreationOptions();

            var libPath = DerivedInterpreterFactory.FindLibPath(prefixPath);

            result.PrefixPath = prefixPath;
            result.LibraryPath = libPath;

            if (baseInterpreter == null) {
                baseInterpreter = DerivedInterpreterFactory.FindBaseInterpreterFromVirtualEnv(
                    prefixPath,
                    libPath,
                    service
                );
            }

            string interpExe, winterpExe;

            if (baseInterpreter != null) {
                // The interpreter name should be the same as the base interpreter.
                interpExe = Path.GetFileName(baseInterpreter.Configuration.InterpreterPath);
                winterpExe = Path.GetFileName(baseInterpreter.Configuration.WindowsInterpreterPath);
                var scripts = new[] { "Scripts", "bin" };
                result.InterpreterPath = CommonUtils.FindFile(prefixPath, interpExe, firstCheck: scripts);
                result.WindowInterpreterPath = CommonUtils.FindFile(prefixPath, winterpExe, firstCheck: scripts);
                result.PathEnvironmentVariableName = baseInterpreter.Configuration.PathEnvironmentVariable;
            } else {
                result.InterpreterPath = string.Empty;
                result.WindowInterpreterPath = string.Empty;
                result.PathEnvironmentVariableName = string.Empty;
            }

            if (baseInterpreter != null) {
                result.Description = string.Format(
                    "{0} ({1})",
                    CommonUtils.GetFileOrDirectoryName(prefixPath),
                    baseInterpreter.Description
                );

                result.Id = baseInterpreter.Id;
                result.LanguageVersion = baseInterpreter.Configuration.Version;
                result.Architecture = baseInterpreter.Configuration.Architecture;
                result.WatchLibraryForNewModules = true;
            } else {
                result.Description = CommonUtils.GetFileOrDirectoryName(prefixPath);

                result.Id = Guid.Empty;
                result.LanguageVersion = new Version(0, 0);
                result.Architecture = ProcessorArchitecture.None;
                result.WatchLibraryForNewModules = false;
            }

            return result;
        }
        /// <summary>
        /// Creates a derived interpreter factory from the specified set of
        /// options. This function will modify the project, raise the
        /// <see cref="InterpreterFactoriesChanged"/> event and potentially
        /// display UI.
        /// </summary>
        /// <param name="options">
        /// <para>The options for the new interpreter:</para>
        /// <para>Guid: ID of the base interpreter.</para>
        /// <para>Version: Version of the base interpreter. This will also be
        /// the version of the new interpreter.</para>
        /// <para>PythonPath: Either the path to the root of the virtual
        /// environment, or directly to the interpreter executable. If no file
        /// exists at the provided path, the name of the interpreter specified
        /// for the base interpreter is tried. If that is not found, "scripts"
        /// is added as the last directory. If that is not found, an exception
        /// is raised.</para>
        /// <para>PythonWindowsPath [optional]: The path to the interpreter
        /// executable for windowed applications. If omitted, an executable with
        /// the same name as the base interpreter's will be used if it exists.
        /// Otherwise, this will be set to the same as PythonPath.</para>
        /// <para>PathEnvVar [optional]: The name of the environment variable to
        /// set for search paths. If omitted, the value from the base
        /// interpreter will be used.</para>
        /// <para>Description [optional]: The user-friendly name of the
        /// interpreter. If omitted, the relative path from the project home to
        /// the directory containing the interpreter is used. If this path ends
        /// in "\\Scripts", the last segment is also removed.</para>
        /// </param>
        /// <returns>The ID of the created interpreter.</returns>
        public Guid CreateInterpreterFactory(InterpreterFactoryCreationOptions options) {
            var projectHome = PathUtils.GetAbsoluteDirectoryPath(_project.DirectoryPath, _project.GetPropertyValue("ProjectHome"));
            var rootPath = PathUtils.GetAbsoluteDirectoryPath(projectHome, options.PrefixPath);

            IPythonInterpreterFactory fact;
            var id = Guid.NewGuid();
            var baseInterp = _service.FindInterpreter(options.Id, options.LanguageVersion)
                as PythonInterpreterFactoryWithDatabase;
            if (baseInterp != null) {
                var pathVar = options.PathEnvironmentVariableName;
                if (string.IsNullOrEmpty(pathVar)) {
                    pathVar = baseInterp.Configuration.PathEnvironmentVariable;
                }

                var description = options.Description;
                if (string.IsNullOrEmpty(description)) {
                    description = PathUtils.CreateFriendlyDirectoryPath(projectHome, rootPath);
                    int i = description.LastIndexOf("\\scripts", StringComparison.OrdinalIgnoreCase);
                    if (i > 0) {
                        description = description.Remove(i);
                    }
                }

                MigrateOldDerivedInterpreterFactoryDatabase(id, baseInterp.Configuration.Version, options.PrefixPath);
                fact = new DerivedInterpreterFactory(
                    baseInterp,
                    new InterpreterFactoryCreationOptions {
                        Id = id,
                        LanguageVersion = baseInterp.Configuration.Version,
                        Description = description,
                        InterpreterPath = options.InterpreterPath,
                        WindowInterpreterPath = options.WindowInterpreterPath,
                        LibraryPath = options.LibraryPath,
                        PrefixPath = options.PrefixPath,
                        PathEnvironmentVariableName = pathVar,
                        Architecture = baseInterp.Configuration.Architecture,
                        WatchLibraryForNewModules = true
                    }
                );
            } else {
                fact = InterpreterFactoryCreator.CreateInterpreterFactory(
                    new InterpreterFactoryCreationOptions {
                        Id = id,
                        LanguageVersion = options.LanguageVersion,
                        Description = options.Description,
                        InterpreterPath = options.InterpreterPath,
                        WindowInterpreterPath = options.WindowInterpreterPath,
                        LibraryPath = options.LibraryPath,
                        PrefixPath = options.PrefixPath,
                        PathEnvironmentVariableName = options.PathEnvironmentVariableName,
                        Architecture = options.Architecture,
                        WatchLibraryForNewModules = options.WatchLibraryForNewModules
                    }
                );
            }

            AddInterpreter(fact, true);

            return id;
        }
Пример #7
0
        private static ProjectItemElement AddVirtualEnvironment(
            ProjectRootElement project,
            string sourcePath,
            InterpreterFactoryCreationOptions options
        ) {
            var prefixPath = options.PrefixPath ?? string.Empty;
            var interpreterPath = string.IsNullOrEmpty(options.InterpreterPath) ?
                string.Empty :
                CommonUtils.GetRelativeFilePath(prefixPath, options.InterpreterPath);
            var windowInterpreterPath = string.IsNullOrEmpty(options.WindowInterpreterPath) ?
                string.Empty :
                CommonUtils.GetRelativeFilePath(prefixPath, options.WindowInterpreterPath);
            var libraryPath = string.IsNullOrEmpty(options.LibraryPath) ?
                string.Empty :
                CommonUtils.GetRelativeDirectoryPath(prefixPath, options.LibraryPath);
            prefixPath = CommonUtils.GetRelativeDirectoryPath(sourcePath, prefixPath);

            return project.AddItem(
                MSBuildProjectInterpreterFactoryProvider.InterpreterItem,
                prefixPath,
                new Dictionary<string, string> {
                    { MSBuildProjectInterpreterFactoryProvider.IdKey, Guid.NewGuid().ToString("B") },
                    { MSBuildProjectInterpreterFactoryProvider.DescriptionKey, options.Description },
                    { MSBuildProjectInterpreterFactoryProvider.BaseInterpreterKey, options.IdString },
                    { MSBuildProjectInterpreterFactoryProvider.InterpreterPathKey, interpreterPath },
                    { MSBuildProjectInterpreterFactoryProvider.WindowsPathKey, windowInterpreterPath },
                    { MSBuildProjectInterpreterFactoryProvider.LibraryPathKey, libraryPath },
                    { MSBuildProjectInterpreterFactoryProvider.VersionKey, options.LanguageVersionString },
                    { MSBuildProjectInterpreterFactoryProvider.ArchitectureKey, options.ArchitectureString },
                    { MSBuildProjectInterpreterFactoryProvider.PathEnvVarKey, options.PathEnvironmentVariableName }
                }
            );
        }
        public IPythonInterpreterFactory SetOptions(InterpreterFactoryCreationOptions options) {
            var collection = PythonInterpreterKey + "\\" + options.IdString;
            var store = _settings.GetWritableSettingsStore(SettingsScope.UserSettings);
            store.CreateCollection(collection);
            store.SetString(collection, PathKey, options.InterpreterPath ?? string.Empty);
            store.SetString(collection, WindowsPathKey, options.WindowInterpreterPath ?? string.Empty);
            store.SetString(collection, LibraryPathKey, options.LibraryPath ?? string.Empty);
            store.SetString(collection, ArchitectureKey, options.ArchitectureString);
            store.SetString(collection, VersionKey, options.LanguageVersionString);
            store.SetString(collection, PathEnvVarKey, options.PathEnvironmentVariableName ?? string.Empty);
            store.SetString(collection, DescriptionKey, options.Description ?? string.Empty);

            var newInterp = LoadUserDefinedInterpreter(store, options.IdString);
            if (newInterp == null) {
                throw new InvalidOperationException("Unable to load user defined interpreter");
            }

            PythonInterpreterFactoryWithDatabase existing;
            if (_interpreters.TryGetValue(newInterp.Id, out existing)) {
                existing.Dispose();
            }
            _interpreters[newInterp.Id] = newInterp;
            OnInterpreterFactoriesChanged();
            return newInterp;
        }
Пример #9
0
        /// <summary>
        /// Creates a derived interpreter factory from the specified set of
        /// options. This function will modify the project, raise the
        /// <see cref="InterpreterFactoriesChanged"/> event and potentially
        /// display UI.
        /// </summary>
        /// <param name="options">
        /// <para>The options for the new interpreter:</para>
        /// <para>Guid: ID of the base interpreter.</para>
        /// <para>Version: Version of the base interpreter. This will also be
        /// the version of the new interpreter.</para>
        /// <para>PythonPath: Either the path to the root of the virtual
        /// environment, or directly to the interpreter executable. If no file
        /// exists at the provided path, the name of the interpreter specified
        /// for the base interpreter is tried. If that is not found, "scripts"
        /// is added as the last directory. If that is not found, an exception
        /// is raised.</para>
        /// <para>PythonWindowsPath [optional]: The path to the interpreter
        /// executable for windowed applications. If omitted, an executable with
        /// the same name as the base interpreter's will be used if it exists.
        /// Otherwise, this will be set to the same as PythonPath.</para>
        /// <para>PathEnvVar [optional]: The name of the environment variable to
        /// set for search paths. If omitted, the value from the base
        /// interpreter will be used.</para>
        /// <para>Description [optional]: The user-friendly name of the
        /// interpreter. If omitted, the relative path from the project home to
        /// the directory containing the interpreter is used. If this path ends
        /// in "\\Scripts", the last segment is also removed.</para>
        /// </param>
        /// <returns>The ID of the created interpreter.</returns>
        public Guid CreateInterpreterFactory(InterpreterFactoryCreationOptions options)
        {
            var projectHome = CommonUtils.GetAbsoluteDirectoryPath(_project.DirectoryPath, _project.GetPropertyValue("ProjectHome"));
            var rootPath    = CommonUtils.GetAbsoluteDirectoryPath(projectHome, options.PrefixPath);

            IPythonInterpreterFactory fact;
            var id         = Guid.NewGuid();
            var baseInterp = _service.FindInterpreter(options.Id, options.LanguageVersion)
                             as PythonInterpreterFactoryWithDatabase;

            if (baseInterp != null)
            {
                var pathVar = options.PathEnvironmentVariableName;
                if (string.IsNullOrEmpty(pathVar))
                {
                    pathVar = baseInterp.Configuration.PathEnvironmentVariable;
                }

                var description = options.Description;
                if (string.IsNullOrEmpty(description))
                {
                    description = CommonUtils.CreateFriendlyDirectoryPath(projectHome, rootPath);
                    int i = description.LastIndexOf("\\scripts", StringComparison.OrdinalIgnoreCase);
                    if (i > 0)
                    {
                        description = description.Remove(i);
                    }
                }

                MigrateOldDerivedInterpreterFactoryDatabase(id, baseInterp.Configuration.Version, options.PrefixPath);
                fact = new DerivedInterpreterFactory(
                    baseInterp,
                    new InterpreterFactoryCreationOptions {
                    Id = id,
                    LanguageVersion             = baseInterp.Configuration.Version,
                    Description                 = description,
                    InterpreterPath             = options.InterpreterPath,
                    WindowInterpreterPath       = options.WindowInterpreterPath,
                    LibraryPath                 = options.LibraryPath,
                    PrefixPath                  = options.PrefixPath,
                    PathEnvironmentVariableName = pathVar,
                    Architecture                = baseInterp.Configuration.Architecture,
                    WatchLibraryForNewModules   = true
                }
                    );
            }
            else
            {
                fact = InterpreterFactoryCreator.CreateInterpreterFactory(
                    new InterpreterFactoryCreationOptions {
                    Id = id,
                    LanguageVersion             = options.LanguageVersion,
                    Description                 = options.Description,
                    InterpreterPath             = options.InterpreterPath,
                    WindowInterpreterPath       = options.WindowInterpreterPath,
                    LibraryPath                 = options.LibraryPath,
                    PrefixPath                  = options.PrefixPath,
                    PathEnvironmentVariableName = options.PathEnvironmentVariableName,
                    Architecture                = options.Architecture,
                    WatchLibraryForNewModules   = options.WatchLibraryForNewModules
                }
                    );
            }

            AddInterpreter(fact, true);

            return(id);
        }
Пример #10
0
        /// <summary>
        /// Creates a new interpreter factory backed by a type database.
        /// </summary>
        /// <remarks>
        /// <see cref="RefreshIsCurrent"/> must be called after creation to
        /// ensure the database state is correctly reflected.
        /// </remarks>
        public PythonInterpreterFactoryWithDatabase(
            InterpreterConfiguration config,
            InterpreterFactoryCreationOptions options
            )
        {
            if (config == null)
            {
                throw new ArgumentNullException(nameof(config));
            }
            if (options == null)
            {
                options = new InterpreterFactoryCreationOptions();
            }
            Configuration = config;

            DatabasePath = options.DatabasePath;

            // Avoid creating a interpreter with an unsupported version.
            // https://github.com/Microsoft/PTVS/issues/706
            try {
                var langVer = config.Version.ToLanguageVersion();
            } catch (InvalidOperationException ex) {
                throw new ArgumentException(ex.Message, ex);
            }

            if (options.WatchFileSystem && !string.IsNullOrEmpty(DatabasePath))
            {
                // Assume the database is valid if the version is up to date, then
                // switch to invalid after we've checked.
                _isValid            = PythonTypeDatabase.IsDatabaseVersionCurrent(DatabasePath);
                _isCheckingDatabase = true;

                _verWatcher    = CreateDatabaseVerWatcher();
                _verDirWatcher = CreateDatabaseDirectoryWatcher();
#if DEBUG
                var creationStack = new StackTrace(true).ToString();
                Task.Delay(1000).ContinueWith(t => {
                    Debug.Assert(
                        _hasEverCheckedDatabase,
                        "Database check was not triggered for {0}".FormatUI(Configuration.Id),
                        creationStack
                        );
                });
#endif
            }
            else
            {
                // Assume the database is valid
                _isValid = true;
            }

            try {
                var pm = options.PackageManager;
                if (pm != null)
                {
                    pm.SetInterpreterFactory(this);
                    pm.InstalledFilesChanged += PackageManager_InstalledFilesChanged;
                    PackageManager            = pm;
                }
            } catch (NotSupportedException) {
            }
        }
Пример #11
0
        /// <summary>
        /// Creates a new interpreter factory with the specified options. This
        /// interpreter always includes a cached completion database.
        /// </summary>
        public static PythonInterpreterFactoryWithDatabase CreateInterpreterFactory(InterpreterConfiguration configuration, InterpreterFactoryCreationOptions options = null)
        {
            options = options?.Clone() ?? new InterpreterFactoryCreationOptions();

            if (string.IsNullOrEmpty(options.DatabasePath))
            {
                options.DatabasePath = Path.Combine(
                    PythonTypeDatabase.CompletionDatabasePath,
                    GetRelativePathForConfigurationId(configuration.Id)
                    );
            }

            var fact = new CPythonInterpreterFactory(configuration, options);

            if (options.WatchFileSystem)
            {
                fact.BeginRefreshIsCurrent();
            }
            return(fact);
        }
Пример #12
0
        /// <summary>
        /// Creates a new interpreter factory with the specified options. This
        /// interpreter always includes a cached completion database.
        /// </summary>
        public static IPythonInterpreterFactory CreateInterpreterFactory(InterpreterConfiguration configuration, InterpreterFactoryCreationOptions options = null)
        {
            options = options?.Clone() ?? new InterpreterFactoryCreationOptions();

            if (string.IsNullOrEmpty(options.DatabasePath))
            {
                options.DatabasePath = Path.Combine(
                    PythonTypeDatabase.CompletionDatabasePath,
                    GetRelativePathForConfigurationId(configuration.Id)
                    );
            }

            if (options.NoDatabase)
            {
                // Use the (currenty experimental) non-database backed factory
                var fact = new Ast.AstPythonInterpreterFactory(configuration, options);
                return(fact);
            }
            else
            {
                // Use the database-backed factory
                var fact = new CPythonInterpreterFactory(configuration, options);
                if (options.WatchFileSystem)
                {
                    fact.BeginRefreshIsCurrent();
                }
                return(fact);
            }
        }
Пример #13
0
 public static PythonInterpreterFactoryWithDatabase CreateInterpreterFactory(InterpreterConfiguration configuration, InterpreterFactoryCreationOptions options)
 {
     return(new CPythonInterpreterFactory(configuration, options));
 }
Пример #14
0
 public AstPythonInterpreterFactory(InterpreterConfiguration config, InterpreterFactoryCreationOptions options)
     : this(config, options, string.IsNullOrEmpty(options?.DatabasePath))
 {
 }
Пример #15
0
        /// <summary>
        /// Creates a new interpreter factory with the specified options. This
        /// interpreter always includes a cached completion database.
        /// </summary>
        public static PythonInterpreterFactoryWithDatabase CreateInterpreterFactory(InterpreterConfiguration configuration, InterpreterFactoryCreationOptions options = null)
        {
            options = options?.Clone() ?? new InterpreterFactoryCreationOptions();

            if (string.IsNullOrEmpty(options.DatabasePath))
            {
                var subpath = configuration.Id.Replace('|', '\\');
                if (!PathUtils.IsValidPath(subpath))
                {
                    subpath = Convert.ToBase64String(new UTF8Encoding(false).GetBytes(configuration.Id));
                }
                options.DatabasePath = Path.Combine(PythonTypeDatabase.CompletionDatabasePath, subpath);
            }

            var fact = new CPythonInterpreterFactory(configuration, options);

            if (options.WatchFileSystem)
            {
                fact.BeginRefreshIsCurrent();
            }
            return(fact);
        }