ArcMapで使用される「Python.exe」のパスをプログラムで取得する方法


15

C#でArcMapのアドインを使用しています。C#コードから、いくつかのPythonスクリプトを実行しました。さて、これらのスクリプトを実行するために、Pythonパスをハードコーディングしています。しかし、これは移植性がありません。したがって、コードからPython実行可能ファイルのパスを取得して使用したいと思います。

質問:

ArcMapで使用されるPython実行可能ファイルのパスをC#コードから取得するにはどうすればよいですか?

編集:

あなたの提案から、今のところ私はPythonのパスを取得するために「パス環境」を使用しています。

//get python path from environtment variable
string GetPythonPath()
{
    IDictionary environmentVariables = Environment.GetEnvironmentVariables();
    string pathVariable = environmentVariables["Path"] as string;
    if (pathVariable != null)
    {
        string[] allPaths = pathVariable.Split(';');
        foreach (var path in allPaths)
        {
            string pythonPathFromEnv = path + "\\python.exe";
            if (File.Exists(pythonPathFromEnv))
                return pythonPathFromEnv;
        }
    }
}

しかし問題がある:

異なるバージョンのpythonがマシンにインストールされている場合、使用している「python.exe」がArcGISでも使用しているという保証はありません。

「python.exe」パスを取得するために別のツールを使用するのは好ましくありません。したがって、レジストリキーからパスを取得する方法があるかどうかは本当に考えています。「ArcGIS10.0」レジストリ次のようになります。 ここに画像の説明を入力してください

そしてそのために、私はパスを取得するための次の方法を考えています:

//get python path from registry key
string GetPythonPath()
{
    const string regKey = "Python";
    string pythonPath = null;
    try
    {
        RegistryKey registryKey = Registry.LocalMachine;
        RegistryKey subKey = registryKey.OpenSubKey("SOFTWARE");
        if (subKey == null)
            return null;

        RegistryKey esriKey = subKey.OpenSubKey("ESRI");
        if (esriKey == null)
            return null;

        string[] subkeyNames = esriKey.GetSubKeyNames();//get all keys under "ESRI" key
        int index = -1;
     /*"Python" key contains arcgis version no in its name. So, the key name may be 
     varied version to version. For ArcGIS10.0, key name is: "Python10.0". So, from
     here I can get ArcGIS version also*/
        for (int i = 0; i < subkeyNames.Length; i++)
        {
            if (subkeyNames[i].Contains("Python"))
            {
                index = i;
                break;
            }
        }
        if(index < 0)
            return null;
        RegistryKey pythonKey = esriKey.OpenSubKey(subkeyNames[index]);

        string arcgisVersion = subkeyNames[index].Remove(0, 6); //remove "python" and get the version
        var pythonValue = pythonKey.GetValue("Python") as string;
        if (pythonValue != "True")//I guessed the true value for python says python is installed with ArcGIS.
            return;

        var pythonDirectory = pythonKey.GetValue("PythonDir") as string;
        if (pythonDirectory != null && Directory.Exists(pythonDirectory))
        {
            string pythonPathFromReg = pythonDirectory + "ArcGIS" + arcgisVersion + "\\python.exe";
            if (File.Exists(pythonPathFromReg))
                pythonPath = pythonPathFromReg;
        }  
    }
    catch (Exception e)
    {
        MessageBox.Show(e + "\r\nReading registry " + regKey.ToUpper());
        pythonPath = null;
    }
    return pythonPath ;
}

しかし、2番目の手順を使用する前に、推測について確認する必要があります。推測は次のとおりです。

  1. Pythonに関連付けられた「True」は、ArcGISでPythonがインストールされていることを意味します
  2. ArcGIS 10.0と上位バージョンのレジストリキーは同じプロセスで書き込まれます。

私の推測についての明確化を手伝ってください。


5
あなたは、作成を検討しているスクリプトツールをのArcObjectsからそれを実行しますか
blah238

3
アドインのインストール要件として、ArcGIS Python exeにPATH環境変数を設定するだけではいけませんか?
チャドクーパー

@ChadCooperの考えは最良の方法でなければならないということです。逆方向に作業するのではなく、インストール時に一度だけ設定してください。
elrobis

@elrobis:PATH環境でパスを設定するのは良い方法です。しかし、私はPythonを見つけてユーザーを中断することなくすべてを行う方法があるかどうかを知りたいと思っていました。
エミ

@ blah238ご提案ありがとうございます。スクリプトツールを使用したことはありません。それについて学ぶ必要があるかもしれません
エミ

回答:


2

2番目のコード例を取り上げて、64ビットと32ビットの両方のOSで動作させ、少し簡略化しました。Windows 7 64ビットで10.1で動作しますが、可能な限り多くの環境でテストし、必要と思われる防御的なプログラミングチェックを再度追加する必要があります。

Pythonを使用しないArcGIS Desktop 10.1のクリーンインストールをテストした後、Python10.xサブキーは含まれておらず、「Python」のTrue / False値は含まれていません(目的は不明ですが、必要に応じてESRIサポートにお問い合わせください)知っている)。

string GetPythonPath()
{
    string pythonPath = null;
    var localmachineKey = Registry.LocalMachine;
    // Check whether we are on a 64-bit OS by checking for the Wow6432Node key (32-bit version of the Software registry key)
    var softwareKey = localmachineKey.OpenSubKey(@"SOFTWARE\Wow6432Node"); // This is the correct key for 64-bit OS's
    if (softwareKey == null) {
        softwareKey = localmachineKey.OpenSubKey("SOFTWARE"); // This is the correct key for 32-bit OS's
    }
    var esriKey = softwareKey.OpenSubKey("ESRI");
    var realVersion = (string)esriKey.OpenSubKey("ArcGIS").GetValue("RealVersion"); // Get the "real", canonical version of ArcGIS
    var shortVersion = String.Join(".", realVersion.Split('.').Take(2).ToArray()); // Get just the Major.Minor part of the version number, e.g. 10.1
    var pythonKey = esriKey.OpenSubKey("Python" + shortVersion); // Open the Python10.x sub-key
    if (pythonKey == null) {
        throw new InvalidOperationException("Python not installed with ArcGIS!");
    }
    var pythonDirectory = (string)pythonKey.GetValue("PythonDir");
    if (Directory.Exists(pythonDirectory))
    {
        // Build path to python.exe
        string pythonPathFromReg = Path.Combine(Path.Combine(pythonDirectory, "ArcGIS" + shortVersion), "python.exe");
        if (File.Exists(pythonPathFromReg)) {
            pythonPath = pythonPathFromReg;
        }
    }
    return pythonPath;
}

Pythonを搭載したDesktop 10.1マシンでは、これはを返しますC:\Python27\ArcGIS10.1\python.exe。PythonのないDesktop 10.1マシンでは、Python10.xキーが存在しないため、InvalidOperationExceptionが発生します。

うまくいけば、これはあなたが実際に達成しようとしていることのすべてに役立つことを願っています。


7

このヘルプトピックでは、Python実行可能ファイルを探す代わりに、その場所を限定せずにシェルアウトしcmd.exeて実行するpython.exeことをお勧めします。注:ただし、これはことをすべき仕事をセットアップインストーラArcGIS Desktopのため (編集:最近、10.1でテストし、それはしません)へのパスに依存しているpython.exeユーザーのに追加されたPATH環境変数。

別のアプローチは、作成することで、スクリプトツールをのArcObjectsからそれを実行します

ArcGISのバージョンへのパスを本当に求めている場合python.exe、ArcObjects +スクリプトツールアプローチの拡張により、出力のみの値を持つPythonスクリプトツールを作成できますsys.exec_prefix。これは、ArcGISのバージョンのPythonを含むフォルダーのパスです(例:)C:\Python27\ArcGIS10.1

サイドノートsys.executableリターンパスArcMap.exeとNOT python.exe私はその変数を使用することをお勧めしない理由でインプロセスで実行、。

ArcObjectsからスクリプトツールを呼び出し、返されたものから出力を取得します IGeoProcessorResultオブジェクト。

更新:これは、ArcMapが使用するパスを単に表示するアドイン内にパッケージ化されたスクリプトツールを使用するサンプルのArcMapアドインプロジェクト(VS2010、.NET 3.5)ですpython.exe http://wfurl.com/cbd5091が

ボタンをクリックするだけで、次のパスを含むメッセージボックスがポップアップ表示されます。

ボタン メッセージボックス

興味深いコード:

  • 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)
  • 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();
    }

2
しかし、このドキュメントには、ArcGIS Desktopインストーラーがpython.exeへのパスをユーザーのPATH環境変数に設定することは記載されていません。そのため、pythonのパスがPATH環境変数にない可能性があります。その後、エラーが作成されます。だから、どうすればPythonの実行可能パスがユーザーのPATH環境変数にあることを確認できますか?
エミ

2
人生のほとんどのことやコンピューティングのように、できることは仮定を立てて物事がうまくいくことを望み、うまくいかないときにフォールバック計画を立てることだけです(PATH環境変数にそれを追加する手順を提供します)。つまり、通常のインストールの場合、ArcGIS DesktopインストーラーはそのパスをPATH環境変数に追加すると考えています。
blah238

2
arcgisでインストールされたpythonがパスにない多くのインストールを見てきました。そして、2つのバージョンがインストールされており、「間違った」バージョンがパスにある場合はどうなりますか?
blindjesse

3番目の段落で、PATH環境変数に関係なくPythonのArcGISのインストールを見つける必要があるソリューションを提供しました。
blah238

@ blah238はスクリプトツールを作成しないため、アドインの移植性が低下したり、他のマシンへのアドインのインストールプロセスが難しくなったりしませんか?
エミ

6

レジストリにアクセスできますか?

ArcMapをインストールすると、見つからない場合はPythonがインストールされます。レジストリを調べて、Pythonが既にインストールされているかどうかを確認します。これの標準的なレジストリの場所は次のとおりです: computer \ HKEY_LOCAL_MACHINE \ SOFTWARE \ PYTHON \ PythonCore \ 2.7 \ InstallPath デフォルトのキーのパスの場所(2.7は10.1、2.6は10.0)

このキーの値が間違っている/その理由を考えることはできませんが、いつでもこの方法で行くことができます。レジストリのEsri \ Desktopハイブ内はPythonの場所です。Python.exeがあることを確認するために取得して、さらにパスを構築できる単純なパス。たとえば、64ビットマシンのキーは、computer \ HKEY_LOCAL_MACHINE \ SOFTWARE \ Wow6432Node \ ESRI \ Python10.1にインストールされ ます。PythonDir キーと関連するパス値が含まれます

しかし、@ blah238の回答が好きです。プログラムからプロンプトを開き、そこで実行するだけです。これが機能しない理由はわかりません。


2
複数のPythonインストールが存在する可能性があり、ArcGISで使用されているものをプログラムで簡単に決定する方法がないため、このアプローチにも欠陥があります。ただし、arcpyを実行していない場合、これは重要ではありません。それでも、最も堅牢なソリューションには、レジストリとかなりのロジックが必要だと思います。私はそこに行くつもりはありません。
blah238

さて、ロジックは最新のバージョン2.7から開始し、後方に動作する必要があります。もちろん、新しいバージョンのPythonをインストールしてから、古いバージョンのPythonをインストールする古いバージョンのArcGISをインストールした場合、これは失敗する可能性があります。確かに、この可能性があることに同意しますが、可能性は低いです(または、arc10.1 = py2.7、arc10.0 = py26 ...などのルックアップを100%確実に構築することもできます)。先ほど言ったように、最善の方法はおそらくコマンドプロンプトにシェルアウトすることです。
KHibma

@KHibmaレジストリを検索しました。しかし、「PYTHON」キーに目を通すのは本当に面倒だと思います。私のマシンには2つのpythonバージョンがインストールされており、両方を返します。「ESRI」キーを調べて、真の値を持つ「Python」サブキーがある場合、「PythonDir」サブキーの値を取得することをお勧めします。私の場合はうまく
エミ

これは「ESRI」キーを使用してレジストリ内のPythonパスを検索する間違った方法ですか?またはレジストリにキーと値を作成するために、ESRIの用途が変更とコードでできる方法は多分それを読み取ることができない、という万が一あり
エミ

レジストリを「検索する」と言うときは、上記で提供した実際のパスを使用することを意味します。誰かがよく知っていない限り、これらのレジストリキーの場所(レジストリ内)はマシンごとに変更されません。そのため、パスをハードコーディングして、キーがそこに存在するかどうかを確認します。存在する場合、値はどうなりますか
-KHibma

5

[編集]setプログラムで実行すると(以下に示すように)、望みどおりの結果が得られましたが、Environment.GetEnvironmentVariables()を使用してより簡単に、よりクリーンなコードで実行できます。

1つのオプションは、システム上のすべての環境変数をスキャンして、次のことを証明しようとすることです。

1)環境変数の値はディレクトリですか?(そしてそうならば..)

2)そのディレクトリに含まれていpython.exeますか?

.Net Process APIを介してコマンド実行することsetによりプログラムでこれを行うことができました。このコマンドをパラメーターなしで使用すると、システムで使用されているすべての環境変数が返されます。ですから、から解析し、から放出されたSTDOUTの結果を整理し、それらをスクリーニングして、システム環境を通じて利用可能なもの(およびANYTHING)が最終的に指し示しているものがあるかどうかを確認します。setsetpython.exe

コマンドについて説明しているこのページからset

パラメーターなしでSETと入力すると、現在のすべての環境変数が表示されます。

説明のために、上記で説明したことを実行するメソッドの組み合わせ(およびヘルパークラス)を作成しました。これらは最適化することができ、いくつかの防弾(Try..Catchなど)を使用できますが、コンピューターにを指す環境変数がある場合python.exe、このアプローチはそれを見つけるはずです!VARが呼び出された場合、私は気にしないPATHABBRACADABBRAまたはそれが指している場合どのような... python.exe、これはそれを見つける必要があります。

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

これtermsは、環境変数の名前またはそのn値(つまりPATH、複数の値を持つことができますが、他のほとんどの変数には1つしかありません)を探すためにルーチンに渡す文字列の配列です。のすべての文字列termsが大文字であることを確認してください!

(これをテストしたときC:\Python27\python.exe、ホームシステムにある「PYTHON」を使用しました。しかし、python.exe返された候補のパスをさらに調べたい場合は、簡単に拡張して別の用語の文字列[]を含めることができます。例、ArcGISのビンにあるかどうかを確認するなど)

// Top-level method that organizes everything below..
private void scrapeEnvironmentVariables(string[] terms)
{
    // !! ValueObject !! This is a Helper Class, find it at the bottom..
    List<ValueObject> 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<ValueObject> buildListOfEnvironmentObjects()
{
    // Return a List of 1:n key..value objects.
    List<ValueObject> voList = new List<ValueObject>();

    IDictionary variableDictionary = Environment.GetEnvironmentVariables();
    foreach (DictionaryEntry entry in variableDictionary)
    {
        // Explode multi-values into a List of values (n).
        List<string> values = new List<string>();
        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;
}    

そして、メインクラスの下部に、次のヘルパークラスを含めました。

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

    public string key;
    public string[] values;
}

1
ユーザーはArcGIS DesktopインストーラーでPythonインストールディレクトリをカスタマイズできるため、これは脆弱です。また、PYTHONPATH変数は必要なものではありません。
blah238

@ blah238、時には壊れやすいものだけで十分です。ArcがPYTHONPATHに接続されているのを見て驚いた。これがデフォルトの9.2インストールです。それでも、OPはプログラムでArcGISのpython.exeにアクセスする方法を尋ねましたが、私が推奨するアプローチは、壊れやすいかどうかにかかわらず、それを行います。
elrobis

私が下票を理解しているとは言えませんが、この答えは本当に「役に立たない」のでしょうか?それは素晴らしいことではないかもしれませんが、確かにオプションであり、おそらく典型的なArcインストールで機能します。少なくとも、スレッドに役立つものを追加します。具体的には、Pythonをリンクすることを選択したデフォルトのArcインストールを示しています。以外の環境変数を持つexe PATH
elrobis

申し訳ありませんが、あなたは間違っています。PYTHONPATH変数は、ArcGISがPythonを見つけるためではなく、Pythonがモジュールを見つけるために使用さます。リンクを確認してください。
blah238

@ blah238、私はスクリーンショットが私がしようとしていたポイントを圧倒的/曖昧にしていたと思います。(具体的には、OPへの私の提案は強調するつもりはありませんでしたがPYTHONPATH、それがたまたまその特定のシステムで唯一の変数python.exeです。このアプローチにまだ同意しないかどうかを知る。ありがとう/ E。
elrobis

4

上記の質問に対する私のコメントに基づいて、代替ソリューションを提供したいと思います。現在のプロジェクトでは、非常に似たようなことをしています。.NETアドインがあり、ユーザーがArcMap UIでボタンをクリックすると、Pythonスクリプトが実行されます。ArcGIS Python実行可能ファイルに設定されたPATH環境変数を要件にしたので、.exeコードにPython exeへのパスを含めることを本当に心配する必要はありません。

現在、開発者はテスターがPATH変数を手動で設定しているだけです。しかし、最終的には、アドインをインストールし、Pythonの依存関係をインストールし、必要なPATH変数を設定するWindowsインストーラー(exe)を作成します。このために、Windowsインストーラーを作成するためのオープンソースシステムであるNullsoft Scriptable Install System(NSIS)を使用しています。これまでに作成したコードの一部を次に示しますが、これはかなり大雑把です。基本的に、レジストリを調べて目的のPATH変数が存在するかどうかを確認し、存在しない場合は追加します。もちろん、管理者として実行する必要があります。

include "StrFunc.nsh"
!include "LogicLib.nsh"

/*
  Name: VIESORE_Installer.nsi
  Author: Chad Cooper, CAST
  Date: 7/16/2012
  Purpose: NSIS installer script for .exe creation by NSIS. Installs VIESORE components and sets up environment.
*/

Name "VIESORE"
Caption "VIESORE Installer"
Outfile "VIESOREInstaller.exe"

RequestExecutionLevel admin

# Initialize functions
${StrLoc}
# Initialize user variables
Var path

Section "Set SYSTEM PATH environmental variables"
    ReadRegStr $0 HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" "Path"
    ${StrLoc} $1 $0 "C:\Python26\ArcGIS10.0" ">"
    ${StrLoc} $2 $0 "C:\Python26\ArcGIS10.0\Scripts" ">"
        ${StrLoc} $3 $0 "C:\Python26\ArcGIS10.0\Lib\site-packages" ">"
        ${StrLoc} $4 $0 "C:\Program Files\e-on software\Vue 10 Infinite\Application" ">"
        # Test to see if env vars exist in current system PATH, if not add them to $path variable
        ${If} $3 == ""
                StrCpy $path "C:\Python26\ArcGIS10.0\Lib\site-packages"
        ${EndIf}
        ${If} $2 == ""
                StrCpy $path "C:\Python26\ArcGIS10.0\Scripts;$path"
        ${EndIf}
        ${If} $1 == ""
                StrCpy $path "C:\Python26\ArcGIS10.0;$path"
        ${EndIf}
        ${If} $4 == ""
                StrCpy $path "C:\Program Files\e-on software\Vue 10 Infinite\Application;$path"
        ${EndIf}
        DetailPrint "$path written to system PATH"
    WriteRegStr HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" "Path" "$0;$path"
    ReadRegStr $5 HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" "Path"
    DetailPrint "New Path: $5"
SectionEnd

したがって、これでもArcGIS Python exeへのパスは見つかりませんが、エンドユーザーが適切かつ簡単に設定できるようにすることができます。


+1私はこの勧告に完全に同意します---高レベルで、チャドは「問題を逆に動かしてArcのpythonインスタンスを推測せず、インストーラーを使用してSysAdminに任せて正しいpythonを確立する」と言っていますインスタンス。」@ ChadCooper、NSISはUIコントロールを提供するので、必要に応じてこれらのデフォルトパスをオーバーライドできますか?私はそれがコードによって暗示されるのを見ていませんが、私はそれがそこにあることを賭けています。
elrobis

@elrobis-既存のものをオーバーライド/編集/変更できることは間違いありません-NSISは非常に設定可能であり、非常に滑らかなインストーラーを構築できます-記述するコードを理解する必要があります。
チャドクーパー

アドイン用のインストーラーを作成するのはちょっとおかしいようです。また、10.0、10.2、10.2などをサポートするには、どのような修正が必要ですか?
blah238

@ blah238-はい、それはおかしいようですが、この特定のプロジェクトの私のインストーラーは、話されているように、より多くのことをします。私のアドインは10.0専用です。ArcGISのさまざまなバージョンについては、レジストリをチェックしてインストールされているバージョンを確認し、それに応じて行動できると思います。
チャドクーパー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.