diff --git a/src/pl/plpython/expected/plpython_test.out b/src/pl/plpython/expected/plpython_test.out
index a884fc0e27feb677e2e7a38bc569e9f6e5b887bb..f377e614ed3d03be1b0db73e5cbaa778daa99c5e 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 6678d02b5956079b7e54fe2f947696163ca3c282..eab002d4d24ce59174e40c0d71afa19c1882207f 100644
--- a/src/pl/plpython/plpy_procedure.c
+++ b/src/pl/plpython/plpy_procedure.c
@@ -144,6 +144,7 @@ PLy_procedure_create(HeapTuple procTup, Oid fn_oid, bool is_trigger)
 	bool		isnull;
 	int			i,
 				rv;
+	char	   *ptr;
 
 	procStruct = (Form_pg_proc) GETSTRUCT(procTup);
 	rv = snprintf(procName, sizeof(procName),
@@ -153,6 +154,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 = '_';
+	}
+
 	proc = PLy_malloc(sizeof(PLyProcedure));
 	proc->proname = PLy_strdup(NameStr(procStruct->proname));
 	proc->pyname = PLy_strdup(procName);
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