Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Python 11 and 12 support #2441

Merged
merged 25 commits into from
Dec 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
da4cd0f
Require version 3.12.7 or higher
edwardalee Nov 25, 2024
4ee2c4f
Remove call to Py_FinalizeEx() that causes memory problems
edwardalee Nov 25, 2024
1c3967f
Pull in changes from PR #1902
edwardalee Nov 25, 2024
6cc855b
Use exact match for Python version and define CMAKE_INSTALL_BINDIR
edwardalee Nov 29, 2024
404ff9c
Temporarily set Python to version 3.10 to see if any tests break
edwardalee Nov 29, 2024
bda6120
Align reactor-c
edwardalee Nov 29, 2024
c6f1a23
Hopefully restored Docker capability
edwardalee Nov 30, 2024
8aa2296
Spotless
edwardalee Nov 30, 2024
6057a85
back to Head
MoezBHH Dec 3, 2024
f4cb056
Fix segmentation error on Python > 3.10
MoezBHH Dec 5, 2024
db3dbcf
Fix segmentation error on Python > 3.10
MoezBHH Dec 6, 2024
3271089
fix file formatting
MoezBHH Dec 6, 2024
3381032
Align reactor-c
edwardalee Dec 6, 2024
928267d
Fix warning about serialized type
edwardalee Dec 7, 2024
afd045c
Merge branch 'master' into python-12
edwardalee Dec 7, 2024
252a2ae
Generate preambles only once in Python file
edwardalee Dec 7, 2024
20f1703
Import pickle_serializer
edwardalee Dec 7, 2024
a9b6d78
Update to allow Python versions bigger than 3.10
edwardalee Dec 7, 2024
23b5922
Added target property for Python version
edwardalee Dec 7, 2024
7a3a789
Added missing file
edwardalee Dec 7, 2024
f51aa71
Format
edwardalee Dec 7, 2024
33db01a
Merge branch 'master' into python-12
edwardalee Dec 8, 2024
16389a3
Align reactor-c
edwardalee Dec 8, 2024
33cc862
Fix Python version to 3.12
edwardalee Dec 9, 2024
4b20770
Align reactor-c
edwardalee Dec 9, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/lsp-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ jobs:
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: "3.10"
python-version: "3.12"
- name: Run language server Python tests without PyLint
run: ./gradlew core:integrationTest --tests org.lflang.tests.lsp.LspTests.pythonValidationTestSyntaxOnly core:integrationTestCodeCoverageReport
- name: Install pylint
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/py-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
python-version: '3.12'
- name: Install dependencies OS X
run: |
brew install coreutils
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ protected String generateSerializationIncludes(
return code.getCode();
}

@Override
public String getNetworkBufferType() {
return "PyObject*";
}

@Override
public String generateNetworkSenderBody(
VarRef sendingPort,
Expand Down
11 changes: 10 additions & 1 deletion core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public class CCmakeGenerator {

private final FileConfig fileConfig;
private final List<String> additionalSources;
private final SetUpMainTarget setUpMainTarget;
private SetUpMainTarget setUpMainTarget;
private final String installCode;

public CCmakeGenerator(FileConfig fileConfig, List<String> additionalSources) {
Expand All @@ -90,6 +90,15 @@ public CCmakeGenerator(
this.installCode = installCode;
}

/**
* Set the code generator for the CMake main target.
*
* @param setUpMainTarget
*/
public void setCmakeGenerator(SetUpMainTarget setUpMainTarget) {
this.setUpMainTarget = setUpMainTarget;
}

/**
* Generate the contents of a CMakeLists.txt that builds the provided LF C 'sources'. Any error
* will be reported in the 'errorReporter'.
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/org/lflang/generator/c/CGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ public class CGenerator extends GeneratorBase {

private final CTypes types;

private final CCmakeGenerator cmakeGenerator;
protected CCmakeGenerator cmakeGenerator;

protected CGenerator(
LFGeneratorContext context,
Expand Down
44 changes: 34 additions & 10 deletions core/src/main/java/org/lflang/generator/python/PythonGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
import org.lflang.target.Target;
import org.lflang.target.property.DockerProperty;
import org.lflang.target.property.ProtobufsProperty;
import org.lflang.target.property.PythonVersionProperty;
import org.lflang.util.FileUtil;
import org.lflang.util.LFCommand;

Expand All @@ -82,14 +83,17 @@
*
* @author Soroush Bateni
*/
public class PythonGenerator extends CGenerator {
public class PythonGenerator extends CGenerator implements CCmakeGenerator.SetUpMainTarget {

// Used to add statements that come before reactor classes and user code
private final CodeBuilder pythonPreamble = new CodeBuilder();

// Used to add module requirements to setup.py (delimited with ,)
private final List<String> pythonRequiredModules = new ArrayList<>();

/** Indicator that we have already generated top-level preambles. */
private Set<Model> generatedTopLevelPreambles = new HashSet<Model>();

private final PythonTypes types;

public PythonGenerator(LFGeneratorContext context) {
Expand All @@ -104,8 +108,9 @@ public PythonGenerator(LFGeneratorContext context) {
"lib/python_tag.c",
"lib/python_time.c",
"lib/pythontarget.c"),
PythonGenerator::setUpMainTarget,
null, // Temporarily, because can't pass this.
generateCmakeInstall(context.getFileConfig())));
cmakeGenerator.setCmakeGenerator(this);
}

private PythonGenerator(
Expand Down Expand Up @@ -186,6 +191,7 @@ public String generatePythonCode(String pyModuleName) {
"\n",
"import os",
"import sys",
"print(\"******* Using Python version: %s.%s.%s\" % sys.version_info[:3])",
"sys.path.append(os.path.dirname(__file__))",
"# List imported names, but do not use pylint's --extension-pkg-allow-list option",
"# so that these names will be assumed present without having to compile and install.",
Expand Down Expand Up @@ -270,7 +276,12 @@ protected String generateTopLevelPreambles(Reactor ignored) {
models.add((Model) ASTUtils.toDefinition(this.mainDef.getReactorClass()).eContainer());
}
for (Model m : models) {
pythonPreamble.pr(PythonPreambleGenerator.generatePythonPreambles(m.getPreambles()));
// In the generated Python code, unlike C, all reactors go into the same file.
// Therefore, we do not need to generate this if it has already been generated.
if (!generatedTopLevelPreambles.contains(m)) {
generatedTopLevelPreambles.add(m);
pythonPreamble.pr(PythonPreambleGenerator.generatePythonPreambles(m.getPreambles()));
}
}
return PythonPreambleGenerator.generateCIncludeStatements(
targetConfig, targetLanguageIsCpp(), hasModalReactors);
Expand Down Expand Up @@ -486,9 +497,6 @@ protected void generateUserPreamblesForReactor(Reactor reactor, CodeBuilder src)
@Override
protected void generateReactorClassHeaders(
TypeParameterizedReactor tpr, String headerName, CodeBuilder header, CodeBuilder src) {
header.pr(
PythonPreambleGenerator.generateCIncludeStatements(
targetConfig, targetLanguageIsCpp(), hasModalReactors));
super.generateReactorClassHeaders(tpr, headerName, header, src);
}

Expand Down Expand Up @@ -639,15 +647,27 @@ protected void additionalPostProcessingForModes() {
PythonModeGenerator.generateResetReactionsIfNeeded(reactors);
}

private static String setUpMainTarget(
boolean hasMain, String executableName, Stream<String> cSources) {
public String getCmakeCode(boolean hasMain, String executableName, Stream<String> cSources) {
// According to https://cmake.org/cmake/help/latest/module/FindPython.html#hints, the following
// should work to select the version of Python given in your virtual environment.
// However, this does not work for me (macOS Sequoia 15.0.1).
// As a consequence, the python-version target property can be used to specify the exact Python
// version.
var pythonVersion =
"3.10.0"; // Allows 3.10 or later. Change to "3.10.0...<3.11.0" to require 3.10 by default.
if (targetConfig.isSet(PythonVersionProperty.INSTANCE)) {
pythonVersion = targetConfig.get(PythonVersionProperty.INSTANCE) + " EXACT";
}
return ("""
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
add_compile_definitions(_PYTHON_TARGET_ENABLED)
add_subdirectory(core)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR})
set(LF_MAIN_TARGET <pyModuleName>)
find_package(Python 3.10.0...<3.11.0 REQUIRED COMPONENTS Interpreter Development)
set(Python_FIND_VIRTUALENV FIRST)
set(Python_FIND_STRATEGY LOCATION)
set(Python_FIND_FRAMEWORK LAST)
find_package(Python <pyVersion> REQUIRED COMPONENTS Interpreter Development)
Python_add_library(
${LF_MAIN_TARGET}
MODULE
Expand All @@ -667,7 +687,8 @@ private static String setUpMainTarget(
target_link_libraries(${LF_MAIN_TARGET} PRIVATE ${Python_LIBRARIES})
target_compile_definitions(${LF_MAIN_TARGET} PUBLIC MODULE_NAME=<pyModuleName>)
""")
.replace("<pyModuleName>", generatePythonModuleName(executableName));
.replace("<pyModuleName>", generatePythonModuleName(executableName))
.replace("<pyVersion>", pythonVersion);
// The use of fileConfig.name will break federated execution, but that's fine
}

Expand All @@ -677,6 +698,9 @@ private static String generateCmakeInstall(FileConfig fileConfig) {
// need to replace '\' with '\\' on Windwos for proper escaping in cmake
final var pyMainName = pyMainPath.toString().replace("\\", "\\\\");
return """
if (NOT DEFINED CMAKE_INSTALL_BINDIR)
set(CMAKE_INSTALL_BINDIR "bin")
endif()
if(WIN32)
file(GENERATE OUTPUT <fileName>.bat CONTENT
"@echo off
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,6 @@ public static String generatePythonListForContainedBank(
" }",
" /* Release the thread. No Python API allowed beyond this point. */",
" PyGILState_Release(gstate);",
" Py_FinalizeEx();",
" exit(1);",
"}",
"for (int i = 0; i < " + generateWidthVariable(reactorName) + "; i++) {",
Expand All @@ -193,7 +192,6 @@ public static String generatePythonListForContainedBank(
" }",
" /* Release the thread. No Python API allowed beyond this point. */",
" PyGILState_Release(gstate);",
" Py_FinalizeEx();",
" exit(1);",
" }",
"}");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ public static String generateCDefineDirectives(
public static String generateCIncludeStatements(
TargetConfig targetConfig, boolean CCppMode, boolean hasModalReactors) {
CodeBuilder code = new CodeBuilder();
code.pr(CPreambleGenerator.generateIncludeStatements(targetConfig, CCppMode));
code.pr("#include \"pythontarget.h\"");
code.pr(CPreambleGenerator.generateIncludeStatements(targetConfig, CCppMode));
if (hasModalReactors) {
code.pr("#include \"include/modal_models/definitions.h\"");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,16 @@ private static String generateCPythonFunctionCaller(
+ "."
+ pythonFunctionName
+ "\");",
"PyObject *arglist = Py_BuildValue(\"("
+ "O".repeat(pyObjects.size())
+ ")\""
+ pyObjectsJoined
+ ");",
"PyObject *rValue = PyObject_CallObject(",
" self->" + cpythonFunctionName + ", ",
" Py_BuildValue(\"(" + "O".repeat(pyObjects.size()) + ")\"" + pyObjectsJoined + ")",
" arglist",
");",
"Py_DECREF(arglist);",
"if (rValue == NULL) {",
" lf_print_error(\"FATAL: Calling reaction "
+ reactorDeclName
Expand Down
35 changes: 2 additions & 33 deletions core/src/main/java/org/lflang/target/Target.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,39 +26,7 @@
import java.util.Set;
import net.jcip.annotations.Immutable;
import org.lflang.lf.TargetDecl;
import org.lflang.target.property.AuthProperty;
import org.lflang.target.property.BuildCommandsProperty;
import org.lflang.target.property.BuildTypeProperty;
import org.lflang.target.property.CargoDependenciesProperty;
import org.lflang.target.property.CargoFeaturesProperty;
import org.lflang.target.property.ClockSyncModeProperty;
import org.lflang.target.property.ClockSyncOptionsProperty;
import org.lflang.target.property.CmakeIncludeProperty;
import org.lflang.target.property.CompileDefinitionsProperty;
import org.lflang.target.property.CompilerProperty;
import org.lflang.target.property.CoordinationOptionsProperty;
import org.lflang.target.property.CoordinationProperty;
import org.lflang.target.property.DockerProperty;
import org.lflang.target.property.ExportDependencyGraphProperty;
import org.lflang.target.property.ExternalRuntimePathProperty;
import org.lflang.target.property.FilesProperty;
import org.lflang.target.property.KeepaliveProperty;
import org.lflang.target.property.NoRuntimeValidationProperty;
import org.lflang.target.property.NoSourceMappingProperty;
import org.lflang.target.property.PlatformProperty;
import org.lflang.target.property.PrintStatisticsProperty;
import org.lflang.target.property.ProtobufsProperty;
import org.lflang.target.property.Ros2DependenciesProperty;
import org.lflang.target.property.Ros2Property;
import org.lflang.target.property.RuntimeVersionProperty;
import org.lflang.target.property.RustIncludeProperty;
import org.lflang.target.property.SchedulerProperty;
import org.lflang.target.property.SingleFileProjectProperty;
import org.lflang.target.property.SingleThreadedProperty;
import org.lflang.target.property.TracePluginProperty;
import org.lflang.target.property.TracingProperty;
import org.lflang.target.property.VerifyProperty;
import org.lflang.target.property.WorkersProperty;
import org.lflang.target.property.*;

/**
* Enumeration of targets and their associated properties.
Expand Down Expand Up @@ -634,6 +602,7 @@ public void initialize(TargetConfig config) {
KeepaliveProperty.INSTANCE,
NoSourceMappingProperty.INSTANCE,
ProtobufsProperty.INSTANCE,
PythonVersionProperty.INSTANCE,
SchedulerProperty.INSTANCE,
SingleThreadedProperty.INSTANCE,
TracingProperty.INSTANCE,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.lflang.target.property;

/** A specific Python version to use. */
public final class PythonVersionProperty extends StringProperty {

/** Singleton target property instance. */
public static final PythonVersionProperty INSTANCE = new PythonVersionProperty();

private PythonVersionProperty() {
super();
}

@Override
public String name() {
return "python-version";
}
}
5 changes: 4 additions & 1 deletion test/Python/src/serialization/CustomSerializer.lf
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ target Python {
}

preamble {=
# Note that both federates will try to install the pickle_serializer package. One will likely fail,
# but the other will succeed.
os.system("pip install ./src/serialization/pickle_serializer/ --user")
import pickle_serializer
=}

reactor Client {
Expand Down Expand Up @@ -66,5 +69,5 @@ federated reactor {
client = new Client()
server = new Server()
server.server_message -> client.server_message after 100 ms serializer "pickle_serializer"
client.client_message -> server.client_message serializer "pickle_serializer"
client.client_message -> server.client_message after 100 ms serializer "pickle_serializer"
}
Loading