From 43dd499c3a8289673e1ce154bf10c59a0e50014c Mon Sep 17 00:00:00 2001 From: Samantha Demi Date: Fri, 7 Feb 2020 00:42:11 -0500 Subject: [PATCH 1/2] updating licenses, and adding mypy coverage --- .gitignore | 16 ++--- Dangerfile | 6 +- LICENSE | 4 +- Makefile | 40 ++++++----- pyc.py | 42 ++++++------ pyconfig/Analyzer/Engine.py | 21 +++--- pyconfig/Analyzer/Linter.py | 51 +++++++------- pyconfig/Analyzer/__init__.py | 2 +- pyconfig/Deserializer/Comment.py | 2 +- pyconfig/Deserializer/Include.py | 2 +- pyconfig/Deserializer/KeyValue.py | 19 +++--- pyconfig/Deserializer/Resolver.py | 5 +- pyconfig/Deserializer/XCLineItem.py | 2 +- pyconfig/Deserializer/__init__.py | 2 +- pyconfig/Deserializer/xcconfig.py | 2 +- pyconfig/Graph/Grapher.py | 6 +- pyconfig/Graph/Searcher.py | 15 +++-- pyconfig/Graph/__init__.py | 2 +- pyconfig/Helpers/Executor.py | 12 +--- pyconfig/Helpers/Logger.py | 30 +++++---- pyconfig/Helpers/OrderedDictionary.py | 2 +- pyconfig/Helpers/Switch.py | 4 +- pyconfig/Helpers/__init__.py | 2 +- pyconfig/Interpreter/Consumer.py | 6 +- pyconfig/Interpreter/Dependent.py | 21 +++--- pyconfig/Interpreter/LangParser.py | 2 +- pyconfig/Interpreter/__init__.py | 2 +- pyconfig/Keyword/BaseKeyword.py | 8 +-- pyconfig/Keyword/Constants.py | 4 +- pyconfig/Keyword/ExportKeyword.py | 6 +- pyconfig/Keyword/IncludeKeyword.py | 6 +- pyconfig/Keyword/Resolver.py | 3 +- pyconfig/Keyword/SettingKeyword.py | 33 +++++---- pyconfig/Keyword/Words.py | 4 +- pyconfig/Keyword/__init__.py | 2 +- pyconfig/SCM/SCM.py | 15 +++-- pyconfig/SCM/__init__.py | 2 +- pyconfig/Serializer/Serializer.py | 7 +- pyconfig/Serializer/__init__.py | 2 +- pyconfig/Settings/Builtin.py | 2 +- pyconfig/Settings/Runtime.py | 2 +- pyconfig/Settings/TypeConstants.py | 2 +- pyconfig/Settings/__init__.py | 2 +- pyconfig/__init__.py | 2 +- pyconfig/main.py | 4 +- pyconfig/version.py | 4 +- pyconfig/version_info.py | 3 +- readme.md | 16 ++--- setup.py | 48 +++++++------- tests/__init__.py | 40 +++++------ tests/pyconfig_test.py | 70 ++++++++++---------- tests/tests/flags/scm-info/svn/.svn/entries | 1 - tests/tests/flags/scm-info/svn/.svn/format | 1 - tests/tests/flags/scm-info/svn/.svn/wc.db | Bin 48128 -> 52224 bytes tools/hooks-config.py | 4 +- tox.ini | 6 +- 56 files changed, 308 insertions(+), 311 deletions(-) delete mode 100644 tests/tests/flags/scm-info/svn/.svn/entries delete mode 100644 tests/tests/flags/scm-info/svn/.svn/format diff --git a/.gitignore b/.gitignore index b78b3c5..ed09c58 100644 --- a/.gitignore +++ b/.gitignore @@ -1,16 +1,8 @@ -.DS_Store + +tests/**/*.xcconfig + installed_files.txt -build/ -dist/ -pyconfig.egg-info/ -.tox/ -.coverage -*.xcconfig -*.pyc -__pycache__/ -htmlcov/ -.eggs/ -lint_output.txt +*_output.txt # make sure to include the static test output data !*_output.xcconfig diff --git a/Dangerfile b/Dangerfile index f0b4d1e..732a6bc 100644 --- a/Dangerfile +++ b/Dangerfile @@ -1,5 +1,5 @@ -# this dangerfile sets values that will be consumed by the global danger -# file. The global dangerfile is run automatically after this repo-specific +# this dangerfile sets values that will be consumed by the global danger +# file. The global dangerfile is run automatically after this repo-specific # file is run. The global dangerfile is located at: https://github.com/samdmarshall/danger # set the number of lines that must be changed before this classifies as a 'Big PR' @@ -8,7 +8,7 @@ # set the files to watch and warn about if there are changes made @SDM_DANGER_BUILD_FILES = ['Makefile', 'Gemfile', 'Dangerfile', 'circle.yml', '.codeclimate.yml', 'tox.ini', 'pylintrc'] -# set the files to watch and warn about if there are +# set the files to watch and warn about if there are @SDM_DANGER_INSTALL_REQUIREMENTS_FILES = ['requirements.txt', 'setup.py'] # set the files to watch and fail if there are changes diff --git a/LICENSE b/LICENSE index 7d6a271..9820a59 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2016, Samantha Marshall +Copyright (c) 2016-2020, Samantha Marshall All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -9,4 +9,4 @@ Redistribution and use in source and binary forms, with or without modification, 3. Neither the name of Samantha Marshall nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Makefile b/Makefile index 27655eb..3dfc89e 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig @@ -38,7 +38,6 @@ INSTALLED_FILES_RECORD := ./installed_files.txt # names of the executables that are used as a part of this project -PYTHON2_CMD := python PYTHON3_CMD := python3 TOX_CMD := tox COVERAGE_CMD := coverage @@ -52,20 +51,20 @@ PRINTF_CMD := printf TOUCH_CMD := touch CP_CMD := cp CAT_CMD := cat -PIP_CMD := pip +PIP_CMD := pip3 CCTREPORTER_CMD := codeclimate-test-reporter UNAME_CMD := uname EXIT_CMD := exit TPUT_CMD := tput TR_CMD := tr PYLINT_CMD := pylint +MYPY_CMD := mypy PYPARSING := pyparsing TOX_PYENV := tox-pyenv # invoke the specific executable command -PYTHON2 := $(shell command -v $(PYTHON2_CMD) 2> /dev/null) PYTHON3 := $(shell command -v $(PYTHON3_CMD) 2> /dev/null) TOX := $(shell command -v $(TOX_CMD) 2> /dev/null) COVERAGE := $(shell command -v $(COVERAGE_CMD) 2> /dev/null) @@ -86,6 +85,7 @@ EXIT := $(shell command -v $(EXIT_CMD) 2> /dev/null) TPUT := $(shell command -v $(TPUT_CMD) 2> /dev/null) TR := $(shell command -v $(TR_CMD) 2> /dev/null) PYLINT := $(shell command -v $(PYLINT_CMD) 2> /dev/null) +MYPY := $(shell command -v $(MYPY_CMD) 2> /dev/null) SYSTEM := $(shell $(UNAME) -s) ifeq ($(SYSTEM),Darwin) @@ -120,12 +120,12 @@ check: $(call checkfor,$(FIND_CMD)) $(call checkfor,$(XARGS_CMD)) $(call checkfor,$(RM_CMD)) - $(call checkfor,$(PYTHON2_CMD)) $(call checkfor,$(PYTHON3_CMD)) $(call checkfor,$(PIP_CMD)) $(call checkfor,$(TOX_CMD)) $(call checkfor,$(COVERAGE_CMD)) $(call checkfor,$(PYLINT_CMD)) + $(call checkfor,$(MYPY_CMD)) $(call checkfor,$(GEM_CMD)) $(call checkfor,$(DANGER_CMD)) @$(DISPLAY_SEPARATOR) @@ -136,7 +136,6 @@ pipinstall = @$(PIP) install $1 $(USER_FLAG) geminstall = @$(GEM) install $1 $(USER_FLAG) install-deps: - $(call checkfor,$(PYTHON2_CMD)) $(call checkfor,$(PIP_CMD)) $(call pipinstall,$(COVERAGE_CMD)) $(call pipinstall,$(TOX_CMD)) @@ -144,6 +143,7 @@ install-deps: $(call pipinstall,$(TOX_PYENV)) $(call pipinstall,$(CCTREPORTER_CMD)) $(call pipinstall,$(PYLINT_CMD)) + $(call pipinstall,$(MYPY_CMD)) @$(DISPLAY_SEPARATOR) $(call checkfor,$(GEM_CMD)) $(call geminstall,$(DANGER_CMD)) @@ -175,22 +175,19 @@ clean: check @$(removeall) .coverage @$(removeall) ./htmlcov @$(removeall) ./.eggs + @$(removeall) ./.mypy_cache + @$(removeall) ./report $(call cleanlocation, ., -name ".DS_Store") $(call cleanlocation, ., -name "*.pyc") $(call cleanlocation, ., -name "__pycache__" -type d) $(call cleanlocation, ./tests, -name "*.xcconfig" -and -not -name "*_output.xcconfig") + $(call cleanlocation, ., -name "*_output.txt") @$(PRINTF) "done!\n" @$(DISPLAY_SEPARATOR) - -# --- -build2: clean - $(PYTHON2) ./setup.py install $(USER_FLAG) --record $(INSTALLED_FILES_RECORD) - @$(DISPLAY_SEPARATOR) - # --- -build3: clean +build: clean $(PYTHON3) ./setup.py install --record $(INSTALLED_FILES_RECORD) @$(DISPLAY_SEPARATOR) @@ -257,7 +254,7 @@ else @$(DANGER) local --verbose endif @$(DISPLAY_SEPARATOR) - + # --- ci: test lint report danger @@ -265,13 +262,20 @@ ci: test lint report danger # --- lint: check - @$(TOUCH) lint_output.txt + @$(TOUCH) pylint_output.txt @$(PRINTF) "Running linter... " - @$(PYLINT) --rcfile=pylintrc ./pyconfig > lint_output.txt || : + @$(PYLINT) --rcfile=pylintrc ./pyconfig > pylint_output.txt || : @$(PRINTF) " done!\n" - @$(PRINTF) "Generated linter report: lint_output.txt\n" + @$(PRINTF) "Generated linter report: pylint_output.txt\n" + + @$(TOUCH) mypy_output.txt + @$(PRINTF) "Running mypy... " + @$(MYPY) ./pyconfig --ignore-missing-imports > mypy_output.txt || : + @$(PRINTF) " done!\n" + @$(PRINTF) "Generated mypy report: mypy_output.txt\n" + @$(DISPLAY_SEPARATOR) # --- -.PHONY: danger lint ci report test build3 build2 clean install-tools install-deps check +.PHONY: danger lint ci report test build clean install-tools install-deps check diff --git a/pyc.py b/pyc.py index a342553..91cb803 100644 --- a/pyc.py +++ b/pyc.py @@ -1,31 +1,31 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016, Samantha Marsh# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig -# -# Redistribution and use in source and binary forms, with or without modification, +# +# Redistribution and use in source and binary forms, with or without modification, # are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, this +# +# 1. Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright notice, +# +# 2. Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation and/or # other materials provided with the distribution. -# -# 3. Neither the name of Samantha Marshall nor the names of its contributors may -# be used to endorse or promote products derived from this software without +# +# 3. Neither the name of Samantha Marshall nor the names of its contributors may +# be used to endorse or promote products derived from this software without # specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # OF THE POSSIBILITY OF SUCH DAMAGE. import pyconfig @@ -34,4 +34,4 @@ def main(): pyconfig.main() if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/pyconfig/Analyzer/Engine.py b/pyconfig/Analyzer/Engine.py index 4498747..d61fa88 100644 --- a/pyconfig/Analyzer/Engine.py +++ b/pyconfig/Analyzer/Engine.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig @@ -29,6 +29,7 @@ # OF THE POSSIBILITY OF SUCH DAMAGE. import os +import typing from ..Settings import TypeConstants from ..Settings import Builtin from ..Settings import Runtime @@ -36,7 +37,7 @@ from ..Helpers.Logger import Logger from ..SCM import SCM -def findPreviousDefinition(kv_array, configuration, setting_key): +def findPreviousDefinition(kv_array, configuration, setting_key) -> list: previous_definition_indexes = list() for file_name, value in kv_array: if file_name != configuration: @@ -45,9 +46,9 @@ def findPreviousDefinition(kv_array, configuration, setting_key): previous_definition_indexes.append(file_name) return previous_definition_indexes -def findDuplicates(dictionary): +def findDuplicates(dictionary) -> dict: results = dict() - settings_set = set() + settings_set: typing.Set[str] = set() snapshot_of_dict = list(dictionary.items()) for configuration, values in snapshot_of_dict: setting_values = list(values.keys()) @@ -61,7 +62,7 @@ def findDuplicates(dictionary): settings_set.update(setting_values) return results -def gatherAllVariables(dictionary): +def gatherAllVariables(dictionary) -> set: settings_set = set() snapshot_of_dict = list(dictionary.items()) for _configuration, values in snapshot_of_dict: @@ -81,7 +82,7 @@ def __init__(self): self.__namespace_table = dict() self.__user_defined_table = set() - def __runInitializer(self, configuration): + def __runInitializer(self, configuration) -> None: """ This method is to pass through the passed in file """ @@ -89,7 +90,7 @@ def __runInitializer(self, configuration): for item in configuration.config: is_setting = isinstance(item, SettingKeyword.SettingKeyword) if is_setting: - is_unset = (item.build_setting_name not in list(self.__namespace_table[configuration.name].keys())) + is_unset = ( item.build_setting_name not in list(self.__namespace_table[configuration.name].keys()) ) if is_unset: self.__namespace_table[configuration.name][item.build_setting_name] = item else: # pragma: no cover @@ -101,7 +102,7 @@ def __runInitializer(self, configuration): '\n> '+configuration.name+':'+previous_line_number+'' Logger.write().warning(print_string) - def __runDuplicates(self, configuration): + def __runDuplicates(self, configuration) -> None: duplicate_results = findDuplicates(self.__namespace_table) for key, value in list(duplicate_results.items()): for file_containing_dups in value: @@ -116,7 +117,7 @@ def __runDuplicates(self, configuration): '\n> '+file_containing_dups Logger.write().warning(print_message) - def __gatherUserDefinedVariables(self): + def __gatherUserDefinedVariables(self) -> None: self.__user_defined_table = set() snapshot_of_dict = list(self.__namespace_table.items()) for _configuration, values in snapshot_of_dict: @@ -128,7 +129,7 @@ def __gatherUserDefinedVariables(self): if not is_builtin and not is_runtime and not is_known: self.__user_defined_table.add(build_setting_name) - def __runMissing(self): + def __runMissing(self) -> None: variables = gatherAllVariables(self.__namespace_table) # remove any variables that are defined as part of the builtin set variables.difference_update(self.__builtin_table) diff --git a/pyconfig/Analyzer/Linter.py b/pyconfig/Analyzer/Linter.py index a4ce1e8..ba9741e 100644 --- a/pyconfig/Analyzer/Linter.py +++ b/pyconfig/Analyzer/Linter.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig @@ -29,6 +29,7 @@ # OF THE POSSIBILITY OF SUCH DAMAGE. import string +import typing from .. import Keyword from ..Helpers.Logger import Logger from ..Helpers.Switch import Switch @@ -38,14 +39,14 @@ # pylint: disable=protected-access -def readStringFromContent(string_value, content=None, at_index=None): +def readStringFromContent(string_value, content=None, at_index=None) -> typing.Tuple[bool, int]: Logger.write().debug('Attempting to read `%s`' % string_value) end_index = at_index+len(string_value) read_string = content[at_index:end_index] status = read_string == string_value return (status, len(string_value)) -def readUntilStringInContent(terminate_value, content=None, index=None): +def readUntilStringInContent(terminate_value, content=None, index=None) -> typing.Tuple[bool, int]: status = True start_index = index should_advance = index < len(content) @@ -57,7 +58,7 @@ def readUntilStringInContent(terminate_value, content=None, index=None): status = current_char == terminate_value return (status, index - start_index) -def readFromCharacterSet(char_set, content=None, index=None): +def readFromCharacterSet(char_set, content=None, index=None) -> typing.Tuple[bool, int]: status = True start_index = index should_advance = index < len(content) @@ -68,14 +69,14 @@ def readFromCharacterSet(char_set, content=None, index=None): should_advance = index+1 < len(content) return (status, index - start_index) -def readFromCharSetUntilCharFromContent(char_set, terminate_char, content=None, index=None): +def readFromCharSetUntilCharFromContent(char_set, terminate_char, content=None, index=None) -> typing.Tuple[bool, int]: status, read_count = readFromCharacterSet(char_set, content, index) if status is True: current_char = content[index+read_count] status = current_char == terminate_char return (status, read_count) -def readScopeFromContent(starter, closer, content=None, index=None): +def readScopeFromContent(starter, closer, content=None, index=None) -> typing.Tuple[bool, list, int, typing.Optional[str]]: current_char = content[index] error_msg = None status = current_char == starter @@ -118,9 +119,9 @@ def readScopeFromContent(starter, closer, content=None, index=None): end = index # trip the ending brace end -= 1 - return (status, content[start+1:end], index-start, error_msg) + return (status, content[start+1:end], index-start, error_msg) -def readConditionFromContent(content=None, index=None): # pylint: disable=too-many-branches +def readConditionFromContent(content=None, index=None) -> typing.Tuple[bool, int]: # pylint: disable=too-many-branches status = True current_char = content[index] original_index = index @@ -171,7 +172,7 @@ def readConditionFromContent(content=None, index=None): # pylint: disable=too-ma break return (status, index - original_index) -def readNonWhitespace(content=None, index=None): +def readNonWhitespace(content=None, index=None) -> typing.Tuple[bool, int, typing.Optional[str]]: error_msg = None current_char = content[index] status = current_char not in string.whitespace @@ -182,7 +183,7 @@ def readNonWhitespace(content=None, index=None): result = (status, index, error_msg) return result -def readWhitespace(content=None, index=None): +def readWhitespace(content=None, index=None) -> typing.Tuple[bool, int, int, int, int, typing.Optional[str]]: line_number = 0 char_number = 0 last_newline = -1 @@ -201,7 +202,7 @@ def readWhitespace(content=None, index=None): result = (status, index, line_number, char_number, last_newline, error) return result -def validateCommaSeparatedValues(content): +def validateCommaSeparatedValues(content) -> bool: index = 0 status = index < len(content) while status is True: @@ -232,7 +233,7 @@ def __init__(self, contents): self.first_export = True self.current_keyword = None - def readWhitespace(self, content=None, index=None): + def readWhitespace(self, content=None, index=None) -> bool: status, index_increase, line_increase, char_number, last_newline_increase, error = readWhitespace(content, index) # update error message if error is not None: # pragma: no cover @@ -253,7 +254,7 @@ def readWhitespace(self, content=None, index=None): break return status - def readScope(self, starter, closer): + def readScope(self, starter, closer) -> typing.Tuple[bool, list]: Logger.write().debug('Attempting to read content between matching `%s` and `%s`' % (starter, closer)) current_char = self.contents[self.index] start_line_number = self.line_number @@ -297,7 +298,7 @@ def readScope(self, starter, closer): end -= 1 return (status, self.contents[start:end]) - def readFromCharacterSetUntilCharacter(self, char_set, terminate_char): + def readFromCharacterSetUntilCharacter(self, char_set, terminate_char) -> bool: status, read_count = readFromCharSetUntilCharFromContent(char_set, terminate_char, self.contents, self.index) self.index += read_count self.char_number += read_count @@ -306,7 +307,7 @@ def readFromCharacterSetUntilCharacter(self, char_set, terminate_char): self.error = 'Encountered `%s` before `%s` at line: %i, index: %i' % (current_char, terminate_char, self.line_number, self.char_number) return status - def readQuotedString(self): + def readQuotedString(self) -> bool: status = True while status is True: status = self.readString('"') @@ -323,7 +324,7 @@ def readQuotedString(self): break return status - def readString(self, string_value, optional=False): + def readString(self, string_value, optional=False) -> bool: status, read_count = readStringFromContent(string_value, self.contents, self.index) if status is True: self.index += read_count @@ -333,7 +334,7 @@ def readString(self, string_value, optional=False): self.error = 'Expected `%s` at line %i, index: %i' % (string_value, self.line_number, self.char_number) return status - def findCharacterBeforeCharacter(self, expected_char, unexpected_char): + def findCharacterBeforeCharacter(self, expected_char, unexpected_char) -> bool: status = True unexpected_index = self.contents[self.index:].find(unexpected_char) expected_index = self.contents[self.index:].find(expected_char) @@ -347,7 +348,7 @@ def findCharacterBeforeCharacter(self, expected_char, unexpected_char): self.index += expected_index return status - def validateIf(self, scope_contents, index): # pylint: disable=too-many-branches + def validateIf(self, scope_contents, index) -> typing.Tuple[bool, int]: # pylint: disable=too-many-branches status = True while status is True: should_try_reading_assignment = True @@ -411,7 +412,7 @@ def validateIf(self, scope_contents, index): # pylint: disable=too-many-branches break return (status, index) - def validateFor(self, scope_contents, index): + def validateFor(self, scope_contents, index) -> typing.Tuple[bool, int]: status = True while status is True: # read `for` @@ -454,7 +455,7 @@ def validateFor(self, scope_contents, index): break return (status, index) - def readSettingScopeContent(self, scope_contents, original_index): + def readSettingScopeContent(self, scope_contents, original_index) -> bool: status = True offset = original_index index = original_index - offset @@ -480,7 +481,7 @@ def readSettingScopeContent(self, scope_contents, original_index): should_advance = index < len(scope_contents) return status - def validateComment(self): + def validateComment(self) -> bool: old_index = self.index eol_index = self.contents[self.index:].find('\n') if eol_index == -1: @@ -489,7 +490,7 @@ def validateComment(self): self.char_number += self.index - old_index return True - def validateExport(self): + def validateExport(self) -> bool: status = True while status is True: status = self.has_finished_exports is False @@ -513,7 +514,7 @@ def validateExport(self): break return status - def validateInclude(self): + def validateInclude(self) -> bool: status = True while status is True: status = self.has_finished_includes is False @@ -545,7 +546,7 @@ def validateInclude(self): break return status - def validateSetting(self): # pylint: disable=too-many-branches + def validateSetting(self) -> bool: # pylint: disable=too-many-branches status = True while status is True: self.current_keyword = Keyword.Constants._setting @@ -596,7 +597,7 @@ def validateSetting(self): # pylint: disable=too-many-branches break return status - def validates(self): # pylint: disable=too-many-branches,too-many-statements + def validates(self) -> bool: # pylint: disable=too-many-branches,too-many-statements should_advance = len(self.contents) > 0 status = True while should_advance is True and status is True: diff --git a/pyconfig/Analyzer/__init__.py b/pyconfig/Analyzer/__init__.py index 9564712..c2ec478 100644 --- a/pyconfig/Analyzer/__init__.py +++ b/pyconfig/Analyzer/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig diff --git a/pyconfig/Deserializer/Comment.py b/pyconfig/Deserializer/Comment.py index 6ad3f22..dae5ffe 100644 --- a/pyconfig/Deserializer/Comment.py +++ b/pyconfig/Deserializer/Comment.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig diff --git a/pyconfig/Deserializer/Include.py b/pyconfig/Deserializer/Include.py index 7e14286..9166918 100644 --- a/pyconfig/Deserializer/Include.py +++ b/pyconfig/Deserializer/Include.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig diff --git a/pyconfig/Deserializer/KeyValue.py b/pyconfig/Deserializer/KeyValue.py index 8717ea4..5a72010 100644 --- a/pyconfig/Deserializer/KeyValue.py +++ b/pyconfig/Deserializer/KeyValue.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig @@ -29,10 +29,11 @@ # OF THE POSSIBILITY OF SUCH DAMAGE. import re +import typing from . import XCLineItem from ..Helpers.Switch import Switch -def shouldAppendConditionItem(condition): +def shouldAppendConditionItem(condition) -> bool: result = False for case in Switch(condition): if case(''): @@ -44,7 +45,7 @@ def shouldAppendConditionItem(condition): break return result -def splitByConditions(conditions_string): +def splitByConditions(conditions_string) -> list: results_array = list() conditions_string_array = re.split(r'[\[|\]]', conditions_string) for condition in conditions_string_array: @@ -57,8 +58,8 @@ class KeyValue(XCLineItem.XCLineItem): def __init__(self, line): super(KeyValue, self).__init__(line) offset = KeyValue.findKeyValueAssignmentOffset(self.contents, 0) - self.__key = self.contents[:offset] - self.__value = self.contents[offset+1:] + self.__key: str = self.contents[:offset] + self.__value: str = self.contents[offset+1:] def __eq__(self, other): contents_match = super(KeyValue, self).__eq__(other) @@ -71,7 +72,7 @@ def __eq__(self, other): return configs_match @classmethod - def findKeyValueAssignmentOffset(cls, line, offset): + def findKeyValueAssignmentOffset(cls, line, offset) -> int: result_offset = -1 find_open_bracket = line.find('[') find_equals = line.find('=') @@ -90,7 +91,7 @@ def findKeyValueAssignmentOffset(cls, line, offset): result_offset = new_offset return result_offset - def key(self): + def key(self) -> str: key = self.__key result_key = key find_bracket = key.find('[') @@ -102,7 +103,7 @@ def key(self): result_key = key[:find_bracket] return result_key - def conditions(self): + def conditions(self) -> dict: conditions = {} key = self.__key find_bracket = key.find('[') @@ -116,7 +117,7 @@ def conditions(self): conditions[cond_key] = cond_value return conditions - def value(self): + def value(self) -> str: value = self.__value if len(value) == 0: value = '' diff --git a/pyconfig/Deserializer/Resolver.py b/pyconfig/Deserializer/Resolver.py index 5127ba3..97c6da7 100644 --- a/pyconfig/Deserializer/Resolver.py +++ b/pyconfig/Deserializer/Resolver.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig @@ -28,12 +28,13 @@ # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # OF THE POSSIBILITY OF SUCH DAMAGE. +import typing from . import XCLineItem from . import Include from . import Comment from . import KeyValue -def ResolveLineType(line): +def ResolveLineType(line) -> typing.Any: type_ = XCLineItem.XCLineItem if line.startswith('//'): type_ = Comment.Comment diff --git a/pyconfig/Deserializer/XCLineItem.py b/pyconfig/Deserializer/XCLineItem.py index ebdd59c..b26498a 100644 --- a/pyconfig/Deserializer/XCLineItem.py +++ b/pyconfig/Deserializer/XCLineItem.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig diff --git a/pyconfig/Deserializer/__init__.py b/pyconfig/Deserializer/__init__.py index 9564712..c2ec478 100644 --- a/pyconfig/Deserializer/__init__.py +++ b/pyconfig/Deserializer/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig diff --git a/pyconfig/Deserializer/xcconfig.py b/pyconfig/Deserializer/xcconfig.py index aaa033e..e8acea3 100644 --- a/pyconfig/Deserializer/xcconfig.py +++ b/pyconfig/Deserializer/xcconfig.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig diff --git a/pyconfig/Graph/Grapher.py b/pyconfig/Graph/Grapher.py index e75f65e..a4b3100 100644 --- a/pyconfig/Graph/Grapher.py +++ b/pyconfig/Graph/Grapher.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig @@ -28,7 +28,7 @@ # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # OF THE POSSIBILITY OF SUCH DAMAGE. -def TraverseNodes(graph_nodes=None): +def TraverseNodes(graph_nodes=None) -> list: graph_nodes = list() if graph_nodes is None else graph_nodes graph_list = list() @@ -42,7 +42,7 @@ def TraverseNodes(graph_nodes=None): visited.update(set(child_nodes)) return graph_list -def WalkNodes(visited=None, nodes_with_children=None): +def WalkNodes(visited=None, nodes_with_children=None) -> list: visited = set() if visited is None else visited nodes_with_children = list() if nodes_with_children is None else nodes_with_children diff --git a/pyconfig/Graph/Searcher.py b/pyconfig/Graph/Searcher.py index e57af6e..a0737a6 100644 --- a/pyconfig/Graph/Searcher.py +++ b/pyconfig/Graph/Searcher.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig @@ -29,10 +29,11 @@ # OF THE POSSIBILITY OF SUCH DAMAGE. import os +import typing from ..Helpers.Logger import Logger -def LocateParentWithPath(start_file_path, parent_item): - parent_path = start_file_path +def LocateParentWithPath(start_file_path: str, parent_item: str) -> typing.Optional[str]: + parent_path: typing.Optional[str] = start_file_path search_file_path = os.path.join(start_file_path, parent_item) if start_file_path == '/': parent_path = None @@ -40,21 +41,21 @@ def LocateParentWithPath(start_file_path, parent_item): parent_path = LocateParentWithPath(os.path.dirname(start_file_path), parent_item) return parent_path -def locateWorkingDirectoryForPath(file_path): +def locateWorkingDirectoryForPath(file_path: str) -> str: working_path = file_path if os.path.isfile(file_path): fs_path = os.path.dirname(file_path) working_path = os.path.normpath(os.path.join(os.getcwd(), fs_path)) return working_path -def locateDirectories(root, dirs): +def locateDirectories(root: str, dirs: list) -> list: found_configs = list() for dir_name in dirs: relative_path = os.path.join(root, dir_name) found_configs.extend(locateConfigs(relative_path)) return found_configs -def locateFiles(root, files): +def locateFiles(root: str, files: list) -> list: found_configs = list() for file_name in files: relative_path = os.path.join(root, file_name) @@ -65,7 +66,7 @@ def locateFiles(root, files): found_configs.append(full_path) return found_configs -def locateConfigs(fs_path): +def locateConfigs(fs_path: str) -> list: found_configs = list() for root, dirs, files in os.walk(fs_path, followlinks=True): found_configs.extend(locateDirectories(root, dirs)) diff --git a/pyconfig/Graph/__init__.py b/pyconfig/Graph/__init__.py index 9564712..c2ec478 100644 --- a/pyconfig/Graph/__init__.py +++ b/pyconfig/Graph/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig diff --git a/pyconfig/Helpers/Executor.py b/pyconfig/Helpers/Executor.py index d55f6e1..2916787 100644 --- a/pyconfig/Helpers/Executor.py +++ b/pyconfig/Helpers/Executor.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig @@ -31,17 +31,11 @@ import sys import subprocess -try: - from subprocess import DEVNULL -except ImportError: # pragma: no cover - import os - DEVNULL = open(os.devnull, 'wb') - -def Invoke(call_args, shell_state=False): +def Invoke(call_args, shell_state=False) -> tuple: error = 0 output = None try: - output = subprocess.check_output(call_args, shell=shell_state, stderr=DEVNULL).decode(sys.stdout.encoding) + output = subprocess.check_output(call_args, shell=shell_state, stderr=subprocess.DEVNULL).decode(sys.stdout.encoding) except subprocess.CalledProcessError as exception: output = exception.output.decode(sys.stdout.encoding) error = exception.returncode diff --git a/pyconfig/Helpers/Logger.py b/pyconfig/Helpers/Logger.py index f8d5d03..ad15d00 100644 --- a/pyconfig/Helpers/Logger.py +++ b/pyconfig/Helpers/Logger.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig @@ -29,15 +29,19 @@ # OF THE POSSIBILITY OF SUCH DAMAGE. import logging +import typing class Singleton(type): - _instances = {} + _instances: typing.Dict[typing.Any, typing.Any] = dict() def __call__(cls, *args, **kwargs): # pragma: no cover if cls not in cls._instances.keys(): cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) return cls._instances[cls] + +LOGGER_NAME = 'com.pewpewthespells.py.logging_helper' + #These are the sequences need to get colored ouput RESET_SEQ = '\033[0m' BOLD_SEQ = '\033[1m' @@ -66,7 +70,7 @@ def __init__(self, msg, use_color=True): logging.Formatter.__init__(self, msg) self.use_color = use_color - def format(self, record): # pragma: no cover + def format(self, record) -> str: # pragma: no cover levelname = record.levelname if self.use_color and levelname in LEVELS: levelname_color = LEVELS[levelname] + levelname + RESET_SEQ @@ -75,7 +79,7 @@ def format(self, record): # pragma: no cover class Logger(object): __metaclass__ = Singleton - _internal_logger = None + _internal_logger = logging.Logger('') _debug_logging = False _use_ansi_codes = False @@ -83,15 +87,15 @@ def __init__(self, *args, **kwargs): # pragma: no cover pass @staticmethod - def enableDebugLogger(is_debug_logger=False): + def enableDebugLogger(is_debug_logger=False) -> None: Logger._debug_logging = is_debug_logger @staticmethod - def disableANSI(disable_ansi=False): + def disableANSI(disable_ansi=False) -> None: Logger._use_ansi_codes = not disable_ansi @staticmethod - def setupLogger(): + def setupLogger() -> None: Logger._internal_logger = logging.getLogger('com.pewpewthespells.py.logging_helper') level = logging.DEBUG if Logger._debug_logging else logging.INFO @@ -114,22 +118,22 @@ def setupLogger(): Logger._internal_logger.addHandler(handler) @staticmethod - def isVerbose(verbose_logging=False): - if Logger._internal_logger is None: # pragma: no cover + def isVerbose(verbose_logging=False) -> None: + if Logger._internal_logger.name is not LOGGER_NAME: # pragma: no cover Logger.setupLogger() if not verbose_logging: Logger._internal_logger.setLevel(logging.WARNING) @staticmethod - def isSilent(should_quiet=False): - if Logger._internal_logger is None: # pragma: no cover + def isSilent(should_quiet=False) -> None: + if Logger._internal_logger.name is not LOGGER_NAME: # pragma: no cover Logger.setupLogger() if should_quiet: logging_filter = logging.Filter(name='com.pewpewthespells.py.logging_helper.shut_up') Logger._internal_logger.addFilter(logging_filter) @staticmethod - def write(): - if Logger._internal_logger is None: # pragma: no cover + def write() -> logging.Logger: + if Logger._internal_logger.name is not LOGGER_NAME: # pragma: no cover Logger.setupLogger() return Logger._internal_logger diff --git a/pyconfig/Helpers/OrderedDictionary.py b/pyconfig/Helpers/OrderedDictionary.py index aef1556..ad4fa3a 100644 --- a/pyconfig/Helpers/OrderedDictionary.py +++ b/pyconfig/Helpers/OrderedDictionary.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig diff --git a/pyconfig/Helpers/Switch.py b/pyconfig/Helpers/Switch.py index e10359b..007fc0b 100644 --- a/pyconfig/Helpers/Switch.py +++ b/pyconfig/Helpers/Switch.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig @@ -40,7 +40,7 @@ def __iter__(self): yield self.match raise StopIteration # pragma: no cover - def match(self, *args): + def match(self, *args) -> bool: """Indicate whether or not to enter a case suite""" result = False if self.fall or not args: diff --git a/pyconfig/Helpers/__init__.py b/pyconfig/Helpers/__init__.py index 9564712..c2ec478 100644 --- a/pyconfig/Helpers/__init__.py +++ b/pyconfig/Helpers/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig diff --git a/pyconfig/Interpreter/Consumer.py b/pyconfig/Interpreter/Consumer.py index d8d7f1f..3c9eadf 100644 --- a/pyconfig/Interpreter/Consumer.py +++ b/pyconfig/Interpreter/Consumer.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig @@ -32,7 +32,7 @@ from . import Dependent from ..Helpers.Logger import Logger from ..Analyzer.Linter import Linter -def CreateNodeFromString(config_name="", config_contents=""): +def CreateNodeFromString(config_name="", config_contents="") -> Dependent.DependentNode: # now parse the file's contents parsed_contents = LangParser._config.parseString(config_contents) # pylint: disable=protected-access @@ -40,7 +40,7 @@ def CreateNodeFromString(config_name="", config_contents=""): return node -def CreateGraphNodes(pyconfig_path_list=None): +def CreateGraphNodes(pyconfig_path_list=None) -> set: pyconfig_path_list = list() if pyconfig_path_list is None else pyconfig_path_list parsed_configs = set() diff --git a/pyconfig/Interpreter/Dependent.py b/pyconfig/Interpreter/Dependent.py index 8df822a..27b7f25 100644 --- a/pyconfig/Interpreter/Dependent.py +++ b/pyconfig/Interpreter/Dependent.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig @@ -29,13 +29,14 @@ # OF THE POSSIBILITY OF SUCH DAMAGE. import os +import typing from ..Keyword import ExportKeyword from ..Keyword import IncludeKeyword from ..Keyword import Constants from ..Keyword import Resolver from ..Helpers.Logger import Logger -def findParents(graph, current_config): +def findParents(graph, current_config) -> list: included_configs = list() for config in graph: if config.exportName() == current_config.include_path: @@ -63,32 +64,30 @@ def __init__(self, contents, name): self.config = parsed_contents self.name = name - def chainParents(self): + def chainParents(self) -> list: # needs to include the current name or we will never get any elements chain = [self.name] for parent in self.parents: chain = parent.chainParents() + chain return chain - def importChain(self): + def importChain(self) -> list: parents = self.chainParents() chain = parents + [self.name] # don't include children as they will resolve on their own. - chain_set = set() # uniquing the list that was created - chain = [link for link in chain if not (link in chain_set or chain_set.add(link))] - return chain + return list(set(chain)) - def filterContentsByType(self, class_type): + def filterContentsByType(self, class_type) -> list: results = [node for node in self.config if isinstance(node, class_type)] return results - def exportPath(self): + def exportPath(self) -> str: base_path = os.path.dirname(self.name) export_file = self.exportName() export_path = os.path.normpath(os.path.join(base_path, export_file)) return export_path - def exportName(self): + def exportName(self) -> str: xcconfig_name = '' exported_name_info = None export_info_array = self.filterContentsByType(ExportKeyword.ExportKeyword) @@ -100,7 +99,7 @@ def exportName(self): xcconfig_name = file_name + '.xcconfig' return xcconfig_name - def resolvePaths(self, graph): + def resolvePaths(self, graph) -> None: config_includes_array = self.filterContentsByType(IncludeKeyword.IncludeKeyword) for parent_config in config_includes_array: included_config_array = findParents(graph, parent_config) diff --git a/pyconfig/Interpreter/LangParser.py b/pyconfig/Interpreter/LangParser.py index ad1b6cc..62e125f 100644 --- a/pyconfig/Interpreter/LangParser.py +++ b/pyconfig/Interpreter/LangParser.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig diff --git a/pyconfig/Interpreter/__init__.py b/pyconfig/Interpreter/__init__.py index 9564712..c2ec478 100644 --- a/pyconfig/Interpreter/__init__.py +++ b/pyconfig/Interpreter/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig diff --git a/pyconfig/Keyword/BaseKeyword.py b/pyconfig/Keyword/BaseKeyword.py index 5d44b36..6bc8c22 100644 --- a/pyconfig/Keyword/BaseKeyword.py +++ b/pyconfig/Keyword/BaseKeyword.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig @@ -40,7 +40,7 @@ def __init__(self): def __eq__(self, other): # pylint: disable=no-self-use ; # pragma: no cover raise Exception('Please subclass this class and implement this method') - def serialize(self): # pylint: disable=no-self-use ; # pragma: no cover + def serialize(self) -> str: # pylint: disable=no-self-use ; # pragma: no cover raise Exception('Please subclass this class and implement this method') def consumePath(self, constant, parsed_item=None): # pylint: disable=no-self-use ; # pragma: no cover @@ -50,11 +50,11 @@ def consumePath(self, constant, parsed_item=None): # pylint: disable=no-self-use result = parsed_item[1][1:-1] return result - def consume(self, parsed_item=None): # pragma: no cover + def consume(self, parsed_item=None) -> None: # pragma: no cover parsed_item = list() if parsed_item is None else parsed_item self.__parsed_item = parsed_item - def deserialize(self, xcconfig_line=''): # pylint: disable=no-self-use ; # pragma: no cover + def deserialize(self, xcconfig_line='') -> None: # pylint: disable=no-self-use ; # pragma: no cover _unused = xcconfig_line raise Exception('Please subclass this class and implement this method') diff --git a/pyconfig/Keyword/Constants.py b/pyconfig/Keyword/Constants.py index 65feb3d..a810e53 100644 --- a/pyconfig/Keyword/Constants.py +++ b/pyconfig/Keyword/Constants.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig @@ -44,4 +44,4 @@ _specialCase = '*' _equals = '=' _export = 'export' -_comment = '#' +_comment = '#' diff --git a/pyconfig/Keyword/ExportKeyword.py b/pyconfig/Keyword/ExportKeyword.py index e1503f4..c291a2f 100644 --- a/pyconfig/Keyword/ExportKeyword.py +++ b/pyconfig/Keyword/ExportKeyword.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig @@ -41,10 +41,10 @@ def __eq__(self, other): # pragma: no cover cmp_export = (self.export_path == other.export_path) return cmp_export - def consume(self, parsed_item=None): + def consume(self, parsed_item=None) -> None: parsed_item = list() if parsed_item is None else parsed_item super(ExportKeyword, self).consume(parsed_item) self.export_path = self.consumePath(Constants._export, parsed_item) # pylint: disable=protected-access - def serialize(self): # pragma: no cover + def serialize(self) -> str: # pragma: no cover raise Exception('The "export" keyword should never be serialized! Something has gone wrong!') diff --git a/pyconfig/Keyword/IncludeKeyword.py b/pyconfig/Keyword/IncludeKeyword.py index 8726c95..b8c20d4 100644 --- a/pyconfig/Keyword/IncludeKeyword.py +++ b/pyconfig/Keyword/IncludeKeyword.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig @@ -42,13 +42,13 @@ def __eq__(self, other): # pragma: no cover cmp_include = (self.include_path == other.include_path) return cmp_include - def consume(self, parsed_item=None): + def consume(self, parsed_item=None) -> None: parsed_item = list() if parsed_item is None else parsed_item super(IncludeKeyword, self).consume(parsed_item) self.optional = parsed_item[0].startswith('?') self.include_path = self.consumePath(Constants._include, parsed_item) # pylint: disable=protected-access - def serialize(self): + def serialize(self) -> str: serialized_string = '' include_type_string = '' if self.optional: diff --git a/pyconfig/Keyword/Resolver.py b/pyconfig/Keyword/Resolver.py index 590620e..b4d07ab 100644 --- a/pyconfig/Keyword/Resolver.py +++ b/pyconfig/Keyword/Resolver.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig @@ -28,6 +28,7 @@ # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # OF THE POSSIBILITY OF SUCH DAMAGE. +import typing from . import Constants from . import BaseKeyword from . import ExportKeyword diff --git a/pyconfig/Keyword/SettingKeyword.py b/pyconfig/Keyword/SettingKeyword.py index de69403..62917e5 100644 --- a/pyconfig/Keyword/SettingKeyword.py +++ b/pyconfig/Keyword/SettingKeyword.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig @@ -55,7 +55,7 @@ def __eq__(self, other): # pragma: no cover cmp_for = (self.uses_for and (self.uses_for == other.uses_for)) return cmp_name and (cmp_if or cmp_for) - def consumeForStatement(self, statement): + def consumeForStatement(self, statement) -> None: configuration_name = statement[1] value = '' if len(statement) == 3: @@ -65,7 +65,7 @@ def consumeForStatement(self, statement): else: self.default_value = ' '.join(value) - def consumeModifiers(self, modifiers): + def consumeModifiers(self, modifiers) -> None: if len(modifiers): if modifiers[0] == Constants._use: # pylint: disable=protected-access self.substitutes = True @@ -73,7 +73,7 @@ def consumeModifiers(self, modifiers): if modifiers[-1] == Constants._inherits: # pylint: disable=protected-access self.inherits = True - def consumeConfigurationAssignment(self, configurations): + def consumeConfigurationAssignment(self, configurations) -> None: keywords_used = list() for setting_configuration in configurations: keywords_used.append(setting_configuration[0]) @@ -86,7 +86,7 @@ def consumeConfigurationAssignment(self, configurations): self.uses_if = (used_keyword_in_assignemnt == Constants._if) # pylint: disable=protected-access self.uses_for = (used_keyword_in_assignemnt == Constants._for) # pylint: disable=protected-access - def consumeIfStatement(self, statement): + def consumeIfStatement(self, statement) -> None: conditions = statement[1] value = '' if len(statement) == 3: @@ -97,7 +97,7 @@ def consumeIfStatement(self, statement): conditional_key_value_string = ','.join(conditional_key_value_list) self.configuration_values[conditional_key_value_string] = ' '.join(value) - def consume(self, parsed_item=None): + def consume(self, parsed_item=None) -> None: parsed_item = list() if parsed_item is None else parsed_item super(SettingKeyword, self).consume(parsed_item) @@ -119,17 +119,22 @@ def consume(self, parsed_item=None): if configuration_type == Constants._if: # pylint: disable=protected-access self.consumeIfStatement(setting_configuration) - def serializeInheritedValues(self): + def serializeInheritedValues(self) -> str: serialize_string = '' if self.inherits: serialize_string += '$(inherited) ' return serialize_string - def isConfigurationCase(self): + def isConfigurationCase(self) -> bool: keys = list(self.configuration_values.keys()) - return (len(keys) > 1) or (len(keys) and keys[0] != Constants._specialCase) # pylint: disable=protected-access - - def serializeForStatement(self, key, value): + has_keys = len(keys) != 0 + has_many_keys = len(keys) > 1 + not_special_key = has_keys and keys[0] != Constants._specialCase + # (len(keys) > 1) or (len(keys) and keys[0] != Constants._specialCase) # pylint: disable=protected-access + result = has_many_keys or not_special_key + return result + + def serializeForStatement(self, key, value) -> str: serialize_string = '' serialize_string += self.build_setting_name if self.isConfigurationCase(): @@ -139,7 +144,7 @@ def serializeForStatement(self, key, value): serialize_string += value + '\n' return serialize_string - def serializeForConditionalStatement(self): + def serializeForConditionalStatement(self) -> str: serialize_string = '' serialize_string += self.build_setting_name + ' = ' serialize_string += self.serializeInheritedValues() @@ -151,14 +156,14 @@ def serializeForConditionalStatement(self): serialize_string += '\n' return serialize_string - def serializeIfStatement(self, key, value): + def serializeIfStatement(self, key, value) -> str: serialize_string = '' serialize_string += self.build_setting_name+'['+key+']'+' = ' serialize_string += self.serializeInheritedValues() serialize_string += value+'\n' return serialize_string - def serialize(self): + def serialize(self) -> str: serialize_string = '' if self.uses_for: for key, value in self.configuration_values.items(): diff --git a/pyconfig/Keyword/Words.py b/pyconfig/Keyword/Words.py index 1df413e..4e1e9e7 100644 --- a/pyconfig/Keyword/Words.py +++ b/pyconfig/Keyword/Words.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig @@ -31,7 +31,7 @@ import pyparsing from . import Constants -def addLocnToTokens(string_value, location, token): +def addLocnToTokens(string_value, location, token) -> None: token['locn'] = location substring = string_value[:location] token['line'] = substring.count('\n') + 1 diff --git a/pyconfig/Keyword/__init__.py b/pyconfig/Keyword/__init__.py index c4f9a3f..3aa0e57 100644 --- a/pyconfig/Keyword/__init__.py +++ b/pyconfig/Keyword/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig diff --git a/pyconfig/SCM/SCM.py b/pyconfig/SCM/SCM.py index 6738803..4a3bf1f 100644 --- a/pyconfig/SCM/SCM.py +++ b/pyconfig/SCM/SCM.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig @@ -31,6 +31,7 @@ import os from ..Graph import Searcher from ..Interpreter import Consumer +from ..Interpreter import Dependent from ..Helpers.Switch import Switch from ..Helpers import Executor from ..Helpers.Logger import Logger @@ -38,14 +39,14 @@ SCM_DEFAULT_EXPORT_NAME = 'scm-version' SCM_NODE_NAME = 'SCM Information' -def DetectError(output, error, detect_mode, error_string): +def DetectError(output, error, detect_mode, error_string) -> bool: should_append_data = True if error != 0 and detect_mode is False: # pragma: no cover should_append_data = False Logger.write().error(error_string % output) return should_append_data -def InfoFromGit(detect_mode=False): +def InfoFromGit(detect_mode=False) -> str: content_string = '' should_append_data = True @@ -70,7 +71,7 @@ def InfoFromGit(detect_mode=False): '}\n' return content_string -def InfoFromSVN(detect_mode=False): +def InfoFromSVN(detect_mode=False) -> str: content_string = '' should_append_data = True @@ -94,7 +95,7 @@ def InfoFromSVN(detect_mode=False): '}\n' return content_string -def InfoFromMercurial(detect_mode=False): +def InfoFromMercurial(detect_mode=False) -> str: content_string = '' content_string = '' @@ -121,7 +122,7 @@ def InfoFromMercurial(detect_mode=False): '}\n' return content_string -def GenerateSCMContents(scm_type='detect'): +def GenerateSCMContents(scm_type='detect') -> str: scm_content_string = '' detect_mode = False for case in Switch(scm_type): @@ -143,7 +144,7 @@ def GenerateSCMContents(scm_type='detect'): break return scm_content_string -def CreateNodeForSCM(scm_type='detect', file_path=''): +def CreateNodeForSCM(scm_type='detect', file_path='') -> Dependent.DependentNode: working_dir = Searcher.locateWorkingDirectoryForPath(file_path) original_dir = os.getcwd() diff --git a/pyconfig/SCM/__init__.py b/pyconfig/SCM/__init__.py index 9564712..c2ec478 100644 --- a/pyconfig/SCM/__init__.py +++ b/pyconfig/SCM/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig diff --git a/pyconfig/Serializer/Serializer.py b/pyconfig/Serializer/Serializer.py index 3a9b8d2..1fc0963 100644 --- a/pyconfig/Serializer/Serializer.py +++ b/pyconfig/Serializer/Serializer.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig @@ -47,9 +47,10 @@ def openOutputFileToWrite(input_string): except OSError as error: if error.errno != 17: raise - return open(file_path, 'w') + fd = open(file_path, 'w') + return fd -def writeFile(config_node=None, scheme_name=None): +def writeFile(config_node=None, scheme_name=None) -> None: """ Takes a configuration file node object and a string of the scheme name and will write out a file to disk. diff --git a/pyconfig/Serializer/__init__.py b/pyconfig/Serializer/__init__.py index 9564712..c2ec478 100644 --- a/pyconfig/Serializer/__init__.py +++ b/pyconfig/Serializer/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig diff --git a/pyconfig/Settings/Builtin.py b/pyconfig/Settings/Builtin.py index 65cb400..7f82d5f 100644 --- a/pyconfig/Settings/Builtin.py +++ b/pyconfig/Settings/Builtin.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig diff --git a/pyconfig/Settings/Runtime.py b/pyconfig/Settings/Runtime.py index 40b056e..9ebf4fb 100644 --- a/pyconfig/Settings/Runtime.py +++ b/pyconfig/Settings/Runtime.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig diff --git a/pyconfig/Settings/TypeConstants.py b/pyconfig/Settings/TypeConstants.py index a4234aa..b939376 100644 --- a/pyconfig/Settings/TypeConstants.py +++ b/pyconfig/Settings/TypeConstants.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig diff --git a/pyconfig/Settings/__init__.py b/pyconfig/Settings/__init__.py index 9564712..c2ec478 100644 --- a/pyconfig/Settings/__init__.py +++ b/pyconfig/Settings/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig diff --git a/pyconfig/__init__.py b/pyconfig/__init__.py index 8fa04e8..9a522ff 100644 --- a/pyconfig/__init__.py +++ b/pyconfig/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig diff --git a/pyconfig/main.py b/pyconfig/main.py index 234fc31..a0365e6 100755 --- a/pyconfig/main.py +++ b/pyconfig/main.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig @@ -40,7 +40,7 @@ from .SCM import SCM # Main -def main(argv=sys.argv[1:]): +def main(argv=sys.argv[1:]) -> None: # setup the argument parsing parser = argparse.ArgumentParser(description='pyconfig is a tool to generate xcconfig files from a simple DSL') parser.add_argument( diff --git a/pyconfig/version.py b/pyconfig/version.py index e977d88..bdea3fa 100644 --- a/pyconfig/version.py +++ b/pyconfig/version.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig @@ -30,4 +30,4 @@ from . import version_info -__version__ = '1.1.3.1 ('+version_info.remote_origin+' @ '+version_info.commit_hash+')' +__version__ = '1.2.0 ('+version_info.remote_origin+' @ '+version_info.commit_hash+')' diff --git a/pyconfig/version_info.py b/pyconfig/version_info.py index 11cf4af..e58cf68 100644 --- a/pyconfig/version_info.py +++ b/pyconfig/version_info.py @@ -1,2 +1 @@ -remote_origin = 'git@github.com:samdmarshall/pyconfig.git' -commit_hash = 'a2b141e' +remote_origin = 'ssh://github.com/samdmarshall/pyconfig'\ncommit_hash = '10c5d2c' diff --git a/readme.md b/readme.md index 9bef337..cd3975f 100644 --- a/readme.md +++ b/readme.md @@ -1,4 +1,4 @@ -pyconfig +pyconfig ======== [![Code Climate](https://img.shields.io/codeclimate/github/samdmarshall/pyconfig.svg)](https://codeclimate.com/github/samdmarshall/pyconfig) @@ -6,22 +6,20 @@ pyconfig [![CircleCI branch](https://img.shields.io/circleci/project/samdmarshall/pyconfig/develop.svg)](https://circleci.com/gh/samdmarshall/pyconfig/tree/develop) [![Dependency Status](https://dependencyci.com/github/samdmarshall/pyconfig/badge)](https://dependencyci.com/github/samdmarshall/pyconfig) -**pyconfig** is a tool that allows you to write the contents of your [`.xcconfig` files](http://pewpewthespells.com/blog/xcconfig_guide.html) in a simple and more expressive language and have them be generated prior to building a target in Xcode. +**pyconfig** is a tool that allows you to write the contents of your [`.xcconfig` files](http://pewpewthespells.com/blog/xcconfig_guide.html) in a simple and more expressive language and have them be generated prior to building a target in Xcode. ## Contributing and Code of Conduct [![License](https://img.shields.io/badge/License-3--Clause%20BSD-blue.svg)](./LICENSE) This project and related material has a Code of Conduct that is listed in the [contributing.md](./contributing.md) file. This must be read and adhered to when interacting with this project. Additionally this code is released under a 3-clause BSD license that you can read [here](./LICENSE). -## Requirements ![Python](https://img.shields.io/badge/Python2-2.7.10-brightgreen.svg) ![Python](https://img.shields.io/badge/Python3-3.6.0-brightgreen.svg) -This tool is built and tested against Python 2.7.10 and 3.6.0. +## Requirements ![Python](https://img.shields.io/badge/Python3-3.6.0-brightgreen.svg) +This tool is built and tested against Python 3.7.6. Module | Version ----------|----------- pyparsing | >=2.0.1 -Note: All of these modules come as part of the system Python installation for OS X (which is 2.7.10 as of 10.11.5), but you will have to install them yourself if necessary on other systems. These modules can be accquired through `pip install`. - ## Installation [![homebrew](https://img.shields.io/badge/homebrew-v1.1.3-brightgreen.svg)](https://github.com/samdmarshall/homebrew-formulae) [![homebrew](https://img.shields.io/badge/homebrew-HEAD-orange.svg)](https://github.com/samdmarshall/homebrew-formulae) Via [homebrew](http://brew.sh): @@ -32,13 +30,9 @@ Via [homebrew](http://brew.sh): To install the tool from the repo, clone from Github then run the respective `make` command for the desired version. -### Installing for Python 2 - - $ make build2 - ### Installing for Python 3 - $ make build3 + $ make build ## Usage diff --git a/setup.py b/setup.py index daa81f9..d2ac8c4 100644 --- a/setup.py +++ b/setup.py @@ -1,44 +1,44 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig -# -# Redistribution and use in source and binary forms, with or without modification, +# +# Redistribution and use in source and binary forms, with or without modification, # are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, this +# +# 1. Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright notice, +# +# 2. Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation and/or # other materials provided with the distribution. -# -# 3. Neither the name of Samantha Marshall nor the names of its contributors may -# be used to endorse or promote products derived from this software without +# +# 3. Neither the name of Samantha Marshall nor the names of its contributors may +# be used to endorse or promote products derived from this software without # specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # OF THE POSSIBILITY OF SUCH DAMAGE. from setuptools import setup setup( name = 'pyconfig', - version = '1.1.3.1', + version = '1.2.0', description = 'Tool for generating xcconfig files', url = 'https://github.com/samdmarshall/pyconfig', author = 'Samantha Marshall', author_email = 'hello@pewpewthespells.com', license = 'BSD 3-Clause', - packages = [ + packages = [ 'pyconfig', 'pyconfig/Analyzer', 'pyconfig/Deserializer', @@ -50,8 +50,8 @@ 'pyconfig/Settings', 'pyconfig/SCM', ], - entry_points = { - 'console_scripts': [ 'pyconfig = pyconfig:main' ] + entry_points = { + 'console_scripts': [ 'pyconfig = pyconfig:main' ] }, test_suite = 'tests.pyconfig_test', zip_safe = False, diff --git a/tests/__init__.py b/tests/__init__.py index a72ad31..c2ec478 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,29 +1,29 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig -# -# Redistribution and use in source and binary forms, with or without modification, +# +# Redistribution and use in source and binary forms, with or without modification, # are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, this +# +# 1. Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright notice, +# +# 2. Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation and/or # other materials provided with the distribution. -# -# 3. Neither the name of Samantha Marshall nor the names of its contributors may -# be used to endorse or promote products derived from this software without +# +# 3. Neither the name of Samantha Marshall nor the names of its contributors may +# be used to endorse or promote products derived from this software without # specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/tests/pyconfig_test.py b/tests/pyconfig_test.py index 675f402..c48af04 100755 --- a/tests/pyconfig_test.py +++ b/tests/pyconfig_test.py @@ -1,31 +1,31 @@ -# Copyright (c) 2016, Samantha Marshall (http://pewpewthespells.com) +# Copyright (c) 2016-2020, Samantha Marshall (http://pewpewthespells.com) # All rights reserved. # # https://github.com/samdmarshall/pyconfig -# -# Redistribution and use in source and binary forms, with or without modification, +# +# Redistribution and use in source and binary forms, with or without modification, # are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, this +# +# 1. Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright notice, +# +# 2. Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation and/or # other materials provided with the distribution. -# -# 3. Neither the name of Samantha Marshall nor the names of its contributors may -# be used to endorse or promote products derived from this software without +# +# 3. Neither the name of Samantha Marshall nor the names of its contributors may +# be used to endorse or promote products derived from this software without # specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # OF THE POSSIBILITY OF SUCH DAMAGE. import os @@ -57,22 +57,22 @@ class pyconfigTestCases(unittest.TestCase): def test_comments(self): LoadTestDirectoryAndTestWithName(self, 'comments', 'test') - + def test_conditionals(self): LoadTestDirectoryAndTestWithName(self, 'conditionals', 'test') - + def test_direct_assignment_specific(self): LoadTestDirectoryAndTestWithName(self, 'direct assignment/specific', 'test') - + def test_direct_assignment_automatic(self): LoadTestDirectoryAndTestWithName(self, 'direct assignment/automatic', 'test') - + def test_export_with_keyword(self): LoadTestDirectoryAndTestWithName(self, 'export/with-export', 'defaults') - + def test_export_with_keyword_and_include(self): LoadTestDirectoryAndTestWithName(self, 'export/with-export-and-include', 'defaults') - + def test_export_without_keyword(self): LoadTestDirectoryAndTestWithName(self, 'export/without-export', 'test') @@ -87,35 +87,35 @@ def test_include_legacy(self): def test_include_missing_required(self): LoadTestDirectoryAndTestWithName(self, 'include/missing required', 'test') - + def test_inherits(self): LoadTestDirectoryAndTestWithName(self, 'inherits', 'test') - + def test_variable_substitution_with_use(self): LoadTestDirectoryAndTestWithName(self, 'variable substitution/with-use', 'test') - + def test_variable_substitution_without_use(self): LoadTestDirectoryAndTestWithName(self, 'variable substitution/without-use', 'test') - + def test_search_direct_file(self): test_pyconfig_path_sub = 'search/direct-file' test_pyconfig_path = os.path.join(test_directory, test_pyconfig_path_sub) direct_file_path = os.path.join(test_pyconfig_path, 'test.pyconfig') LoadTestDirectoryAndTestWithName(self, test_pyconfig_path_sub, 'test', [direct_file_path], True) - + def test_search_directory_path(self): test_pyconfig_path_sub = 'search/directory' test_pyconfig_path = os.path.join(test_directory, test_pyconfig_path_sub) LoadTestDirectoryAndTestWithName(self, test_pyconfig_path, 'test-dir/test', [test_pyconfig_path], True) - + def test_duplicate_definition_single_file(self): LoadTestDirectoryAndTestWithName(self, 'duplicate definitions/single file', 'test') - + def test_duplicate_definition_multiple_files(self): test_pyconfig_path_sub = 'duplicate definitions/multiple files' test_pyconfig_path = os.path.join(test_directory, test_pyconfig_path_sub) LoadTestDirectoryAndTestWithName(self, test_pyconfig_path, 'test', [test_pyconfig_path], True) - + def test_flags_scheme_name(self): LoadTestDirectoryAndTestWithName(self, 'flags/scheme name', 'test', ['--scheme', 'MyAppDebug']) @@ -138,4 +138,4 @@ def test_debug_flag(self): LoadTestDirectoryAndTestWithName(self, 'comments', 'test', ['--verbose', '--debug']) if __name__ == '__main__': - unittest.main() \ No newline at end of file + unittest.main() diff --git a/tests/tests/flags/scm-info/svn/.svn/entries b/tests/tests/flags/scm-info/svn/.svn/entries deleted file mode 100644 index 48082f7..0000000 --- a/tests/tests/flags/scm-info/svn/.svn/entries +++ /dev/null @@ -1 +0,0 @@ -12 diff --git a/tests/tests/flags/scm-info/svn/.svn/format b/tests/tests/flags/scm-info/svn/.svn/format deleted file mode 100644 index 48082f7..0000000 --- a/tests/tests/flags/scm-info/svn/.svn/format +++ /dev/null @@ -1 +0,0 @@ -12 diff --git a/tests/tests/flags/scm-info/svn/.svn/wc.db b/tests/tests/flags/scm-info/svn/.svn/wc.db index 8975bddb73be241646d3617ae885212b9dce5e16..74b7f98031fb60cbdc26c118da38bb666cc476ea 100644 GIT binary patch delta 2310 zcmdUw?Q2t49LLW&zngoT)YvE6n?B~&8gJ6pv}t|l8XU{RRf93HwVjIKB_^@SOl@rA zd;qEGHU-^_ma~EQ0FHrn!q~J!C!0*)iLV^uU@#aA_HMZOW*c*EJ2&RkwDlj@g?sZk z-{1HA?s@v}tI#YQ zBmH*TA>yV5O=Q_4v1nJUiRKS%6ba|{rC_C+5CN zoFpsK2UE%MbS|0Dv*Tmg3B@0d`sssy2i-f;Z|p#dUK~ld2_phg_C!5!8>0X3O{nLa zu#qiQJeJ9{Zn^07nLdk|DOG;9-vh<{w$bTJ7J@2oWN@VlcaRyKL2w+L zA}C?E7-=QRmKt-7qjf=*+g@GnS>|l=keE#b48!Tt4)iQN)d_kCpLe;M(>`t zinw)wbopk5Fkl?er(YNc)JByLZPF-KmTIVCkybBa`y#19T()F_5^iB*4=kDVS}fF( zi%3EmB5AM?f@jg+NF#S<@?Dnv+BQkXhR#A2}<74TAiR96czI`yXV<;5S z^lia)oIL?n2t%3@iUhS?%0iD4jVRowI7buf^mr;6KQM84)Rj~uS(S0VzL+`^4Qe~| zZP7QiU;(?0w0@SiF#eb6OMFK5LQ`=biRNN_d zm0mv89NxN0lpPMdCl}k7NlqNfuu9V>aF0`N6T+LxbF>KyGx_yG-dj^or)OncN$;I?(TB4~h|@(wvw^wIpWLqYTi8IF$uk6h zz!Ufxet<{t0Pew;@EKfzOYi}lg()}&Sr~!6FbrV`KtFiE33jLhD+uJ-T$ON}OqQ82 zVzq)>IVc?L99lRub7~_%mmtDH~rV4 z3ZemDuT}-YfbTz61#G}^RTW4_!@y#|Ue?QGfRE)VGoX?6DrCOw zP|GD_7#PkYIL}@=4MNF3*M=tCY-M3H(GfgkU&|@j0uAIha+kbMbY|DcWQSR>_qJ)f zhP1(mFT5k9&!ZmHHnD08df3;-xO){(PnlrX?DLM|;fx*5jTP#sq_2nf^0+0T(P!To z(8JNd)+IgYuTgW&yw@oTwO+enqyrIo%e>xc652XkzQEA1FRU9y7t)K3?Y==RGSt`2 z##eZF*jW1np)J%_;-=W!k|^=Cfgr1Dp?E`ubj8vyu_zvu2(oL<0@EvA)}wgbSdcfq O$VT4?+pI6Mu;73Bt{M9P delta 539 zcmXw$O-LI-6vyAkB+)g|#AsF%H>-#qM3Lg58ZY$&RA>=TLIp({8Y2Lpo3pJlK0Kz4zk5o<#7}9vX1mbsx8#}2H+$RDGY{rp_$-GB;=53<;dgiJX)xgm0`Aya*t%!@B#UMMl!u-kMM zLk*zDTYLiNGA7C`Vt=9|WSSy09m~N>~XLL*jdPy<7$6vUOi->RyKcT{V_@0NcujH)BvPu*7dDiQh?O9qn zKkSb(LTGs#J)WiH>YEpYNiXa6tn1M%G@Ak#K^+MnI(_KS6*k6Pjk?;!N!^6F?v9(~(Y IbJdIX2Z`-|#sB~S diff --git a/tools/hooks-config.py b/tools/hooks-config.py index 86bf39b..7ba3663 100755 --- a/tools/hooks-config.py +++ b/tools/hooks-config.py @@ -7,8 +7,8 @@ import stat # Copies the commit-msg file into the .git/hooks directory to be executed by -# git during commits if it does not already exist or if the file has been changed. -# Files in the .git/hooks are not tracked, so any updates to commit-msg must +# git during commits if it does not already exist or if the file has been changed. +# Files in the .git/hooks are not tracked, so any updates to commit-msg must # occur in the root and be copied over. base_git_hooks_path = '.git/hooks/' base_tools_hooks_path = './tools/hooks/' diff --git a/tox.ini b/tox.ini index b64c6fd..d72bde0 100644 --- a/tox.ini +++ b/tox.ini @@ -1,12 +1,12 @@ [tox] platform = linux2|darwin -envlist = py27,py36 +envlist = py36 [testenv] -commands = +commands = coverage run --source=./pyconfig/ setup.py test -deps = +deps = coverage pyparsing From 6cacf8f85e433d506c1f09fb6c4305ceea57d254 Mon Sep 17 00:00:00 2001 From: Samantha Demi Date: Fri, 7 Feb 2020 00:46:45 -0500 Subject: [PATCH 2/2] updating hook to use bash, not sh --- pyconfig/version_info.py | 3 ++- tools/hooks/pre-commit | 9 +++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/pyconfig/version_info.py b/pyconfig/version_info.py index e58cf68..e628a76 100644 --- a/pyconfig/version_info.py +++ b/pyconfig/version_info.py @@ -1 +1,2 @@ -remote_origin = 'ssh://github.com/samdmarshall/pyconfig'\ncommit_hash = '10c5d2c' +remote_origin = 'ssh://github.com/samdmarshall/pyconfig' +commit_hash = '43dd499' diff --git a/tools/hooks/pre-commit b/tools/hooks/pre-commit index 622880a..576422f 100755 --- a/tools/hooks/pre-commit +++ b/tools/hooks/pre-commit @@ -1,10 +1,11 @@ -#!/bin/sh +#!/usr/bin/env bash git_path=`git rev-parse --show-toplevel` pushd $git_path - + commit_hash=`git rev-parse --short HEAD` remote_origin=`git ls-remote --get-url` -echo "remote_origin = '$remote_origin'\ncommit_hash = '$commit_hash'" > ./pyconfig/version_info.py +echo "remote_origin = '$remote_origin'" > ./pyconfig/version_info.py +echo "commit_hash = '$commit_hash'" >> ./pyconfig/version_info.py git add ./pyconfig/version_info.py -popd \ No newline at end of file +popd