diff --git a/.gitignore b/.gitignore index a1467b4df..c5ef8e56e 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ gh-pages gh *.pyc +python/setup.py python/*/__pycache__ python/MANIFEST python/build diff --git a/Makefile b/Makefile index c80ef8132..018678cb7 100644 --- a/Makefile +++ b/Makefile @@ -79,11 +79,17 @@ js/lib/*.js: $(BUILD_DIR)/node $(BUILD_DIR)/generate $(wildcard js/src/*) $(wild # python package generation -python/dist/*: $(BUILD_DIR)/python $(wildcard python/**/*.py) python/jsbeautifier/* +python/dist/*: $(BUILD_DIR)/python $(wildcard python/**/*.py) python/jsbeautifier/* python/cssbeautifier/* @echo Building python package... rm -f python/dist/* @cd python && \ - $(PYTHON) setup.py sdist + cp setup-js.py setup.py && \ + $(PYTHON) setup.py sdist && \ + rm setup.py + @cd python && \ + cp setup-css.py setup.py && \ + $(PYTHON) setup.py sdist && \ + rm setup.py $(SCRIPT_DIR)/python-rel pip install -U python/dist/* # python package generation @@ -121,9 +127,11 @@ $(BUILD_DIR)/node: package.json package-lock.json | $(BUILD_DIR) $(NPM) --version @touch $(BUILD_DIR)/node -$(BUILD_DIR)/python: python/setup.py | $(BUILD_DIR) $(BUILD_DIR)/virtualenv +$(BUILD_DIR)/python: python/setup-js.py python/setup-css.py | $(BUILD_DIR) $(BUILD_DIR)/virtualenv @$(PYTHON) --version + @cp ./python/setup-js.py ./python/setup.py $(SCRIPT_DIR)/python-dev pip install -e ./python + @rm ./python/setup.py @touch $(BUILD_DIR)/python $(BUILD_DIR)/virtualenv: | $(BUILD_DIR) diff --git a/python/cssbeautifier/__init__.py b/python/cssbeautifier/__init__.py index aef82eafc..97efd86e0 100644 --- a/python/cssbeautifier/__init__.py +++ b/python/cssbeautifier/__init__.py @@ -23,210 +23,29 @@ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -from __future__ import print_function import sys -import os -import io -import re -import copy -import getopt -from jsbeautifier.__version__ import __version__ -from jsbeautifier import isFileDifferent, mkdir_p -from cssbeautifier.css.options import BeautifierOptions -from cssbeautifier.css.beautifier import Beautifier def default_options(): - return BeautifierOptions() + _main = __import__("cssbeautifier", globals(), locals(), ["_main"])._main + return _main.default_options() -def beautify(string, opts=default_options()): - b = Beautifier(string, opts) - return b.beautify() +def beautify(string, opts=None): + _main = __import__("cssbeautifier", globals(), locals(), ["_main"])._main + return _main.beautify(string, opts) -def beautify_file(file_name, opts=default_options()): - if file_name == "-": # stdin - try: - if sys.stdin.isatty(): - raise Exception() - - stream = sys.stdin - except Exception: - print("Must pipe input or define input file.\n", file=sys.stderr) - usage(sys.stderr) - raise Exception() - else: - stream = open(file_name) - - content = "".join(stream.readlines()) - b = Beautifier(content, opts) - return b.beautify() +def beautify_file(file_name, opts=None): + _main = __import__("cssbeautifier", globals(), locals(), ["_main"])._main + return _main.beautify_file(file, opts) def usage(stream=sys.stdout): - - print( - "cssbeautifier.py@" - + __version__ - + """ - -CSS beautifier (https://beautifier.io/) - -Usage: cssbeautifier.py [options] - - can be "-", which means stdin. - -Input options: - - -i, --stdin Read input from stdin - -Output options: - - -s, --indent-size=NUMBER Indentation size. (default 4). - -c, --indent-char=CHAR Character to indent with. (default space). - -e, --eol=STRING Character(s) to use as line terminators. - (default first newline in file, otherwise "\\n") - -t, --indent-with-tabs Indent with tabs, overrides -s and -c - --preserve-newlines Preserve existing line breaks. - --disable-selector-separator-newline - Do not print each selector on a separate line. - -b, --brace-style=collapse Brace style (collapse, expand) - -n, --end-with-newline End output with newline - --disable-newline-between-rules - Do not print empty line between rules. - --space-around-combinator Print spaces around combinator. - --indent-empty-lines Keep indentation on empty lines - -r, --replace Write output in-place, replacing input - -o, --outfile=FILE Specify a file to output to (default stdout) - -Rarely needed options: - - -h, --help, --usage Prints this help statement. - -v, --version Show the version - -""", - file=stream, - ) - if stream == sys.stderr: - return 1 - else: - return 0 + _main = __import__("cssbeautifier", globals(), locals(), ["_main"])._main + return _main._sage(stream) def main(): - - argv = sys.argv[1:] - - try: - opts, args = getopt.getopt( - argv, - "hvio:rs:c:e:tnb:", - [ - "help", - "usage", - "version", - "stdin", - "outfile=", - "replace", - "indent-size=", - "indent-char=", - "eol=", - "indent-with-tabs", - "preserve-newlines", - "brace-style=", - "disable-selector-separator-newline", - "end-with-newline", - "disable-newline-between-rules", - "space-around-combinator", - "indent-empty-lines", - ], - ) - except getopt.GetoptError as ex: - print(ex, file=sys.stderr) - return usage(sys.stderr) - - css_options = default_options() - - file = None - outfile = "stdout" - replace = False - if len(args) == 1: - file = args[0] - - for opt, arg in opts: - if opt in ("--stdin", "-i"): - file = "-" - elif opt in ("--outfile", "-o"): - outfile = arg - elif opt in ("--replace", "-r"): - replace = True - elif opt in ("--version", "-v"): - return print(__version__) - elif opt in ("--help", "--usage", "-h"): - return usage() - - elif opt in ("--indent-size", "-s"): - css_options.indent_size = int(arg) - elif opt in ("--indent-char", "-c"): - css_options.indent_char = arg - elif opt in ("--eol", "-e"): - css_options.eol = arg - elif opt in ("--indent-with-tabs", "-t"): - css_options.indent_with_tabs = True - elif opt in ("--preserve-newlines"): - css_options.preserve_newlines = True - elif opt in ("--disable-selector-separator-newline"): - css_options.selector_separator_newline = False - elif opt in ("--brace-style", "-b"): - css_options.brace_style = arg - elif opt in ("--end-with-newline", "-n"): - css_options.end_with_newline = True - elif opt in ("--disable-newline-between-rules"): - css_options.newline_between_rules = False - elif opt in ("--space-around-combinator"): - css_options.space_around_combinator = True - elif opt in ("--indent-empty-lines"): - css_options.indent_empty_lines = True - - if not file: - file = "-" - - try: - if outfile == "stdout" and replace and not file == "-": - outfile = file - - pretty = beautify_file(file, css_options) - - if outfile == "stdout": - # python automatically converts newlines in text to "\r\n" when on windows - # switch to binary to prevent this - if sys.platform == "win32": - import msvcrt - - msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) - - sys.stdout.write(pretty) - else: - if isFileDifferent(outfile, pretty): - mkdir_p(os.path.dirname(outfile)) - - # python automatically converts newlines in text to "\r\n" when on windows - # set newline to empty to prevent this - with io.open(outfile, "wt", newline="") as f: - print("writing " + outfile, file=sys.stderr) - try: - f.write(pretty) - except TypeError: - # This is not pretty, but given how we did the version import - # it is the only way to do this without having setup.py - # fail on a missing six dependency. - six = __import__("six") - f.write(six.u(pretty)) - - except Exception as ex: - print(ex, file=sys.stderr) - return 1 - - # Success - return 0 + _main = __import__("cssbeautifier", globals(), locals(), ["_main"])._main + return _main.main() diff --git a/python/cssbeautifier/_main.py b/python/cssbeautifier/_main.py new file mode 100644 index 000000000..e1f4e31e6 --- /dev/null +++ b/python/cssbeautifier/_main.py @@ -0,0 +1,234 @@ +# +# The MIT License (MIT) + +# Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. + +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: + +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from __future__ import print_function +import sys +import os +import io +import re +import copy +import getopt +from cssbeautifier.__version__ import __version__ +from jsbeautifier import isFileDifferent, mkdir_p +from cssbeautifier.css.options import BeautifierOptions +from cssbeautifier.css.beautifier import Beautifier + +__all__ = ["default_options", "beautify", "beautify_file", "usage", "main"] + + +def default_options(): + return BeautifierOptions() + + +def beautify(string, opts=None): + b = Beautifier(string, opts) + return b.beautify() + + +def beautify_file(file_name, opts=None): + if file_name == "-": # stdin + try: + if sys.stdin.isatty(): + raise Exception() + + stream = sys.stdin + except Exception: + print("Must pipe input or define input file.\n", file=sys.stderr) + usage(sys.stderr) + raise Exception() + else: + stream = open(file_name) + + content = "".join(stream.readlines()) + b = Beautifier(content, opts) + return b.beautify() + + +def usage(stream=sys.stdout): + + print( + "cssbeautifier.py@" + + __version__ + + """ + +CSS beautifier (https://beautifier.io/) + +Usage: cssbeautifier.py [options] + + can be "-", which means stdin. + +Input options: + + -i, --stdin Read input from stdin + +Output options: + + -s, --indent-size=NUMBER Indentation size. (default 4). + -c, --indent-char=CHAR Character to indent with. (default space). + -e, --eol=STRING Character(s) to use as line terminators. + (default first newline in file, otherwise "\\n") + -t, --indent-with-tabs Indent with tabs, overrides -s and -c + --preserve-newlines Preserve existing line breaks. + --disable-selector-separator-newline + Do not print each selector on a separate line. + -b, --brace-style=collapse Brace style (collapse, expand) + -n, --end-with-newline End output with newline + --disable-newline-between-rules + Do not print empty line between rules. + --space-around-combinator Print spaces around combinator. + --indent-empty-lines Keep indentation on empty lines + -r, --replace Write output in-place, replacing input + -o, --outfile=FILE Specify a file to output to (default stdout) + +Rarely needed options: + + -h, --help, --usage Prints this help statement. + -v, --version Show the version + +""", + file=stream, + ) + if stream == sys.stderr: + return 1 + else: + return 0 + + +def main(): + + argv = sys.argv[1:] + + try: + opts, args = getopt.getopt( + argv, + "hvio:rs:c:e:tnb:", + [ + "help", + "usage", + "version", + "stdin", + "outfile=", + "replace", + "indent-size=", + "indent-char=", + "eol=", + "indent-with-tabs", + "preserve-newlines", + "brace-style=", + "disable-selector-separator-newline", + "end-with-newline", + "disable-newline-between-rules", + "space-around-combinator", + "indent-empty-lines", + ], + ) + except getopt.GetoptError as ex: + print(ex, file=sys.stderr) + return usage(sys.stderr) + + css_options = default_options() + + file = None + outfile = "stdout" + replace = False + if len(args) == 1: + file = args[0] + + for opt, arg in opts: + if opt in ("--stdin", "-i"): + file = "-" + elif opt in ("--outfile", "-o"): + outfile = arg + elif opt in ("--replace", "-r"): + replace = True + elif opt in ("--version", "-v"): + return print(__version__) + elif opt in ("--help", "--usage", "-h"): + return usage() + + elif opt in ("--indent-size", "-s"): + css_options.indent_size = int(arg) + elif opt in ("--indent-char", "-c"): + css_options.indent_char = arg + elif opt in ("--eol", "-e"): + css_options.eol = arg + elif opt in ("--indent-with-tabs", "-t"): + css_options.indent_with_tabs = True + elif opt in ("--preserve-newlines"): + css_options.preserve_newlines = True + elif opt in ("--disable-selector-separator-newline"): + css_options.selector_separator_newline = False + elif opt in ("--brace-style", "-b"): + css_options.brace_style = arg + elif opt in ("--end-with-newline", "-n"): + css_options.end_with_newline = True + elif opt in ("--disable-newline-between-rules"): + css_options.newline_between_rules = False + elif opt in ("--space-around-combinator"): + css_options.space_around_combinator = True + elif opt in ("--indent-empty-lines"): + css_options.indent_empty_lines = True + + if not file: + file = "-" + + try: + if outfile == "stdout" and replace and not file == "-": + outfile = file + + pretty = beautify_file(file, css_options) + + if outfile == "stdout": + # python automatically converts newlines in text to "\r\n" when on windows + # switch to binary to prevent this + if sys.platform == "win32": + import msvcrt + + msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) + + sys.stdout.write(pretty) + else: + if isFileDifferent(outfile, pretty): + mkdir_p(os.path.dirname(outfile)) + + # python automatically converts newlines in text to "\r\n" when on windows + # set newline to empty to prevent this + with io.open(outfile, "wt", newline="") as f: + print("writing " + outfile, file=sys.stderr) + try: + f.write(pretty) + except TypeError: + # This is not pretty, but given how we did the version import + # it is the only way to do this without having setup.py + # fail on a missing six dependency. + six = __import__("six") + f.write(six.u(pretty)) + + except Exception as ex: + print(ex, file=sys.stderr) + return 1 + + # Success + return 0 diff --git a/python/cssbeautifier/css/beautifier.py b/python/cssbeautifier/css/beautifier.py index 289e60796..09214ce5c 100644 --- a/python/cssbeautifier/css/beautifier.py +++ b/python/cssbeautifier/css/beautifier.py @@ -6,7 +6,7 @@ from jsbeautifier.core.output import Output from jsbeautifier.core.inputscanner import InputScanner from jsbeautifier.core.directives import Directives -from jsbeautifier.__version__ import __version__ +from cssbeautifier.__version__ import __version__ # This is not pretty, but given how we did the version import # it is the only way to do this without having setup.py fail on a missing @@ -419,7 +419,7 @@ def beautify(self): # line. Block comments are also affected, but # a new line is always output before one inside # that section - if self._input.peek() is not "/": + if self._input.peek() != "/": self._output.add_new_line() else: self.print_string(self._ch) diff --git a/python/setup-css.py b/python/setup-css.py index 123a6273c..df9873e9a 100755 --- a/python/setup-css.py +++ b/python/setup-css.py @@ -3,8 +3,6 @@ import os import sys -from setup import PyTest # from setyp.py, not setuptools! - from setuptools import setup from cssbeautifier.__version__ import __version__ @@ -13,15 +11,22 @@ DIR_CSS = "cssbeautifier/tests/" -class PyTestCSS(PyTest): +class PyTestCSS(TestCommand): + user_options = [("pytest-args=", "a", "Arguments to pass to py.test")] + def initialize_options(self): TestCommand.initialize_options(self) self.pytest_args = ["--assert=plain"] + [ - DIR_CSS + x - for x in os.listdir(DIR_CSS) - if x.endswith(".py") and x[0] not in "._" + DIR + x for x in os.listdir(DIR) if x.endswith(".py") and x[0] not in "._" ] + def run_tests(self): + # import here, cause outside the eggs aren't loaded + import pytest + + errno = pytest.main(self.pytest_args) + sys.exit(errno) + setup( name="cssbeautifier", diff --git a/python/setup.py b/python/setup-js.py similarity index 100% rename from python/setup.py rename to python/setup-js.py diff --git a/tools/release-all.sh b/tools/release-all.sh index 7508db131..06fb246cb 100755 --- a/tools/release-all.sh +++ b/tools/release-all.sh @@ -17,8 +17,11 @@ release_python() git clean -xfd || exit 1 cd python # python setup.py register -r pypi + cp setup-js.py setup.py sdist || exit 1 python setup.py sdist || exit 1 - python setup-css.py sdist || exit 1 + cp setup-css.py setup.py sdist || exit 1 + python setup.py sdist || exit 1 + rm setup.py || exit 1 python -m twine upload dist/* || exit 1 }