using Python.Runtime;
using System.ComponentModel;
using System.Text.Json;
namespace dopt.DeltaBarth
{
///
/// Spiegelung der internen Fehlertypen innerhalb der Python-Bibliothek
///
public enum StatusCodes
{
///
/// erfolgreiche, fehlerfreie Durchführung der Routine
///
[Description("Keine Fehler aufgetreten")]
Erfolg = 0,
///
/// Bei der API-Abfrage wurde der Timeout getriggert.
///
[Description("Bei der Verbindung zum API-Server kam es zum Timeout")]
VerbindungTimeout = 1,
///
/// Bei der API-Abfrage ist ein unerwarteter Fehler aufgetreten, der unmittelbar die HTTP-Anfrage betrifft.
///
[Description("Bei der Verbindung zum API-Server ist ein Fehler aufgetreten")]
VerbindungFehler = 2,
///
/// Der ausgewählte Datensatz enthält nicht genügend Datenpunkte.
///
[Description("Der bereitgestellte Datensatz enthält in Summe zu wenige Einzeleinträge")]
DatensatzZuWenigeDatenpunkte = 3,
///
/// Der ausgewählte Datensatz enthält nach Aggregation pro Monat nicht genügend Datenpunkte.
///
[Description("Der bereitgestellte Datensatz enthält nach Aggregation zu Monaten zu wenig Einträge")]
DatensatzZuWenigeMonatsdatenpunkte = 4,
///
/// Die Prognosequalität des Modells ist nicht zufriedenstellend. Eine verlässliche Prognose ist nicht möglich.
///
[Description("Die Prognosequalität des Modells erfüllt nicht die Mindestanforderungen")]
KeineVerlaesslichePrognose = 5,
///
/// Es ist intern ein Fehler aufgetreten aufgetreten
///
[Description("Interne Fehler, die während der Routine aufgetreten sind")]
InternerFehler = 100,
///
/// Es ist ein Fehler beim Schreiben der programminternen Datenbank aufgetreten.
///
[Description("Interne Fehler, die während der Datenbankinteraktion aufgetreten sind")]
InternerDbFehler = 150,
///
/// Es ist ein Fehler auf dem API-Server aufgetreten.
/// Das dazugehörige Status-Objekt sollte diesen Fehler zur Verfügung stellen können.
///
///
///
[Description("Vom API-Server wurde eine Fehlermeldung zurückgegeben")]
ApiServerFehler = 400,
}
///
/// Eine Exception, die genutzt wird, um anzuzeigen, dass beim Parsen der Python-Objekte
/// ein Fehler aufgetreten ist.
///
public class PythonParsingException : Exception
{
///
/// Konstruktor ohne Inhalt
///
public PythonParsingException() { }
///
/// Konstruktor mit Nachricht
///
///
public PythonParsingException(string message) : base(message) { }
}
///
/// Plugin-Klasse, mit der die Interaktion der zugrundeliegenden Python-Runtime erfolgt
///
public class Plugin : SharpPython.BasePlugin
{
///
/// Python-interne Zustandsverwaltung
///
protected dynamic pyModManagement;
///
/// Python-interne Routinen und Pipelines
///
protected dynamic pyModPipeline;
///
/// Debug-Modul für Python-Umgebung
///
protected dynamic pyDebug;
///
/// Konstruktor der Plugin-Klasse.
/// Kann mit beliebigem Pfad zu einer Python-Runtime initialisiert werden.
///
/// Der Pfad zur Python-Runtime. Dieser muss zu dem Ordner zeigen,
/// in welchem die Runtime in Form eines Ordners mit dem Namen "python" abliegt.
public Plugin(string runtimePath) : base(SharpPython.PyOptimLevels.O, threaded: true, runtimePath: runtimePath, verbose: false)
{
base.Initialise();
using (Py.GIL())
{
pyModManagement = Py.Import("delta_barth.management");
pyModPipeline = Py.Import("delta_barth.pipelines");
pyDebug = Py.Import("delta_barth._debug");
}
}
///
/// Gibt Runtime-relevante Pfade in der Konsole aus
///
public string DebugCall()
{
string infos;
using (Py.GIL())
{
infos = pyDebug.print_infos();
}
Console.WriteLine(infos);
Console.WriteLine($"PyEngine - PYHOME: {PythonEngine.PythonHome}");
Console.WriteLine($"PyEngine - PYPATH: {PythonEngine.PythonPath}");
return infos;
}
/////
///// Initialisiert das Plugin mit allen relevanten Paramtern für die weitere Nutzung.
///// Diese Methode sollte nur einmal je Instanz genutzt werden.
/////
///// Pfad zu einem Ordner, in dem Programmdaten ohne Bedenken dauerhaft abgelegt werden können.
///// Basis-URL zum Zugriff auf die API. Dies muss eine vollständige URL sein inkl. der Route "/api".
///// Nutzername für die Datenbankanmeldung.
///// Passwort für die Datenbankanmeldung.
///// Name der Datenbank, bei der die Anmeldung erfolgen soll.
///// Mandant für die Datenbankanmeldung.
//public void Startup(string datenPfad, string basisApiUrl, string nutzername, string passwort, string datenbank, string mandant)
//{
// AssertNotDisposed();
// Setup(datenPfad, basisApiUrl);
// SetzeNutzerdaten(nutzername, passwort, datenbank, mandant);
//}
/////
///// Diese Methode erlaubt es, die relevanten Nutzerdaten zur Laufzeit des Plugins zu ändern.
///// Dies beinhaltet: Nutzername, Passwort, Datenbankname, Mandant
/////
///// Nutzername für die Datenbankanmeldung.
///// Passwort für die Datenbankanmeldung.
///// Name der Datenbank, bei der die Anmeldung erfolgen soll.
///// Mandant für die Datenbankanmeldung.
//public void SetzeNutzerdaten(string nutzername, string passwort, string datenbank, string mandant)
//{
// AssertNotDisposed();
// using (Py.GIL()) {
// pyModManagement.set_credentials(nutzername, passwort, datenbank, mandant);
// }
//}
/////
///// Ausführung der Umsatzprognose-Pipeline mit Dummy-Daten.
///// Es werden keine API-Abrufe durchgeführt und somit auch keine Live-Daten genutzt.
/////
///// optional: Firmen-ID, für die die Pipeline ausgeführt werden soll.
///// Wird der Parameter nicht zur Verfügung gestellt, werden alle Firmen bzw. Kunden abgerufen
///// optional: Start-Datum, ab dem die Daten für die Erstellung des Prognosemodells genutzt werden.
///// Daten, die weiter in der Vergangenheit liegen, werden nicht berücksichtigt.
///// Wird der Parameter nicht zur Verfügung gestellt, wird die gesamte Historie genutzt.
///// Umsatzprognose inkl. Status-Objekt zur Nachvollziehbarkeit etwaig aufgetretener Fehler.
/////
//public DataObjects.UmsatzPrognoseAusgabe UmsatzprognoseDummy(int? firmaId, DateTime? analyseBeginn)
//{
// AssertNotDisposed();
// string pyJson;
// using (Py.GIL())
// {
// pyJson = pyModPipeline.pipeline_sales_forecast_dummy(firmaId, analyseBeginn);
// }
// var parsed = JsonSerializer.Deserialize(pyJson) ?? throw new PythonParsingException("Could not correctly parse object from Python");
// return parsed;
//}
/////
///// Ausführung der Umsatzprognose-Pipeline mit Live-Daten.
///// Es werden API-Abrufe durchgeführt und somit auch Live-Daten genutzt.
///// Hierfür muss sichergestellt sein, dass der API-Server erreichbar und abrufbereit ist.
/////
///// optional: Liste von Firmen-IDs, für die die Pipeline ausgeführt werden soll.
///// Wird der Parameter nicht zur Verfügung gestellt, werden alle Firmen bzw. Kunden abgerufen
///// optional: Start-Datum, ab dem die Daten für die Erstellung des Prognosemodells genutzt werden.
///// Daten, die weiter in der Vergangenheit liegen, werden nicht berücksichtigt.
///// Wird der Parameter nicht zur Verfügung gestellt, wird die gesamte Historie genutzt.
///// Umsatzprognose inkl. Status-Objekt zur Nachvollziehbarkeit etwaig aufgetretener Fehler.
/////
//public DataObjects.UmsatzPrognoseAusgabe Umsatzprognose(List? firmaIds, DateTime? analyseBeginn)
//{
// AssertNotDisposed();
// string pyJson;
// using (Py.GIL())
// {
// pyJson = pyModPipeline.pipeline_sales_forecast(firmaIds, analyseBeginn);
// }
// var parsed = JsonSerializer.Deserialize(pyJson) ?? throw new PythonParsingException("Could not correctly parse object from Python");
// return parsed;
//}
/////
///// Setup der Python-internen Umgebung
/////
///// Pfad zu einem Ordner, in dem Programmdaten ohne Bedenken dauerhaft abgelegt werden können.
///// Basis-URL zum Zugriff auf die API. Dies muss eine vollständige URL sein inkl. der Route "/api".
//protected void Setup(string datenPfad, string basisApiUrl)
//{
// AssertNotDisposed();
// using (Py.GIL())
// {
// pyModManagement.setup(datenPfad, basisApiUrl);
// }
//}
/////
///// Hole die konfigurierte API-Basis-URL aus der Python-Umgebung
/////
///// konfigurierte Basis-URL
//protected string GetBaseApiUrl()
//{
// AssertNotDisposed();
// string pyJson;
// using (Py.GIL())
// {
// pyJson = (string)pyModManagement.get_base_url();
// }
// return pyJson;
//}
/////
///// Hole den konfigurierten Datenpfad zur Dateiverwaltung aus der Python-Umgebung
/////
///// konfigurierten Datenpfad
//protected string GetDataPath()
//{
// AssertNotDisposed();
// string pyJson;
// using (Py.GIL())
// {
// pyJson = (string)pyModManagement.get_data_path();
// }
// return pyJson;
//}
/////
///// Hole die konfigurierten Nutzerdaten zur API-Interaktion aus der Python-Umgebung
/////
///// konfigurierte Nutzerdaten
/////
//protected DataObjects.Credentials GetCredentials()
//{
// AssertNotDisposed();
// string pyJson;
// using (Py.GIL())
// {
// pyJson = (string)pyModManagement.get_credentials();
// }
// DataObjects.Credentials? parsed = JsonSerializer.Deserialize(pyJson);
// return parsed ?? throw new PythonParsingException("Could not correctly parse object from Python");
//}
}
}