Browse Source

Merge branch 'master' into develop

pull/1289/head
JackDandy 5 years ago
parent
commit
dff879bda7
  1. 9
      CHANGES.md
  2. BIN
      lib/dateutil/zoneinfo/dateutil-zoneinfo.tar.gz
  3. 19
      lib/js2py/base.py
  4. 2
      lib/js2py/internals/constructors/jsfunction.py
  5. 15
      lib/js2py/internals/constructors/jsmath.py
  6. 2
      lib/js2py/internals/constructors/jsstring.py
  7. 15
      lib/js2py/internals/speed.py
  8. 3
      lib/js2py/legecy_translators/constants.py
  9. 4
      lib/js2py/legecy_translators/exps.py
  10. 4
      lib/js2py/legecy_translators/flow.py
  11. 6
      lib/js2py/legecy_translators/functions.py
  12. 11
      lib/js2py/legecy_translators/jsparser.py
  13. 6
      lib/js2py/legecy_translators/nodevisitor.py
  14. 12
      lib/js2py/legecy_translators/objects.py
  15. 4
      lib/js2py/legecy_translators/translator.py
  16. 31
      lib/js2py/node_import.py
  17. 9
      lib/js2py/test_internals.py
  18. 11
      lib/js2py/translators/translating_nodes.py
  19. 1
      sickbeard/naming.py

9
CHANGES.md

@ -51,9 +51,16 @@
* Update urllib3 release 1.25.6 (4a6c288) to 1.25.7 (37ba61a) * Update urllib3 release 1.25.6 (4a6c288) to 1.25.7 (37ba61a)
### 0.21.29 (2020-04-29 02:10:00 UTC)
* Change update fallback timezone info file to 2020a
* Fix TVEpisodeSample to fix comparison on patterns with limited multi ep naming
* Update Js2Py 0.64 (7858d1d) to 0.70 (f297498)
### 0.21.28 (2020-04-24 09:40:00 UTC) ### 0.21.28 (2020-04-24 09:40:00 UTC)
* Change improve Cloudflare connectivity * Change improve Cloudflare connectivity
### 0.21.27 (2020-04-22 20:35:00 UTC) ### 0.21.27 (2020-04-22 20:35:00 UTC)

BIN
lib/dateutil/zoneinfo/dateutil-zoneinfo.tar.gz

Binary file not shown.

19
lib/js2py/base.py

@ -126,7 +126,7 @@ def HJs(val):
except Exception as e: except Exception as e:
message = 'your Python function failed! ' message = 'your Python function failed! '
try: try:
message += e.message message += str(e)
except: except:
pass pass
raise MakeError('Error', message) raise MakeError('Error', message)
@ -319,7 +319,7 @@ class PyJs(object):
#prop = prop.value #prop = prop.value
if self.Class == 'Undefined' or self.Class == 'Null': if self.Class == 'Undefined' or self.Class == 'Null':
raise MakeError('TypeError', raise MakeError('TypeError',
'Undefined and null dont have properties!') 'Undefined and null dont have properties (tried getting property %s)' % repr(prop))
if not isinstance(prop, basestring): if not isinstance(prop, basestring):
prop = prop.to_string().value prop = prop.to_string().value
if not isinstance(prop, basestring): raise RuntimeError('Bug') if not isinstance(prop, basestring): raise RuntimeError('Bug')
@ -361,7 +361,7 @@ class PyJs(object):
* / % + - << >> & ^ |''' * / % + - << >> & ^ |'''
if self.Class == 'Undefined' or self.Class == 'Null': if self.Class == 'Undefined' or self.Class == 'Null':
raise MakeError('TypeError', raise MakeError('TypeError',
'Undefined and null dont have properties!') 'Undefined and null don\'t have properties (tried setting property %s)' % repr(prop))
if not isinstance(prop, basestring): if not isinstance(prop, basestring):
prop = prop.to_string().value prop = prop.to_string().value
if NUMPY_AVAILABLE and prop.isdigit(): if NUMPY_AVAILABLE and prop.isdigit():
@ -991,7 +991,8 @@ class PyJs(object):
cand = self.get(prop) cand = self.get(prop)
if not cand.is_callable(): if not cand.is_callable():
raise MakeError('TypeError', raise MakeError('TypeError',
'%s is not a function' % cand.typeof()) '%s is not a function (tried calling property %s of %s)' % (
cand.typeof(), repr(prop), repr(self.Class)))
return cand.call(self, args) return cand.call(self, args)
def to_python(self): def to_python(self):
@ -1304,7 +1305,7 @@ class PyObjectWrapper(PyJs):
except Exception as e: except Exception as e:
message = 'your Python function failed! ' message = 'your Python function failed! '
try: try:
message += e.message message += str(e)
except: except:
pass pass
raise MakeError('Error', message) raise MakeError('Error', message)
@ -1464,9 +1465,11 @@ class PyJsFunction(PyJs):
except NotImplementedError: except NotImplementedError:
raise raise
except RuntimeError as e: # maximum recursion except RuntimeError as e: # maximum recursion
raise MakeError( try:
'RangeError', e.message if msg = e.message
not isinstance(e, NotImplementedError) else 'Not implemented!') except:
msg = repr(e)
raise MakeError('RangeError', msg)
def has_instance(self, other): def has_instance(self, other):
# I am not sure here so instanceof may not work lol. # I am not sure here so instanceof may not work lol.

2
lib/js2py/internals/constructors/jsfunction.py

@ -7,7 +7,7 @@ from ..byte_trans import ByteCodeGenerator, Code
def Function(this, args): def Function(this, args):
# convert arguments to python list of strings # convert arguments to python list of strings
a = map(to_string, tuple(args)) a = list(map(to_string, tuple(args)))
_body = u';' _body = u';'
_args = () _args = ()
if len(a): if len(a):

15
lib/js2py/internals/constructors/jsmath.py

@ -16,7 +16,8 @@ CONSTANTS = {
'SQRT1_2': 0.7071067811865476, 'SQRT1_2': 0.7071067811865476,
'SQRT2': 1.4142135623730951 'SQRT2': 1.4142135623730951
} }
def is_infinity(x):
return x - 1e10 == x
class MathFunctions: class MathFunctions:
def abs(this, args): def abs(this, args):
@ -65,22 +66,22 @@ class MathFunctions:
def ceil(this, args): def ceil(this, args):
x = get_arg(args, 0) x = get_arg(args, 0)
a = to_number(x) a = to_number(x)
if a != a: # it must be a nan if not is_finite(x):
return NaN return x
return float(math.ceil(a)) return float(math.ceil(a))
def floor(this, args): def floor(this, args):
x = get_arg(args, 0) x = get_arg(args, 0)
a = to_number(x) a = to_number(x)
if a != a: # it must be a nan if not is_finite(x):
return NaN return x
return float(math.floor(a)) return float(math.floor(a))
def round(this, args): def round(this, args):
x = get_arg(args, 0) x = get_arg(args, 0)
a = to_number(x) a = to_number(x)
if a != a: # it must be a nan if not is_finite(x):
return NaN return x
return float(round(a)) return float(round(a))
def sin(this, args): def sin(this, args):

2
lib/js2py/internals/constructors/jsstring.py

@ -1,6 +1,6 @@
from ..conversions import * from ..conversions import *
from ..func_utils import * from ..func_utils import *
from six import unichr
def fromCharCode(this, args): def fromCharCode(this, args):
res = u'' res = u''

15
lib/js2py/internals/speed.py

@ -1,7 +1,14 @@
from __future__ import print_function
from timeit import timeit from timeit import timeit
from collections import namedtuple from collections import namedtuple
from array import array from array import array
from itertools import izip try:
#python 2 code
from itertools import izip as zip
except ImportError:
pass
from collections import deque from collections import deque
@ -47,7 +54,7 @@ t = []
Type = None Type = None
try: try:
print timeit( print(timeit(
""" """
t.append(4) t.append(4)
@ -56,7 +63,7 @@ t.pop()
""", """,
"from __main__ import X,Y,namedtuple,array,t,add,Type, izip", "from __main__ import X,Y,namedtuple,array,t,add,Type, zip",
number=1000000) number=1000000))
except: except:
raise raise

3
lib/js2py/legecy_translators/constants.py

@ -1,3 +1,4 @@
from __future__ import print_function
from string import ascii_lowercase, digits from string import ascii_lowercase, digits
################################## ##################################
StringName = u'PyJsConstantString%d_' StringName = u'PyJsConstantString%d_'
@ -305,4 +306,4 @@ if __name__ == '__main__':
''') ''')
t, d = remove_constants(test) t, d = remove_constants(test)
print t, d print(t, d)

4
lib/js2py/legecy_translators/exps.py

@ -16,6 +16,8 @@ If case of parsing errors it must return a pos of error.
NOTES: NOTES:
Strings and other literals are not present so each = means assignment Strings and other literals are not present so each = means assignment
""" """
from __future__ import print_function
from utils import * from utils import *
from jsparser import * from jsparser import *
@ -80,4 +82,4 @@ def bass_translator(s):
if __name__ == '__main__': if __name__ == '__main__':
print bass_translator('3.ddsd = 40') print(bass_translator('3.ddsd = 40'))

4
lib/js2py/legecy_translators/flow.py

@ -9,6 +9,8 @@ FOR 123
FOR iter FOR iter
CONTINUE, BREAK, RETURN, LABEL, THROW, TRY, SWITCH CONTINUE, BREAK, RETURN, LABEL, THROW, TRY, SWITCH
""" """
from __future__ import print_function
from utils import * from utils import *
from jsparser import * from jsparser import *
from nodevisitor import exp_translator from nodevisitor import exp_translator
@ -477,4 +479,4 @@ def translate_flow(source):
if __name__ == '__main__': if __name__ == '__main__':
#print do_dowhile('do {} while(k+f)', 0)[0] #print do_dowhile('do {} while(k+f)', 0)[0]
#print 'e: "%s"'%do_expression('++(c?g:h); mj', 0)[0] #print 'e: "%s"'%do_expression('++(c?g:h); mj', 0)[0]
print translate_flow('a; yimport test')[0] print(translate_flow('a; yimport test')[0])

6
lib/js2py/legecy_translators/functions.py

@ -1,4 +1,6 @@
"""This module removes JS functions from source code""" """This module removes JS functions from source code"""
from __future__ import print_function
from jsparser import * from jsparser import *
from utils import * from utils import *
@ -94,5 +96,5 @@ def remove_functions(source, all_inline=False):
if __name__ == '__main__': if __name__ == '__main__':
print remove_functions( print(remove_functions(
'5+5 function n (functiona ,functionaj) {dsd s, dsdd}') '5+5 function n (functiona ,functionaj) {dsd s, dsdd}'))

11
lib/js2py/legecy_translators/jsparser.py

@ -45,6 +45,7 @@ TODO
""" """
from __future__ import print_function
from utils import * from utils import *
@ -64,7 +65,7 @@ OP_METHODS = {
def dbg(source): def dbg(source):
try: try:
with open('C:\Users\Piotrek\Desktop\dbg.py', 'w') as f: with open(r'C:\Users\Piotrek\Desktop\dbg.py', 'w') as f:
f.write(source) f.write(source)
except: except:
pass pass
@ -77,13 +78,13 @@ def indent(lines, ind=4):
def inject_before_lval(source, lval, code): def inject_before_lval(source, lval, code):
if source.count(lval) > 1: if source.count(lval) > 1:
dbg(source) dbg(source)
print print()
print lval print(lval)
raise RuntimeError('To many lvals (%s)' % lval) raise RuntimeError('To many lvals (%s)' % lval)
elif not source.count(lval): elif not source.count(lval):
dbg(source) dbg(source)
print print()
print lval print(lval)
assert lval not in source assert lval not in source
raise RuntimeError('No lval found "%s"' % lval) raise RuntimeError('No lval found "%s"' % lval)
end = source.index(lval) end = source.index(lval)

6
lib/js2py/legecy_translators/nodevisitor.py

@ -1,3 +1,5 @@
from __future__ import print_function
from jsparser import * from jsparser import *
from utils import * from utils import *
import re import re
@ -557,6 +559,6 @@ if __name__ == '__main__':
#print 'Here', trans('(eee ) . ii [ PyJsMarker ] [ jkj ] ( j , j ) . #print 'Here', trans('(eee ) . ii [ PyJsMarker ] [ jkj ] ( j , j ) .
# jiji (h , ji , i)(non )( )()()()') # jiji (h , ji , i)(non )( )()()()')
for e in xrange(3): for e in xrange(3):
print exp_translator('jk = kk.ik++') print(exp_translator('jk = kk.ik++'))
#First line translated with PyJs: PyJsStrictEq(PyJsAdd((Js(100)*Js(50)),Js(30)), Js("5030")), yay! #First line translated with PyJs: PyJsStrictEq(PyJsAdd((Js(100)*Js(50)),Js(30)), Js("5030")), yay!
print exp_translator('delete a.f') print(exp_translator('delete a.f'))

12
lib/js2py/legecy_translators/objects.py

@ -1,6 +1,8 @@
""" This module removes all objects/arrays from JS source code and replace them with LVALS. """ This module removes all objects/arrays from JS source code and replace them with LVALS.
Also it has s function translating removed object/array to python code. Also it has s function translating removed object/array to python code.
Use this module just after removing constants. Later move on to removing functions""" Use this module just after removing constants. Later move on to removing functions"""
from __future__ import print_function
OBJECT_LVAL = 'PyJsLvalObject%d_' OBJECT_LVAL = 'PyJsLvalObject%d_'
ARRAY_LVAL = 'PyJsLvalArray%d_' ARRAY_LVAL = 'PyJsLvalArray%d_'
from utils import * from utils import *
@ -180,7 +182,7 @@ def translate_object(obj, lval, obj_count=1, arr_count=1):
try: try:
key, value = spl key, value = spl
except: #len(spl)> 2 except: #len(spl)> 2
print 'Unusual case ' + repr(e) print('Unusual case ' + repr(e))
key = spl[0] key = spl[0]
value = ':'.join(spl[1:]) value = ':'.join(spl[1:])
key = key.strip() key = key.strip()
@ -293,8 +295,8 @@ if __name__ == '__main__':
#print remove_objects(test) #print remove_objects(test)
#print list(bracket_split(' {}')) #print list(bracket_split(' {}'))
print print()
print remove_arrays( print(remove_arrays(
'typeof a&&!db.test(a)&&!ib[(bb.exec(a)||["",""], [][[5][5]])[1].toLowerCase()])' 'typeof a&&!db.test(a)&&!ib[(bb.exec(a)||["",""], [][[5][5]])[1].toLowerCase()])'
) ))
print is_object('', ')') print(is_object('', ')'))

4
lib/js2py/legecy_translators/translator.py

@ -1,3 +1,5 @@
from __future__ import print_function
from flow import translate_flow from flow import translate_flow
from constants import remove_constants, recover_constants from constants import remove_constants, recover_constants
from objects import remove_objects, remove_arrays, translate_object, translate_array, set_func_translator from objects import remove_objects, remove_arrays, translate_object, translate_array, set_func_translator
@ -148,4 +150,4 @@ if __name__ == '__main__':
#res = translate_js(jq) #res = translate_js(jq)
res = translate_js(t) res = translate_js(t)
dbg(SANDBOX % indent(res)) dbg(SANDBOX % indent(res))
print 'Done' print('Done')

31
lib/js2py/node_import.py

@ -1,7 +1,10 @@
__all__ = ['require'] __all__ = ['require']
import subprocess, os, codecs, glob import subprocess, os, codecs, glob
from .evaljs import translate_js, DEFAULT_HEADER from .evaljs import translate_js, DEFAULT_HEADER
from .translators.friendly_nodes import is_valid_py_name
import six import six
DID_INIT = False DID_INIT = False
DIRNAME = os.path.dirname(os.path.abspath(__file__)) DIRNAME = os.path.dirname(os.path.abspath(__file__))
PY_NODE_MODULES_PATH = os.path.join(DIRNAME, 'py_node_modules') PY_NODE_MODULES_PATH = os.path.join(DIRNAME, 'py_node_modules')
@ -46,15 +49,23 @@ GET_FROM_GLOBALS_FUNC = '''
''' '''
def _get_module_py_name(module_name): def _get_module_py_name(module_name):
return module_name.replace('-', '_') return module_name.replace('-', '_')
def _get_module_var_name(module_name): def _get_module_var_name(module_name):
return _get_module_py_name(module_name).rpartition('/')[-1] cand = _get_module_py_name(module_name).rpartition('/')[-1]
if not is_valid_py_name(cand):
raise ValueError(
"Invalid Python module name %s (generated from %s). Unsupported/invalid npm module specification?" % (
repr(cand), repr(module_name)))
return cand
def _get_and_translate_npm_module(module_name, include_polyfill=False, update=False): def _get_and_translate_npm_module(module_name, include_polyfill=False, update=False, maybe_version_str=""):
assert isinstance(module_name, str), 'module_name must be a string!' assert isinstance(module_name, str), 'module_name must be a string!'
py_name = _get_module_py_name(module_name) py_name = _get_module_py_name(module_name)
module_filename = '%s.py' % py_name module_filename = '%s.py' % py_name
var_name = _get_module_var_name(module_name) var_name = _get_module_var_name(module_name)
@ -74,6 +85,8 @@ def _get_and_translate_npm_module(module_name, include_polyfill=False, update=Fa
f.write(code.encode('utf-8') if six.PY3 else code) f.write(code.encode('utf-8') if six.PY3 else code)
pkg_name = module_name.partition('/')[0] pkg_name = module_name.partition('/')[0]
if maybe_version_str:
pkg_name += '@' + maybe_version_str
# make sure the module is installed # make sure the module is installed
assert subprocess.call( assert subprocess.call(
'cd %s;npm install %s' % (repr(DIRNAME), pkg_name), 'cd %s;npm install %s' % (repr(DIRNAME), pkg_name),
@ -117,21 +130,25 @@ def _get_and_translate_npm_module(module_name, include_polyfill=False, update=Fa
return py_code return py_code
def require(module_name, include_polyfill=False, update=False, context=None): def require(module_name, include_polyfill=True, update=False, context=None):
""" """
Installs the provided npm module, exports a js bundle via browserify, converts to ECMA 5.1 via babel and Installs the provided npm module, exports a js bundle via browserify, converts to ECMA 5.1 via babel and
finally translates the generated JS bundle to Python via Js2Py. finally translates the generated JS bundle to Python via Js2Py.
Returns a pure python object that behaves like the installed module. Nice! Returns a pure python object that behaves like the installed module. Nice!
:param module_name: Name of the npm module to require. For example 'esprima'. :param module_name: Name of the npm module to require. For example 'esprima'. Supports specific versions via @
specification. Eg: 'crypto-js@3.3'.
:param include_polyfill: Whether the babel-polyfill should be included as part of the translation. May be needed :param include_polyfill: Whether the babel-polyfill should be included as part of the translation. May be needed
for some modules that use unsupported features. for some modules that use unsupported features of JS6 such as Map or typed arrays.
:param update: Whether to force update the translation. Otherwise uses a cached version if exists. :param update: Whether to force update the translation. Otherwise uses a cached version if exists.
:param context: Optional context in which the translated module should be executed in. If provided, the :param context: Optional context in which the translated module should be executed in. If provided, the
header (js2py imports) will be skipped as it is assumed that the context already has all the necessary imports. header (js2py imports) will be skipped as it is assumed that the context already has all the necessary imports.
:return: The JsObjectWrapper containing the translated module object. Can be used like a standard python object. :return: The JsObjectWrapper containing the translated module object. Can be used like a standard python object.
""" """
py_code = _get_and_translate_npm_module(module_name, include_polyfill=include_polyfill, update=update) module_name, maybe_version = (module_name+"@@@").split('@')[:2]
py_code = _get_and_translate_npm_module(module_name, include_polyfill=include_polyfill, update=update,
maybe_version_str=maybe_version)
# this is a bit hacky but we need to strip the default header from the generated code... # this is a bit hacky but we need to strip the default header from the generated code...
if context is not None: if context is not None:
if not py_code.startswith(DEFAULT_HEADER): if not py_code.startswith(DEFAULT_HEADER):
@ -141,5 +158,5 @@ def require(module_name, include_polyfill=False, update=False, context=None):
assert py_code.startswith(DEFAULT_HEADER), "Unexpected header." assert py_code.startswith(DEFAULT_HEADER), "Unexpected header."
py_code = py_code[len(DEFAULT_HEADER):] py_code = py_code[len(DEFAULT_HEADER):]
context = {} if context is None else context context = {} if context is None else context
exec (py_code, context) exec(py_code, context)
return context['var'][_get_module_var_name(module_name)].to_py() return context['var'][_get_module_var_name(module_name)].to_py()

9
lib/js2py/test_internals.py

@ -1,9 +0,0 @@
from internals import byte_trans
from internals import seval
import pyjsparser
x = r'''
function g() {var h123 = 11; return [function g1() {return h123}, new Function('return h123')]}
g()[1]()
'''
print seval.eval_js_vm(x)

11
lib/js2py/translators/translating_nodes.py

@ -108,6 +108,13 @@ def to_key(literal_or_identifier):
else: else:
return unicode(k) return unicode(k)
def is_iteration_statement(cand):
if not isinstance(cand, dict):
# Multiple statements.
return False
return cand.get("type", "?") in {"ForStatement", "ForInStatement", "WhileStatement", "DoWhileStatement"}
def trans(ele, standard=False): def trans(ele, standard=False):
"""Translates esprima syntax tree to python by delegating to appropriate translating node""" """Translates esprima syntax tree to python by delegating to appropriate translating node"""
@ -440,8 +447,8 @@ def LabeledStatement(type, label, body):
# todo consider using smarter approach! # todo consider using smarter approach!
inside = trans(body) inside = trans(body)
defs = '' defs = ''
if inside.startswith('while ') or inside.startswith( if is_iteration_statement(body) and (inside.startswith('while ') or inside.startswith(
'for ') or inside.startswith('#for'): 'for ') or inside.startswith('#for')):
# we have to add contine label as well... # we have to add contine label as well...
# 3 or 1 since #for loop type has more lines before real for. # 3 or 1 since #for loop type has more lines before real for.
sep = 1 if not inside.startswith('#for') else 3 sep = 1 if not inside.startswith('#for') else 3

1
sickbeard/naming.py

@ -118,6 +118,7 @@ class TVEpisodeSample(tv.TVEpisode):
self._release_name = 'Show.Name.S02E03.HDTV.XviD-RLSGROUP' # type: AnyStr self._release_name = 'Show.Name.S02E03.HDTV.XviD-RLSGROUP' # type: AnyStr
self._is_proper = True # type: bool self._is_proper = True # type: bool
self._version = 2 # type: int self._version = 2 # type: int
self._epid = season + (100 * episode) # type: int
def check_force_season_folders(pattern=None, multi=None, anime_type=None): def check_force_season_folders(pattern=None, multi=None, anime_type=None):

Loading…
Cancel
Save