import collections (dynamic class targeting EASY FIX)
Context: I am using Transcrypt to convert the code in this repository: https://github.com/deepmind/pysc2 to javascript.
Problem: I can't import collections, therefore I cant target the classes that are generated by collections, for example:
class Feature(collections.namedtuple(
"Feature", ["index", "name", "layer_set", "full_name", "scale", "type",
"palette", "clip"])):
Solution: Create a local copy of 'collections' module in a file named collections.py. Modify the namedtuple function to print the class or write the stringified class template to a target directory. I took the code from collections (python version 2) to make the following method:
def print_class(typename, field_names):
numfields = len(field_names)
argtxt = repr(field_names).replace("'", "")[1:-1] # tuple repr without parens or quotes
reprtxt = ', '.join('%s=%%r' % name for name in field_names)
template = '''class %(typename)s(tuple):
'%(typename)s(%(argtxt)s)' \n
__slots__ = () \n
_fields = %(field_names)r \n
def __new__(_cls, %(argtxt)s):
'Create new instance of %(typename)s(%(argtxt)s)'
return _tuple.__new__(_cls, (%(argtxt)s)) \n
@classmethod
def _make(cls, iterable, new=tuple.__new__, len=len):
'Make a new %(typename)s object from a sequence or iterable'
result = new(cls, iterable)
if len(result) != %(numfields)d:
raise TypeError('Expected %(numfields)d arguments, got %%d' %% len(result))
return result \n
def __repr__(self):
'Return a nicely formatted representation string'
return '%(typename)s(%(reprtxt)s)' %% self \n
def _asdict(self):
'Return a new OrderedDict which maps field names to their values'
return OrderedDict(zip(self._fields, self)) \n
def _replace(_self, **kwds):
'Return a new %(typename)s object replacing specified fields with new values'
result = _self._make(map(kwds.pop, %(field_names)r, _self))
if kwds:
raise ValueError('Got unexpected field names: %%r' %% kwds.keys())
return result \n
def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return tuple(self) \n\n''' % locals()
for i, name in enumerate(field_names):
template += " %s = _property(_itemgetter(%d), doc='Alias for field number %d')\n" % (name, i, i)
print(template)
The function print_class is called inside the namedtuple method inside of the collections.py file.
This way, anytime a class is dynamically generated at run time, I can then go back and target the classes that the collections module would have been using internally. Easy peasy.
I know its hacky as hell, but it got the job done. And I believe that this approach could be used to ease the burden of developers utilizing Transcrypt to develop javascript projects from existing python projects.
I'll leave this issue open in case you want to triage it or something, but I'm giving up on using transcrypt for my project. Not being able to make use of a number of core python modules has made this basically impossible. Being able to use operator.py (import operator) would be a huge step for this project imo.
Cheers!