Skip to content

Non-literal list concatenation and sorting: TypeError: t.py_sort is not a function #679

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
darthglowball opened this issue Oct 1, 2019 · 13 comments
Assignees
Labels

Comments

@darthglowball
Copy link

Hi,

sorting a non-literal concatenated list causes the error: TypeError: t.py_sort is not a function. While the lists are literals, the concatenation is done by variables and the plus operator.

a = [5,6,7]
b = [8,9,10]
t = a + b
t.sort()
print(t)
@vkbsb
Copy link

vkbsb commented Oct 4, 2019

have you tried t.js_sort() instead?

@darthglowball
Copy link
Author

darthglowball commented Oct 4, 2019

@vkbsb no, thanks, but I fixed it with some after-processing on the Javascript by changing a + b to a.concat(b) while keeping py_sort. But it's still a Transcrypt bug. I want to keep my code as Pythonic as possible, so I think using a js_sort would defeat that purpose (maybe not for this example, but for others).

@fzzylogic
Copy link

@darthglowball You may want to enabe operator overloading when compiling (using -o switch for global, or pragma('opov') for local).

@darthglowball
Copy link
Author

darthglowball commented Oct 5, 2019

@fzzylogic something happens now, but in Firefox I get the incorrect result [10, 5, 6, 7, 8, 9]. Nevermind my after-processing solution with a.concat(b): it produces the same incorrect result. Same with using Javascript's .sort() without imported Transcrypt variables. Looks like Javascript has this way of sorting that I don't understand.

@darthglowball
Copy link
Author

Even with the -o switch, you get a py_sort in the generated code:

(function () {
	var __accu0__ = t;
	return __call__ (__accu0__.py_sort, __accu0__);
}) ();

That doesn't behave like a Python sort (see previous post).

@AlexECX
Copy link

AlexECX commented Oct 26, 2019

In the transcrypt runtime.js the sort function used is the javascript .sort() (__sort__ function, Line:1976). The problem is that, in javascript, .sort() treats strings and/or numbers as strings and sort alphabetically. To correct this, Line:1976 should be changed from:
iterable.sort ();
to:
iterable.sort ((a,b) => a > b ? 1 : -(1));

Even better would be to change Line:1972 and Line:1976 to use __gt__(a,b) instead of a > b.

@darthglowball incidentally, .py_sort will branch to a code section that does exactly what this fix will do when using the key parameter of the python .sort(). Using t.sort(lambda a:a) will sort correctly.

@JdeH JdeH added the IS: bug? label Oct 27, 2019
@AlexECX
Copy link

AlexECX commented Oct 28, 2019

related to #605

@AlexECX
Copy link

AlexECX commented Oct 28, 2019

More precisely in transcrypt/modules/org/transcrypt/__runtime__.py:

107| iterable.sort () # JavaScript sort
could be :
107| iterable.sort (lambda a, b: 1 if a > b else -1)

Output:

> [10,1,2,20,9].sort()
 [1, 2, 9, 10, 20]

> ["10","1","2","20","9"].sort()
["1", "10", "2", "20", "9"]

@darthglowball
Copy link
Author

@AlexECX yes, Python t.sort() maps to Javascript t.sort(function(a,b){return a>b}) but while Transcrypt allows a positional or keyword argument in sort, it should be a keyword argument in Python 2.7.16 & 3.7.2.

@AlexECX
Copy link

AlexECX commented Oct 28, 2019

@AlexECX yes, Python t.sort() maps to Javascript t.sort(function(a,b){return a>b}) but while Transcrypt allows a positional or keyword argument in sort, it should be a keyword argument in Python 2.7.16 & 3.7.2.

Currently Transcrypts .sort() maps to Javascript's .sort(), which is why it sorts alphabetically. Mapping it to .sort ((a,b) => a > b ? 1 : -(1)) instead will resolve the sorting order. (Note that .sort(function(a,b){return a>b}) has the same problem, at least in chrome).

I believe the Transcrypt sort() signature is practically the same as Python's (key = None, reverse = False), but currently the arguments are not passed properly (see #687).

@darthglowball
Copy link
Author

@AlexECX you're right about Chrome giving the incorrect result with .sort(function(a,b){return a>b}). Same problem with Opera. Firefox does it correctly. .sort ((a,b) => a > b ? 1 : -(1)) works on all three. Good catch.

@JennaSys
Copy link
Collaborator

JennaSys commented Jul 6, 2024

More precisely in transcrypt/modules/org/transcrypt/__runtime__.py:

107| iterable.sort () # JavaScript sort could be : 107| iterable.sort (lambda a, b: 1 if a > b else -1)

This has been implemented in the dev_3.9.3 branch to be released in v3.9.3

@JennaSys
Copy link
Collaborator

Merged to master on PR #876

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

When branches are created from issues, their pull requests are automatically linked.

6 participants