From 51a7fd2178bb08415a426bb83f99c7a88a1fbfcf Mon Sep 17 00:00:00 2001 From: scls19fr Date: Mon, 5 Nov 2018 08:36:17 +0100 Subject: [PATCH 1/8] Release 1.3.2 --- CHANGELOG.md | 38 +++++++++++++++++++++++++++++++ CODE_OF_CONDUCT.md | 46 ++++++++++++++++++++++++++++++++++++++ CONTRIBUTING.md | 52 +++++++++++++++++++++++++++++++++++++++++++ CONTRIBUTORS.md | 11 +++++++++ RELEASE_PROCEDURE.md | 51 ++++++++++++++++++++++++++++++++++++++++++ constraint/version.py | 4 ++-- 6 files changed, 200 insertions(+), 2 deletions(-) create mode 100644 CHANGELOG.md create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 CONTRIBUTORS.md create mode 100644 RELEASE_PROCEDURE.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..26dd4fa --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,38 @@ +# Change Log + +## Python Contraint + +All notable changes to this code base will be documented in this file, +in every released version. + +### Version 1.3.2 + +- Released: 2018-11-05 +- Issues/Enhancements: + - Add tests around `SomeNotInSetConstraint.` + - Minor `README` fixes + - Fix `dict.keys()` issue with Python 3 and add some unit tests + +### Version 1.3.1 + +- Released: 2017-03-31 +- Issues/Enhancements: + - Better `README` rendering (using reStructuredText) + +### Version 1.3 + +- Released: 2017-03-31 +- Maintainer: Sébastien Celles +- Issues/Enhancements: + - Original code forked from https://labix.org/python-constraint + - Publish on Github + - Python 2 / 3 support + - Remove Python 2.6 support + - Unit tests and continuous integration + - Create a registered pip instalable package + - PEP8 + +### Initial development + +- Author: Gustavo Biemeyer +- URL: https://labix.org/python-constraint diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..f615b2d --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,46 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at s.celles@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..b8f6810 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,52 @@ +# Contributing + +If you discover issues, have ideas for improvements or new features, +please report them to the [issue tracker](https://github.com/python-constraint/python-constraint/issues) of the repository. +After this you can help by fixing it submitting a pull request (PR). +Please, try to follow these guidelines when you +do so. + +## Issue reporting + +* Check that the issue has not already been reported. +* Check that the issue has not already been fixed in the latest code + (a.k.a. `master`). So be certain that you are using latest `master` code version + (not latest released version). Installing latest development version can be done using: + +```bash +$ pip install git+https://github.com/python-constraint/python-constraint +``` + +or + +```bash +$ git clone https://github.com/python-constraint/python-constraint +$ python setup.py install +``` + +* Be clear, concise and precise in your description of the problem. +* Open an issue with a descriptive title and a summary in grammatically correct, + complete sentences. +* Mention your Python version and operating system. +* Include any relevant code to the issue summary. + +A [Minimal Working Example (MWE)](https://en.wikipedia.org/wiki/Minimal_Working_Example) can help. + +### Reporting bugs + +When reporting bugs it's a good idea to provide stacktrace messages to +the bug report makes it easier to track down bugs. Some steps to reproduce a bug +reliably would also make a huge difference. + +## Pull requests + +* Read [how to properly contribute to open source projects on Github](http://gun.io/blog/how-to-github-fork-branch-and-pull-request). +* Use a topic branch to easily amend a pull request later, if necessary. +* Use the same coding conventions as the rest of the project. +* Make sure that the unit tests are passing (`py.test`). +* Write [good commit messages](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html). +* Mention related tickets in the commit messages (e.g. `[Fix #N] Add command ...`). +* Update the [changelog](https://github.com/python-constraint/python-constraint/blob/master/CHANGELOG.md). +* [Squash related commits together](http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html). +* Open a [pull request](https://help.github.com/articles/using-pull-requests) that relates to *only* one subject with a clear title + and description in grammatically correct, complete sentences. diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md new file mode 100644 index 0000000..0ae7417 --- /dev/null +++ b/CONTRIBUTORS.md @@ -0,0 +1,11 @@ +# List of python-constraint contributors and notable users (sorted alphabetically) + +- Sébastien Celles - https://github.com/scls19fr - project co-maintainer +- Aron Griffis - https://github.com/agriffis +- Matt Kindy - https://github.com/mattkindy-praetorian +- Arun Mahapatra - https://github.com/codito +- Gustavo Niemeyer - https://github.com/niemeyer/ - initial author + +[Full Github contributors list](https://github.com/python-constraint/python-constraint/graphs/contributors). + +and maybe more... diff --git a/RELEASE_PROCEDURE.md b/RELEASE_PROCEDURE.md new file mode 100644 index 0000000..d8c490c --- /dev/null +++ b/RELEASE_PROCEDURE.md @@ -0,0 +1,51 @@ +# Release procedue + +* Ensure supported Python versions in `setup.py` and `.travis.yml` are corrects + +* Ensure `python-constraint` version is up to date in `version.py` + +* Ensure `CHANGELOG.md` have been updated + +* Tag commit and push to github + +using Github website + +Go to https://github.com/python-constraint/python-constraint/releases/new +tag: vx.x.x + +or using cli + +```bash +git tag -a x.x.x -m 'Version x.x.x' +git push python-constraint master --tags +``` + +* Upload to PyPI + +Ensure a `~/.pypirc` exists + +``` +[distutils] # this tells distutils what package indexes you can push to +index-servers = pypi + pypi # the live PyPI + pypitest # test PyPI + +[pypi] +repository:http://pypi.python.org/pypi +username:scls +password:********** +``` + +Upload + +``` +git clean -xfd +python setup.py register sdist bdist_wheel --universal +python setup.py sdist bdist_wheel upload +``` + +* Verify on PyPI + +Go to https://pypi.python.org/pypi/python-constraint/ + +Verify that new version is published. diff --git a/constraint/version.py b/constraint/version.py index af97862..7ad1c2f 100644 --- a/constraint/version.py +++ b/constraint/version.py @@ -1,8 +1,8 @@ __author__ = "Gustavo Niemeyer" -__copyright__ = "Copyright (c) 2005-2014 - Gustavo Niemeyer " +__copyright__ = "Copyright (c) 2005-2018 - Gustavo Niemeyer " __credits__ = ["Sebastien Celles"] __license__ = "" -__version__ = "1.3.1" +__version__ = "1.3.2" __email__ = "gustavo@niemeyer.net" __status__ = "Development" __url__ = 'https://github.com/python-constraint/python-constraint' From 4a3aa84c7948d190e0c5924f2fcf0a88992ab5f2 Mon Sep 17 00:00:00 2001 From: scls19fr Date: Mon, 5 Nov 2018 08:42:07 +0100 Subject: [PATCH 2/8] Auto formatting with Black --- constraint/__init__.py | 156 ++++++++++++-------- constraint/compat.py | 2 +- constraint/version.py | 2 +- examples/crosswords/crosswords.py | 17 ++- examples/einstein/einstein.py | 198 ++++++++++++++------------ examples/queens/queens.py | 9 +- examples/rooks/rooks.py | 3 +- examples/studentdesks/studentdesks.py | 22 +-- examples/sudoku/sudoku.py | 61 +++++--- examples/wordmath/seisseisdoze.py | 16 ++- examples/wordmath/sendmoremoney.py | 36 +++-- examples/wordmath/twotwofour.py | 13 +- examples/xsum/xsum.py | 31 ++-- setup.py | 91 +++++------- tests/test_constraint.py | 79 ++++++---- tests/test_solvers.py | 8 +- tests/test_some_not_in_set.py | 91 ++++++------ 17 files changed, 475 insertions(+), 360 deletions(-) diff --git a/constraint/__init__.py b/constraint/__init__.py index 7932aa3..50e8908 100644 --- a/constraint/__init__.py +++ b/constraint/__init__.py @@ -47,20 +47,42 @@ from __future__ import absolute_import, division, print_function -from .version import (__author__, __copyright__, __credits__, __license__, # noqa - __version__, __email__, __status__, __url__) # noqa +from .version import ( + __author__, + __copyright__, + __credits__, + __license__, # noqa + __version__, + __email__, + __status__, + __url__, +) # noqa import random import copy from .compat import xrange -__all__ = ["Problem", "Variable", "Domain", "Unassigned", - "Solver", "BacktrackingSolver", "RecursiveBacktrackingSolver", - "MinConflictsSolver", "Constraint", "FunctionConstraint", - "AllDifferentConstraint", "AllEqualConstraint", "MaxSumConstraint", - "ExactSumConstraint", "MinSumConstraint", "InSetConstraint", - "NotInSetConstraint", "SomeInSetConstraint", - "SomeNotInSetConstraint"] +__all__ = [ + "Problem", + "Variable", + "Domain", + "Unassigned", + "Solver", + "BacktrackingSolver", + "RecursiveBacktrackingSolver", + "MinConflictsSolver", + "Constraint", + "FunctionConstraint", + "AllDifferentConstraint", + "AllEqualConstraint", + "MaxSumConstraint", + "ExactSumConstraint", + "MinSumConstraint", + "InSetConstraint", + "NotInSetConstraint", + "SomeInSetConstraint", + "SomeNotInSetConstraint", +] class Problem(object): @@ -145,7 +167,7 @@ def addVariable(self, variable, domain): if variable in self._variables: msg = "Tried to insert duplicated variable %s" % repr(variable) raise ValueError(msg) - if hasattr(domain, '__getitem__'): + if hasattr(domain, "__getitem__"): domain = Domain(domain) elif isinstance(domain, Domain): domain = copy.copy(domain) @@ -204,8 +226,7 @@ def addConstraint(self, constraint, variables=None): if callable(constraint): constraint = FunctionConstraint(constraint) else: - msg = "Constraints must be instances of subclasses "\ - "of the Constraint class" + msg = "Constraints must be instances of subclasses " "of the Constraint class" raise ValueError(msg) self._constraints.append((constraint, variables)) @@ -272,8 +293,7 @@ def getSolutionIter(self): domains, constraints, vconstraints = self._getArgs() if not domains: return iter(()) - return self._solver.getSolutionIter(domains, constraints, - vconstraints) + return self._solver.getSolutionIter(domains, constraints, vconstraints) def _getArgs(self): domains = self._variables.copy() @@ -290,8 +310,7 @@ def _getArgs(self): for variable in variables: vconstraints[variable].append((constraint, variables)) for constraint, variables in constraints[:]: - constraint.preProcess(variables, domains, - constraints, vconstraints) + constraint.preProcess(variables, domains, constraints, vconstraints) for domain in domains.values(): domain.resetState() if not domain: @@ -299,6 +318,7 @@ def _getArgs(self): # doArc8(getArcs(domains, constraints), domains, {}) return domains, constraints, vconstraints + # ---------------------------------------------------------------------- # Solvers # ---------------------------------------------------------------------- @@ -315,12 +335,8 @@ def getArcs(domains, constraints): constraint, variables = x if len(variables) == 2: variable1, variable2 = variables - arcs.setdefault(variable1, {})\ - .setdefault(variable2, [])\ - .append(x) - arcs.setdefault(variable2, {})\ - .setdefault(variable1, [])\ - .append(x) + arcs.setdefault(variable1, {}).setdefault(variable2, []).append(x) + arcs.setdefault(variable2, {}).setdefault(variable1, []).append(x) return arcs @@ -351,8 +367,9 @@ def doArc8(arcs, domains, assignments): for othervalue in otherdomain: assignments[othervariable] = othervalue for constraint, variables in arcconstraints: - if not constraint(variables, domains, - assignments, True): + if not constraint( + variables, domains, assignments, True + ): break else: # All constraints passed. Value is safe. @@ -472,8 +489,10 @@ def getSolutionIter(self, domains, constraints, vconstraints): while True: # Mix the Degree and Minimum Remaing Values (MRV) heuristics - lst = [(-len(vconstraints[variable]), - len(domains[variable]), variable) for variable in domains] + lst = [ + (-len(vconstraints[variable]), len(domains[variable]), variable) + for variable in domains + ] lst.sort() for item in lst: if item[-1] not in assignments: @@ -481,8 +500,11 @@ def getSolutionIter(self, domains, constraints, vconstraints): variable = item[-1] values = domains[variable][:] if forwardcheck: - pushdomains = [domains[x] for x in domains - if x not in assignments and x != variable] + pushdomains = [ + domains[x] + for x in domains + if x not in assignments and x != variable + ] else: pushdomains = None break @@ -521,8 +543,7 @@ def getSolutionIter(self, domains, constraints, vconstraints): domain.pushState() for constraint, variables in vconstraints[variable]: - if not constraint(variables, domains, assignments, - pushdomains): + if not constraint(variables, domains, assignments, pushdomains): # Value is not good. break else: @@ -587,12 +608,15 @@ def __init__(self, forwardcheck=True): """ self._forwardcheck = forwardcheck - def recursiveBacktracking(self, solutions, domains, vconstraints, - assignments, single): + def recursiveBacktracking( + self, solutions, domains, vconstraints, assignments, single + ): # Mix the Degree and Minimum Remaing Values (MRV) heuristics - lst = [(-len(vconstraints[variable]), - len(domains[variable]), variable) for variable in domains] + lst = [ + (-len(vconstraints[variable]), len(domains[variable]), variable) + for variable in domains + ] lst.sort() for item in lst: if item[-1] not in assignments: @@ -618,14 +642,14 @@ def recursiveBacktracking(self, solutions, domains, vconstraints, for domain in pushdomains: domain.pushState() for constraint, variables in vconstraints[variable]: - if not constraint(variables, domains, assignments, - pushdomains): + if not constraint(variables, domains, assignments, pushdomains): # Value is not good. break else: # Value is good. Recurse and get next variable. - self.recursiveBacktracking(solutions, domains, vconstraints, - assignments, single) + self.recursiveBacktracking( + solutions, domains, vconstraints, assignments, single + ) if solutions and single: return solutions if pushdomains: @@ -635,13 +659,11 @@ def recursiveBacktracking(self, solutions, domains, vconstraints, return solutions def getSolution(self, domains, constraints, vconstraints): - solutions = self.recursiveBacktracking([], domains, vconstraints, - {}, True) + solutions = self.recursiveBacktracking([], domains, vconstraints, {}, True) return solutions and solutions[0] or None def getSolutions(self, domains, constraints, vconstraints): - return self.recursiveBacktracking([], domains, vconstraints, - {}, False) + return self.recursiveBacktracking([], domains, vconstraints, {}, False) class MinConflictsSolver(Solver): @@ -719,6 +741,7 @@ def getSolution(self, domains, constraints, vconstraints): return assignments return None + # ---------------------------------------------------------------------- # Variables # ---------------------------------------------------------------------- @@ -809,6 +832,7 @@ def hideValue(self, value): list.remove(self, value) self._hidden.append(value) + # ---------------------------------------------------------------------- # Constraints # ---------------------------------------------------------------------- @@ -876,8 +900,7 @@ def preProcess(self, variables, domains, constraints, vconstraints): constraints.remove((self, variables)) vconstraints[variable].remove((self, variables)) - def forwardCheck(self, variables, domains, assignments, - _unassigned=Unassigned): + def forwardCheck(self, variables, domains, assignments, _unassigned=Unassigned): """ Helper method for generic forward checking @@ -953,14 +976,22 @@ def __init__(self, func, assigned=True): self._func = func self._assigned = assigned - def __call__(self, variables, domains, assignments, forwardcheck=False, - _unassigned=Unassigned): + def __call__( + self, + variables, + domains, + assignments, + forwardcheck=False, + _unassigned=Unassigned, + ): parms = [assignments.get(x, _unassigned) for x in variables] missing = parms.count(_unassigned) if missing: - return ((self._assigned or self._func(*parms)) and - (not forwardcheck or missing != 1 or - self.forwardCheck(variables, domains, assignments))) + return (self._assigned or self._func(*parms)) and ( + not forwardcheck + or missing != 1 + or self.forwardCheck(variables, domains, assignments) + ) return self._func(*parms) @@ -977,8 +1008,14 @@ class AllDifferentConstraint(Constraint): [[('a', 1), ('b', 2)], [('a', 2), ('b', 1)]] """ - def __call__(self, variables, domains, assignments, forwardcheck=False, - _unassigned=Unassigned): + def __call__( + self, + variables, + domains, + assignments, + forwardcheck=False, + _unassigned=Unassigned, + ): seen = {} for variable in variables: value = assignments.get(variable, _unassigned) @@ -1011,8 +1048,14 @@ class AllEqualConstraint(Constraint): [[('a', 1), ('b', 1)], [('a', 2), ('b', 2)]] """ - def __call__(self, variables, domains, assignments, forwardcheck=False, - _unassigned=Unassigned): + def __call__( + self, + variables, + domains, + assignments, + forwardcheck=False, + _unassigned=Unassigned, + ): singlevalue = _unassigned for variable in variables: value = assignments.get(variable, _unassigned) @@ -1058,8 +1101,7 @@ def __init__(self, maxsum, multipliers=None): self._multipliers = multipliers def preProcess(self, variables, domains, constraints, vconstraints): - Constraint.preProcess(self, variables, domains, - constraints, vconstraints) + Constraint.preProcess(self, variables, domains, constraints, vconstraints) multipliers = self._multipliers maxsum = self._maxsum if multipliers: @@ -1142,8 +1184,7 @@ def __init__(self, exactsum, multipliers=None): self._multipliers = multipliers def preProcess(self, variables, domains, constraints, vconstraints): - Constraint.preProcess(self, variables, domains, - constraints, vconstraints) + Constraint.preProcess(self, variables, domains, constraints, vconstraints) multipliers = self._multipliers exactsum = self._exactsum if multipliers: @@ -1458,4 +1499,5 @@ def __call__(self, variables, domains, assignments, forwardcheck=False): if __name__ == "__main__": import doctest + doctest.testmod() diff --git a/constraint/compat.py b/constraint/compat.py index ef31a00..c20c223 100644 --- a/constraint/compat.py +++ b/constraint/compat.py @@ -4,7 +4,7 @@ import sys PY2 = sys.version_info[0] == 2 -PY3 = (sys.version_info[0] >= 3) +PY3 = sys.version_info[0] >= 3 if PY3: string_types = str diff --git a/constraint/version.py b/constraint/version.py index 7ad1c2f..2c86351 100644 --- a/constraint/version.py +++ b/constraint/version.py @@ -5,4 +5,4 @@ __version__ = "1.3.2" __email__ = "gustavo@niemeyer.net" __status__ = "Development" -__url__ = 'https://github.com/python-constraint/python-constraint' +__url__ = "https://github.com/python-constraint/python-constraint" diff --git a/examples/crosswords/crosswords.py b/examples/crosswords/crosswords.py index df0fce6..dc9b79d 100755 --- a/examples/crosswords/crosswords.py +++ b/examples/crosswords/crosswords.py @@ -72,21 +72,24 @@ def main(puzzle, lines): if hchar in vword: hci = hword.index(hchar) vci = vword.index(hchar) - problem.addConstraint(lambda hw, vw, hci=hci, vci=vci: - hw[hci] == vw[vci], - ("h%d" % hi, "v%d" % vi)) + problem.addConstraint( + lambda hw, vw, hci=hci, vci=vci: hw[hci] == vw[vci], + ("h%d" % hi, "v%d" % vi), + ) for char, letter in predefined.items(): for hi, hword in enumerate(horizontal): if char in hword: hci = hword.index(char) - problem.addConstraint(lambda hw, hci=hci, letter=letter: - hw[hci] == letter, ("h%d" % hi,)) + problem.addConstraint( + lambda hw, hci=hci, letter=letter: hw[hci] == letter, ("h%d" % hi,) + ) for vi, vword in enumerate(vertical): if char in vword: vci = vword.index(char) - problem.addConstraint(lambda vw, vci=vci, letter=letter: - vw[vci] == letter, ("v%d" % vi,)) + problem.addConstraint( + lambda vw, vci=vci, letter=letter: vw[vci] == letter, ("v%d" % vi,) + ) wordsbylen = {} for hword in horizontal: diff --git a/examples/einstein/einstein.py b/examples/einstein/einstein.py index 2ce6e45..ee6cae1 100755 --- a/examples/einstein/einstein.py +++ b/examples/einstein/einstein.py @@ -43,143 +43,155 @@ def solve(): problem = Problem() for i in range(1, 6): - problem.addVariable("color%d" % i, - ["red", "white", "green", "yellow", "blue"]) - problem.addVariable("nationality%d" % i, - ["brit", "swede", "dane", "norwegian", "german"]) - problem.addVariable("drink%d" % i, - ["tea", "coffee", "milk", "beer", "water"]) - problem.addVariable("smoke%d" % i, - ["pallmall", "dunhill", "blends", - "bluemaster", "prince"]) - problem.addVariable("pet%d" % i, - ["dogs", "birds", "cats", "horses", "fish"]) - - problem.addConstraint(AllDifferentConstraint(), - ["color%d" % i for i in range(1, 6)]) - problem.addConstraint(AllDifferentConstraint(), - ["nationality%d" % i for i in range(1, 6)]) - problem.addConstraint(AllDifferentConstraint(), - ["drink%d" % i for i in range(1, 6)]) - problem.addConstraint(AllDifferentConstraint(), - ["smoke%d" % i for i in range(1, 6)]) - problem.addConstraint(AllDifferentConstraint(), - ["pet%d" % i for i in range(1, 6)]) + problem.addVariable("color%d" % i, ["red", "white", "green", "yellow", "blue"]) + problem.addVariable( + "nationality%d" % i, ["brit", "swede", "dane", "norwegian", "german"] + ) + problem.addVariable("drink%d" % i, ["tea", "coffee", "milk", "beer", "water"]) + problem.addVariable( + "smoke%d" % i, ["pallmall", "dunhill", "blends", "bluemaster", "prince"] + ) + problem.addVariable("pet%d" % i, ["dogs", "birds", "cats", "horses", "fish"]) + + problem.addConstraint( + AllDifferentConstraint(), ["color%d" % i for i in range(1, 6)] + ) + problem.addConstraint( + AllDifferentConstraint(), ["nationality%d" % i for i in range(1, 6)] + ) + problem.addConstraint( + AllDifferentConstraint(), ["drink%d" % i for i in range(1, 6)] + ) + problem.addConstraint( + AllDifferentConstraint(), ["smoke%d" % i for i in range(1, 6)] + ) + problem.addConstraint(AllDifferentConstraint(), ["pet%d" % i for i in range(1, 6)]) for i in range(1, 6): # Hint 1 - problem.addConstraint(lambda nationality, color: - nationality != "brit" or color == "red", - ("nationality%d" % i, "color%d" % i)) + problem.addConstraint( + lambda nationality, color: nationality != "brit" or color == "red", + ("nationality%d" % i, "color%d" % i), + ) # Hint 2 - problem.addConstraint(lambda nationality, pet: - nationality != "swede" or pet == "dogs", - ("nationality%d" % i, "pet%d" % i)) + problem.addConstraint( + lambda nationality, pet: nationality != "swede" or pet == "dogs", + ("nationality%d" % i, "pet%d" % i), + ) # Hint 3 - problem.addConstraint(lambda nationality, drink: - nationality != "dane" or drink == "tea", - ("nationality%d" % i, "drink%d" % i)) + problem.addConstraint( + lambda nationality, drink: nationality != "dane" or drink == "tea", + ("nationality%d" % i, "drink%d" % i), + ) # Hint 4 if i < 5: - problem.addConstraint(lambda colora, colorb: - colora != "green" or colorb == "white", - ("color%d" % i, "color%d" % (i + 1))) + problem.addConstraint( + lambda colora, colorb: colora != "green" or colorb == "white", + ("color%d" % i, "color%d" % (i + 1)), + ) else: - problem.addConstraint(lambda color: color != "green", - ("color%d" % i,)) + problem.addConstraint(lambda color: color != "green", ("color%d" % i,)) # Hint 5 - problem.addConstraint(lambda color, drink: - color != "green" or drink == "coffee", - ("color%d" % i, "drink%d" % i)) + problem.addConstraint( + lambda color, drink: color != "green" or drink == "coffee", + ("color%d" % i, "drink%d" % i), + ) # Hint 6 - problem.addConstraint(lambda smoke, pet: - smoke != "pallmall" or pet == "birds", - ("smoke%d" % i, "pet%d" % i)) + problem.addConstraint( + lambda smoke, pet: smoke != "pallmall" or pet == "birds", + ("smoke%d" % i, "pet%d" % i), + ) # Hint 7 - problem.addConstraint(lambda color, smoke: - color != "yellow" or smoke == "dunhill", - ("color%d" % i, "smoke%d" % i)) + problem.addConstraint( + lambda color, smoke: color != "yellow" or smoke == "dunhill", + ("color%d" % i, "smoke%d" % i), + ) # Hint 8 if i == 3: - problem.addConstraint(lambda drink: drink == "milk", - ("drink%d" % i,)) + problem.addConstraint(lambda drink: drink == "milk", ("drink%d" % i,)) # Hint 9 if i == 1: - problem.addConstraint(lambda nationality: - nationality == "norwegian", - ("nationality%d" % i,)) + problem.addConstraint( + lambda nationality: nationality == "norwegian", ("nationality%d" % i,) + ) # Hint 10 if 1 < i < 5: - problem.addConstraint(lambda smoke, peta, petb: - smoke != "blends" or peta == "cats" or - petb == "cats", - ("smoke%d" % i, "pet%d" % (i - 1), - "pet%d" % (i + 1))) + problem.addConstraint( + lambda smoke, peta, petb: smoke != "blends" + or peta == "cats" + or petb == "cats", + ("smoke%d" % i, "pet%d" % (i - 1), "pet%d" % (i + 1)), + ) else: - problem.addConstraint(lambda smoke, pet: - smoke != "blends" or pet == "cats", - ("smoke%d" % i, - "pet%d" % (i == 1 and 2 or 4))) + problem.addConstraint( + lambda smoke, pet: smoke != "blends" or pet == "cats", + ("smoke%d" % i, "pet%d" % (i == 1 and 2 or 4)), + ) # Hint 11 if 1 < i < 5: - problem.addConstraint(lambda pet, smokea, smokeb: - pet != "horses" or smokea == "dunhill" or - smokeb == "dunhill", - ("pet%d" % i, "smoke%d" % (i - 1), - "smoke%d" % (i + 1))) + problem.addConstraint( + lambda pet, smokea, smokeb: pet != "horses" + or smokea == "dunhill" + or smokeb == "dunhill", + ("pet%d" % i, "smoke%d" % (i - 1), "smoke%d" % (i + 1)), + ) else: - problem.addConstraint(lambda pet, smoke: - pet != "horses" or smoke == "dunhill", - ("pet%d" % i, - "smoke%d" % (i == 1 and 2 or 4))) + problem.addConstraint( + lambda pet, smoke: pet != "horses" or smoke == "dunhill", + ("pet%d" % i, "smoke%d" % (i == 1 and 2 or 4)), + ) # Hint 12 - problem.addConstraint(lambda smoke, drink: - smoke != "bluemaster" or drink == "beer", - ("smoke%d" % i, "drink%d" % i)) + problem.addConstraint( + lambda smoke, drink: smoke != "bluemaster" or drink == "beer", + ("smoke%d" % i, "drink%d" % i), + ) # Hint 13 - problem.addConstraint(lambda nationality, smoke: - nationality != "german" or smoke == "prince", - ("nationality%d" % i, "smoke%d" % i)) + problem.addConstraint( + lambda nationality, smoke: nationality != "german" or smoke == "prince", + ("nationality%d" % i, "smoke%d" % i), + ) # Hint 14 if 1 < i < 5: - problem.addConstraint(lambda nationality, colora, colorb: - nationality != "norwegian" or - colora == "blue" or colorb == "blue", - ("nationality%d" % i, "color%d" % (i - 1), - "color%d" % (i + 1))) + problem.addConstraint( + lambda nationality, colora, colorb: nationality != "norwegian" + or colora == "blue" + or colorb == "blue", + ("nationality%d" % i, "color%d" % (i - 1), "color%d" % (i + 1)), + ) else: - problem.addConstraint(lambda nationality, color: - nationality != "norwegian" or - color == "blue", - ("nationality%d" % i, - "color%d" % (i == 1 and 2 or 4))) + problem.addConstraint( + lambda nationality, color: nationality != "norwegian" + or color == "blue", + ("nationality%d" % i, "color%d" % (i == 1 and 2 or 4)), + ) # Hint 15 if 1 < i < 5: - problem.addConstraint(lambda smoke, drinka, drinkb: - smoke != "blends" or - drinka == "water" or drinkb == "water", - ("smoke%d" % i, "drink%d" % (i - 1), - "drink%d" % (i + 1))) + problem.addConstraint( + lambda smoke, drinka, drinkb: smoke != "blends" + or drinka == "water" + or drinkb == "water", + ("smoke%d" % i, "drink%d" % (i - 1), "drink%d" % (i + 1)), + ) else: - problem.addConstraint(lambda smoke, drink: - smoke != "blends" or drink == "water", - ("smoke%d" % i, - "drink%d" % (i == 1 and 2 or 4))) + problem.addConstraint( + lambda smoke, drink: smoke != "blends" or drink == "water", + ("smoke%d" % i, "drink%d" % (i == 1 and 2 or 4)), + ) solutions = problem.getSolutions() return solutions diff --git a/examples/queens/queens.py b/examples/queens/queens.py index 88aa565..8d1f082 100755 --- a/examples/queens/queens.py +++ b/examples/queens/queens.py @@ -15,9 +15,12 @@ def solve(): for col1 in cols: for col2 in cols: if col1 < col2: - problem.addConstraint(lambda row1, row2, col1=col1, col2=col2: - abs(row1 - row2) != abs(col1 - col2) and - row1 != row2, (col1, col2)) + problem.addConstraint( + lambda row1, row2, col1=col1, col2=col2: abs(row1 - row2) + != abs(col1 - col2) + and row1 != row2, + (col1, col2), + ) solutions = problem.getSolutions() return solutions, size diff --git a/examples/rooks/rooks.py b/examples/rooks/rooks.py index a797901..7422e44 100755 --- a/examples/rooks/rooks.py +++ b/examples/rooks/rooks.py @@ -18,8 +18,7 @@ def solve(size): for col1 in cols: for col2 in cols: if col1 < col2: - problem.addConstraint(lambda row1, row2: row1 != row2, - (col1, col2)) + problem.addConstraint(lambda row1, row2: row1 != row2, (col1, col2)) solutions = problem.getSolutions() return solutions diff --git a/examples/studentdesks/studentdesks.py b/examples/studentdesks/studentdesks.py index a2978ec..0d9e294 100755 --- a/examples/studentdesks/studentdesks.py +++ b/examples/studentdesks/studentdesks.py @@ -5,12 +5,14 @@ from constraint import Problem, AllDifferentConstraint, SomeInSetConstraint import sys -STUDENTDESKS = [[0, 1, 0, 0, 0, 0], - [0, 2, 3, 4, 5, 6], - [0, 7, 8, 9, 10, 0], - [0, 11, 12, 13, 14, 0], - [15, 16, 17, 18, 19, 0], - [0, 0, 0, 0, 20, 0]] +STUDENTDESKS = [ + [0, 1, 0, 0, 0, 0], + [0, 2, 3, 4, 5, 6], + [0, 7, 8, 9, 10, 0], + [0, 11, 12, 13, 14, 0], + [15, 16, 17, 18, 19, 0], + [0, 0, 0, 0, 20, 0], +] def solve(): @@ -23,8 +25,12 @@ def solve(): problem.addConstraint(SomeInSetConstraint(["E"], 4, True)) for row in range(len(STUDENTDESKS) - 1): for col in range(len(STUDENTDESKS[row]) - 1): - lst = [STUDENTDESKS[row][col], STUDENTDESKS[row][col + 1], - STUDENTDESKS[row + 1][col], STUDENTDESKS[row + 1][col + 1]] + lst = [ + STUDENTDESKS[row][col], + STUDENTDESKS[row][col + 1], + STUDENTDESKS[row + 1][col], + STUDENTDESKS[row + 1][col + 1], + ] lst = [x for x in lst if x] problem.addConstraint(AllDifferentConstraint(), lst) solutions = problem.getSolution() diff --git a/examples/sudoku/sudoku.py b/examples/sudoku/sudoku.py index 820c76d..6be0a6f 100644 --- a/examples/sudoku/sudoku.py +++ b/examples/sudoku/sudoku.py @@ -21,34 +21,55 @@ def solve(): problem.addConstraint(AllDifferentConstraint(), range(10 + i, 100 + i, 10)) # Each 3x3 box has different values - problem.addConstraint(AllDifferentConstraint(), [11, 12, 13, 21, 22, 23, 31, 32, 33]) - problem.addConstraint(AllDifferentConstraint(), [41, 42, 43, 51, 52, 53, 61, 62, 63]) - problem.addConstraint(AllDifferentConstraint(), [71, 72, 73, 81, 82, 83, 91, 92, 93]) + problem.addConstraint( + AllDifferentConstraint(), [11, 12, 13, 21, 22, 23, 31, 32, 33] + ) + problem.addConstraint( + AllDifferentConstraint(), [41, 42, 43, 51, 52, 53, 61, 62, 63] + ) + problem.addConstraint( + AllDifferentConstraint(), [71, 72, 73, 81, 82, 83, 91, 92, 93] + ) - problem.addConstraint(AllDifferentConstraint(), [14, 15, 16, 24, 25, 26, 34, 35, 36]) - problem.addConstraint(AllDifferentConstraint(), [44, 45, 46, 54, 55, 56, 64, 65, 66]) - problem.addConstraint(AllDifferentConstraint(), [74, 75, 76, 84, 85, 86, 94, 95, 96]) + problem.addConstraint( + AllDifferentConstraint(), [14, 15, 16, 24, 25, 26, 34, 35, 36] + ) + problem.addConstraint( + AllDifferentConstraint(), [44, 45, 46, 54, 55, 56, 64, 65, 66] + ) + problem.addConstraint( + AllDifferentConstraint(), [74, 75, 76, 84, 85, 86, 94, 95, 96] + ) - problem.addConstraint(AllDifferentConstraint(), [17, 18, 19, 27, 28, 29, 37, 38, 39]) - problem.addConstraint(AllDifferentConstraint(), [47, 48, 49, 57, 58, 59, 67, 68, 69]) - problem.addConstraint(AllDifferentConstraint(), [77, 78, 79, 87, 88, 89, 97, 98, 99]) + problem.addConstraint( + AllDifferentConstraint(), [17, 18, 19, 27, 28, 29, 37, 38, 39] + ) + problem.addConstraint( + AllDifferentConstraint(), [47, 48, 49, 57, 58, 59, 67, 68, 69] + ) + problem.addConstraint( + AllDifferentConstraint(), [77, 78, 79, 87, 88, 89, 97, 98, 99] + ) # Some value is given. - initValue = [[0, 9, 0, 7, 0, 0, 8, 6, 0], - [0, 3, 1, 0, 0, 5, 0, 2, 0], - [8, 0, 6, 0, 0, 0, 0, 0, 0], - [0, 0, 7, 0, 5, 0, 0, 0, 6], - [0, 0, 0, 3, 0, 7, 0, 0, 0], - [5, 0, 0, 0, 1, 0, 7, 0, 0], - [0, 0, 0, 0, 0, 0, 1, 0, 9], - [0, 2, 0, 6, 0, 0, 0, 5, 0], - [0, 5, 4, 0, 0, 8, 0, 7, 0]] + initValue = [ + [0, 9, 0, 7, 0, 0, 8, 6, 0], + [0, 3, 1, 0, 0, 5, 0, 2, 0], + [8, 0, 6, 0, 0, 0, 0, 0, 0], + [0, 0, 7, 0, 5, 0, 0, 0, 6], + [0, 0, 0, 3, 0, 7, 0, 0, 0], + [5, 0, 0, 0, 1, 0, 7, 0, 0], + [0, 0, 0, 0, 0, 0, 1, 0, 9], + [0, 2, 0, 6, 0, 0, 0, 5, 0], + [0, 5, 4, 0, 0, 8, 0, 7, 0], + ] for i in range(1, 10): for j in range(1, 10): if initValue[i - 1][j - 1] != 0: - problem.addConstraint(lambda var, val=initValue[i - 1][j - 1]: - var == val, (i * 10 + j,)) + problem.addConstraint( + lambda var, val=initValue[i - 1][j - 1]: var == val, (i * 10 + j,) + ) # Get the solutions. solutions = problem.getSolutions() diff --git a/examples/wordmath/seisseisdoze.py b/examples/wordmath/seisseisdoze.py index 22776db..998f586 100755 --- a/examples/wordmath/seisseisdoze.py +++ b/examples/wordmath/seisseisdoze.py @@ -15,11 +15,14 @@ def solve(): problem = Problem() problem.addVariables("seidoz", range(10)) problem.addConstraint(lambda s, e: (2 * s) % 10 == e, "se") - problem.addConstraint(lambda i, s, z, e: ((10 * 2 * i) + (2 * s)) % 100 == - z * 10 + e, "isze") - problem.addConstraint(lambda s, e, i, d, o, z: - 2 * (s * 1000 + e * 100 + i * 10 + s) == - d * 1000 + o * 100 + z * 10 + e, "seidoz") + problem.addConstraint( + lambda i, s, z, e: ((10 * 2 * i) + (2 * s)) % 100 == z * 10 + e, "isze" + ) + problem.addConstraint( + lambda s, e, i, d, o, z: 2 * (s * 1000 + e * 100 + i * 10 + s) + == d * 1000 + o * 100 + z * 10 + e, + "seidoz", + ) problem.addConstraint(lambda s: s != 0, "s") problem.addConstraint(lambda d: d != 0, "d") problem.addConstraint(AllDifferentConstraint()) @@ -31,8 +34,7 @@ def main(): solutions = solve() print("SEIS+SEIS=DOZE") for s in solutions: - print("%(s)d%(e)d%(i)d%(s)s+%(s)d%(e)d%(i)d%(s)d=" - "%(d)d%(o)d%(z)d%(e)d") % s + print("%(s)d%(e)d%(i)d%(s)s+%(s)d%(e)d%(i)d%(s)d=" "%(d)d%(o)d%(z)d%(e)d") % s if __name__ == "__main__": diff --git a/examples/wordmath/sendmoremoney.py b/examples/wordmath/sendmoremoney.py index 9e9578e..f118d2d 100755 --- a/examples/wordmath/sendmoremoney.py +++ b/examples/wordmath/sendmoremoney.py @@ -15,14 +15,26 @@ def solve(): problem = Problem() problem.addVariables("sendmory", range(10)) problem.addConstraint(lambda d, e, y: (d + e) % 10 == y, "dey") - problem.addConstraint(lambda n, d, r, e, y: (n * 10 + d + r * 10 + e) % 100 == - e * 10 + y, "ndrey") - problem.addConstraint(lambda e, n, d, o, r, y: - (e * 100 + n * 10 + d + o * 100 + r * 10 + e) % 1000 == - n * 100 + e * 10 + y, "endory") - problem.addConstraint(lambda s, e, n, d, m, o, r, y: - 1000 * s + 100 * e + 10 * n + d + 1000 * m + 100 * o + 10 * r + e == - 10000 * m + 1000 * o + 100 * n + 10 * e + y, "sendmory") + problem.addConstraint( + lambda n, d, r, e, y: (n * 10 + d + r * 10 + e) % 100 == e * 10 + y, "ndrey" + ) + problem.addConstraint( + lambda e, n, d, o, r, y: (e * 100 + n * 10 + d + o * 100 + r * 10 + e) % 1000 + == n * 100 + e * 10 + y, + "endory", + ) + problem.addConstraint( + lambda s, e, n, d, m, o, r, y: 1000 * s + + 100 * e + + 10 * n + + d + + 1000 * m + + 100 * o + + 10 * r + + e + == 10000 * m + 1000 * o + 100 * n + 10 * e + y, + "sendmory", + ) problem.addConstraint(NotInSetConstraint([0]), "sm") problem.addConstraint(AllDifferentConstraint()) solutions = problem.getSolutions() @@ -33,9 +45,11 @@ def main(): solutions = solve() print("SEND+MORE=MONEY") for s in solutions: - print("%(s)d%(e)d%(n)d%(d)d+" - "%(m)d%(o)d%(r)d%(e)d=" - "%(m)d%(o)d%(n)d%(e)d%(y)d" % s) + print( + "%(s)d%(e)d%(n)d%(d)d+" + "%(m)d%(o)d%(r)d%(e)d=" + "%(m)d%(o)d%(n)d%(e)d%(y)d" % s + ) if __name__ == "__main__": diff --git a/examples/wordmath/twotwofour.py b/examples/wordmath/twotwofour.py index 33e4aab..f86d56e 100755 --- a/examples/wordmath/twotwofour.py +++ b/examples/wordmath/twotwofour.py @@ -15,11 +15,14 @@ def solve(): problem = Problem() problem.addVariables("twofur", range(10)) problem.addConstraint(lambda o, r: (2 * o) % 10 == r, "or") - problem.addConstraint(lambda w, o, u, - r: ((10 * 2 * w) + (2 * o)) % 100 == u * 10 + r, "wour") - problem.addConstraint(lambda t, w, o, f, u, r: - 2 * (t * 100 + w * 10 + o) == - f * 1000 + o * 100 + u * 10 + r, "twofur") + problem.addConstraint( + lambda w, o, u, r: ((10 * 2 * w) + (2 * o)) % 100 == u * 10 + r, "wour" + ) + problem.addConstraint( + lambda t, w, o, f, u, r: 2 * (t * 100 + w * 10 + o) + == f * 1000 + o * 100 + u * 10 + r, + "twofur", + ) problem.addConstraint(NotInSetConstraint([0]), "ft") problem.addConstraint(AllDifferentConstraint()) solutions = problem.getSolutions() diff --git a/examples/xsum/xsum.py b/examples/xsum/xsum.py index 987438f..d6d055d 100755 --- a/examples/xsum/xsum.py +++ b/examples/xsum/xsum.py @@ -15,10 +15,12 @@ def solve(): problem = Problem() problem.addVariables("abcdxefgh", range(1, 10)) - problem.addConstraint(lambda a, b, c, d, x: - a < b < c < d and a + b + c + d + x == 27, "abcdx") - problem.addConstraint(lambda e, f, g, h, x: - e < f < g < h and e + f + g + h + x == 27, "efghx") + problem.addConstraint( + lambda a, b, c, d, x: a < b < c < d and a + b + c + d + x == 27, "abcdx" + ) + problem.addConstraint( + lambda e, f, g, h, x: e < f < g < h and e + f + g + h + x == 27, "efghx" + ) problem.addConstraint(AllDifferentConstraint()) solutions = problem.getSolutions() return solutions @@ -32,16 +34,25 @@ def main(): def showSolutions(solutions): for solution in solutions: - print(""" %d %d + print( + """ %d %d %d %d %d %d %d %d %d -""" % (solution["a"], solution["e"], - solution["b"], solution["f"], - solution["x"], - solution["g"], solution["c"], - solution["h"], solution["d"])) +""" + % ( + solution["a"], + solution["e"], + solution["b"], + solution["f"], + solution["x"], + solution["g"], + solution["c"], + solution["h"], + solution["d"], + ) + ) if __name__ == "__main__": diff --git a/setup.py b/setup.py index 4a597e5..d1f4f53 100755 --- a/setup.py +++ b/setup.py @@ -6,118 +6,97 @@ from os import path import io -NAME = 'python-constraint' -filename = "%s/version.py" % 'constraint' +NAME = "python-constraint" +filename = "%s/version.py" % "constraint" with open(filename) as f: exec(f.read()) here = path.abspath(path.dirname(__file__)) + def readme(): - filename = path.join(here, 'README.rst') - with io.open(filename, 'rt', encoding='UTF-8') as f: + filename = path.join(here, "README.rst") + with io.open(filename, "rt", encoding="UTF-8") as f: return f.read() + setup( name=NAME, - # Versions should comply with PEP440. For a discussion on single-sourcing # the version across setup.py and the project code, see # https://packaging.python.org/en/latest/development.html#single-sourcing-the-version - #version='0.0.1', + # version='0.0.1', version=__version__, - - description="python-constraint is a module implementing support "\ - "for handling CSPs (Constraint Solving Problems) over finite domain", - + description="python-constraint is a module implementing support " + "for handling CSPs (Constraint Solving Problems) over finite domain", long_description=readme(), - # The project's main homepage. url=__url__, - # Author details author=__author__, author_email=__email__, - # Choose your license license=__license__, - # See https://pypi.python.org/pypi?%3Aaction=list_classifiers classifiers=[ # How mature is this project? Common values are # 3 - Alpha # 4 - Beta # 5 - Production/Stable - 'Development Status :: 3 - Alpha', - + "Development Status :: 3 - Alpha", # Indicate who your project is intended for - 'Environment :: Console', - #'Topic :: Software Development :: Build Tools', - 'Intended Audience :: Science/Research', - 'Operating System :: OS Independent', - + "Environment :: Console", + # 'Topic :: Software Development :: Build Tools', + "Intended Audience :: Science/Research", + "Operating System :: OS Independent", # Specify the Python versions you support here. In particular, ensure # that you indicate whether you support Python 2, Python 3 or both. - 'Programming Language :: Cython', - - 'Programming Language :: Python', - #'Programming Language :: Python :: 2', - #'Programming Language :: Python :: 2.6', - 'Programming Language :: Python :: 2.7', - #'Programming Language :: Python :: 3', - #'Programming Language :: Python :: 3.2', - 'Programming Language :: Python :: 3.3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - - 'Topic :: Scientific/Engineering', - + "Programming Language :: Cython", + "Programming Language :: Python", + # 'Programming Language :: Python :: 2', + # 'Programming Language :: Python :: 2.6', + "Programming Language :: Python :: 2.7", + # 'Programming Language :: Python :: 3', + # 'Programming Language :: Python :: 3.2', + "Programming Language :: Python :: 3.3", + "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Topic :: Scientific/Engineering", # Pick your license as you wish (should match "license" above) - 'License :: OSI Approved :: BSD License', - + "License :: OSI Approved :: BSD License", ], - # What does your project relate to? - keywords='csp constraint solving problems problem solver', - + keywords="csp constraint solving problems problem solver", # You can just specify the packages manually here if your project is # simple. Or you can use find_packages(). - packages=find_packages(exclude=['contrib', 'docs', 'tests*']), - + packages=find_packages(exclude=["contrib", "docs", "tests*"]), # List run-time dependencies here. These will be installed by pip when your # project is installed. For an analysis of "install_requires" vs pip's # requirements files see: # https://packaging.python.org/en/latest/technical.html#install-requires-vs-requirements-files install_requires=[], - # List additional groups of dependencies here (e.g. development dependencies). # You can install these using the following syntax, for example: # $ pip install -e .[dev,test] - extras_require = { - 'dev': ['check-manifest', 'nose'], - 'test': ['coverage', 'nose'], - }, - + extras_require={"dev": ["check-manifest", "nose"], "test": ["coverage", "nose"]}, # If there are data files included in your packages that need to be # installed, specify them here. If using Python 2.6 or less, then these # have to be included in MANIFEST.in as well. - #package_data={ + # package_data={ # 'sample': ['logging.conf'], - #}, - + # }, # Although 'package_data' is the preferred approach, in some case you may # need to place data files outside of your packages. # see http://docs.python.org/3.4/distutils/setupscript.html#installing-additional-files # In this case, 'data_file' will be installed into '/my_data' - #data_files=[('my_data', ['data/data_file'])], - + # data_files=[('my_data', ['data/data_file'])], # To provide executable scripts, use entry points in preference to the # "scripts" keyword. Entry points provide cross-platform support and allow # pip to create the appropriate form of executable for the target platform. - #entry_points={ + # entry_points={ # 'console_scripts': [ # 'sample=sample:main', # ], - #}, + # }, ) diff --git a/tests/test_constraint.py b/tests/test_constraint.py index e644bf4..d4ef738 100644 --- a/tests/test_constraint.py +++ b/tests/test_constraint.py @@ -2,11 +2,13 @@ from examples.abc import abc from examples.coins import coins + # from examples.crosswords import crosswords from examples.einstein import einstein from examples.queens import queens from examples.rooks import rooks from examples.studentdesks import studentdesks + # from examples.sudoku import sudoku # from examples.wordmath import (seisseisdoze, sendmoremoney, twotwofour) # from examples.xsum import xsum @@ -18,7 +20,7 @@ def test_abc(): solutions = abc.solve() minvalue, minsolution = solutions assert minvalue == 37 - assert minsolution == {'a': 1, 'c': 2, 'b': 1} + assert minsolution == {"a": 1, "c": 2, "b": 1} def test_coins(): @@ -30,31 +32,31 @@ def test_einstein(): solutions = einstein.solve() expected_solutions = [ { - 'nationality2': 'dane', - 'nationality3': 'brit', - 'nationality1': 'norwegian', - 'nationality4': 'german', - 'nationality5': 'swede', - 'color1': 'yellow', - 'color3': 'red', - 'color2': 'blue', - 'color5': 'white', - 'color4': 'green', - 'drink4': 'coffee', - 'drink5': 'beer', - 'drink1': 'water', - 'drink2': 'tea', - 'drink3': 'milk', - 'smoke5': 'bluemaster', - 'smoke4': 'prince', - 'smoke3': 'pallmall', - 'smoke2': 'blends', - 'smoke1': 'dunhill', - 'pet5': 'dogs', - 'pet4': 'fish', - 'pet1': 'cats', - 'pet3': 'birds', - 'pet2': 'horses' + "nationality2": "dane", + "nationality3": "brit", + "nationality1": "norwegian", + "nationality4": "german", + "nationality5": "swede", + "color1": "yellow", + "color3": "red", + "color2": "blue", + "color5": "white", + "color4": "green", + "drink4": "coffee", + "drink5": "beer", + "drink1": "water", + "drink2": "tea", + "drink3": "milk", + "smoke5": "bluemaster", + "smoke4": "prince", + "smoke3": "pallmall", + "smoke2": "blends", + "smoke1": "dunhill", + "pet5": "dogs", + "pet4": "fish", + "pet1": "cats", + "pet3": "birds", + "pet2": "horses", } ] assert solutions == expected_solutions @@ -75,7 +77,28 @@ def test_rooks(): def test_studentdesks(): solutions = studentdesks.solve() - expected_solutions = {1: 'A', 2: 'E', 3: 'D', 4: 'E', 5: 'D', 6: 'A', 7: 'C', 8: 'B', 9: 'C', 10: 'B', 11: 'E', 12: 'D', 13: 'E', 14: 'D', 15: 'A', 16: 'C', 17: 'B', 18: 'C', 19: 'B', 20: 'A'} + expected_solutions = { + 1: "A", + 2: "E", + 3: "D", + 4: "E", + 5: "D", + 6: "A", + 7: "C", + 8: "B", + 9: "C", + 10: "B", + 11: "E", + 12: "D", + 13: "E", + 14: "D", + 15: "A", + 16: "C", + 17: "B", + 18: "C", + 19: "B", + 20: "A", + } assert solutions == expected_solutions @@ -84,7 +107,7 @@ def test_constraint_without_variables(): problem.addVariable("a", [1, 2, 3]) problem.addConstraint(lambda a: a * 2 == 6) solutions = problem.getSolutions() - assert solutions == [{'a': 3}] + assert solutions == [{"a": 3}] def test_version(): diff --git a/tests/test_solvers.py b/tests/test_solvers.py index 1a24d38..3fac3c9 100644 --- a/tests/test_solvers.py +++ b/tests/test_solvers.py @@ -8,10 +8,10 @@ def test_min_conflicts_solver(): solution = problem.getSolution() possible_solutions = [ - {'x': 0, 'y': 0}, - {'x': 0, 'y': 1}, - {'x': 1, 'y': 0}, - {'x': 1, 'y': 1} + {"x": 0, "y": 0}, + {"x": 0, "y": 1}, + {"x": 1, "y": 0}, + {"x": 1, "y": 1}, ] assert solution in possible_solutions diff --git a/tests/test_some_not_in_set.py b/tests/test_some_not_in_set.py index 31ac4fc..c625285 100644 --- a/tests/test_some_not_in_set.py +++ b/tests/test_some_not_in_set.py @@ -3,100 +3,97 @@ def test_empty_constraint(): constrainer = SomeNotInSetConstraint(set()) - v1, v2 = variables = [Variable('v1'), Variable('v2')] - assignments = {v1: 'a', v2: 'b'} + v1, v2 = variables = [Variable("v1"), Variable("v2")] + assignments = {v1: "a", v2: "b"} assert constrainer(variables, {}, assignments) def test_no_overlap(): - constrainer = SomeNotInSetConstraint(set('zy')) - v1, v2 = variables = [Variable('v1'), Variable('v2')] - assignments = {v1: 'a', v2: 'b'} + constrainer = SomeNotInSetConstraint(set("zy")) + v1, v2 = variables = [Variable("v1"), Variable("v2")] + assignments = {v1: "a", v2: "b"} assert constrainer(variables, {}, assignments) def test_some_overlap(): - constrainer = SomeNotInSetConstraint(set('b')) - v1, v2 = variables = [Variable('v1'), Variable('v2')] - assignments = {v1: 'a', v2: 'b'} + constrainer = SomeNotInSetConstraint(set("b")) + v1, v2 = variables = [Variable("v1"), Variable("v2")] + assignments = {v1: "a", v2: "b"} assert constrainer(variables, {}, assignments) def test_too_much_overlap(): - constrainer = SomeNotInSetConstraint(set('ab')) - v1, v2 = variables = [Variable('v1'), Variable('v2')] - assignments = {v1: 'a', v2: 'b'} + constrainer = SomeNotInSetConstraint(set("ab")) + v1, v2 = variables = [Variable("v1"), Variable("v2")] + assignments = {v1: "a", v2: "b"} assert not constrainer(variables, {}, assignments) def test_exact(): - constrainer = SomeNotInSetConstraint(set('abc'), n=2, exact=True) - v1, v2, v3 = variables = [Variable('v1'), Variable('v2'), Variable('v3')] + constrainer = SomeNotInSetConstraint(set("abc"), n=2, exact=True) + v1, v2, v3 = variables = [Variable("v1"), Variable("v2"), Variable("v3")] - assignments = {v1: 'a', v2: 'y', v3: 'z'} + assignments = {v1: "a", v2: "y", v3: "z"} assert constrainer(variables, {}, assignments) - assignments = {v1: 'a', v2: 'y'} + assignments = {v1: "a", v2: "y"} assert constrainer(variables, {}, assignments) - assignments = {v1: 'a', v2: 'b', v3: 'z'} + assignments = {v1: "a", v2: "b", v3: "z"} assert not constrainer(variables, {}, assignments) - assignments = {v1: 'a', v2: 'b'} + assignments = {v1: "a", v2: "b"} assert not constrainer(variables, {}, assignments) - assignments = {v1: 'a', v2: 'b', v3: 'c'} + assignments = {v1: "a", v2: "b", v3: "c"} assert not constrainer(variables, {}, assignments) - assignments = {v1: 'x', v2: 'y', v3: 'z'} + assignments = {v1: "x", v2: "y", v3: "z"} assert not constrainer(variables, {}, assignments) def test_forwardcheck(): - constrainer = SomeNotInSetConstraint(set('abc'), n=2) - v1, v2, v3 = variables = [Variable('v1'), Variable('v2'), Variable('v3')] + constrainer = SomeNotInSetConstraint(set("abc"), n=2) + v1, v2, v3 = variables = [Variable("v1"), Variable("v2"), Variable("v3")] - domains = {v1: Domain(['a']), v2: Domain(['b', 'y']), - v3: Domain(['c', 'z'])} - assert constrainer(variables, domains, {v1: 'a'}) - assert ['a'] == list(domains[v1]) - assert ['b', 'y'] == list(domains[v2]) - assert ['c', 'z'] == list(domains[v3]) + domains = {v1: Domain(["a"]), v2: Domain(["b", "y"]), v3: Domain(["c", "z"])} + assert constrainer(variables, domains, {v1: "a"}) + assert ["a"] == list(domains[v1]) + assert ["b", "y"] == list(domains[v2]) + assert ["c", "z"] == list(domains[v3]) - assert constrainer(variables, domains, {v1: 'a'}, True) - assert ['a'] == list(domains[v1]) - assert ['y'] == list(domains[v2]) - assert ['z'] == list(domains[v3]) + assert constrainer(variables, domains, {v1: "a"}, True) + assert ["a"] == list(domains[v1]) + assert ["y"] == list(domains[v2]) + assert ["z"] == list(domains[v3]) def test_forwardcheck_empty_domain(): - constrainer = SomeNotInSetConstraint(set('abc')) - v1, v2 = variables = [Variable('v1'), Variable('v2')] + constrainer = SomeNotInSetConstraint(set("abc")) + v1, v2 = variables = [Variable("v1"), Variable("v2")] - domains = {v1: Domain(['a']), v2: Domain(['b'])} - assert constrainer(variables, domains, {v1: 'a'}) - assert not constrainer(variables, domains, {v1: 'a'}, True) + domains = {v1: Domain(["a"]), v2: Domain(["b"])} + assert constrainer(variables, domains, {v1: "a"}) + assert not constrainer(variables, domains, {v1: "a"}, True) def test_forwardcheck_exact(): - constrainer = SomeNotInSetConstraint(set('abc'), n=2, exact=True) - v1, v2, v3 = variables = [Variable('v1'), Variable('v2'), Variable('v3')] - assignments = {v1: 'a'} + constrainer = SomeNotInSetConstraint(set("abc"), n=2, exact=True) + v1, v2, v3 = variables = [Variable("v1"), Variable("v2"), Variable("v3")] + assignments = {v1: "a"} - domains = {v1: Domain(['a', 'x']), v2: Domain(['b', 'y']), - v3: Domain(['c', 'z'])} + domains = {v1: Domain(["a", "x"]), v2: Domain(["b", "y"]), v3: Domain(["c", "z"])} assert constrainer(variables, domains, assignments) assert constrainer(variables, domains, assignments, True) - assert 'b' not in domains[v2] - assert 'y' in domains[v2] - assert 'c' not in domains[v3] - assert 'z' in domains[v3] + assert "b" not in domains[v2] + assert "y" in domains[v2] + assert "c" not in domains[v3] + assert "z" in domains[v3] - domains = {v1: Domain(['a', 'x']), v2: Domain(['b', 'y']), - v3: Domain(['c'])} + domains = {v1: Domain(["a", "x"]), v2: Domain(["b", "y"]), v3: Domain(["c"])} assert constrainer(variables, domains, assignments) assert not constrainer(variables, domains, assignments, True) From 5aa4cf488f6479f759065647d3ec8d84b06cc150 Mon Sep 17 00:00:00 2001 From: scls19fr Date: Mon, 5 Nov 2018 08:44:56 +0100 Subject: [PATCH 3/8] noqa --- constraint/__init__.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/constraint/__init__.py b/constraint/__init__.py index 50e8908..99e2ff7 100644 --- a/constraint/__init__.py +++ b/constraint/__init__.py @@ -47,16 +47,14 @@ from __future__ import absolute_import, division, print_function -from .version import ( - __author__, - __copyright__, - __credits__, - __license__, # noqa - __version__, - __email__, - __status__, - __url__, -) # noqa +from .version import __author__ # noqa +from .version import __copyright__ # noqa +from .version import __credits__ # noqa +from .version import __license__ # noqa +from .version import __version__ # noqa +from .version import __email__ # noqa +from .version import __status__ # noqa +from .version import __url__ # noqa import random import copy From 33a0b356df176cd4425da08526277e05b7d17c91 Mon Sep 17 00:00:00 2001 From: scls19fr Date: Mon, 5 Nov 2018 08:58:09 +0100 Subject: [PATCH 4/8] Fix W503 line break before binary operator --- constraint/__init__.py | 6 +----- examples/einstein/einstein.py | 28 ++++++++++++++-------------- examples/queens/queens.py | 4 ++-- examples/wordmath/seisseisdoze.py | 4 ++-- examples/wordmath/sendmoremoney.py | 22 +++++++++++----------- examples/wordmath/twotwofour.py | 4 ++-- 6 files changed, 32 insertions(+), 36 deletions(-) diff --git a/constraint/__init__.py b/constraint/__init__.py index 99e2ff7..9d9a9cc 100644 --- a/constraint/__init__.py +++ b/constraint/__init__.py @@ -985,11 +985,7 @@ def __call__( parms = [assignments.get(x, _unassigned) for x in variables] missing = parms.count(_unassigned) if missing: - return (self._assigned or self._func(*parms)) and ( - not forwardcheck - or missing != 1 - or self.forwardCheck(variables, domains, assignments) - ) + return (self._assigned or self._func(*parms)) and (not forwardcheck or missing != 1 or self.forwardCheck(variables, domains, assignments)) return self._func(*parms) diff --git a/examples/einstein/einstein.py b/examples/einstein/einstein.py index ee6cae1..894ee90 100755 --- a/examples/einstein/einstein.py +++ b/examples/einstein/einstein.py @@ -127,9 +127,9 @@ def solve(): # Hint 10 if 1 < i < 5: problem.addConstraint( - lambda smoke, peta, petb: smoke != "blends" - or peta == "cats" - or petb == "cats", + lambda smoke, peta, petb: smoke != "blends" or + peta == "cats" or + petb == "cats", ("smoke%d" % i, "pet%d" % (i - 1), "pet%d" % (i + 1)), ) else: @@ -141,9 +141,9 @@ def solve(): # Hint 11 if 1 < i < 5: problem.addConstraint( - lambda pet, smokea, smokeb: pet != "horses" - or smokea == "dunhill" - or smokeb == "dunhill", + lambda pet, smokea, smokeb: pet != "horses" or + smokea == "dunhill" or + smokeb == "dunhill", ("pet%d" % i, "smoke%d" % (i - 1), "smoke%d" % (i + 1)), ) else: @@ -167,24 +167,24 @@ def solve(): # Hint 14 if 1 < i < 5: problem.addConstraint( - lambda nationality, colora, colorb: nationality != "norwegian" - or colora == "blue" - or colorb == "blue", + lambda nationality, colora, colorb: nationality != "norwegian" or + colora == "blue" or + colorb == "blue", ("nationality%d" % i, "color%d" % (i - 1), "color%d" % (i + 1)), ) else: problem.addConstraint( - lambda nationality, color: nationality != "norwegian" - or color == "blue", + lambda nationality, color: nationality != "norwegian" or + color == "blue", ("nationality%d" % i, "color%d" % (i == 1 and 2 or 4)), ) # Hint 15 if 1 < i < 5: problem.addConstraint( - lambda smoke, drinka, drinkb: smoke != "blends" - or drinka == "water" - or drinkb == "water", + lambda smoke, drinka, drinkb: smoke != "blends" or + drinka == "water" or + drinkb == "water", ("smoke%d" % i, "drink%d" % (i - 1), "drink%d" % (i + 1)), ) else: diff --git a/examples/queens/queens.py b/examples/queens/queens.py index 8d1f082..b4ac581 100755 --- a/examples/queens/queens.py +++ b/examples/queens/queens.py @@ -17,8 +17,8 @@ def solve(): if col1 < col2: problem.addConstraint( lambda row1, row2, col1=col1, col2=col2: abs(row1 - row2) - != abs(col1 - col2) - and row1 != row2, + != abs(col1 - col2) and + row1 != row2, (col1, col2), ) solutions = problem.getSolutions() diff --git a/examples/wordmath/seisseisdoze.py b/examples/wordmath/seisseisdoze.py index 998f586..9acc93e 100755 --- a/examples/wordmath/seisseisdoze.py +++ b/examples/wordmath/seisseisdoze.py @@ -19,8 +19,8 @@ def solve(): lambda i, s, z, e: ((10 * 2 * i) + (2 * s)) % 100 == z * 10 + e, "isze" ) problem.addConstraint( - lambda s, e, i, d, o, z: 2 * (s * 1000 + e * 100 + i * 10 + s) - == d * 1000 + o * 100 + z * 10 + e, + lambda s, e, i, d, o, z: 2 * (s * 1000 + e * 100 + i * 10 + s) == + d * 1000 + o * 100 + z * 10 + e, "seidoz", ) problem.addConstraint(lambda s: s != 0, "s") diff --git a/examples/wordmath/sendmoremoney.py b/examples/wordmath/sendmoremoney.py index f118d2d..6fd95a7 100755 --- a/examples/wordmath/sendmoremoney.py +++ b/examples/wordmath/sendmoremoney.py @@ -19,20 +19,20 @@ def solve(): lambda n, d, r, e, y: (n * 10 + d + r * 10 + e) % 100 == e * 10 + y, "ndrey" ) problem.addConstraint( - lambda e, n, d, o, r, y: (e * 100 + n * 10 + d + o * 100 + r * 10 + e) % 1000 - == n * 100 + e * 10 + y, + lambda e, n, d, o, r, y: (e * 100 + n * 10 + d + o * 100 + r * 10 + e) % 1000 == + n * 100 + e * 10 + y, "endory", ) problem.addConstraint( - lambda s, e, n, d, m, o, r, y: 1000 * s - + 100 * e - + 10 * n - + d - + 1000 * m - + 100 * o - + 10 * r - + e - == 10000 * m + 1000 * o + 100 * n + 10 * e + y, + lambda s, e, n, d, m, o, r, y: 1000 * s + + 100 * e + + 10 * n + + d + + 1000 * m + + 100 * o + + 10 * r + + e == + 10000 * m + 1000 * o + 100 * n + 10 * e + y, "sendmory", ) problem.addConstraint(NotInSetConstraint([0]), "sm") diff --git a/examples/wordmath/twotwofour.py b/examples/wordmath/twotwofour.py index f86d56e..c1624d9 100755 --- a/examples/wordmath/twotwofour.py +++ b/examples/wordmath/twotwofour.py @@ -19,8 +19,8 @@ def solve(): lambda w, o, u, r: ((10 * 2 * w) + (2 * o)) % 100 == u * 10 + r, "wour" ) problem.addConstraint( - lambda t, w, o, f, u, r: 2 * (t * 100 + w * 10 + o) - == f * 1000 + o * 100 + u * 10 + r, + lambda t, w, o, f, u, r: 2 * (t * 100 + w * 10 + o) == + f * 1000 + o * 100 + u * 10 + r, "twofur", ) problem.addConstraint(NotInSetConstraint([0]), "ft") From 909a3a19aedc1b6b4cf18d8dba42b38fdff6cff7 Mon Sep 17 00:00:00 2001 From: scls19fr Date: Mon, 5 Nov 2018 09:04:41 +0100 Subject: [PATCH 5/8] PEP8 --- .travis.yml | 2 +- constraint/__init__.py | 6 +++++- examples/queens/queens.py | 6 +++--- examples/wordmath/seisseisdoze.py | 2 +- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2bf2b8a..9ed1e3c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,7 @@ install: # command to run tests script: - nosetests -s -v --with-coverage --cover-package=constraint - - flake8 --ignore E501 constraint examples tests + - flake8 --ignore E501 W504 constraint examples tests after_success: - coveralls diff --git a/constraint/__init__.py b/constraint/__init__.py index 9d9a9cc..c8bec19 100644 --- a/constraint/__init__.py +++ b/constraint/__init__.py @@ -985,7 +985,11 @@ def __call__( parms = [assignments.get(x, _unassigned) for x in variables] missing = parms.count(_unassigned) if missing: - return (self._assigned or self._func(*parms)) and (not forwardcheck or missing != 1 or self.forwardCheck(variables, domains, assignments)) + return (self._assigned or self._func(*parms)) and ( + not forwardcheck or + missing != 1 or + self.forwardCheck(variables, domains, assignments) + ) return self._func(*parms) diff --git a/examples/queens/queens.py b/examples/queens/queens.py index b4ac581..3230521 100755 --- a/examples/queens/queens.py +++ b/examples/queens/queens.py @@ -16,9 +16,9 @@ def solve(): for col2 in cols: if col1 < col2: problem.addConstraint( - lambda row1, row2, col1=col1, col2=col2: abs(row1 - row2) - != abs(col1 - col2) and - row1 != row2, + lambda row1, row2, col1=col1, + col2=col2: abs(row1 - row2) != + abs(col1 - col2) and row1 != row2, (col1, col2), ) solutions = problem.getSolutions() diff --git a/examples/wordmath/seisseisdoze.py b/examples/wordmath/seisseisdoze.py index 9acc93e..4e37a2b 100755 --- a/examples/wordmath/seisseisdoze.py +++ b/examples/wordmath/seisseisdoze.py @@ -19,7 +19,7 @@ def solve(): lambda i, s, z, e: ((10 * 2 * i) + (2 * s)) % 100 == z * 10 + e, "isze" ) problem.addConstraint( - lambda s, e, i, d, o, z: 2 * (s * 1000 + e * 100 + i * 10 + s) == + lambda s, e, i, d, o, z: 2 * (s * 1000 + e * 100 + i * 10 + s) == d * 1000 + o * 100 + z * 10 + e, "seidoz", ) From 64176e68c124467a5428e6a86f2434f4128bf7c5 Mon Sep 17 00:00:00 2001 From: scls19fr Date: Mon, 5 Nov 2018 09:15:49 +0100 Subject: [PATCH 6/8] PEP8 --- .travis.yml | 2 +- examples/queens/queens.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9ed1e3c..ae4b7db 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,7 @@ install: # command to run tests script: - nosetests -s -v --with-coverage --cover-package=constraint - - flake8 --ignore E501 W504 constraint examples tests + - flake8 --ignore E501,W504 constraint examples tests after_success: - coveralls diff --git a/examples/queens/queens.py b/examples/queens/queens.py index 3230521..0d3dbc5 100755 --- a/examples/queens/queens.py +++ b/examples/queens/queens.py @@ -16,7 +16,7 @@ def solve(): for col2 in cols: if col1 < col2: problem.addConstraint( - lambda row1, row2, col1=col1, + lambda row1, row2, col1=col1, col2=col2: abs(row1 - row2) != abs(col1 - col2) and row1 != row2, (col1, col2), From 247984f847b2d76f6964420013bc80dd28e221b3 Mon Sep 17 00:00:00 2001 From: scls19fr Date: Mon, 5 Nov 2018 09:24:17 +0100 Subject: [PATCH 7/8] Drop Python 3.3 --- .travis.yml | 1 - CHANGELOG.md | 3 ++- constraint/version.py | 2 +- setup.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index ae4b7db..be0a481 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ language: python python: - "2.7" - - "3.3" - "3.4" - "3.5" - "3.6" diff --git a/CHANGELOG.md b/CHANGELOG.md index 26dd4fa..bcd0769 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,13 +5,14 @@ All notable changes to this code base will be documented in this file, in every released version. -### Version 1.3.2 +### Version 1.4.0 - Released: 2018-11-05 - Issues/Enhancements: - Add tests around `SomeNotInSetConstraint.` - Minor `README` fixes - Fix `dict.keys()` issue with Python 3 and add some unit tests + - Drop Python 3.3 support ### Version 1.3.1 diff --git a/constraint/version.py b/constraint/version.py index 2c86351..b3dddc1 100644 --- a/constraint/version.py +++ b/constraint/version.py @@ -2,7 +2,7 @@ __copyright__ = "Copyright (c) 2005-2018 - Gustavo Niemeyer " __credits__ = ["Sebastien Celles"] __license__ = "" -__version__ = "1.3.2" +__version__ = "1.4.0" __email__ = "gustavo@niemeyer.net" __status__ = "Development" __url__ = "https://github.com/python-constraint/python-constraint" diff --git a/setup.py b/setup.py index d1f4f53..77b0253 100755 --- a/setup.py +++ b/setup.py @@ -58,7 +58,7 @@ def readme(): "Programming Language :: Python :: 2.7", # 'Programming Language :: Python :: 3', # 'Programming Language :: Python :: 3.2', - "Programming Language :: Python :: 3.3", + # "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", From 8be4a77be4c7754bc91f49192149862e75466abb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Celles?= Date: Mon, 5 Nov 2018 09:57:03 +0100 Subject: [PATCH 8/8] Deploy --- .travis.yml | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/.travis.yml b/.travis.yml index be0a481..0ef994d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,20 +1,22 @@ language: python python: - - "2.7" - - "3.4" - - "3.5" - - "3.6" - -# command to install dependencies +- '2.7' +- '3.4' +- '3.5' +- '3.6' install: - - "pip install -qq flake8" - - "pip install coveralls --quiet" - - "pip install ." - -# command to run tests +- pip install -qq flake8 +- pip install coveralls --quiet +- pip install . script: - - nosetests -s -v --with-coverage --cover-package=constraint - - flake8 --ignore E501,W504 constraint examples tests - +- nosetests -s -v --with-coverage --cover-package=constraint +- flake8 --ignore E501,W504 constraint examples tests after_success: - - coveralls +- coveralls +deploy: + provider: pypi + user: "scls" + password: + secure: YP1I8vi04F2mhaexylEK4PoizOMKfPy6ixDGYYLg5WAvgNdHvBN39xFsd9WHavMGg0RcV3xn5jAawQN1dDnXYVNW8LAivwfkUazXjqxAf4IeMp92203kOjQij/D494etHYeIw4SNJgk7J2tDil+goITJ/OhJ4t7fDC0eA0nILn8ifyZZQUgZppW5CoAf1L8cxY1JWICXLKQFQ42zPkFaIA9oBSOgok5wlNoyguScJ70mqUwZewhZHk4L07WSFRbDEOawHe5CAHCPO8rVCkhk2WdLWRoY9uHijDxHn9eCZ3zm4ac/jAwPtFol43q5u9wTCSm8WmeVfU/mJLjgGvmyDhb5Z2fTVbWGsX/N/WHvASr85HfKS0Vq2hAHYozukLbJ8EQZL6ZoOiFhjbL1LJv6Ex3EZ3PTkjKZEGEiLS/aiLZSj95CDMnfKjaNnAN2qFxzR1yi7tFHttS7XiaTCuKoegeN/RNA1iTdFPsXIcmCklhqYr9jCoTaKOXic8W5C1ej3V8oogx1xA79/mf7ZtHxtHWeT9o7cG2EK5gYfvPi6bhKPZDQ2hq49tt8AbcjX4/ycovTmX/cTn0CCoUfLB7Ok9/UvdcdUiflVZEm4cH1WAXAeD3CW+WGTOEHSgNArl9ERxUyomsWhyhutGPmeZIPQ1COeuqFFBTIaHWDG1ytqN4= + on: + tags: true