Thread: Possible bug in PL/Python?
Hi,
In a current project I've a PL/Python function that uses default parameters, like this:
CREATE FUNCTION auth.create_user(
email text,
initial_password text,
display_name text DEFAULT NULL,
mobile_phone text DEFAULT NULL,
status auth.enum_user_status DEFAULT 'active'
) RETURNS text AS $$
... rest of function ...
Now I try to test if 'display_name' is actually passed or not, and if not set it to something sensible, like so:
...
if display_name is None:
display_name = email[:email.find('@')]
...
And ... that fails with an error stating that 'display_name' is referenced before assignment.
However, if I do it like this, it works:
...
if display_name is None:
real_display_name = email[:email.find('@')]
...
In straight Python the first example works, however in PL/Python only the second works.
Is this how it is supposed to be and did I perhaps miss something in the docs, or is it a bug?
Kind regards,
Jeroen
On Tuesday, January 17, 2012 8:27:19 am Jeroen van Dongen wrote: > Hi, > > In a current project I've a PL/Python function that uses default > parameters, like this: > > CREATE FUNCTION auth.create_user( > email text, > initial_password text, > display_name text DEFAULT NULL, > mobile_phone text DEFAULT NULL, > status auth.enum_user_status DEFAULT 'active' > ) RETURNS text AS $$ > ... rest of function ... > > Now I try to test if 'display_name' is actually passed or not, and if not > set it to something sensible, like so: > ... > if display_name is None: > display_name = email[:email.find('@')] > ... > > And ... that fails with an error stating that 'display_name' is referenced > before assignment. > However, if I do it like this, it works: > ... > if display_name is None: > real_display_name = email[:email.find('@')] > ... > > In straight Python the first example works, however in PL/Python only the > second works. > > Is this how it is supposed to be and did I perhaps miss something in the > docs, or is it a bug? http://www.postgresql.org/docs/9.0/interactive/plpython-funcs.html " The arguments are set as global variables. Because of the scoping rules of Python, this has the subtle consequence that an argument variable cannot be reassigned inside the function to the value of an expression that involves the variable name itself, unless the variable is redeclared as global in the block. For example, the following won't work: CREATE FUNCTION pystrip(x text) RETURNS text AS $$ x = x.strip() # error return x $$ LANGUAGE plpythonu; because assigning to x makes x a local variable for the entire block, and so the x on the right-hand side of the assignment refers to a not-yet-assigned local variable x, not the PL/Python function parameter. Using the global statement, this can be made to work: CREATE FUNCTION pystrip(x text) RETURNS text AS $$ global x x = x.strip() # ok now return x $$ LANGUAGE plpythonu; But it is advisable not to rely on this implementation detail of PL/Python. It is better to treat the function parameters as read-only. " > > Kind regards, > Jeroen -- Adrian Klaver adrian.klaver@gmail.com
Thanks! I'd missed that part apparently :( Regards, Jeroen Op 17 jan. 2012 om 17:40 heeft Adrian Klaver <adrian.klaver@gmail.com> het volgende geschreven: > On Tuesday, January 17, 2012 8:27:19 am Jeroen van Dongen wrote: >> Hi, >> >> In a current project I've a PL/Python function that uses default >> parameters, like this: >> >> CREATE FUNCTION auth.create_user( >> email text, >> initial_password text, >> display_name text DEFAULT NULL, >> mobile_phone text DEFAULT NULL, >> status auth.enum_user_status DEFAULT 'active' >> ) RETURNS text AS $$ >> ... rest of function ... >> >> Now I try to test if 'display_name' is actually passed or not, and if not >> set it to something sensible, like so: >> ... >> if display_name is None: >> display_name = email[:email.find('@')] >> ... >> >> And ... that fails with an error stating that 'display_name' is referenced >> before assignment. >> However, if I do it like this, it works: >> ... >> if display_name is None: >> real_display_name = email[:email.find('@')] >> ... >> >> In straight Python the first example works, however in PL/Python only the >> second works. >> >> Is this how it is supposed to be and did I perhaps miss something in the >> docs, or is it a bug? > > http://www.postgresql.org/docs/9.0/interactive/plpython-funcs.html > > " > The arguments are set as global variables. Because of the scoping rules of > Python, this has the subtle consequence that an argument variable cannot be > reassigned inside the function to the value of an expression that involves the > variable name itself, unless the variable is redeclared as global in the block. > For example, the following won't work: > > CREATE FUNCTION pystrip(x text) > RETURNS text > AS $$ > x = x.strip() # error > return x > $$ LANGUAGE plpythonu; > because assigning to x makes x a local variable for the entire block, and so the > x on the right-hand side of the assignment refers to a not-yet-assigned local > variable x, not the PL/Python function parameter. Using the global statement, > this can be made to work: > > CREATE FUNCTION pystrip(x text) > RETURNS text > AS $$ > global x > x = x.strip() # ok now > return x > $$ LANGUAGE plpythonu; > But it is advisable not to rely on this implementation detail of PL/Python. It > is better to treat the function parameters as read-only. > > " >> >> Kind regards, >> Jeroen > > -- > Adrian Klaver > adrian.klaver@gmail.com