Added JSON serialisation for Lambda functions#1695
Added JSON serialisation for Lambda functions#1695bennthomsen wants to merge 6 commits intoQCoDeS:mainfrom
Conversation
for more information, see https://pre-commit.ci
…oadbean into JSONserialisation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1695 +/- ##
==========================================
- Coverage 72.12% 71.16% -0.97%
==========================================
Files 9 9
Lines 1539 1602 +63
==========================================
+ Hits 1110 1140 +30
- Misses 429 462 +33 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
why are there two duplicated(?) plots instead of one in this example? or is it github mis-rendering?
| # for ii, name in enumerate(namelist): | ||
| # if isinstance(funlist[ii], str): | ||
| # namelist[ii] = funlist[ii] | ||
| # elif name == "": | ||
| # namelist[ii] = funlist[ii].__name__ | ||
| for ii, name in enumerate(namelist): | ||
| if isinstance(funlist[ii], str): | ||
| namelist[ii] = funlist[ii] | ||
| if name == "": | ||
| namelist[ii] = funlist[ii] | ||
| elif name == "": | ||
| namelist[ii] = funlist[ii].__name__ |
There was a problem hiding this comment.
also, what happens now in the else of if isinstance(funlist[ii], str): if name == "":? I am a bit worried about the test coverage of this portion of the code being too low to ensure this change is not breaking anything - what do you think?
why keeping the commented out code part?
|
|
||
| self._namelist = namelist | ||
| namelist = self._make_names_unique(namelist) | ||
| self._namelist = namelist |
There was a problem hiding this comment.
this looks like a good catch! thank you!
| func_source = "lambda t, **kwargs: 0" | ||
| except (OSError, TypeError): | ||
| # Fallback: create a generic lambda string | ||
| func_source = "lambda t, **kwargs: 0" # Default fallback |
There was a problem hiding this comment.
shouldn't it rather be None, like in case the source code of named function is not possible to retireve? This would make the behavior consistent while having a default fallback can become confusing
| if func_name in local_ns: | ||
| func_obj = local_ns[func_name] | ||
| except Exception as e: | ||
| print( |
There was a problem hiding this comment.
next to printing please use logging.warning so that this information can also show as a proper warning, and be included in logs (if those are used)
| # Regular function - store name and try to get source | ||
| func_name = func_obj.__name__ | ||
| try: | ||
| func_source = inspect.getsource(func_obj) |
There was a problem hiding this comment.
isn't it extremely fragile? What is a function is using functions from math module or numpy, would those imports be also part of the source?
also, i can't imagine that noone tried to solve this problem before - can't more functions/methods from the python standard library or perhaps even an external package be used to support this rather than implementing a custom function code serialization here?
| func_obj, kwargs_dict = self._argslist[sn] | ||
|
|
||
| # Serialize the function | ||
| if hasattr(func_obj, "__name__") and func_obj.__name__ != "<lambda>": |
There was a problem hiding this comment.
could you move the logic of extracting code a function into a separate function in order not to mix it with the logic of creating blueprint description?
| try: | ||
| # Execute the function source in a local namespace | ||
| local_ns = {} | ||
| exec(func_source, globals(), local_ns) |
There was a problem hiding this comment.
this is dangerous to make globals available, both from security perspective but also from the perspective of writing code that would prepare some globals to exist before deserializing certain blueprints and their arbitrary functions. Would it be possible to limit support to self-sufficient functions? at least to start with
Pull Request Summary
Title: Added JSON serialization for Lambda functions
Description
This PR adds support for serializing and deserializing
BluePrintobjects that contain arbitrary functions (arb_func), including lambda functions and named functions, to/from JSON format.Changes
Files Modified:
src/broadbean/blueprint.py(+131 lines) - Core serialization/deserialization logictests/test_arb_func_serialization.py(+263 lines) - New comprehensive test suitetests/test_blueprint.py(+1 line) - Updated existing testKey Features
Lambda Function Serialization: Lambda functions used with
PulseAtoms.arb_funccan now be serialized to JSON by storing their source code, extracted usinginspect.getsource()with regex parsing.Named Function Serialization: Regular named functions are serialized with both their name and full source code, allowing reconstruction even in different Python sessions.
Graceful Fallbacks: When functions cannot be reconstructed (e.g., missing dependencies or invalid source), the system falls back to a zero function with appropriate warnings.
Sample Rate Persistence: The
SR(sample rate) property is now included in the blueprint description and restored during deserialization.Backward Compatibility: Legacy JSON formats without the new
func_typefield are still supported.Usage Example
Example with a named function:
Technical Details
Serialization (
descriptionproperty):arb_funcsegments and extracts function informationDeserialization (
blueprint_from_description):eval()Testing
Added comprehensive test suite (
test_arb_func_serialization.py) covering:Breaking Changes
None - existing functionality and JSON format remains compatible.