Skip to content

Add module-level remove_unused_platforms option #97

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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