pyarmor.cli 9.2.1__tar.gz → 9.2.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. {pyarmor_cli-9.2.1 → pyarmor_cli-9.2.2}/PKG-INFO +1 -1
  2. {pyarmor_cli-9.2.1 → pyarmor_cli-9.2.2}/pyarmor/cli/__init__.py +1 -1
  3. {pyarmor_cli-9.2.1 → pyarmor_cli-9.2.2}/pyarmor/cli/__main__.py +3 -0
  4. {pyarmor_cli-9.2.1 → pyarmor_cli-9.2.2}/pyarmor/cli/command.py +17 -2
  5. {pyarmor_cli-9.2.1 → pyarmor_cli-9.2.2}/pyarmor/cli/config.py +3 -3
  6. {pyarmor_cli-9.2.1 → pyarmor_cli-9.2.2}/pyarmor/cli/context.py +8 -2
  7. pyarmor_cli-9.2.2/pyarmor/cli/core.data.1 +0 -0
  8. pyarmor_cli-9.2.2/pyarmor/cli/core.data.2 +0 -0
  9. pyarmor_cli-9.2.2/pyarmor/cli/core.data.3 +0 -0
  10. {pyarmor_cli-9.2.1 → pyarmor_cli-9.2.2}/pyarmor/cli/default.cfg +1 -1
  11. {pyarmor_cli-9.2.1 → pyarmor_cli-9.2.2}/pyarmor/cli/model.py +9 -0
  12. {pyarmor_cli-9.2.1 → pyarmor_cli-9.2.2}/pyarmor/cli/plugin.py +5 -5
  13. {pyarmor_cli-9.2.1 → pyarmor_cli-9.2.2}/pyarmor/cli/project.py +94 -21
  14. {pyarmor_cli-9.2.1 → pyarmor_cli-9.2.2}/pyarmor/cli/shell.py +5 -2
  15. {pyarmor_cli-9.2.1 → pyarmor_cli-9.2.2}/pyarmor.cli.egg-info/PKG-INFO +1 -1
  16. {pyarmor_cli-9.2.1 → pyarmor_cli-9.2.2}/setup.py +1 -1
  17. pyarmor_cli-9.2.1/pyarmor/cli/core.data.1 +0 -0
  18. pyarmor_cli-9.2.1/pyarmor/cli/core.data.2 +0 -0
  19. pyarmor_cli-9.2.1/pyarmor/cli/core.data.3 +0 -0
  20. {pyarmor_cli-9.2.1 → pyarmor_cli-9.2.2}/README.rst +0 -0
  21. {pyarmor_cli-9.2.1 → pyarmor_cli-9.2.2}/pyarmor/cli/batch.py +0 -0
  22. {pyarmor_cli-9.2.1 → pyarmor_cli-9.2.2}/pyarmor/cli/bootstrap.py +0 -0
  23. {pyarmor_cli-9.2.1 → pyarmor_cli-9.2.2}/pyarmor/cli/bug.py +0 -0
  24. {pyarmor_cli-9.2.1 → pyarmor_cli-9.2.2}/pyarmor/cli/docker.py +0 -0
  25. {pyarmor_cli-9.2.1 → pyarmor_cli-9.2.2}/pyarmor/cli/generate.py +0 -0
  26. {pyarmor_cli-9.2.1 → pyarmor_cli-9.2.2}/pyarmor/cli/hdinfo.py +0 -0
  27. {pyarmor_cli-9.2.1 → pyarmor_cli-9.2.2}/pyarmor/cli/merge.py +0 -0
  28. {pyarmor_cli-9.2.1 → pyarmor_cli-9.2.2}/pyarmor/cli/mixer.py +0 -0
  29. {pyarmor_cli-9.2.1 → pyarmor_cli-9.2.2}/pyarmor/cli/public_capsule.zip +0 -0
  30. {pyarmor_cli-9.2.1 → pyarmor_cli-9.2.2}/pyarmor/cli/register.py +0 -0
  31. {pyarmor_cli-9.2.1 → pyarmor_cli-9.2.2}/pyarmor/cli/repack.py +0 -0
  32. {pyarmor_cli-9.2.1 → pyarmor_cli-9.2.2}/pyarmor/cli/resource.py +0 -0
  33. {pyarmor_cli-9.2.1 → pyarmor_cli-9.2.2}/pyarmor.cli.egg-info/SOURCES.txt +0 -0
  34. {pyarmor_cli-9.2.1 → pyarmor_cli-9.2.2}/pyarmor.cli.egg-info/dependency_links.txt +0 -0
  35. {pyarmor_cli-9.2.1 → pyarmor_cli-9.2.2}/pyarmor.cli.egg-info/entry_points.txt +0 -0
  36. {pyarmor_cli-9.2.1 → pyarmor_cli-9.2.2}/pyarmor.cli.egg-info/requires.txt +0 -0
  37. {pyarmor_cli-9.2.1 → pyarmor_cli-9.2.2}/pyarmor.cli.egg-info/top_level.txt +0 -0
  38. {pyarmor_cli-9.2.1 → pyarmor_cli-9.2.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyarmor.cli
3
- Version: 9.2.1
3
+ Version: 9.2.2
4
4
  Summary: A comand line tool to obfuscate python scripts
5
5
  Home-page: https://github.com/dashingsoft/pyarmor
6
6
  Author: Jondy Zhao
@@ -1,6 +1,6 @@
1
1
  import logging
2
2
 
3
- __VERSION__ = '9.2.1'
3
+ __VERSION__ = '9.2.2'
4
4
 
5
5
  logger = logging.getLogger('cli')
6
6
 
@@ -767,6 +767,9 @@ def main_entry(argv):
767
767
  if not (x == 3 and y > 6 and y < 16):
768
768
  raise CliError('Python %s.%s is not supported' % (x, y))
769
769
 
770
+ if ctx.py_gil_disabled:
771
+ raise CliError('Pyarmor does not support free-threading Python')
772
+
770
773
  if args.version:
771
774
  print_version(ctx)
772
775
  parser.exit()
@@ -167,9 +167,20 @@ class Commander:
167
167
  )
168
168
  group.add_argument(
169
169
  '--ecc-rft', dest='target', default='std',
170
- action="store_const", const='ecc',
170
+ action="store_const", const='ecc-rft',
171
171
  help='generate scripts by combining --rft and --ecc'
172
172
  )
173
+ group.add_argument(
174
+ '--ecc-nogil', dest='target', default='std',
175
+ action="store_const", const='ecc-nogil',
176
+ help='genetate ECC scripts for free-threading Python'
177
+ )
178
+ group.add_argument(
179
+ '--ecc-rft-nogil', dest='target', default='std',
180
+ action="store_const", const='ecc-rft-nogil',
181
+ help=('generate scripts by combining --rft and --ecc'
182
+ ' for free-threading Python')
183
+ )
173
184
  group.add_argument(
174
185
  '--list', dest='target', default='std',
175
186
  action="store_const", const='list',
@@ -348,7 +359,7 @@ class Commander:
348
359
  logger.info('%-20s: %s', key, value)
349
360
 
350
361
  makedirs(ctx.local_path, exist_ok=True)
351
- with open(ctx.local_config, 'w') as f:
362
+ with open(ctx.local_config, 'w', encoding=ctx.encoding) as f:
352
363
  cfg.write(f)
353
364
  logger.info('project saved')
354
365
 
@@ -376,6 +387,10 @@ class Commander:
376
387
  )
377
388
  cfg.read([ctx.local_config], encoding=ctx.encoding)
378
389
 
390
+ x, y = ctx.python_version
391
+ if not (x == 3 and y > 8 and y < 16):
392
+ raise CliError('`pyarmor build` only works for Python 3.9+')
393
+
379
394
  sectname = 'project'
380
395
  if not cfg.has_section(sectname):
381
396
  raise CliError('no project information')
@@ -43,7 +43,7 @@ class Configer(object):
43
43
 
44
44
  def __init__(self, ctx, encoding=None):
45
45
  self.ctx = ctx
46
- self._encoding = encoding
46
+ self._encoding = encoding or ctx.encoding
47
47
 
48
48
  def _read_config(self, filename):
49
49
  cfg = configparser.ConfigParser(empty_lines_in_values=False)
@@ -166,7 +166,7 @@ class Configer(object):
166
166
  cfg.set(sect, optname, optvalue)
167
167
 
168
168
  os.makedirs(os.path.dirname(filename), exist_ok=True)
169
- with open(filename, 'w') as f:
169
+ with open(filename, 'w', encoding=self._encoding) as f:
170
170
  cfg.write(f)
171
171
 
172
172
  self._list_value(sect, optname, local=local, name=name)
@@ -196,7 +196,7 @@ class Configer(object):
196
196
  logger.info('remove empty section "%s"', section)
197
197
  cfg.remove_section(section)
198
198
 
199
- with open(filename, 'w') as f:
199
+ with open(filename, 'w', encoding=self._encoding) as f:
200
200
  cfg.write(f)
201
201
 
202
202
  def _clear(self, section=None, options=None, local=True, name=None):
@@ -164,9 +164,9 @@ class Context(object):
164
164
  os.path.join(self.home_path, rpath)
165
165
 
166
166
  # self.encoding is just for reading config file
167
- self.encoding = encoding
167
+ self.encoding = encoding if encoding else 'utf-8'
168
168
  cfglist = self.default_config, self.global_config, self.local_config
169
- self.cfg = self._read_config(cfglist, encoding=encoding)
169
+ self.cfg = self._read_config(cfglist, encoding=self.encoding)
170
170
 
171
171
  # self.runtime_package = 'pyarmor_runtime'
172
172
  # self.runtime_suffix = '_000000'
@@ -205,6 +205,7 @@ class Context(object):
205
205
  empty_lines_in_values=False,
206
206
  interpolation=configparser.ExtendedInterpolation(),
207
207
  )
208
+ encoding = encoding or self.encoding
208
209
  cfg.read(filelist, encoding=encoding)
209
210
  return cfg
210
211
 
@@ -330,6 +331,11 @@ class Context(object):
330
331
  def python_version(self):
331
332
  return sys.version_info[:2]
332
333
 
334
+ @property
335
+ def py_gil_disabled(self):
336
+ from sysconfig import get_config_var
337
+ return 1 if get_config_var("Py_GIL_DISABLED") else 0
338
+
333
339
  @property
334
340
  def default_config(self):
335
341
  return os.path.join(os.path.dirname(__file__), 'default.cfg')
@@ -3,7 +3,7 @@
3
3
  ;; Pyarmor version
4
4
  major = 9
5
5
  minor = 2
6
- patch = 1
6
+ patch = 2
7
7
 
8
8
  ;; Compatible core version for package: pyarmor.cli.core
9
9
  cli.core = 8.1.0
@@ -401,6 +401,15 @@ SECTIONS = {
401
401
  cls='DictOption',
402
402
  ),
403
403
  ],
404
+ 'mini': [
405
+ OptionModel(
406
+ name='import_from',
407
+ cls='NameOption',
408
+ value='pyarmor.mini.pyarmor_mini',
409
+ ),
410
+ ],
411
+ 'vmc': [],
412
+ 'ecc': [],
404
413
  }
405
414
 
406
415
 
@@ -186,7 +186,7 @@ class MultiPythonPlugin:
186
186
  os.makedirs(verpath)
187
187
 
188
188
  pkgscript = os.path.join(pkgpath, '__init__.py')
189
- with open(pkgscript) as f:
189
+ with open(pkgscript, encoding=ctx.encoding) as f:
190
190
  lines = f.readlines()
191
191
  start = 1 if lines[0].startswith('#') else 0
192
192
 
@@ -196,13 +196,13 @@ class MultiPythonPlugin:
196
196
  '{0} = __import__("py%d%d.pyarmor_runtime" % py_version[:2],'
197
197
  ' globals(), locals(), ["{0}"], 1).{0}'.format('__pyarmor__')
198
198
  ])
199
- with open(pkgscript, 'w') as f:
199
+ with open(pkgscript, 'w', encoding=ctx.encoding) as f:
200
200
  f.write(''.join(lines))
201
201
  for x in MultiPythonPlugin.RUNTIME_FILES:
202
202
  move(x, verpath)
203
203
  else:
204
204
  lines[start:start] = 'from sys import version_info as py_version\n'
205
- with open(pkgscript, 'w') as f:
205
+ with open(pkgscript, 'w', encoding=ctx.encoding) as f:
206
206
  f.write(''.join(lines).replace(
207
207
  "join(['_'", "join(['py%d%d' % py_version[:2], '_'"))
208
208
  for x in MultiPythonPlugin.RUNTIME_FILES:
@@ -253,7 +253,7 @@ class DarwinUniversalPlugin:
253
253
  return
254
254
 
255
255
  def rebuild_init(oneplat, init_script):
256
- with open(init_script, 'r') as f:
256
+ with open(init_script, 'r', encoding=ctx.encoding) as f:
257
257
  lines = f.readlines()
258
258
  if oneplat:
259
259
  lines[1:] = ['from .pyarmor_runtime import __pyarmor__']
@@ -262,7 +262,7 @@ class DarwinUniversalPlugin:
262
262
  if lines[i].strip().startswith("# mach = 'universal'"):
263
263
  lines[i] = lines[i].replace('# ', '')
264
264
  break
265
- with open(init_script, 'w') as f:
265
+ with open(init_script, 'w', encoding=ctx.encoding) as f:
266
266
  f.write(''.join(lines))
267
267
 
268
268
  rtpath = find_runtime_package(ctx, outputs[0])
@@ -23,7 +23,7 @@
23
23
  #
24
24
  # - Define project object for Pyarmor 9.
25
25
  # - Define project commands: init, build
26
- # - Define targets: std, fly, vmc, ecc, rft
26
+ # - Define targets: std, mini, vmc, ecc, rft
27
27
 
28
28
  """Manage projects
29
29
 
@@ -151,6 +151,8 @@ class Module:
151
151
  self._tree = None
152
152
  self._type = None
153
153
 
154
+ self._shebang = ''
155
+
154
156
  @property
155
157
  def name(self):
156
158
  return '' if self._name == '__init__' else self._name
@@ -190,14 +192,21 @@ class Module:
190
192
  s = self.qualname + ('' if self.name else '.__init__')
191
193
  return joinpath(*s.split('.')) + splitext(self.path)[-1]
192
194
 
193
- def compile_file(self, force=False):
195
+ @property
196
+ def shebang(self):
197
+ return self._shebang
198
+
199
+ def compile_file(self, force=False, optimize=-1):
194
200
  if self._co is not None and not force:
195
201
  return
196
202
 
197
203
  self.parse_file(force=force)
198
204
 
205
+ options = {
206
+ 'optimize': optimize
207
+ }
199
208
  logger.info('compile %s ...', self.qualname)
200
- self._co = compile(self._tree, self.abspath, 'exec')
209
+ self._co = compile(self._tree, self.abspath, 'exec', **options)
201
210
  logger.info('compile %s end', self.qualname)
202
211
 
203
212
  def parse_file(self, force=False):
@@ -206,7 +215,9 @@ class Module:
206
215
 
207
216
  filename = self.abspath
208
217
  with open(filename, 'rb') as f:
209
- encoding, _ = tokenize.detect_encoding(f.readline)
218
+ encoding, lines = tokenize.detect_encoding(f.readline)
219
+ if lines and lines[0].startswith(b'#!'):
220
+ self._shebang = lines[0].decode(encoding)
210
221
 
211
222
  with open(filename, 'r', encoding=encoding) as f:
212
223
  logger.info('parse %s ...', self.qualname)
@@ -385,6 +396,11 @@ class Project:
385
396
  self._rft_include_attrs = None
386
397
  self._used_external_types = None
387
398
 
399
+ self._std_options = None
400
+ self._mini_options = None
401
+ self._vmc_options = None
402
+ self._ecc_options = None
403
+
388
404
  # Log variable name in chain attributes
389
405
  #
390
406
  # For example, in module "foo.py":
@@ -496,6 +512,20 @@ class Project:
496
512
  for x in self._namespaces:
497
513
  yield x
498
514
 
515
+ @property
516
+ def std_options(self):
517
+ """Options got from ctx.builder, not in project"""
518
+ if self._std_options is None:
519
+ cfg = self.ctx.cfg
520
+ optimize = cfg['builder'].getint('optimize', -1)
521
+ self._std_options = {
522
+ 'optimize': optimize
523
+ }
524
+ return self._std_options
525
+
526
+ def std_opt(self, name):
527
+ return self.std_options.get(name)
528
+
499
529
  @property
500
530
  def rft_options(self):
501
531
  """Refactor options:
@@ -764,6 +794,62 @@ class Project:
764
794
  self._rft_type_rules = vartypes
765
795
  return self._rft_type_rules
766
796
 
797
+ @property
798
+ def mini_options(self):
799
+ """MINI mode options:
800
+
801
+ - import_from: str
802
+
803
+ Default value is "pyarmor.mini.pyarmor_mini", it means from
804
+ package `pyarmor.mini` import extension `pyarmor_mini`
805
+
806
+ Set it to "pyarmor_mini" if it's distributed with obfuscated
807
+ scripts
808
+ """
809
+ if self._mini_options is None:
810
+ cfg = self.ctx.cfg
811
+ sect = 'mini'
812
+ if cfg.has_section(sect):
813
+ self._mini_options = dict(cfg.items(sect))
814
+ else:
815
+ self._mini_options = {}
816
+ self._mini_options.setdefault(
817
+ 'import_from', 'pyarmor.mini.pyarmor_mini')
818
+ return self._mini_options
819
+
820
+ def mini_opt(self, name):
821
+ return self.mini_options.get(name)
822
+
823
+ @property
824
+ def vmc_options(self):
825
+ """VMC mode options"""
826
+ if self._vmc_options is None:
827
+ cfg = self.ctx.cfg
828
+ sect = 'vmc'
829
+ if cfg.has_section(sect):
830
+ self._vmc_options = dict(cfg.items(sect))
831
+ else:
832
+ self._vmc_options = {}
833
+ return self._vmc_options
834
+
835
+ def vmc_opt(self, name):
836
+ return self.vmc_options.get(name)
837
+
838
+ @property
839
+ def ecc_options(self):
840
+ """ECC mode options"""
841
+ if self._ecc_options is None:
842
+ cfg = self.ctx.cfg
843
+ sect = 'ecc'
844
+ if cfg.has_section(sect):
845
+ self._ecc_options = dict(cfg.items(sect))
846
+ else:
847
+ self._ecc_options = {}
848
+ return self._ecc_options
849
+
850
+ def ecc_opt(self, name):
851
+ return self.ecc_options.get(name)
852
+
767
853
  @property
768
854
  def builtins(self):
769
855
  if self._builtins is None:
@@ -780,7 +866,7 @@ class Project:
780
866
  for name in names.split():
781
867
  if name.endswith('.json'):
782
868
  if exists(name):
783
- with open(name) as f:
869
+ with open(name, encoding='utf-8') as f:
784
870
  used_types.update(jsonload(f))
785
871
  else:
786
872
  modname = name.split('::')[0]
@@ -819,19 +905,6 @@ class Project:
819
905
  self._rft_include_attrs.update(value.split())
820
906
  return self._rft_include_attrs
821
907
 
822
- def std_options(self):
823
- """Obfuscation options only for std target
824
-
825
- - std_assert_import
826
- - std_assert_call
827
- - std_restrict_module
828
- - std_expired_date
829
- - std_bind_devices
830
-
831
- Got from command line, not in config file
832
- """
833
- pass
834
-
835
908
  def get_module(self, qualname):
836
909
  """Get module in the project by unique qualname
837
910
  It equals one dict: map_qualname_to_module
@@ -1013,7 +1086,7 @@ class Project:
1013
1086
  if not exists(rulefile):
1014
1087
  logger.info('no found %s', rulefile)
1015
1088
  return
1016
- with open(rulefile) as f:
1089
+ with open(rulefile, encoding='utf-8') as f:
1017
1090
  fixtable = jsonload(f)
1018
1091
 
1019
1092
  if mode == 2:
@@ -1071,7 +1144,7 @@ class Project:
1071
1144
  inattrs = fixtable.get('include_attrs', [])
1072
1145
  rftattrs = header.substitute(attrs='\n'.join(
1073
1146
  [f'[[*{x}][{x}]]' for x in inattrs]))
1074
- with open(output, 'w') as fp:
1147
+ with open(output, 'w', encoding='utf-8') as fp:
1075
1148
  fp.write(rftattrs)
1076
1149
  for attr in inattrs:
1077
1150
  infos = attrinfo.get(attr)
@@ -1164,7 +1237,7 @@ class Project:
1164
1237
  """))
1165
1238
 
1166
1239
  attrs = sorted(rftattrs.keys())
1167
- with open(output, 'w') as fp:
1240
+ with open(output, 'w', encoding='utf-8') as fp:
1168
1241
  fp.write(header.substitute(
1169
1242
  attrs='\n'.join([f'[[*{x}][{x}]]' for x in attrs])
1170
1243
  ))
@@ -86,7 +86,7 @@ class CfgEntity:
86
86
  self._reader = self._writer = None
87
87
 
88
88
  def save(self):
89
- with open(self.cfgfile, 'w') as f:
89
+ with open(self.cfgfile, 'w', encoding=self._encoding) as f:
90
90
  self.writer.write(f)
91
91
 
92
92
 
@@ -260,7 +260,7 @@ class PyarmorShell(cmd.Cmd):
260
260
  ctx.default_config,
261
261
  ctx.global_config,
262
262
  ctx.local_config
263
- ])
263
+ ], encoding=ctx.encoding)
264
264
  self._domains = self._init_domains()
265
265
  self._domain = self._section = self._domains[domain]
266
266
 
@@ -281,6 +281,9 @@ class PyarmorShell(cmd.Cmd):
281
281
  domain.add_group(name, GROUPS[name])
282
282
 
283
283
  ps.add_section('rft')
284
+ ps.add_section('mini')
285
+ ps.add_section('vmc')
286
+ ps.add_section('ecc')
284
287
 
285
288
  return {'global': gs, 'local': ls, 'project': ps}
286
289
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyarmor.cli
3
- Version: 9.2.1
3
+ Version: 9.2.2
4
4
  Summary: A comand line tool to obfuscate python scripts
5
5
  Home-page: https://github.com/dashingsoft/pyarmor
6
6
  Author: Jondy Zhao
@@ -1,6 +1,6 @@
1
1
  from setuptools import setup
2
2
 
3
- __VERSION__ = ' 9.2.1'
3
+ __VERSION__ = ' 9.2.2'
4
4
 
5
5
  with open('README.rst') as f:
6
6
  long_description = f.read()
Binary file
Binary file
Binary file
File without changes
File without changes