Skip to content

Commit

Permalink
Add module-level remove_unused_platforms option
Browse files Browse the repository at this point in the history
  • Loading branch information
garynthompson committed Jan 14, 2024
1 parent eb46ee6 commit d2ffca7
Show file tree
Hide file tree
Showing 8 changed files with 668 additions and 4 deletions.
1 change: 1 addition & 0 deletions docs/source/transforms/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@ They can be enabled or disabled through the minify function, or passing options
rename_globals
remove_asserts
remove_debug
remove_unused_platforms
34 changes: 34 additions & 0 deletions docs/source/transforms/remove_unused_platforms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
value = 10
_PLATFORM = "linux" # Normally this is derived from sys.uname or platform.

# Supported Statements that will be kept in this example
if _PLATFORM == "linux":
value += 1


# Supported Statements that will be removed in this example
if _PLATFORM == "armchair":
value += 1

# Basic if/elif can be used

if _PLATFORM == "linux":
value += 1
elif _PLATFORM == "armchair":
value += 1

# So can else
if _PLATFORM == "armchair":
value += 1
else:
value += 1

# Statements that are not supported by PyMinify
if _PLATFORM:
value += 1

if _PLATFORM in ["linux", "windows"]:
value += 1


print(value)
38 changes: 38 additions & 0 deletions docs/source/transforms/remove_unused_platforms.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
Remove Unused Platforms
=======================

This transform removes ``if`` blocks that do not match a platform value. This only supports
module level if blocks and is configured to keep a single explicit match.

The transform is disabled by default.

When using the API, enable it by either passing ``remove_unused_platforms=True``
argument to the :func:`python_minifier.minify`, or by passing ``remove_unused_platforms=unused_option``
to the function where unused_option is an instance of :class:`RemoveUnusedPlatformOptions`.

When using the pyminify command, enable it with ``--remove-unused-platforms`` and set the options
as required.

Options
-------

These arguments can be used with the pyminify command as shown by the following examples:

``--platform-test-key=_PLATFORM`` The variable name that is testing the platform

``--platform-preserve-value=linux`` The value that matches the target platform


Example
-------

Input
~~~~~

.. literalinclude:: remove_unused_platforms.py

Output
~~~~~~

.. literalinclude:: remove_unused_platforms.min.py
:language: python
24 changes: 21 additions & 3 deletions src/python_minifier/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
from python_minifier.transforms.remove_object_base import RemoveObject
from python_minifier.transforms.remove_pass import RemovePass
from python_minifier.transforms.remove_posargs import remove_posargs
from python_minifier.transforms.remove_unused_platform_options import RemoveUnusedPlatformOptions
from python_minifier.transforms.remove_unused_platforms import RemoveUnusedPlatforms


class UnstableMinification(RuntimeError):
Expand Down Expand Up @@ -72,12 +74,13 @@ def minify(
remove_debug=False,
remove_explicit_return_none=True,
remove_builtin_exception_brackets=True,
constant_folding=True
constant_folding=True,
remove_unused_platforms=RemoveUnusedPlatformOptions(),
):
"""
Minify a python module
The module is transformed according the the arguments.
The module is transformed according the arguments.
If all transformation arguments are False, no transformations are made to the AST, the returned string will
parse into exactly the same module.
Expand Down Expand Up @@ -106,7 +109,8 @@ def minify(
:param bool remove_explicit_return_none: If explicit return None statements should be replaced with a bare return
:param bool remove_builtin_exception_brackets: If brackets should be removed when raising exceptions with no arguments
:param bool constant_folding: If literal expressions should be evaluated
:param remove_unused_platforms: If top level platform masking blocks can be removed.
:type remove_unused_platforms: bool or RemoveUnusedPlatformOptions
:rtype: str
"""
Expand Down Expand Up @@ -157,6 +161,20 @@ def minify(
if constant_folding:
module = FoldConstants()(module)

if isinstance(remove_unused_platforms, bool):
remove_unused_platforms_options = RemoveUnusedPlatformOptions(
platform_test_key=RemoveUnusedPlatformOptions.platform_test_key,
platform_preserve_value=RemoveUnusedPlatformOptions.platform_preserve_value,
)
elif isinstance(remove_unused_platforms, RemoveUnusedPlatformOptions):
remove_unused_platforms_options = remove_unused_platforms
else:
raise TypeError('remove_unused_platforms must be a bool or RemoveUnusedPlatformOptions')

if remove_unused_platforms_options:
module = RemoveUnusedPlatforms(remove_unused_platforms_options)(module)


bind_names(module)
resolve_names(module)

Expand Down
39 changes: 38 additions & 1 deletion src/python_minifier/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from python_minifier import minify
from python_minifier.transforms.remove_annotations_options import RemoveAnnotationsOptions
from python_minifier.transforms.remove_unused_platform_options import RemoveUnusedPlatformOptions

try:
version = get_distribution('python_minifier').version
Expand Down Expand Up @@ -229,6 +230,30 @@ def parse_args():
dest='remove_class_attribute_annotations',
)


platform_options = parser.add_argument_group('remove unused platform options', 'Options that affect platform removal')
platform_options.add_argument(
'--remove-unused-platforms',
action='store_true',
help='Remove code blocks that are masked out for a specific platform',
dest='remove_unused_platforms',
)
platform_options.add_argument(
'--platform-test-key',
type=str,
default="_PLATFORM",
help='The variable name that is testing for a platform',
dest='platform_test_key',
)
platform_options.add_argument(
'--platform-preserve-value',
type=str,
default="linux",
help='The value that matches the target platform',
dest='platform_preserve_value',
)


parser.add_argument('--version', '-v', action='version', version=version)

args = parser.parse_args()
Expand Down Expand Up @@ -296,6 +321,17 @@ def do_minify(source, filename, minification_args):
remove_class_attribute_annotations=minification_args.remove_class_attribute_annotations,
)

if minification_args.remove_unused_platforms is False:
remove_unused_platforms = RemoveUnusedPlatformOptions(
platform_test_key="",
platform_preserve_value=""
)
else:
remove_unused_platforms = RemoveUnusedPlatformOptions(
platform_test_key=minification_args.platform_test_key,
platform_preserve_value=minification_args.platform_preserve_value
)

return minify(
source,
filename=filename,
Expand All @@ -315,7 +351,8 @@ def do_minify(source, filename, minification_args):
remove_debug=minification_args.remove_debug,
remove_explicit_return_none=minification_args.remove_explicit_return_none,
remove_builtin_exception_brackets=minification_args.remove_exception_brackets,
constant_folding=minification_args.constant_folding
constant_folding=minification_args.constant_folding,
remove_unused_platforms=remove_unused_platforms
)


Expand Down
27 changes: 27 additions & 0 deletions src/python_minifier/transforms/remove_unused_platform_options.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
class RemoveUnusedPlatformOptions(object):
"""
Options for the RemoveUnusedPlatform transform
This can be passed to the minify function as the remove_unused_platforms argument
:param platform_test_key: The key used to indicate a platform check statement
:type platform_test_key: str
:param platform_preserve_value: The value of the test to keep
:type platform_preserve_value: str
"""

platform_test_key = "_PLATFORM"
platform_preserve_value = "linux"

def __init__(self, platform_test_key="", platform_preserve_value=""):
self.platform_test_key = platform_test_key
self.platform_preserve_value = platform_preserve_value

def __repr__(self):
return 'RemoveUnusedPlatformOptions(platform_test_key=%s, platform_preserve_value=%s)' % (self.platform_test_key, self.platform_preserve_value)

def __nonzero__(self):
return any((self.platform_test_key, self.platform_preserve_value))

def __bool__(self):
return self.__nonzero__()
Loading

0 comments on commit d2ffca7

Please sign in to comment.