You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Gems/EditorPythonBindings/Code/Source/PythonLogSymbolsComponent.cpp

767 lines
30 KiB
C++

/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <PythonLogSymbolsComponent.h>
#include <Source/PythonCommon.h>
#include <Source/PythonUtility.h>
#include <Source/PythonTypeCasters.h>
#include <Source/PythonProxyBus.h>
#include <Source/PythonProxyObject.h>
#include <pybind11/embed.h>
#include <AzCore/PlatformDef.h>
#include <AzCore/RTTI/AttributeReader.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/IO/SystemFile.h>
#include <AzCore/IO/FileIO.h>
#include <AzCore/std/sort.h>
#include <AzCore/Serialization/Utils.h>
#include <AzFramework/CommandLine/CommandRegistrationBus.h>
#include <AzFramework/StringFunc/StringFunc.h>
namespace EditorPythonBindings
{
namespace Internal
{
struct FileHandle final
{
explicit FileHandle(AZ::IO::HandleType handle)
: m_handle(handle)
{}
~FileHandle()
{
Close();
}
void Close()
{
if (IsValid())
{
AZ::IO::FileIOBase::GetInstance()->Close(m_handle);
}
m_handle = AZ::IO::InvalidHandle;
}
bool IsValid() const
{
return m_handle != AZ::IO::InvalidHandle;
}
operator AZ::IO::HandleType() const { return m_handle; }
AZ::IO::HandleType m_handle;
};
void Indent(int level, AZStd::string& buffer)
{
buffer.append(level * 4, ' ');
}
void AddCommentBlock(int level, const AZStd::string& comment, AZStd::string& buffer)
{
Indent(level, buffer);
AzFramework::StringFunc::Append(buffer, "\"\"\"\n");
Indent(level, buffer);
AzFramework::StringFunc::Append(buffer, comment.c_str());
Indent(level, buffer);
AzFramework::StringFunc::Append(buffer, "\"\"\"\n");
}
}
void PythonLogSymbolsComponent::Reflect(AZ::ReflectContext* context)
{
if (auto&& serialize = azrtti_cast<AZ::SerializeContext*>(context))
{
serialize->Class<PythonLogSymbolsComponent, AZ::Component>()
->Version(0);
}
}
void PythonLogSymbolsComponent::Activate()
{
PythonSymbolEventBus::Handler::BusConnect();
EditorPythonBindingsNotificationBus::Handler::BusConnect();
AZ::Interface<AzToolsFramework::EditorPythonConsoleInterface>::Register(this);
}
void PythonLogSymbolsComponent::Deactivate()
{
AZ::Interface<AzToolsFramework::EditorPythonConsoleInterface>::Unregister(this);
PythonSymbolEventBus::Handler::BusDisconnect();
EditorPythonBindingsNotificationBus::Handler::BusDisconnect();
}
void PythonLogSymbolsComponent::OnPostInitialize()
{
m_basePath.clear();
if (AZ::IO::FileIOBase::GetInstance()->GetAlias("@user@"))
{
// clear out the previous symbols path
char pythonSymbolsPath[AZ_MAX_PATH_LEN];
AZ::IO::FileIOBase::GetInstance()->ResolvePath("@user@/python_symbols", pythonSymbolsPath, AZ_MAX_PATH_LEN);
AZ::IO::FileIOBase::GetInstance()->CreatePath(pythonSymbolsPath);
m_basePath = pythonSymbolsPath;
}
EditorPythonBindingsNotificationBus::Handler::BusDisconnect();
}
void PythonLogSymbolsComponent::WriteMethod(AZ::IO::HandleType handle, AZStd::string_view methodName, const AZ::BehaviorMethod& behaviorMethod, const AZ::BehaviorClass* behaviorClass)
{
AZStd::string buffer;
int indentLevel = 0;
AZStd::vector<AZStd::string> pythonArgs;
const bool isMemberLike = behaviorClass ? PythonProxyObjectManagement::IsMemberLike(behaviorMethod, behaviorClass->m_typeId) : false;
if (isMemberLike)
{
indentLevel = 1;
Internal::Indent(indentLevel, buffer);
pythonArgs.emplace_back("self");
}
else
{
indentLevel = 0;
}
AzFramework::StringFunc::Append(buffer, "def ");
if (isMemberLike || !behaviorClass)
{
AzFramework::StringFunc::Append(buffer, methodName.data());
}
else
{
AzFramework::StringFunc::Append(buffer, behaviorClass->m_name.c_str());
AzFramework::StringFunc::Append(buffer, "_");
AzFramework::StringFunc::Append(buffer, methodName.data());
}
AzFramework::StringFunc::Append(buffer, "(");
AZStd::string bufferArg;
for (size_t argIndex = 0; argIndex < behaviorMethod.GetNumArguments(); ++argIndex)
{
const AZStd::string* name = behaviorMethod.GetArgumentName(argIndex);
if (!name || name->empty())
{
bufferArg = AZStd::string::format(" arg%zu", argIndex);
}
else
{
bufferArg = *name;
}
AZStd::string type = FetchPythonTypeName(*behaviorMethod.GetArgument(argIndex));
if (!type.empty())
{
AzFramework::StringFunc::Append(bufferArg, ": ");
AzFramework::StringFunc::Append(bufferArg, type.data());
}
pythonArgs.push_back(bufferArg);
bufferArg.clear();
}
AZStd::string argsList;
AzFramework::StringFunc::Join(buffer, pythonArgs.begin(), pythonArgs.end(), ",");
AzFramework::StringFunc::Append(buffer, ") -> None:\n");
Internal::Indent(indentLevel + 1, buffer);
AzFramework::StringFunc::Append(buffer, "pass\n\n");
AZ::IO::FileIOBase::GetInstance()->Write(handle, buffer.c_str(), buffer.size());
}
void PythonLogSymbolsComponent::WriteProperty(AZ::IO::HandleType handle, int level, AZStd::string_view propertyName, const AZ::BehaviorProperty& property, [[maybe_unused]] const AZ::BehaviorClass * behaviorClass)
{
AZStd::string buffer;
// property declaration
Internal::Indent(level, buffer);
AzFramework::StringFunc::Append(buffer, "@property\n");
Internal::Indent(level, buffer);
AzFramework::StringFunc::Append(buffer, "def ");
AzFramework::StringFunc::Append(buffer, propertyName.data());
AzFramework::StringFunc::Append(buffer, "(self) -> ");
AZStd::string_view type = FetchPythonTypeAndTraits(property.GetTypeId(), AZ::BehaviorParameter::TR_NONE);
if (type.empty())
{
AzFramework::StringFunc::Append(buffer, "Any");
}
else
{
AzFramework::StringFunc::Append(buffer, type.data());
}
AzFramework::StringFunc::Append(buffer, ":\n");
Internal::Indent(level + 1, buffer);
AzFramework::StringFunc::Append(buffer, "pass\n\n");
AZ::IO::FileIOBase::GetInstance()->Write(handle, buffer.c_str(), buffer.size());
}
void PythonLogSymbolsComponent::LogClass(AZStd::string_view moduleName, AZ::BehaviorClass* behaviorClass)
{
LogClassWithName(moduleName, behaviorClass, behaviorClass->m_name.c_str());
}
void PythonLogSymbolsComponent::LogClassWithName(AZStd::string_view moduleName, AZ::BehaviorClass* behaviorClass, AZStd::string_view className)
{
Internal::FileHandle fileHandle(OpenModuleAt(moduleName));
if (fileHandle.IsValid())
{
// Behavior Class types with member methods and properties
AZStd::string buffer;
AzFramework::StringFunc::Append(buffer, "class ");
AzFramework::StringFunc::Append(buffer, className.data());
AzFramework::StringFunc::Append(buffer, ":\n");
AZ::IO::FileIOBase::GetInstance()->Write(fileHandle, buffer.c_str(), buffer.size());
buffer.clear();
if (behaviorClass->m_methods.empty() && behaviorClass->m_properties.empty())
{
AZStd::string body{ " # behavior class type with no methods or properties \n" };
Internal::Indent(1, body);
AzFramework::StringFunc::Append(body, "pass\n\n");
AZ::IO::FileIOBase::GetInstance()->Write(fileHandle, body.c_str(), body.size());
}
else
{
for (const auto& properyEntry : behaviorClass->m_properties)
{
AZ::BehaviorProperty* property = properyEntry.second;
AZStd::string propertyName{ properyEntry.first };
Scope::FetchScriptName(property->m_attributes, propertyName);
WriteProperty(fileHandle, 1, propertyName, *property, behaviorClass);
}
for (const auto& methodEntry : behaviorClass->m_methods)
{
AZ::BehaviorMethod* method = methodEntry.second;
if (method && PythonProxyObjectManagement::IsMemberLike(*method, behaviorClass->m_typeId))
{
AZStd::string baseMethodName{ methodEntry.first };
Scope::FetchScriptName(method->m_attributes, baseMethodName);
WriteMethod(fileHandle, baseMethodName, *method, behaviorClass);
}
}
}
}
}
void PythonLogSymbolsComponent::LogClassMethod(AZStd::string_view moduleName, AZStd::string_view globalMethodName, AZ::BehaviorClass* behaviorClass, AZ::BehaviorMethod* behaviorMethod)
{
AZ_UNUSED(behaviorClass);
Internal::FileHandle fileHandle(OpenModuleAt(moduleName));
if (fileHandle.IsValid())
{
WriteMethod(fileHandle, globalMethodName, *behaviorMethod, nullptr);
}
}
void PythonLogSymbolsComponent::LogBus(AZStd::string_view moduleName, AZStd::string_view busName, AZ::BehaviorEBus* behaviorEBus)
{
if (behaviorEBus->m_events.empty())
{
return;
}
Internal::FileHandle fileHandle(OpenModuleAt(moduleName));
if (fileHandle.IsValid())
{
AZStd::string buffer;
const auto& eventSenderEntry = behaviorEBus->m_events.begin();
const AZ::BehaviorEBusEventSender& sender = eventSenderEntry->second;
AzFramework::StringFunc::Append(buffer, "def ");
AzFramework::StringFunc::Append(buffer, busName.data());
bool isBroadcast = false;
if (sender.m_event)
{
AZStd::string addressType = FetchPythonTypeName(behaviorEBus->m_idParam);
if (addressType.empty())
{
AzFramework::StringFunc::Append(buffer, "(busCallType: int, busEventName: str, address: Any, args: Tuple[Any])");
}
else
{
AzFramework::StringFunc::Append(buffer, "(busCallType: int, busEventName: str, address: ");
AzFramework::StringFunc::Append(buffer, AZStd::string::format(AZ_STRING_FORMAT, AZ_STRING_ARG(addressType)).c_str());
AzFramework::StringFunc::Append(buffer, ", args: Tuple[Any])");
}
}
else
{
AzFramework::StringFunc::Append(buffer, "(busCallType: int, busEventName: str, args: Tuple[Any])");
isBroadcast = true;
}
AzFramework::StringFunc::Append(buffer, " -> Any:\n");
AZ::IO::FileIOBase::GetInstance()->Write(fileHandle, buffer.c_str(), buffer.size());
buffer.clear();
auto eventInfoBuilder = [this](const AZ::BehaviorMethod* behaviorMethod, AZStd::string& inOutStrBuffer, [[maybe_unused]] TypeMap& typeCache)
{
AzFramework::StringFunc::Append(inOutStrBuffer, "(");
size_t numArguments = behaviorMethod->GetNumArguments();
const AZ::BehaviorParameter* busIdArg = behaviorMethod->GetBusIdArgument();
for (size_t i = 0; i < numArguments; ++i)
{
const AZ::BehaviorParameter* argParam = behaviorMethod->GetArgument(i);
if (argParam == busIdArg)
{
// address argument is part of the bus call, skip from event argument list
continue;
}
AZStd::string_view argType = FetchPythonTypeAndTraits(argParam->m_typeId, argParam->m_traits);
AzFramework::StringFunc::Append(inOutStrBuffer, argType.data());
if (i < (numArguments - 1))
{
AzFramework::StringFunc::Append(inOutStrBuffer, ", ");
}
}
const AZ::BehaviorParameter* resultParam = behaviorMethod->GetResult();
AZStd::string returnType = FetchPythonTypeName(*resultParam);
AZStd::string returnTypeStr = AZStd::string::format(") -> " AZ_STRING_FORMAT" \n", AZ_STRING_ARG(returnType));
AzFramework::StringFunc::Append(inOutStrBuffer, returnTypeStr.c_str());
};
// record the event names the behavior can send, their parameters and return type
AZStd::string comment = behaviorEBus->m_toolTip;
if (!behaviorEBus->m_events.empty())
{
AzFramework::StringFunc::Append(comment, "The following bus Call types, Event names and Argument types are supported by this bus:\n");
AZStd::vector<AZStd::string> events;
for (const auto& eventSenderEntry2 : behaviorEBus->m_events)
{
const AZStd::string& eventName = eventSenderEntry2.first;
AZStd::string eventNameStr = AZStd::string::format("'%s', ", eventName.c_str());
// prefer m_event info over m_broadcast
if (!isBroadcast && eventSenderEntry2.second.m_event != nullptr)
{
AZStd::string eventInfo;
AzFramework::StringFunc::Append(eventInfo, "bus.Event, ");
AzFramework::StringFunc::Append(eventInfo, eventNameStr.c_str());
eventInfoBuilder(eventSenderEntry2.second.m_event, eventInfo, m_typeCache);
events.push_back(eventInfo);
}
else if (isBroadcast && eventSenderEntry2.second.m_broadcast != nullptr)
{
AZStd::string eventInfo;
AzFramework::StringFunc::Append(eventInfo, "bus.Broadcast, ");
AzFramework::StringFunc::Append(eventInfo, eventNameStr.c_str());
eventInfoBuilder(eventSenderEntry2.second.m_broadcast, eventInfo, m_typeCache);
events.push_back(eventInfo);
}
else
{
AZ_Warning("python", false, "Event %s is expected to have valid event information.", eventName.c_str());
}
}
AZStd::sort(events.begin(), events.end());
for (auto& eventInfo : events)
{
Internal::Indent(1, comment);
AzFramework::StringFunc::Append(comment, eventInfo.c_str());
}
}
Internal::AddCommentBlock(1, comment, buffer);
Internal::Indent(1, buffer);
AzFramework::StringFunc::Append(buffer, "pass\n\n");
AZ::IO::FileIOBase::GetInstance()->Write(fileHandle, buffer.c_str(), buffer.size());
// can the EBus create & destroy a handler?
if (behaviorEBus->m_createHandler && behaviorEBus->m_destroyHandler)
{
buffer.clear();
AzFramework::StringFunc::Append(buffer, "def ");
AzFramework::StringFunc::Append(buffer, busName.data());
AzFramework::StringFunc::Append(buffer, "Handler() -> None:\n");
Internal::Indent(1, buffer);
AzFramework::StringFunc::Append(buffer, "pass\n\n");
AZ::IO::FileIOBase::GetInstance()->Write(fileHandle, buffer.c_str(), buffer.size());
}
}
}
void PythonLogSymbolsComponent::LogGlobalMethod(AZStd::string_view moduleName, AZStd::string_view methodName, AZ::BehaviorMethod* behaviorMethod)
{
Internal::FileHandle fileHandle(OpenModuleAt(moduleName));
if (fileHandle.IsValid())
{
WriteMethod(fileHandle, methodName, *behaviorMethod, nullptr);
}
auto functionMapIt = m_globalFunctionMap.find(moduleName);
if (functionMapIt == m_globalFunctionMap.end())
{
auto moduleSetIt = m_moduleSet.find(moduleName);
if (moduleSetIt != m_moduleSet.end())
{
m_globalFunctionMap[*moduleSetIt] = { AZStd::make_pair(behaviorMethod, methodName) };
}
}
else
{
GlobalFunctionList& globalFunctionList = functionMapIt->second;
globalFunctionList.emplace_back(AZStd::make_pair(behaviorMethod, methodName));
}
}
void PythonLogSymbolsComponent::LogGlobalProperty(AZStd::string_view moduleName, AZStd::string_view propertyName, AZ::BehaviorProperty* behaviorProperty)
{
if (!behaviorProperty->m_getter || !behaviorProperty->m_getter->GetResult())
{
return;
}
Internal::FileHandle fileHandle(OpenModuleAt(moduleName));
if (fileHandle.IsValid())
{
AZStd::string buffer;
// add header
AZ::u64 filesize = 0;
AZ::IO::FileIOBase::GetInstance()->Size(fileHandle, filesize);
if (filesize == 0)
{
AzFramework::StringFunc::Append(buffer, "class property():\n");
}
Internal::Indent(1, buffer);
AzFramework::StringFunc::Append(buffer, propertyName.data());
AzFramework::StringFunc::Append(buffer, ": ClassVar[");
const AZ::BehaviorParameter* resultParam = behaviorProperty->m_getter->GetResult();
AZStd::string_view type = FetchPythonTypeAndTraits(resultParam->m_typeId, resultParam->m_traits);
if (type.empty())
{
AzFramework::StringFunc::Append(buffer, "Any");
}
else
{
AzFramework::StringFunc::Append(buffer, type.data());
}
AzFramework::StringFunc::Append(buffer, "] = None");
if (behaviorProperty->m_getter && !behaviorProperty->m_setter)
{
AzFramework::StringFunc::Append(buffer, " # read only");
}
AzFramework::StringFunc::Append(buffer, "\n");
AZ::IO::FileIOBase::GetInstance()->Write(fileHandle, buffer.c_str(), buffer.size());
}
}
void PythonLogSymbolsComponent::Finalize()
{
Internal::FileHandle fileHandle(OpenInitFileAt("azlmbr.bus"));
if (fileHandle)
{
AZStd::string buffer;
AzFramework::StringFunc::Append(buffer, "# Bus dispatch types:\n");
AzFramework::StringFunc::Append(buffer, "from typing_extensions import Final\n");
AzFramework::StringFunc::Append(buffer, "Broadcast: Final[int] = 0\n");
AzFramework::StringFunc::Append(buffer, "Event: Final[int] = 1\n");
AzFramework::StringFunc::Append(buffer, "QueueBroadcast: Final[int] = 2\n");
AzFramework::StringFunc::Append(buffer, "QueueEvent: Final[int] = 3\n");
AZ::IO::FileIOBase::GetInstance()->Write(fileHandle, buffer.c_str(), buffer.size());
}
fileHandle.Close();
}
void PythonLogSymbolsComponent::GetModuleList(AZStd::vector<AZStd::string_view>& moduleList) const
{
moduleList.clear();
moduleList.reserve(m_moduleSet.size());
AZStd::copy(m_moduleSet.begin(), m_moduleSet.end(), AZStd::back_inserter(moduleList));
}
void PythonLogSymbolsComponent::GetGlobalFunctionList(GlobalFunctionCollection& globalFunctionCollection) const
{
globalFunctionCollection.clear();
for (const auto& globalFunctionMapEntry : m_globalFunctionMap)
{
const AZStd::string_view moduleName{ globalFunctionMapEntry.first };
const GlobalFunctionList& moduleFunctionList = globalFunctionMapEntry.second;
AZStd::transform(moduleFunctionList.begin(), moduleFunctionList.end(), AZStd::back_inserter(globalFunctionCollection), [moduleName](auto& entry) -> auto
{
const GlobalFunctionEntry& globalFunctionEntry = entry;
const AZ::BehaviorMethod* behaviorMethod = entry.first;
return AzToolsFramework::EditorPythonConsoleInterface::GlobalFunction({ moduleName, globalFunctionEntry.second, behaviorMethod->m_debugDescription });
});
}
}
AZStd::string PythonLogSymbolsComponent::FetchListType(const AZ::TypeId& typeId)
{
AZStd::string type = "list";
AZStd::vector<AZ::Uuid> typeList = AZ::Utils::GetContainedTypes(typeId);
if (!typeList.empty())
{
// trait info not available, so defaulting to TR_NONE
AZStd::string_view itemType = FetchPythonTypeAndTraits(typeList[0], AZ::BehaviorParameter::TR_NONE);
if (!itemType.empty())
{
type = AZStd::string::format("List[" AZ_STRING_FORMAT "]", AZ_STRING_ARG(itemType));
}
}
return type;
}
AZStd::string PythonLogSymbolsComponent::FetchMapType(const AZ::TypeId& typeId)
{
AZStd::string type = "dict";
AZStd::vector<AZ::Uuid> typeList = AZ::Utils::GetContainedTypes(typeId);
if (!typeList.empty())
{
// trait info not available, so defaulting to TR_NONE
AZStd::string_view kType = FetchPythonTypeAndTraits(typeList[0], AZ::BehaviorParameter::TR_NONE);
AZStd::string_view vType = FetchPythonTypeAndTraits(typeList[1], AZ::BehaviorParameter::TR_NONE);
if (!kType.empty() && !vType.empty())
{
type = AZStd::string::format("Dict[" AZ_STRING_FORMAT ", " AZ_STRING_FORMAT "]",
AZ_STRING_ARG(kType), AZ_STRING_ARG(vType));
}
}
return type;
}
AZStd::string PythonLogSymbolsComponent::FetchOutcomeType(const AZ::TypeId& typeId)
{
AZStd::string type = "Outcome";
AZStd::pair<AZ::Uuid, AZ::Uuid> outcomeTypes = AZ::Utils::GetOutcomeTypes(typeId);
// trait info not available, so defaulting to TR_NONE
AZStd::string_view valueT = FetchPythonTypeAndTraits(outcomeTypes.first, AZ::BehaviorParameter::TR_NONE);
AZStd::string_view errorT = FetchPythonTypeAndTraits(outcomeTypes.second, AZ::BehaviorParameter::TR_NONE);
if (!valueT.empty() && !errorT.empty())
{
type = AZStd::string::format("Outcome[" AZ_STRING_FORMAT ", " AZ_STRING_FORMAT "]",
AZ_STRING_ARG(valueT), AZ_STRING_ARG(errorT));
}
return type;
}
AZStd::string PythonLogSymbolsComponent::TypeNameFallback(const AZ::TypeId& typeId)
{
// fall back to class data m_name
AZ::SerializeContext* serializeContext = nullptr;
AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext);
if (serializeContext)
{
auto classData = serializeContext->FindClassData(typeId);
if (classData)
{
return classData->m_name;
}
}
return "";
}
AZStd::string_view PythonLogSymbolsComponent::FetchPythonTypeAndTraits(const AZ::TypeId& typeId, AZ::u32 traits)
{
if (m_typeCache.find(typeId) == m_typeCache.end())
{
AZStd::string type;
if (AZ::AzTypeInfo<AZStd::string_view>::Uuid() == typeId ||
AZ::AzTypeInfo<AZStd::string>::Uuid() == typeId)
{
type = "str";
}
else if (AZ::AzTypeInfo<char>::Uuid() == typeId &&
traits & AZ::BehaviorParameter::TR_POINTER &&
traits & AZ::BehaviorParameter::TR_CONST)
{
type = "str";
}
else if (AZ::AzTypeInfo<float>::Uuid() == typeId ||
AZ::AzTypeInfo<double>::Uuid() == typeId)
{
type = "float";
}
else if (AZ::AzTypeInfo<bool>::Uuid() == typeId)
{
type = "bool";
}
else if (AZ::AzTypeInfo<AZ::s8>::Uuid() == typeId ||
AZ::AzTypeInfo<AZ::u8>::Uuid() == typeId ||
AZ::AzTypeInfo<AZ::s16>::Uuid() == typeId ||
AZ::AzTypeInfo<AZ::u16>::Uuid() == typeId ||
AZ::AzTypeInfo<AZ::s32>::Uuid() == typeId ||
AZ::AzTypeInfo<AZ::u32>::Uuid() == typeId ||
AZ::AzTypeInfo<AZ::s64>::Uuid() == typeId ||
AZ::AzTypeInfo<AZ::u64>::Uuid() == typeId)
{
type = "int";
}
else if (AZ::AzTypeInfo<AZStd::vector<AZ::u8>>::Uuid() == typeId)
{
type = "bytes";
}
else if (AZ::AzTypeInfo<AZStd::any>::Uuid() == typeId)
{
type = "object";
}
else if (AZ::AzTypeInfo<void>::Uuid() == typeId)
{
type = "None";
}
else if (AZ::Utils::IsVectorContainerType(typeId))
{
type = FetchListType(typeId);
}
else if (AZ::Utils::IsMapContainerType(typeId))
{
type = FetchMapType(typeId);
}
else if (AZ::Utils::IsOutcomeType(typeId))
{
type = FetchOutcomeType(typeId);
}
else
{
type = TypeNameFallback(typeId);
}
m_typeCache[typeId] = type;
}
return m_typeCache[typeId];
}
AZStd::string PythonLogSymbolsComponent::FetchPythonTypeName(const AZ::BehaviorParameter& param)
{
AZStd::string pythonType = FetchPythonTypeAndTraits(param.m_typeId, param.m_traits);
if (pythonType.empty())
{
if (AZ::StringFunc::Equal(param.m_name, "void"))
{
return "None";
}
return param.m_name;
}
return pythonType;
}
AZ::IO::HandleType PythonLogSymbolsComponent::OpenInitFileAt(AZStd::string_view moduleName)
{
if (m_basePath.empty())
{
return AZ::IO::InvalidHandle;
}
// creates the __init__.py file in this path
AZStd::string modulePath(moduleName);
AzFramework::StringFunc::Replace(modulePath, ".", AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING);
AZStd::string initFile;
AzFramework::StringFunc::Path::Join(m_basePath.c_str(), modulePath.c_str(), initFile);
AzFramework::StringFunc::Append(initFile, AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING);
AzFramework::StringFunc::Append(initFile, "__init__.pyi");
AZ::IO::OpenMode openMode = AZ::IO::OpenMode::ModeText | AZ::IO::OpenMode::ModeWrite;
AZ::IO::HandleType fileHandle = AZ::IO::InvalidHandle;
AZ::IO::Result result = AZ::IO::FileIOBase::GetInstance()->Open(initFile.c_str(), openMode, fileHandle);
AZ_Warning("python", result, "Could not open %s to write Python symbols.", initFile.c_str());
if (result)
{
return fileHandle;
}
return AZ::IO::InvalidHandle;
}
AZ::IO::HandleType PythonLogSymbolsComponent::OpenModuleAt(AZStd::string_view moduleName)
{
if (m_basePath.empty())
{
return AZ::IO::InvalidHandle;
}
bool resetFile = false;
if (m_moduleSet.find(moduleName) == m_moduleSet.end())
{
m_moduleSet.insert(moduleName);
resetFile = true;
}
AZStd::vector<AZStd::string> moduleParts;
AzFramework::StringFunc::Tokenize(moduleName.data(), moduleParts, '.');
// prepare target PYI file
AZStd::string targetModule = moduleParts.back();
moduleParts.pop_back();
AzFramework::StringFunc::Append(targetModule, ".pyi");
AZStd::string modulePath;
AzFramework::StringFunc::Append(modulePath, m_basePath.c_str());
AzFramework::StringFunc::Append(modulePath, AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING);
AzFramework::StringFunc::Join(modulePath, moduleParts.begin(), moduleParts.end(), AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING);
// prepare the path
AZ::IO::FileIOBase::GetInstance()->CreatePath(modulePath.c_str());
// assemble the file path
AzFramework::StringFunc::Append(modulePath, AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING);
AzFramework::StringFunc::Append(modulePath, targetModule.c_str());
AzFramework::StringFunc::AssetDatabasePath::Normalize(modulePath);
AZ::IO::OpenMode openMode = AZ::IO::OpenMode::ModeText;
if (AZ::IO::SystemFile::Exists(modulePath.c_str()))
{
openMode |= (resetFile) ? AZ::IO::OpenMode::ModeWrite : AZ::IO::OpenMode::ModeAppend;
}
else
{
openMode |= AZ::IO::OpenMode::ModeWrite;
}
AZ::IO::HandleType fileHandle = AZ::IO::InvalidHandle;
AZ::IO::Result result = AZ::IO::FileIOBase::GetInstance()->Open(modulePath.c_str(), openMode, fileHandle);
AZ_Warning("python", result, "Could not open %s to write Python module symbols.", modulePath.c_str());
if (result)
{
return fileHandle;
}
return AZ::IO::InvalidHandle;
}
}