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)
### 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)
* Change improve Cloudflare connectivity
* Change improve Cloudflare connectivity
### 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:
message = 'your Python function failed! '
try:
message += e.message
message += str(e)
except:
pass
raise MakeError('Error', message)
@ -319,7 +319,7 @@ class PyJs(object):
#prop = prop.value
if self.Class == 'Undefined' or self.Class == 'Null':
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):
prop = prop.to_string().value
if not isinstance(prop, basestring): raise RuntimeError('Bug')
@ -361,7 +361,7 @@ class PyJs(object):
* / % + - << >> & ^ |'''
if self.Class == 'Undefined' or self.Class == 'Null':
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):
prop = prop.to_string().value
if NUMPY_AVAILABLE and prop.isdigit():
@ -991,7 +991,8 @@ class PyJs(object):
cand = self.get(prop)
if not cand.is_callable():
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)
def to_python(self):
@ -1304,7 +1305,7 @@ class PyObjectWrapper(PyJs):
except Exception as e:
message = 'your Python function failed! '
try:
message += e.message
message += str(e)
except:
pass
raise MakeError('Error', message)
@ -1464,9 +1465,11 @@ class PyJsFunction(PyJs):
except NotImplementedError:
raise
except RuntimeError as e: # maximum recursion
raise MakeError(
'RangeError', e.message if
not isinstance(e, NotImplementedError) else 'Not implemented!')
try:
msg = e.message
except:
msg = repr(e)
raise MakeError('RangeError', msg)
def has_instance(self, other):
# 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):
# convert arguments to python list of strings
a = map(to_string, tuple(args))
a = list(map(to_string, tuple(args)))
_body = u';'
_args = ()
if len(a):

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

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

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

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

15
lib/js2py/internals/speed.py

@ -1,7 +1,14 @@
from __future__ import print_function
from timeit import timeit
from collections import namedtuple
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
@ -47,7 +54,7 @@ t = []
Type = None
try:
print timeit(
print(timeit(
"""
t.append(4)
@ -56,7 +63,7 @@ t.pop()
""",
"from __main__ import X,Y,namedtuple,array,t,add,Type, izip",
number=1000000)
"from __main__ import X,Y,namedtuple,array,t,add,Type, zip",
number=1000000))
except:
raise

3
lib/js2py/legecy_translators/constants.py

@ -1,3 +1,4 @@
from __future__ import print_function
from string import ascii_lowercase, digits
##################################
StringName = u'PyJsConstantString%d_'
@ -305,4 +306,4 @@ if __name__ == '__main__':
''')
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:
Strings and other literals are not present so each = means assignment
"""
from __future__ import print_function
from utils import *
from jsparser import *
@ -80,4 +82,4 @@ def bass_translator(s):
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
CONTINUE, BREAK, RETURN, LABEL, THROW, TRY, SWITCH
"""
from __future__ import print_function
from utils import *
from jsparser import *
from nodevisitor import exp_translator
@ -477,4 +479,4 @@ def translate_flow(source):
if __name__ == '__main__':
#print do_dowhile('do {} while(k+f)', 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"""
from __future__ import print_function
from jsparser import *
from utils import *
@ -94,5 +96,5 @@ def remove_functions(source, all_inline=False):
if __name__ == '__main__':
print remove_functions(
'5+5 function n (functiona ,functionaj) {dsd s, dsdd}')
print(remove_functions(
'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 *
@ -64,7 +65,7 @@ OP_METHODS = {
def dbg(source):
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)
except:
pass
@ -77,13 +78,13 @@ def indent(lines, ind=4):
def inject_before_lval(source, lval, code):
if source.count(lval) > 1:
dbg(source)
print
print lval
print()
print(lval)
raise RuntimeError('To many lvals (%s)' % lval)
elif not source.count(lval):
dbg(source)
print
print lval
print()
print(lval)
assert lval not in source
raise RuntimeError('No lval found "%s"' % 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 utils import *
import re
@ -557,6 +559,6 @@ if __name__ == '__main__':
#print 'Here', trans('(eee ) . ii [ PyJsMarker ] [ jkj ] ( j , j ) .
# jiji (h , ji , i)(non )( )()()()')
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!
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.
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"""
from __future__ import print_function
OBJECT_LVAL = 'PyJsLvalObject%d_'
ARRAY_LVAL = 'PyJsLvalArray%d_'
from utils import *
@ -180,7 +182,7 @@ def translate_object(obj, lval, obj_count=1, arr_count=1):
try:
key, value = spl
except: #len(spl)> 2
print 'Unusual case ' + repr(e)
print('Unusual case ' + repr(e))
key = spl[0]
value = ':'.join(spl[1:])
key = key.strip()
@ -293,8 +295,8 @@ if __name__ == '__main__':
#print remove_objects(test)
#print list(bracket_split(' {}'))
print
print remove_arrays(
print()
print(remove_arrays(
'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 constants import remove_constants, recover_constants
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(t)
dbg(SANDBOX % indent(res))
print 'Done'
print('Done')

31
lib/js2py/node_import.py

@ -1,7 +1,10 @@
__all__ = ['require']
import subprocess, os, codecs, glob
from .evaljs import translate_js, DEFAULT_HEADER
from .translators.friendly_nodes import is_valid_py_name
import six
DID_INIT = False
DIRNAME = os.path.dirname(os.path.abspath(__file__))
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):
return module_name.replace('-', '_')
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!'
py_name = _get_module_py_name(module_name)
module_filename = '%s.py' % py_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)
pkg_name = module_name.partition('/')[0]
if maybe_version_str:
pkg_name += '@' + maybe_version_str
# make sure the module is installed
assert subprocess.call(
'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
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
finally translates the generated JS bundle to Python via Js2Py.
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
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 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.
: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...
if context is not None:
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."
py_code = py_code[len(DEFAULT_HEADER):]
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()

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:
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):
"""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!
inside = trans(body)
defs = ''
if inside.startswith('while ') or inside.startswith(
'for ') or inside.startswith('#for'):
if is_iteration_statement(body) and (inside.startswith('while ') or inside.startswith(
'for ') or inside.startswith('#for')):
# we have to add contine label as well...
# 3 or 1 since #for loop type has more lines before real for.
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._is_proper = True # type: bool
self._version = 2 # type: int
self._epid = season + (100 * episode) # type: int
def check_force_season_folders(pattern=None, multi=None, anime_type=None):

Loading…
Cancel
Save