mojo icon indicating copy to clipboard operation
mojo copied to clipboard

[Feature Request] setitem support for PythonObject

Open jeremyBanks opened this issue 1 year ago • 2 comments

Request

Currently it is not possible to assign to an item/subscript of a Python object (such as a list index or a dictionary entry) from Mojo code using the typical Python syntax of object[key] = value. Attempting to do so results in an error indicating that the expression is not mutable, even if the dictionary is in a variable defined using var:

from PythonInterface import Python
from PythonObject import PythonObject

let python_builtins: PythonObject = Python.import_module("builtins")
let dict: PythonObject = python_builtins.dict;

var my_dict: PythonObject = dict()

my_dict["x"] = "hello, world!";
error: Expression [1]:24:12: expression must be mutable in assignment
    my_dict["x"] = "hello, world!";
    ~~~~~~~^~~~~

This same error occurs for any Python value (represented by the PythonObject type in Mojo), such as for lists:

error: Expression [4]:34:12: expression must be mutable in assignment
    my_list[0] = "bonjour!"
    ~~~~~~~^~~

Motivation

Many Python APIs take dictionaries as arguments, either as collections of data, or as parameters/options, so it's valuable to be able to construct these values from Mojo. This is already possible by manually calling the __setitem__ method that Python uses to implement item assignment, but this is a bit clunky and not what Python programmers are used to.

my_dict.__setitem__("x", "hello, world")

my_list.__setitem__(0, "bonjour!")

It would be preferable to be able to populate dictionaries using the typical syntax instead, and generally to use the same syntax as Python for such operations on any Python object.

Description and Requirements

It should be possible to assign to any Python objects that support __setitem__ (including but not limited to dictionary keys and list indices) using the typical Python syntax:

my_dict["x"] = "hello, world!"
my_list[0] = "bonjour!"

This was originally mentioned at https://discord.com/channels/1087530497313357884/1103478447872950312.

(Note that getitem support already appears to be implemented, I'm able to print(my_dict["x"]) and print(my_list[0]) without a similar error.)

jeremyBanks avatar May 04 '23 02:05 jeremyBanks

Steffi is on it, thank you!

lattner avatar May 04 '23 05:05 lattner

Thanks for the feature request! This should be straightforward to add @stumpOS

edit: ninja'd

Mogball avatar May 04 '23 05:05 Mogball

@stumpOS I think you fixed this already?

lattner avatar May 10 '23 13:05 lattner

Yes it is fixed

stumpOS avatar May 11 '23 00:05 stumpOS

It seems that it is not fixed with Mojo 0.0.5 and that this issue could be reopened:

    let python_builtins: PythonObject = Python.import_module("builtins")
    let dict: PythonObject = python_builtins.dict
    let d: PythonObject = dict()
    # error: expression must be mutable in assignment (with Mojo 0.0.5)
    # d["a"] = 0
    # works:
    d.__setitem__("a", 0)
    print(d["a"])

paugier avatar Nov 15 '23 10:11 paugier

@paugier it's fixed in the next release 0.6.0

jackos avatar Nov 15 '23 16:11 jackos

@jackos , I'm trying 0.6.0, and I'm guessing this didn't make it in?

fnands avatar Dec 11 '23 20:12 fnands

I'm not convinced it's fixed in 0.7 either

 let smtp1 = Python.import_module("smtplib")
    let emtext1 = Python.import_module("email.mime.text")
    var msg = emtext1.MIMEText(body)
    msg['Subject'] = "Hello!"
    #error: expression must be mutable in assignment

    let python_builtins: PythonObject = Python.import_module("builtins")
    let dict: PythonObject = python_builtins.dict
    let d = dict()
    # works:
    d.__setitem__("a", 2345)
    #warning: 'PythonObject' value is unused

__setitem__ issues a warning, but does work. In VsCode, only __setattr__ appears in the intelisence

I'm new to Mojo. so sorry if I've misunderstood Does anyone send Emails using Mojo?

jradxl avatar Jan 27 '24 20:01 jradxl