Skip to content

Come si può ottenere programmaticamente il percorso di "Python.exe" utilizzato da ArcMap

Benvenuto nella nostra pagina, in questo sito troverai la soluzione di quello che stai cercando.

Soluzione:

Invece di cercare l'eseguibile Python, questo argomento della guida suggerisce di collegarsi a cmd.exe ed eseguire python.exe senza qualificare la sua posizione. Si noti tuttavia che questo dovrebbe funzionare perché il programma di installazione di ArcGIS Desktop imposta(modifica: testato di recente con 10.1, non funziona) si basa sul percorso di python.exe sia aggiunto alla cartella PATH dell'utente.

Un altro approccio consiste nel creare uno strumento di script ed eseguirlo da ArcObjects.

Se si vuole davvero ottenere il percorso della versione di ArcGIS di python.exe, per estensione dell'approccio ArcObjects + strumento di script, si può creare uno strumento di script Python il cui unico output è il valore di sys.exec_prefix. Questo è il percorso della cartella che contiene la versione di Python di ArcGIS, ad es. C:Python27ArcGIS10.1.

Nota a margine: sys.executable restituisce il percorso di ArcMap.exe e NON python.exe quando viene eseguito nel processo, per questo motivo non suggerisco di usare questa variabile.

Richiamare lo strumento di script da ArcObjects e ottenere l'output dal file restituito IGeoProcessorResult restituito.

Aggiornare: Ecco un esempio di progetto di add-in ArcMap (VS2010, .NET 3.5) che utilizza uno strumento di script confezionato all'interno dell'add-in che visualizza semplicemente il percorso dell'oggetto python.exe utilizzato da ArcMap: http://wfurl.com/cbd5091

È solo un pulsante su cui si fa clic e viene visualizzata una casella di messaggio con il percorso:

PulsanteCasella dei messaggi

Le parti interessanti del codice:

  • Script Python:

    import sys
    import os
    import arcpy
    
    def getPythonPath():
        pydir = sys.exec_prefix
        pyexe = os.path.join(pydir, "python.exe")
        if os.path.exists(pyexe):
            return pyexe
        else:
            raise RuntimeError("No python.exe found in {0}".format(pydir))
    
    if __name__ == "__main__":
        pyexe = getPythonPath()
        arcpy.AddMessage("Python Path: {0}".format(pyexe))
        arcpy.SetParameterAsText(0, pyexe)
    
  • Funzione C#:

    public string GetPythonPath()
    {
        // Build the path to the PythonPathToolbox
        string toolboxPath = Path.Combine(Path.GetDirectoryName(this.GetType().Assembly.Location), "PythonPath.tbx");
    
        // Initialize the geoprocessor.
        IGeoProcessor2 gp = new ESRI.ArcGIS.Geoprocessing.GeoProcessorClass();
    
        // Add the PythonPath toolbox.
        gp.AddToolbox(toolboxPath);
    
        // Need an empty array even though we have no input parameters
        IVariantArray parameters = new VarArrayClass();
    
        // Execute the model tool by name.
        var result = gp.Execute("GetPythonPath", parameters, null);
        return result.GetOutput(0).GetAsText();
    }
    

Avrete accesso al registro di sistema?

Quando si installa ArcMap, installa Python se non lo trova.
Cerca nel registro di sistema per vedere se Python è già installato. Credo che la posizione standard del registro di sistema sia:
computerHKEY_LOCAL_MACHINESOFTWAREPYTHONPythonCore2.7InstallPath
Con una chiave predefinita del percorso
(2.7 è 10.1, 2.6 è 10.0)

Non mi viene in mente una ragione per cui il valore di questa chiave non sia corretto, ma si può sempre procedere in questo modo:
All'interno dell'alveare EsriDesktop del Registro di sistema è presente una posizione Python. È un percorso semplice che si può ottenere e poi costruire altri percorsi per garantire la presenza di Python.exe.
Ad esempio, la chiave su una macchina a 64 bit viene installata in:
computer_HKEY_LOCAL_MACHINESOFTWAREWow6432NodeESRIPython10.1
Con una chiave PythonDir e il valore Path associato

Ma mi piace la risposta di @blah238. Basta aprire un prompt dal proprio programma ed eseguirlo lì. Non riesco a vedere una ragione per cui questo non dovrebbe funzionare.

[Edit] Durante l'esecuzione set programmaticamente (cancellato, sotto) ha fatto quello che volevo, ma può essere realizzato più facilmente e con un codice più pulito usando Environment.GetEnvironmentVariables().

Un'opzione potrebbe essere quella di analizzare tutte le variabili d'ambiente del sistema e provare a dimostrare quanto segue:

1) Il valore della variabile d'ambiente è una directory? (e se sì...)

2) La directory contiene python.exe?

Sono riuscito a farlo in modo programmatico eseguendo il comando set attraverso l'API del processo .Net. Il comando set se usato senza parametri, restituisce TUTTE le variabili d'ambiente utilizzate dal sistema. Quindi potrei analizzare e organizzare i risultati STDOUT emessi da sete analizzarli per vedere se qualcosa (e mi riferisco a QUALCOSA) disponibile attraverso l'ambiente del sistema alla fine puntava a python.exe.

Da questa pagina che parla del set ...il comando set:

Digitare SET senza parametri per visualizzare tutte le variabili d'ambiente correnti.
correnti dell'ambiente.

Per illustrare ho scritto una combinazione di metodi (e una classe di aiuto) che fa ciò che ho discusso sopra. Questi metodi possono essere ottimizzati e potrebbero essere resi più sicuri (Try..Catch, ecc.), ma se il computer ha una QUALSIASI variabile d'ambiente che punta a python.exequesto approccio dovrebbe trovarla! Non mi interessa se la var si chiama PATH, ABBRACADABBRAo altro... se punta a python.exequesto dovrebbe trovarla.

// C#, you'll need these using statements:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text.RegularExpressions;

Qui terms è un array di stringhe che si passano alla routine per cercare il nome della variabile d'ambiente o il suo nome n (cioè PATH può avere diversi valori, ma la maggior parte delle altre variabili ne avrà solo uno). Assicurarsi che tutte le stringhe in terms siano in MAIUSCOLO!

(Quando ho testato questo, ho usato semplicemente "PYTHON", che ha trovato C:Python27python.exe sul mio sistema domestico. Ma si può facilmente estendere per includere un'altra stringa[] di termini, se si volesse ispezionare ulteriormente il percorso di ogni python.exe candidati restituiti, ad esempio per vedere se si trovano nel cestino di ArcGIS, ecc.)

// Top-level method that organizes everything below..
private void scrapeEnvironmentVariables(string[] terms)
{
    // !! ValueObject !! This is a Helper Class, find it at the bottom..
    List voList = buildListOfEnvironmentObjects();

    foreach (ValueObject vo in voList)
    {
        bool candidateFound = ObjectMatchesSearchTerms(vo, terms);

        if (candidateFound)
        {    
            string exeCandidate = "";
            foreach (string unlikelyPath in vo.values)
            {
                if (Directory.Exists(unlikelyPath))
                {
                    string unlikelyExe = unlikelyPath + "\python.exe";
                    if(File.Exists(unlikelyExe))
                        exeCandidate = unlikelyExe;
                }

                if (exeCandidate != "")
                {
                    break;
                    // At this point, exeCandidate is a fully-qualified
                    // path to python.exe..
                }
            }

            // If you only want the first hit, break here..
            // As-is, the code will look for even more matches.
            //if (breakOnFirstHit)
            //    break;
        }
    }
}

// Execute Environment.GetEnvironmentVariables() and organize the 
// key..value pairs into 1:n ValueObjects (see Helper Class below).
private List buildListOfEnvironmentObjects()
{
    // Return a List of 1:n key..value objects.
    List voList = new List();

    IDictionary variableDictionary = Environment.GetEnvironmentVariables();
    foreach (DictionaryEntry entry in variableDictionary)
    {
        // Explode multi-values into a List of values (n).
        List values = new List();
        string[] rawValues = ((string)entry.Value).Split(';');
        foreach (string value in rawValues)
            if (value != "") values.Add(value.ToUpper());

        ValueObject valueObject = new ValueObject();
        valueObject.key = ((string)entry.Key).ToUpper();
        valueObject.values = values.ToArray();

        voList.Add(valueObject);
    }
    return voList;
}

// Compare the key and any value(s) in a ValueObject with all the
// terms submitted to the top-level method. If **ALL** the terms
// match (against any combination of key..value), it returns true.
private bool ObjectMatchesSearchTerms(ValueObject vo, string[] terms)
{
    int matchCount = 0;

    foreach (string term in terms)
    {
        if (vo.key.Contains(term))              // screen the key
            matchCount++;

        foreach (string value in vo.values)     // screen N values
        {
            if (value.Contains(term))
                matchCount++;
        }
    }

    // Test against >= because it's possible the match count could
    // exceed the terms length, like if a match occurred in both the
    // key and the value(s). So >= avoids omiting that possibility.
    return (matchCount >= terms.Length) ? true : false;
}    

In fondo alla mia classe principale, ho incluso la seguente classe Helper:

class ValueObject : Object
{
    public ValueObject() { } // default constructor

    public string key;
    public string[] values;
}

Se hai riserve o disponibilità ad anticipare il nostro post, puoi lasciare un commento e lo leggeremo con desiderio.



Utilizzate il nostro motore di ricerca

Ricerca
Generic filters

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.