diff --git a/src/pl/plpython/expected/plpython_test.out b/src/pl/plpython/expected/plpython_test.out
index 7b76faf4ee68b63f16fa903c61362b6676beb461..f8270a7c5adfcd703f17034cde977db11f58934c 100644
--- a/src/pl/plpython/expected/plpython_test.out
+++ b/src/pl/plpython/expected/plpython_test.out
@@ -16,8 +16,8 @@ select stupidn();
  zarkon
 (1 row)
 
--- test multiple arguments
-CREATE FUNCTION argument_test_one(u users, a1 text, a2 text) RETURNS text
+-- test multiple arguments and odd characters in function name
+CREATE FUNCTION "Argument test #1"(u users, a1 text, a2 text) RETURNS text
 	AS
 'keys = list(u.keys())
 keys.sort()
@@ -27,8 +27,8 @@ for key in keys:
 words = a1 + " " + a2 + " => {" + ", ".join(out) + "}"
 return words'
 	LANGUAGE plpythonu;
-select argument_test_one(users, fname, lname) from users where lname = 'doe' order by 1;
-                           argument_test_one                           
+select "Argument test #1"(users, fname, lname) from users where lname = 'doe' order by 1;
+                           Argument test #1                            
 -----------------------------------------------------------------------
  jane doe => {fname: jane, lname: doe, userid: 1, username: j_doe}
  john doe => {fname: john, lname: doe, userid: 2, username: johnd}
diff --git a/src/pl/plpython/plpy_procedure.c b/src/pl/plpython/plpy_procedure.c
index e1f56209ef00568feea49d1dc3db5cf3f26d166f..a0d0792297a70196f1290bce92ed48ca999d627e 100644
--- a/src/pl/plpython/plpy_procedure.c
+++ b/src/pl/plpython/plpy_procedure.c
@@ -146,6 +146,7 @@ PLy_procedure_create(HeapTuple procTup, Oid fn_oid, bool is_trigger)
 	MemoryContext cxt;
 	MemoryContext oldcxt;
 	int			rv;
+	char	   *ptr;
 
 	procStruct = (Form_pg_proc) GETSTRUCT(procTup);
 	rv = snprintf(procName, sizeof(procName),
@@ -155,6 +156,15 @@ PLy_procedure_create(HeapTuple procTup, Oid fn_oid, bool is_trigger)
 	if (rv >= sizeof(procName) || rv < 0)
 		elog(ERROR, "procedure name would overrun buffer");
 
+	/* Replace any not-legal-in-Python-names characters with '_' */
+	for (ptr = procName; *ptr; ptr++)
+	{
+		if (!((*ptr >= 'A' && *ptr <= 'Z') ||
+			  (*ptr >= 'a' && *ptr <= 'z') ||
+			  (*ptr >= '0' && *ptr <= '9')))
+			*ptr = '_';
+	}
+
 	cxt = AllocSetContextCreate(TopMemoryContext,
 								procName,
 								ALLOCSET_DEFAULT_MINSIZE,
diff --git a/src/pl/plpython/sql/plpython_test.sql b/src/pl/plpython/sql/plpython_test.sql
index c8d5ef5f534613320f857863ade9d39cdb7287e1..3a761047a09119ce60f9d35f3a68cb5b60bbed44 100644
--- a/src/pl/plpython/sql/plpython_test.sql
+++ b/src/pl/plpython/sql/plpython_test.sql
@@ -11,8 +11,8 @@ CREATE FUNCTION stupidn() RETURNS text AS 'return "zarkon"' LANGUAGE plpython2u;
 
 select stupidn();
 
--- test multiple arguments
-CREATE FUNCTION argument_test_one(u users, a1 text, a2 text) RETURNS text
+-- test multiple arguments and odd characters in function name
+CREATE FUNCTION "Argument test #1"(u users, a1 text, a2 text) RETURNS text
 	AS
 'keys = list(u.keys())
 keys.sort()
@@ -23,7 +23,7 @@ words = a1 + " " + a2 + " => {" + ", ".join(out) + "}"
 return words'
 	LANGUAGE plpythonu;
 
-select argument_test_one(users, fname, lname) from users where lname = 'doe' order by 1;
+select "Argument test #1"(users, fname, lname) from users where lname = 'doe' order by 1;
 
 
 -- check module contents