Merge branch 'master' into pr/661
Conflicts: AUTHORS
This commit is contained in:
commit
6995a5aece
1
.dockerignore
Normal file
1
.dockerignore
Normal file
@ -0,0 +1 @@
|
||||
.git
|
@ -8,15 +8,9 @@ python:
|
||||
- "3.4"
|
||||
cache:
|
||||
- $HOME/.pip-cache
|
||||
# command to install dependencies
|
||||
install:
|
||||
- pip install -r requirements-travis.txt --download-cache $HOME/.pip-cache
|
||||
- pip install coveralls --download-cache $HOME/.pip-cache
|
||||
- if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]]; then pip install unittest2; fi # needs for running tests
|
||||
- pip install --allow-all-external -e .
|
||||
# command to run tests
|
||||
script: make travis
|
||||
after_success: coveralls
|
||||
after_success: make coveralls
|
||||
notifications:
|
||||
email:
|
||||
- paultag@gmail.com
|
||||
|
1
AUTHORS
1
AUTHORS
@ -49,3 +49,4 @@
|
||||
* Matthew Wampler-Doty <matthew.wampler.doty@gmail.com>
|
||||
* Tianon Gravi <admwiggin@gmail.com>
|
||||
* Ian Denhardt <ian@zenhack.net>
|
||||
* Ruslan Prokopiev <bismigalis@gmail.com>
|
||||
|
50
Makefile
50
Makefile
@ -1,3 +1,21 @@
|
||||
pypy_url=http://buildbot.pypy.org/nightly/trunk/pypy-c-jit-latest-linux64.tar.bz2
|
||||
pip_url=https://bootstrap.pypa.io/get-pip.py
|
||||
python=python
|
||||
pip=pip
|
||||
coveralls=coveralls
|
||||
nose=nosetests
|
||||
pcache=$(HOME)/.pip-cache
|
||||
|
||||
ifeq (PyPy 2.4,$(findstring PyPy 2.4,$(shell python -V 2>&1 | tail -1)))
|
||||
bad_pypy=1
|
||||
python=./pypy
|
||||
pip=./pip
|
||||
coveralls=./coveralls
|
||||
nose=./nosetests
|
||||
else
|
||||
bad_pypy=
|
||||
endif
|
||||
|
||||
all:
|
||||
@echo "No default step. Use setup.py"
|
||||
@echo ""
|
||||
@ -53,14 +71,42 @@ diff:
|
||||
|
||||
r: d tox diff
|
||||
|
||||
travis:
|
||||
nosetests -s --with-coverage --cover-package hy
|
||||
python:
|
||||
ifeq ($(bad_pypy),1)
|
||||
# Due to stupid PyPy 2.4 bugs, a custom version needs to be downloaded
|
||||
curl $(pypy_url) -o pypy.tbz2
|
||||
tar xf pypy.tbz2
|
||||
ln -sf `pwd`/pypy-*/bin/pypy $(python)
|
||||
curl $(pip_url) | $(python)
|
||||
ln -sf `pwd`/pypy-*/bin/pip $(pip)
|
||||
sudo $(pip) install nose
|
||||
ln -sf `pwd`/pypy-*/bin/nosetests $(nose)
|
||||
endif
|
||||
ifeq (Python 2.6,$(findstring Python 2.6,$(shell python -V 2>&1)))
|
||||
$(pip) install unittest2
|
||||
endif
|
||||
$(pip) install -r requirements-travis.txt --download-cache $(pcache)
|
||||
$(pip) install coveralls --download-cache $(pcache)
|
||||
$(pip) install --allow-all-external -e .
|
||||
ifeq ($(bad_pypy),1)
|
||||
ln -sf `pwd`/pypy-*/bin/coveralls $(coveralls)
|
||||
endif
|
||||
|
||||
travis: python
|
||||
ifeq ($(bad_pypy),1)
|
||||
HY_DIR=`pwd`/pypy-*/bin $(nose) -s --with-coverage --cover-package hy
|
||||
else
|
||||
$(nose) -s --with-coverage --cover-package hy
|
||||
endif
|
||||
ifeq (PyPy,$(findstring PyPy,$(shell python -V 2>&1 | tail -1)))
|
||||
@echo "skipping flake8 on pypy"
|
||||
else
|
||||
flake8 hy bin tests
|
||||
endif
|
||||
|
||||
coveralls:
|
||||
$(coveralls)
|
||||
|
||||
clean:
|
||||
@find . -name "*.pyc" -exec rm {} \;
|
||||
@find -name __pycache__ -delete
|
||||
|
46
NEWS
46
NEWS
@ -1,3 +1,49 @@
|
||||
Changes from 0.10.0
|
||||
|
||||
This release took some time (sorry, all my fault) but it's got a bunch of
|
||||
really nice features. We hope you enjoy hacking with Hy as much as we enjoy
|
||||
hacking on Hy.
|
||||
|
||||
In other news, we're Dockerized as an official library image!
|
||||
<https://registry.hub.docker.com/_/hylang/>
|
||||
|
||||
$ docker run -it --rm hylang
|
||||
hy 0.10.0 using CPython(default) 3.4.1 on Linux
|
||||
=> ((lambda [] (print "Hello, World!")))
|
||||
Hello, World!
|
||||
|
||||
- Hy Society
|
||||
|
||||
[ Language Changes ]
|
||||
* Implement raise :from, Python 3 only.
|
||||
* defmain macro
|
||||
* name & keyword functions added to core
|
||||
* (read) added to core
|
||||
* shadow added to core
|
||||
* New functions interleave interpose zip_longest added to core
|
||||
* nth returns default value when out of bounds
|
||||
* merge-with added
|
||||
* doto macro added
|
||||
* keyword? to findout keywords
|
||||
* setv no longer allows "." in names
|
||||
|
||||
[Internals ]
|
||||
* Builtins reimplemented in terms of python stdlib
|
||||
* gensyms (defmacro/g!) handles non-string types better
|
||||
|
||||
[Tools]
|
||||
* Added hy2py to installed scripts
|
||||
|
||||
[ Misc. Fixes ]
|
||||
* Symbols like true, false, none can't be assigned
|
||||
* Set sys.argv default to [''] like Python does
|
||||
* REPL displays the the python version and platform at startup
|
||||
* Dockerfile added for https://registry.hub.docker.com/_/hylang/
|
||||
|
||||
[ Contrib changes ]
|
||||
* Fix ap-first and ap-last for failure conditions
|
||||
|
||||
|
||||
Changes from 0.9.12
|
||||
|
||||
0.10.0 - the "oh man I'm late for PyCon" release
|
||||
|
@ -449,6 +449,27 @@ Returns the single step macro expansion of form.
|
||||
=> (macroexpand-1 '(-> (a b) (-> (c d) (e f))))
|
||||
(u'_>' (u'a' u'b') (u'c' u'd') (u'e' u'f'))
|
||||
|
||||
|
||||
.. _merge-with-fn:
|
||||
|
||||
merge-with
|
||||
----------
|
||||
|
||||
.. versionadded:: 0.10.1
|
||||
|
||||
Usage: ``(merge-with f &rest maps)
|
||||
|
||||
Returns a map that consist of the rest of the maps joined onto first.
|
||||
If a key occurs in more than one map, the mapping(s) from the latter
|
||||
(left-to-right) will be combined with the mapping in the result by
|
||||
calling ``(f val-in-result val-in-latter)``.
|
||||
|
||||
.. code-block:: clojure
|
||||
|
||||
=> (merge-with (fn [x y] (+ x y)) {"a" 10 "b" 20} {"a" 1 "c" 30})
|
||||
{u'a': 11L, u'c': 30L, u'b': 20L}
|
||||
|
||||
|
||||
.. _neg?-fn:
|
||||
|
||||
neg?
|
||||
|
@ -52,3 +52,9 @@ if PY3:
|
||||
long_type = int
|
||||
else:
|
||||
long_type = long # NOQA
|
||||
|
||||
if PY3:
|
||||
exec('def raise_empty(t, *args): raise t(*args) from None')
|
||||
else:
|
||||
def raise_empty(t, *args):
|
||||
raise t(*args)
|
||||
|
@ -38,7 +38,7 @@ from hy.models.cons import HyCons
|
||||
from hy.errors import HyCompileError, HyTypeError
|
||||
|
||||
import hy.macros
|
||||
from hy._compat import str_type, long_type, PY27, PY33, PY3, PY34
|
||||
from hy._compat import str_type, long_type, PY27, PY33, PY3, PY34, raise_empty
|
||||
from hy.macros import require, macroexpand, reader_macroexpand
|
||||
import hy.importer
|
||||
|
||||
@ -429,7 +429,7 @@ class HyASTCompiler(object):
|
||||
except HyTypeError as e:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise HyCompileError(e, sys.exc_info()[2])
|
||||
raise_empty(HyCompileError, e, sys.exc_info()[2])
|
||||
|
||||
raise HyCompileError(Exception("Unknown type: `%s'" % _type))
|
||||
|
||||
@ -1268,7 +1268,8 @@ class HyASTCompiler(object):
|
||||
def compile_decorate_expression(self, expr):
|
||||
expr.pop(0) # with-decorator
|
||||
fn = self.compile(expr.pop(-1))
|
||||
if not fn.stmts or not isinstance(fn.stmts[-1], ast.FunctionDef):
|
||||
if not fn.stmts or not (isinstance(fn.stmts[-1], ast.FunctionDef) or
|
||||
isinstance(fn.stmts[-1], ast.ClassDef)):
|
||||
raise HyTypeError(expr, "Decorated a non-function")
|
||||
decorators, ret = self._compile_collect(expr)
|
||||
fn.stmts[-1].decorator_list = decorators
|
||||
|
@ -28,10 +28,10 @@
|
||||
(import collections)
|
||||
(import sys)
|
||||
(import [hy._compat [long-type]]) ; long for python2, int for python3
|
||||
(import [hy.models.cons [HyCons]])
|
||||
(import [hy.models.cons [HyCons]]
|
||||
[hy.models.keyword [HyKeyword *keyword-prefix*]])
|
||||
(import [hy.lex [LexException PrematureEndOfInput tokenize]])
|
||||
|
||||
|
||||
(defn _numeric-check [x]
|
||||
(if (not (numeric? x))
|
||||
(raise (TypeError (.format "{0!r} is not a number" x)))))
|
||||
@ -253,6 +253,22 @@
|
||||
(setv name (calling-module-name))
|
||||
(hy.macros.macroexpand-1 form name))
|
||||
|
||||
(defn merge-with [f &rest maps]
|
||||
"Returns a map that consists of the rest of the maps joined onto
|
||||
the first. If a key occurs in more than one map, the mapping(s)
|
||||
from the latter (left-to-right) will be combined with the mapping in
|
||||
the result by calling (f val-in-result val-in-latter)."
|
||||
(if (any maps)
|
||||
(let [[merge-entry (fn [m e]
|
||||
(let [[k (get e 0)] [v (get e 1)]]
|
||||
(if (in k m)
|
||||
(assoc m k (f (get m k) v))
|
||||
(assoc m k v)))
|
||||
m)]
|
||||
[merge2 (fn [m1 m2]
|
||||
(reduce merge-entry (.items m2) (or m1 {})))]]
|
||||
(reduce merge2 maps))))
|
||||
|
||||
(defn neg? [n]
|
||||
"Return true if n is < 0"
|
||||
(_numeric-check n)
|
||||
@ -354,13 +370,45 @@
|
||||
|
||||
(defun Botsbuildbots () (Botsbuildbots))
|
||||
|
||||
(defn zipwith [func &rest lists]
|
||||
"Zip the contents of several lists and map a function to the result"
|
||||
(do
|
||||
(import functools)
|
||||
(map (functools.partial (fn [f args] (apply f args)) func) (apply zip lists))))
|
||||
|
||||
(defn hyify [text]
|
||||
"Convert text to match hy identifier"
|
||||
(.replace (string text) "_" "-"))
|
||||
|
||||
(defn keyword [value]
|
||||
"Create a keyword from the given value. Strings numbers and even objects
|
||||
with the __name__ magic will work"
|
||||
(if (and (string? value) (value.startswith *keyword-prefix*))
|
||||
(hyify value)
|
||||
(if (string? value)
|
||||
(HyKeyword (+ ":" (hyify value)))
|
||||
(try
|
||||
(hyify (.__name__ value))
|
||||
(catch [] (HyKeyword (+ ":" (string value))))))))
|
||||
|
||||
(defn name [value]
|
||||
"Convert the given value to a string. Keyword special character will be stripped.
|
||||
String will be used as is. Even objects with the __name__ magic will work"
|
||||
(if (and (string? value) (value.startswith *keyword-prefix*))
|
||||
(hyify (slice value 2))
|
||||
(if (string? value)
|
||||
(hyify value)
|
||||
(try
|
||||
(hyify (. value __name__))
|
||||
(catch [] (string value))))))
|
||||
|
||||
(def *exports* '[Botsbuildbots
|
||||
butlast calling-module-name coll? cons cons? cycle
|
||||
dec distinct disassemble drop drop-while empty? even?
|
||||
every? first filter filterfalse flatten float? gensym identity
|
||||
inc input instance? integer integer? integer-char? interleave
|
||||
interpose iterable? iterate iterator? keyword? list*
|
||||
macroexpand macroexpand-1 map neg? nil? none? nth
|
||||
numeric? odd? pos? range read remove repeat repeatedly
|
||||
interpose iterable? iterate iterator? keyword keyword? list*
|
||||
macroexpand macroexpand-1 map merge-with name neg? nil? none?
|
||||
nth numeric? odd? pos? range read remove repeat repeatedly
|
||||
rest reduce second some string string? take take-nth
|
||||
take-while zero? zip zip_longest zipwith])
|
||||
|
@ -23,14 +23,17 @@ from hy.models import HyObject
|
||||
from hy._compat import str_type
|
||||
|
||||
|
||||
KEYWORD_PREFIX = "\uFDD0"
|
||||
|
||||
|
||||
class HyKeyword(HyObject, str_type):
|
||||
"""Generic Hy Keyword object. It's either a ``str`` or a ``unicode``,
|
||||
depending on the Python version.
|
||||
"""
|
||||
|
||||
def __new__(cls, value):
|
||||
if not value.startswith("\uFDD0"):
|
||||
value = "\uFDD0" + value
|
||||
if not value.startswith(KEYWORD_PREFIX):
|
||||
value = KEYWORD_PREFIX + value
|
||||
|
||||
obj = str_type.__new__(cls, value)
|
||||
return obj
|
||||
|
@ -20,4 +20,4 @@
|
||||
|
||||
|
||||
__appname__ = "hy"
|
||||
__version__ = "0.10.0"
|
||||
__version__ = "0.10.1"
|
||||
|
@ -1,6 +1,7 @@
|
||||
(import [tests.resources [kwtest function-with-a-dash]]
|
||||
[os.path [exists isdir isfile]]
|
||||
[sys :as systest])
|
||||
[sys :as systest]
|
||||
[operator [or_]])
|
||||
(import sys)
|
||||
|
||||
(import [hy._compat [PY33 PY34]])
|
||||
@ -985,6 +986,24 @@
|
||||
(assert (= (macroexpand-1 '(-> (a b) (-> (c d) (e f))))
|
||||
'(-> (a b) (c d) (e f)))))
|
||||
|
||||
(defn test-merge-with []
|
||||
"NATIVE: test merge-with"
|
||||
(assert (= (merge-with + {} {}) nil))
|
||||
(assert (= (merge-with + {"a" 10 "b" 20} {}) {"a" 10 "b" 20}))
|
||||
(assert (= (merge-with + {} {"a" 10 "b" 20}) {"a" 10 "b" 20}))
|
||||
(assert (= (merge-with + {"a" 10 "b" 20} {"a" 1 "c" 30})
|
||||
{"a" 11 "b" 20 "c" 30}))
|
||||
(assert (= (merge-with +
|
||||
{:a 1 :b 2}
|
||||
{:a 9 :b 98 :c 0}
|
||||
{:a 10 :b 100 :c 10}
|
||||
{:a 5}
|
||||
{:c 5 :d 42})
|
||||
{:d 42 :c 15 :a 25 :b 200}))
|
||||
(assert (= (merge-with or_
|
||||
{"a" (set [1 2 3]) "b" (set [4 5 6])}
|
||||
{"a" (set [2 3 7 8]) "c" (set [1 2 3])})
|
||||
{"a" (set [1 2 3 7 8]) "c" (set [1 2 3]) "b" (set [4 5 6])})))
|
||||
|
||||
(defn test-calling-module-name []
|
||||
"NATIVE: Test the calling-module-name function"
|
||||
@ -1037,11 +1056,11 @@
|
||||
(import [StringIO [StringIO]])
|
||||
(import [io [StringIO]]))
|
||||
(import [hy.models.expression [HyExpression]])
|
||||
|
||||
|
||||
(def stdin-buffer (StringIO "(+ 2 2)\n(- 2 2)"))
|
||||
(assert (= (eval (read stdin-buffer)) 4))
|
||||
(assert (isinstance (read stdin-buffer) HyExpression))
|
||||
|
||||
|
||||
"Multiline test"
|
||||
(def stdin-buffer (StringIO "(\n+\n41\n1\n)\n(-\n2\n1\n)"))
|
||||
(assert (= (eval (read stdin-buffer)) 42))
|
||||
@ -1050,9 +1069,33 @@
|
||||
"EOF test"
|
||||
(def stdin-buffer (StringIO "(+ 2 2)"))
|
||||
(read stdin-buffer)
|
||||
(try
|
||||
(try
|
||||
(read stdin-buffer)
|
||||
(catch [e Exception]
|
||||
(assert (isinstance e EOFError)))))
|
||||
|
||||
(defn test-keyword-creation []
|
||||
"NATIVE: Test keyword creation"
|
||||
(assert (= (keyword "foo") :foo))
|
||||
(assert (= (keyword "foo_bar") :foo-bar))
|
||||
(assert (= (keyword `foo) :foo))
|
||||
(assert (= (keyword `foo-bar) :foo-bar))
|
||||
(assert (= (keyword 'foo) :foo))
|
||||
(assert (= (keyword 'foo-bar) :foo-bar))
|
||||
(assert (= (keyword 1) :1))
|
||||
(assert (= (keyword 1.0) :1.0))
|
||||
(assert (= (keyword :foo_bar) :foo-bar)))
|
||||
|
||||
(defn test-name-conversion []
|
||||
"NATIVE: Test name conversion"
|
||||
(assert (= (name "foo") "foo"))
|
||||
(assert (= (name "foo_bar") "foo-bar"))
|
||||
(assert (= (name `foo) "foo"))
|
||||
(assert (= (name `foo_bar) "foo-bar"))
|
||||
(assert (= (name 'foo) "foo"))
|
||||
(assert (= (name 'foo_bar) "foo-bar"))
|
||||
(assert (= (name 1) "1"))
|
||||
(assert (= (name 1.0) "1.0"))
|
||||
(assert (= (name :foo) "foo"))
|
||||
(assert (= (name :foo_bar) "foo-bar"))
|
||||
(assert (= (name test-name-conversion) "test-name-conversion")))
|
||||
|
@ -7,6 +7,16 @@
|
||||
(* 2 2)))
|
||||
|
||||
|
||||
(defn bardec [cls]
|
||||
(setv cls.my_attr 123)
|
||||
cls)
|
||||
|
||||
(with-decorator bardec
|
||||
(defclass cls []
|
||||
[[my_attr 456]]))
|
||||
|
||||
|
||||
(defn test-decorators []
|
||||
"NATIVE: test decorators."
|
||||
(assert (= (tfunction) 2)))
|
||||
(assert (= (tfunction) 2))
|
||||
(assert (= cls.my_attr 123)))
|
||||
|
@ -26,8 +26,11 @@ import subprocess
|
||||
from hy._compat import PY3
|
||||
|
||||
|
||||
hy_dir = os.environ.get('HY_DIR', '')
|
||||
|
||||
|
||||
def run_cmd(cmd, stdin_data=None):
|
||||
p = subprocess.Popen(cmd,
|
||||
p = subprocess.Popen(os.path.join(hy_dir, cmd),
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
|
Loading…
x
Reference in New Issue
Block a user