Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
42d640c478 | ||
|
|
9376d05d52 | ||
|
|
8c9fe9c141 | ||
|
|
bcbd78b8be | ||
|
|
711d51d4cf | ||
|
|
b931342984 | ||
|
|
9466035cc7 | ||
|
|
fabbefa7af | ||
|
|
96e32846ec | ||
|
|
0dce7022aa | ||
|
|
9c24838596 | ||
|
|
3451971f8e | ||
|
|
931e7ed937 | ||
|
|
5c70bc5b44 | ||
|
|
bcac8d5cfc | ||
|
|
77f0e00fa1 | ||
|
|
d57304504e | ||
|
|
46edf10e9d | ||
|
|
354ce2e307 | ||
|
|
98ebd5b40e | ||
|
|
c1924f3630 | ||
|
|
b579683287 | ||
|
|
ccdeea9ccf |
@@ -275,3 +275,5 @@ docs/_build/
|
||||
target/
|
||||
*.pypirc
|
||||
MANIFEST
|
||||
|
||||
fmatch_idea.txt
|
||||
@@ -1,244 +0,0 @@
|
||||
Title: HumbleMatch - Go sanitize your type-checking
|
||||
Date: 2015-06-19 16:56
|
||||
Authors: bendtherules
|
||||
Category: Projects
|
||||
Tags: HumbleMatch, Launch stuff, Projects
|
||||
Slug: HumbleMatch_Launch
|
||||
|
||||
## Intro
|
||||
|
||||
Hi, I am [Abhas](blog.codesp.in) and personally, I love Python mostly for its intuitive, flexible and beautiful API. But some things, I really hate doing. HumbleMatch is my attempt at solving that pain.
|
||||
|
||||
|
||||
## The Pain Point #1
|
||||
|
||||
For eg, lets say I have a Point class with two function signatures - `Point(x,y)` and `Point([x,y])`. Lets see a typical implementation of this -
|
||||
|
||||
|
||||
class Point(object):
|
||||
|
||||
def __init__(self, x, y=None):
|
||||
if isinstance(x, int) and isinstance(y, int): # check for Point(x,y)
|
||||
self.x = x
|
||||
self.y = y
|
||||
elif isinstance(x, list) and (y is None): # check for Point([x,y])
|
||||
assert(len(x) == 2)
|
||||
assert(isinstance(x[0], int) and isinstance(x[1], int))
|
||||
x, y = x
|
||||
self.x = x
|
||||
self.y = y
|
||||
else:
|
||||
raise TypeError("Pass proper arguments")
|
||||
|
||||
Now, definitely there are some shortcuts you could take there, but the point is this process is quite error-prone and repetitive. For eg, one might easily miss the `(y is None)` or `isinstance` check in the 2nd case.
|
||||
|
||||
Again, this is a pretty basic requirement I imposed upon the `__init__` method. Wouldnt it be awesome if you could do all this easily and also support dicts like `{x:20,y:50}` or hell, even objects with `obj.x = 20, obj.y =50` directly as arguments?
|
||||
|
||||
Lets visit the better side
|
||||
|
||||
|
||||
## Using HumbleMatch #1
|
||||
|
||||
|
||||
from humblematch import w
|
||||
|
||||
|
||||
class Point(object):
|
||||
|
||||
def __init__(self, x, y=None):
|
||||
if w([int, int]) == [x, y]: # check for Point(x,y)
|
||||
self.x = x
|
||||
self.y = y
|
||||
elif w([[int, int], None]) == [x, y]: # check for Point([x,y])
|
||||
x, y = x
|
||||
self.x = x
|
||||
self.y = y
|
||||
else:
|
||||
raise TypeError("Pass proper arguments")
|
||||
|
||||
Look at the difference on line 6 and line 10 - you can put all those isinstance and length checks in one line, and hopefully, it now becomes easier to grasp what the code does at one look. That `w` or `WrapObj` class is the most important among a very few classes that humblematch provides.
|
||||
|
||||
So, lets go through this and see how it works.
|
||||
|
||||
### humblematch.w(object)
|
||||
--------------------------
|
||||
Same as humblematch.WrapObj. It acts as a wrapper, and takes as input any object, be it a class like int or float or list or a value like 5.23.
|
||||
|
||||
It is in itself useless, but has a specialized \__eq__ operator which helps in matching. Object passed to it is considered as the reference against which any other object can be checked.
|
||||
|
||||
#### Methods
|
||||
-------------
|
||||
##### \__eq__(other)
|
||||
Same as `w(obj) == other`
|
||||
|
||||
If *obj* is a *class*, then it returns True if *other* is instance of *obj*. So,can match against types like int.
|
||||
|
||||
If not *class* and not the ones mentioned below, then returns True if `obj == other`. So, can match against values like 5 or "abcd"
|
||||
|
||||
If *obj* is a list-ish iterable (i.e. not string or dict), then each element is checked against that of *other*. Returns True if `other[index] == obj[index]` for every index in *obj* and they both have same number of elements
|
||||
|
||||
If *obj* is a Mapping (eg dict), returns true if for each key in *obj*, `other[key] == obj[key]`. But it is ok for *other* to have extra keys
|
||||
|
||||
If *obj* is a Mapping and you use `w(obj).as_obj() == other`, then *other* is considered as a Object and all the keys in *obj* are looked up on *other* using \__getattribute__ i.e. it returns True if `other.key == obj[key]` for all the keys in *obj*.
|
||||
|
||||
#### Example
|
||||
|
||||
w(int) == 5 is True
|
||||
w(int) == 5.23 is False
|
||||
|
||||
w(int) == int is False # Wont match class itself
|
||||
|
||||
w(5) == 5 is True
|
||||
w(5) == 5.0 is True # as 5 == 5.0 in Python
|
||||
|
||||
w([int, 5]) == [2, 5] is True # Using list
|
||||
w([int, 5]) == [2.23, 5] is False
|
||||
w([list, 50]) == [[200], 50] is True
|
||||
|
||||
w({"a":int}) == {"a":1, "b":99} is True # Using dict
|
||||
|
||||
class object2(object):
|
||||
pass
|
||||
|
||||
q = object2()
|
||||
q.a, q.b = 1, 99
|
||||
w({"b": int}).as_obj() == q is True # Using object
|
||||
|
||||
w({"a":[int,float]}) == {"a":[36,1.26]} # ** OK to nest expressions **
|
||||
|
||||
|
||||
Also, I promised you that you can just as easily use dicts and objects - but from the previous examples, you probably can guess how to do that. So, if you are willing, just go forward and implement that first. Hopefully, you will love the simplicity.
|
||||
|
||||
Now because this is currently the only documentation on it, I'll go ahead with few more examples and provide the remaining doc alongside.
|
||||
|
||||
|
||||
|
||||
## The Pain Point #2
|
||||
|
||||
Lets say, we have a function called `diff_list`, which given *two lists as argument*, returns a *list of two lists, each of them containing the unique/exclusive elements* from the corresponding list passed as argument . (Unique in the sense its not present in the other list). But if any of those return lists dont have any unique argument, the function simply *returns `None` instead of that list*.
|
||||
|
||||
For simplicity, we also assume that the argument lists themselves dont have repeating elements. So, for eg. `diff_list([2,3,4,9],[1,3,9]) == [[2,4],[1]]` and `diff_list([2,3,4,9],[3,9]) == [[2,4],None]`
|
||||
|
||||
|
||||
|
||||
Heres a sample implementation we are going to use -
|
||||
|
||||
|
||||
from humblematch import w
|
||||
|
||||
|
||||
def diff_list(list_1, list_2):
|
||||
try:
|
||||
assert(w([list, list]) == [list_1, list_2])
|
||||
except AssertionError:
|
||||
raise TypeError("Both arguments must be list or a list-ish iterable")
|
||||
|
||||
exclusive_list_1 = []
|
||||
|
||||
for ele in list_1:
|
||||
if ele not in list_2:
|
||||
exclusive_list_1.append(ele)
|
||||
|
||||
exclusive_list_2 = []
|
||||
for ele in list_2:
|
||||
if ele not in list_1:
|
||||
exclusive_list_2.append(ele)
|
||||
|
||||
return [exclusive_list_1 or None, exclusive_list_2 or None]
|
||||
|
||||
Our goal is to test this function from certain directions -
|
||||
|
||||
1. Whether it returns a list of two elements, each of which might be another list or None.
|
||||
2. Given two lists of any size conataining only float as argument (eg. `diff_list([1.12,2.64],[2.56])`), whether all the elements in the sub-lists of the returned list are of type float.
|
||||
|
||||
Obviously, there are some other checks we should do, but this module probably wont be of much help there.
|
||||
|
||||
## Test 1
|
||||
|
||||
|
||||
from humblematch import w, OR
|
||||
from random import random, randint
|
||||
list_1 = [randint(0, 25) for i in range(randint(5, 10))]
|
||||
list_2 = [randint(0, 25) for i in range(randint(5, 10))]
|
||||
|
||||
assert(diff_list(list_1, list_2) == w([OR(list, None), OR(list, None)]))
|
||||
|
||||
|
||||
We need to check that each element in the returned list is either a list or None. So, we need to have some way of checking one argument against a number of types and values, where the check returns True if any of them satisfies. That why we have `humblematch.OR(obj1, obj2, ...)`
|
||||
|
||||
### humblematch.OR(obj1, obj2, ...)
|
||||
------------------------------------
|
||||
|
||||
Also has the signature `humblematch.OR([obj1, obj2, ...])`.
|
||||
|
||||
`OR(obj1,obj2, ...) == other` returns True if `other` matches (isinstance of or is equal to) any of the `obj` passed as argument.
|
||||
|
||||
`OR` also has all the facilities of `w`, so its not required to use `w(OR())` - it is functionally equivalent to just `OR()`.
|
||||
|
||||
#### Example
|
||||
|
||||
OR(int) == 5 is True
|
||||
OR(int, float) == 2.26 is True
|
||||
w(OR([10, None])) == None is True
|
||||
w(OR(str, 5)) == 5 is True
|
||||
|
||||
|
||||
### humblematch.ANY
|
||||
--------------------
|
||||
|
||||
Similar to `OR`, there is `humblematch.ANY` which matches object of any type. It is usually used when we dont care about the type of the argument, but still want it to be there. Also, `ANY` has all facilities of `w` just like `OR`.
|
||||
|
||||
#### Example
|
||||
|
||||
w(Any) == 4 is True
|
||||
Any == [2,{"a":3}] is True
|
||||
|
||||
### OR, ANY and more
|
||||
|
||||
Both `ANY` and `OR` work like Abstract Base Class (ABC). Along with this, we could also use any ABC for eg. those defined in `types` and `number` module.
|
||||
HumbleMatch makes some of the common ones available directly, with slight modifications in some of them (specifically StringTypes). The available ones are:
|
||||
|
||||
* `StringTypes` - Matches strings of both types, `str` and `unicode`
|
||||
* `NumberType` - Matches any kind of number (like `int` or `float`)
|
||||
* `FunctionType` - Matches any function (useful for checking methods in object)
|
||||
* `ClassType` - Matches any class (Probably both new and old-style class)
|
||||
|
||||
`ANY` and `OR` are more important in nested expressions like
|
||||
|
||||
|
||||
w([2,int, OR(str,int), Any]) == [2, 99, "asd", [{"a":55}]] is True
|
||||
|
||||
## Test 2
|
||||
|
||||
|
||||
from humblematch import w, inf
|
||||
from random import random, randint
|
||||
list_1 = [random()*10 for i in range(randint(1, 5))] #eg [1.23,5.32]
|
||||
list_2 = [random()*10 for i in range(randint(1, 5))] #eg [3.3,5.32,6.7]
|
||||
|
||||
assert(diff_list(list_1, list_2) == w([[w([float]).times(0, inf)],
|
||||
[w([float]).times(0, inf)]]))
|
||||
|
||||
Lets say `diff_list(list_1, list_2)` returns `[list_3, list_4]`. We need to check that both *list\_3* and *list\_4* are filled with only float elements. So. to check *list\_3* first, we use `[w([float]).times(0, inf)]`, which means the *list\_3* is a list and it consists of elements which can be eaten up by the pattern `float` when repeated for atleast 0 times and at max infinite times.
|
||||
|
||||
### humblematch.w([pattern_1, pattern_2, ...]).times(min,max)
|
||||
-----------------------------------------------------------------
|
||||
Also has signature `w([pattern_1, pattern_2]).times(exact_times)`
|
||||
|
||||
It works like the `*args` used in functions, it matches a number of elements which follow the given pattern, but should atleast repeat `min` times and atmost `max-1` times (i.e. `max` times is exclusive, just like `range` in python), if both arguments are given. If only one is given, it must repeat exactly `exact_times`.
|
||||
|
||||
But hey, what exactly is the pattern `[pattern_1, pattern_2, ...]`? It means that `pattern_1` must occur first, followed by `pattern_2`, followed by others) to be count as one full match and this type of full match can occur in the `(min,max)` range. If the full match doesnt complete, it is considered invalid and hence doesnt match.
|
||||
|
||||
It is used like this :
|
||||
|
||||
`w([w([pattern_1, pattern_2, ...]).times(min,max)]) == [ele_1, ele_2, ...]`
|
||||
|
||||
Also, `w([pattern_1, pattern_2, ...]).times(min,max)` has another alias `w([pattern_1, pattern_2, ...])*(min,max)`, so we can use `*(min,max)` instead of `.times(min,max)` for shorthand purpose.
|
||||
|
||||
Infact now that we know this, in Test 2 we can remove the repetion of `w([float]).times(0, inf)` twice using another `.times`. Try that if you have some time.
|
||||
|
||||
## Undocumented
|
||||
|
||||
I purposedly missed one method which is already there, called `w(obj).save_as(arg_name)`. How it works is that whatever it matches with is stored as `"arg_name"` and returns a dict filled with all such values, when `==`d with `other`. For eg `w([2, w(int).save_as("a"), OR(str,dict)).save_as("b")]) == [2,5,{"q":1}]` returns `{"a":5,"b":{"q":1}}`. I didnt document it well beacuse I am not mentally ok with a `==` call returning anything other than a `boolean`. Maybe, I will change the API in some way to make it better and document it then. But feel free to also try this, I am proud of this feature :)
|
||||
|
||||
And thats all for now, have fun and write more code.
|
||||
|
Before Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 126 KiB |
|
Before Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 521 KiB |
@@ -1,14 +0,0 @@
|
||||
# HumbleMatch
|
||||
Will **Sanitize your type-checks and duck-checks** for you
|
||||
|
||||
Available at [HumbleMatch@pypi]()
|
||||
|
||||
|
||||
## What the heck is it?
|
||||
|
||||
HumbleMatch is made to *add a zing* to your mundane type-checking and duck-checking code.
|
||||
|
||||
* Check your function arguments reliably, add *more flexible signatures* and most of all, have a lovely API.
|
||||
* Or just *sprinkle some assert* checks to ensure the data is what you expect it to be at any point.
|
||||
* Provide helpful debugging errors, *dont just fail with cryptic errors*
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
Title: HumbleMatch - Go sanitize your type-checking
|
||||
Date: 2015-06-19 16:56
|
||||
Authors: bendtherules
|
||||
Category: Projects
|
||||
Tags: HumbleMatch, Launch stuff, Projects
|
||||
Slug: HumbleMatch_Launch
|
||||
|
||||
## Intro
|
||||
|
||||
Hi, I am [Abhas](blog.codesp.in) and personally, I love Python mostly for its intuitive, flexible and beautiful API. But some things, I really hate doing. HumbleMatch is my attempt at solving that pain.
|
||||
Hi, I am [Abhas](http://blog.codesp.in) and personally, I love Python mostly for its intuitive, flexible and beautiful API. But some things, I really hate doing. HumbleMatch is my attempt at solving that pain.
|
||||
|
||||
|
||||
## The Pain Point #1
|
||||
@@ -241,4 +235,6 @@ Infact now that we know this, in Test 2 we can remove the repetion of `w([float]
|
||||
|
||||
I purposedly missed one method which is already there, called `w(obj).save_as(arg_name)`. How it works is that whatever it matches with is stored as `"arg_name"` and returns a dict filled with all such values, when `==`d with `other`. For eg `w([2, w(int).save_as("a"), OR(str,dict)).save_as("b")]) == [2,5,{"q":1}]` returns `{"a":5,"b":{"q":1}}`. I didnt document it well beacuse I am not mentally ok with a `==` call returning anything other than a `boolean`. Maybe, I will change the API in some way to make it better and document it then. But feel free to also try this, I am proud of this feature :)
|
||||
|
||||
I have not yet talked about how it helps duck-typing code, but I'll add it soon (there is no more API for it, just need to apply these to objects and use FunctionType as type).
|
||||
|
||||
And thats all for now, have fun and write more code.
|
||||
|
||||
|
After Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 521 KiB After Width: | Height: | Size: 5.9 KiB |
@@ -1,7 +1,15 @@
|
||||
# HumbleMatch
|
||||
Will **Sanitize your type-checks and duck-checks** for you
|
||||
|
||||
Available at [HumbleMatch@pypi]()
|
||||
")
|
||||
|
||||
**Install using**
|
||||
`pip install humblematch`
|
||||
|
||||
|
||||
Github Repo at [github.com/bendtherules/humblematch](http://github.com/bendtherules/humblematch)
|
||||
|
||||
Available at [HumbleMatch@pypi](https://pypi.python.org/pypi/humblematch)
|
||||
|
||||
|
||||
## What the heck is it?
|
||||
@@ -12,3 +20,15 @@ HumbleMatch is made to *add a zing* to your mundane type-checking and duck-check
|
||||
* Or just *sprinkle some assert* checks to ensure the data is what you expect it to be at any point.
|
||||
* Provide helpful debugging errors, *dont just fail with cryptic errors*
|
||||
|
||||
## Impress me
|
||||
|
||||
Lets say we want a Point class with two __init__ signatures - `Point(x,y)` and `Point([x,y])`.
|
||||
|
||||
Assume its `__init__` signature looks like `def __init__(self, x, y=None)`
|
||||
|
||||
This is the only typechecking code you'll need for valid arguments.
|
||||
|
||||
from humblematch import w
|
||||
assert( w([int, int]) == [x, y] or w([[int, int], None]) == [x, y] )
|
||||
|
||||
If you like it, please move to the [Tutorials](./Tutorial). Its a bit long, but that all the documentation youll need to know.
|
||||
|
||||
@@ -1,125 +0,0 @@
|
||||
fmatch
|
||||
.matched
|
||||
.wrap
|
||||
.Any
|
||||
.old_matched
|
||||
|
||||
list_ -> fmatch -> [2,+(wrap([Int])*Any), [Any]*4 and fmatch(matched.len < old_matched[-1].len) ] (1)
|
||||
matches [2, 3,5,8,9,1, [1,2,3,4]]
|
||||
|
||||
*(wrap([Int])*Any) => *(wrap([Int]).times(Any))
|
||||
|
||||
list_ -> fmatch -> [2,Any, wrap(int)*4 and (matched[0]*2 > 5 or all([m >6 for m in matched]) ] -> _, a, b
|
||||
|
||||
|
||||
list_ -> fmatch -> [2,Any*Any,5]
|
||||
|
||||
basically need a mock object of sorts which stores everything, tries to stop evaluation, so that invalid (wrt types,values) ones work. invalid syntax still wont work.
|
||||
|
||||
|
||||
macros in python
|
||||
|
||||
pass in a string or function, have a great pattern matching like lisp and then do your own stuff ( like http://stackoverflow.com/questions/267862/what-makes-lisp-macros-so-special#4621882 )
|
||||
|
||||
look for reaasembler in python
|
||||
|
||||
(1) -> [2, multi_0, list(Any,Any,Any,Any)]
|
||||
|
||||
|
||||
wrap([Int]) = wrap_obj(data =[Int])
|
||||
creates wrap_obj with data = param and ops =[]
|
||||
if ops are applied store them
|
||||
apply right then correctly or later (???)
|
||||
|
||||
|
||||
|
||||
(wrap([Int, Float])*Any) = wrap_obj(data =[Int, Float], ops =[__mult__:Any])
|
||||
if ops[__mult__] is Any and data is list:
|
||||
this == wrap_obj(data =[ wrap_multi_obj(data = [Int, Float],multi = Any, ops =None) ], ops =None)
|
||||
if (data not list):
|
||||
# eg 2
|
||||
try normal __mult__ anyway
|
||||
if ops[__mult__] is not Any:
|
||||
# eg [2,3]*5
|
||||
try normal __mult__ anyway
|
||||
|
||||
## Done
|
||||
WrapObj
|
||||
WrapMultiObj
|
||||
|
||||
## Done
|
||||
wrap(Float).times(Any) == wrap_multi_obj(data = [Float],multi = Any, ops =None)
|
||||
wrap([2,3.0]).times(Any) == wrap_multi_obj(data = [[2,3.0]],multi = Any, ops =None)
|
||||
.times means the whole thing will repeat n times
|
||||
first doing all ops and, replace wrap_obj with wrap_multi_obj putting new data=[data]
|
||||
to repeat multiple items sequentially -> (2,3) say n times as in 2,3,2,3,2,3,.. do +(wrap([2,3.0]).times(Any))
|
||||
|
||||
### Not needed ###
|
||||
+(wrap([Int])*Any) == wrap(Int).times(Any)
|
||||
== wrap_multi_obj(data = [Int],multi = Any, ops =None)
|
||||
if prev is wrap_obj and data is list:
|
||||
removes prev node, and replace with wrap_multi_obj with same data
|
||||
|
||||
+ is the unwrap op
|
||||
|
||||
XXXX
|
||||
types of indirect matching
|
||||
|
||||
1. type-based (X This is what exact match does)
|
||||
2. Checking subclass-tree (issubclass)
|
||||
3. explicit conversion-based (converts 1st arg of fmatch to type of 2nd arg) -- usually quite good
|
||||
4. ABC-based somewhat
|
||||
|
||||
try to use abc for multiple types
|
||||
|
||||
functional prog is like passing little chunks of data, however less you can. but you will lose sense of what data it is.
|
||||
imperative prog is like having a structure of data and partially modifying it, yet sending the whole thing over.
|
||||
if you know about every data, fp - like experts.
|
||||
if you want to ask about everything, imp. safer in some sense
|
||||
|
||||
types like putting a label. one label attests to a number of similar properties, so if you got type use all those properties even with the assumptions that how they behave with each other
|
||||
|
||||
duck typing is like letting anyone with a known speciific skill work in your office. They dont need degrees or anything if they know that one thing very well which you'll need. And yes that is very flexible and democratic. But never assume that they will even have some related but different skill. Degrees attest to the fact that they know about a set of skills. All that cool.
|
||||
Now if you have any more requirement, ask if they can do it and if they cant, fire them. Or force them to do it, if they fail fire them. But rest assured, you are more flexible so anyone with both those skills are welcome now, even the one you just fired if they end up learning that skill.
|
||||
|
||||
issue of flexibility vs reliability, you sometimes want both :)
|
||||
|
||||
Ceveats
|
||||
This wont work
|
||||
1. WrapObj({str:5}) == {"w":5} as dicts are not searched for key and yet they are ambiguous if searched. So, keys are taken for what they are, even if it is a class. So, here str is considered as the key
|
||||
|
||||
for mixed type:
|
||||
allow this kind of things -> int or float("inf")
|
||||
|
||||
IDEAS TO DO
|
||||
|
||||
add more debug info
|
||||
debug info or raise custom exception
|
||||
better __repr__ print
|
||||
|
||||
allow matches to store in var (done)
|
||||
|
||||
add __mult__ alternative to .times (done)
|
||||
|
||||
what about dict ? (dicts ok, )
|
||||
|
||||
maybe dict to obj? (done)
|
||||
|
||||
save_as in multimatch with list behaviour(done)
|
||||
|
||||
Any and OR save_as (done)
|
||||
|
||||
test if data == Multi branch, raise error doesnt break anything
|
||||
more docs
|
||||
|
||||
test integration save_as and times
|
||||
|
||||
do smart .times for single value
|
||||
|
||||
allow Any with a module.Class(Any), which allows only object - Any
|
||||
|
||||
more doctest for other methods and helpers
|
||||
|
||||
test helpers
|
||||
|
||||
name change to humblematch
|
||||
@@ -1,4 +1,4 @@
|
||||
from wrap_obj import WrapObj, Any, OR, w
|
||||
from humblematch import WrapObj, Any, OR, w
|
||||
import collections
|
||||
import pytest
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
site_name: HumbleMatch
|
||||
|
||||
theme: cerulean
|
||||
|
||||
docs_dir: humblematch/docs
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
Run doctest -
|
||||
python -m doctest .\wrap_obj.py
|
||||
|
||||
Run py.test-
|
||||
py.test
|
||||
@@ -1,18 +1,56 @@
|
||||
# HumbleMatch
|
||||
--------------
|
||||
Will **Sanitize your type-checks and duck-checks** for you
|
||||
|
||||
")
|
||||
|
||||
**Install using**
|
||||
`pip install humblematch`
|
||||
|
||||
Github Repo at [github.com/bendtherules/humblematch](http://github.com/bendtherules/humblematch)
|
||||
|
||||
Available at [HumbleMatch@pypi](https://pypi.python.org/pypi/humblematch)
|
||||
|
||||
More Docs at [humblematch.readthedocs.org](http://humblematch.readthedocs.org/en/latest/)
|
||||
|
||||
## What the heck is it?
|
||||
|
||||
HumbleMatch is made to *add a zing* to your mundane type-checking and duck-checking code.
|
||||
|
||||
* Check your function arguments reliably, add *more flexible signatures* and most of all, have a lovely API.
|
||||
* Or just *sprinkle some assert* checks to ensure the data is what you expect it to be at any point.
|
||||
* Provide helpful debugging errors, *dont just fail with cryptic errors*
|
||||
|
||||
|
||||
## Run doctest -
|
||||
## Get Running
|
||||
--------------
|
||||
|
||||
python -m doctest .\wrap_obj.py
|
||||
### Run doctest -
|
||||
|
||||
## Run tests-
|
||||
python -m doctest .\humblematch\wrap_obj.py
|
||||
|
||||
### Run tests-
|
||||
cd humblematch
|
||||
py.test
|
||||
|
||||
## To build -
|
||||
### To build code -
|
||||
|
||||
python setup.py sdist bdist_wheel bdist_msi bdist_egg
|
||||
|
||||
python setup.py sdist bdist_wheel
|
||||
python setup.py build --plat-name=win-amd64 bdist_wininst
|
||||
|
||||
python setup.py build --plat-name=win32 bdist_wininst
|
||||
|
||||
To upload -
|
||||
twine upload dist/*
|
||||
### To upload to PYPI-
|
||||
|
||||
twine upload dist/* -r pypi
|
||||
|
||||
### To build or serve docs
|
||||
|
||||
mkdocs build
|
||||
|
||||
or
|
||||
|
||||
mkdocs serve
|
||||
|
||||
-----
|
||||
|
||||
@@ -1,15 +1,43 @@
|
||||
import sys
|
||||
from setuptools import setup
|
||||
from setuptools.command.test import test as TestCommand
|
||||
|
||||
|
||||
class PyTest(TestCommand):
|
||||
user_options = [('pytest-args=', 'a', "Arguments to pass to py.test")]
|
||||
|
||||
def initialize_options(self):
|
||||
TestCommand.initialize_options(self)
|
||||
self.pytest_args = []
|
||||
|
||||
def finalize_options(self):
|
||||
TestCommand.finalize_options(self)
|
||||
self.test_args = []
|
||||
self.test_suite = True
|
||||
|
||||
def run_tests(self):
|
||||
# import here, cause outside the eggs aren't loaded
|
||||
import pytest
|
||||
errno = pytest.main(self.pytest_args)
|
||||
sys.exit(errno)
|
||||
|
||||
|
||||
setup(
|
||||
name='humblematch',
|
||||
packages=['humblematch'], # this must be the same as the name above
|
||||
version='0.1.dev2',
|
||||
version='0.1.1',
|
||||
description='Will Sanitize your type-checks and duck-checks for you',
|
||||
author='bendtherules',
|
||||
author_email='bendtherules@codesp.in',
|
||||
url='https://github.com/bendtherules/humblematch', # use the URL to the github repo
|
||||
download_url='https://github.com/bendtherules/humblematch/tarball/0.1.dev1', # I'll explain this in a second
|
||||
download_url='https://github.com/bendtherules/humblematch/tarball/0.1.dev3', # I'll explain this in a second
|
||||
license='WTFPL',
|
||||
keywords=['type-checking', 'testing', 'assert'], # arbitrary keywords
|
||||
classifiers=['Development Status :: 3 - Alpha', ],
|
||||
package_data={
|
||||
# Include all files in all packages
|
||||
# 'humblematch': ['docs/*.md', 'test/*'],
|
||||
},
|
||||
tests_require=['pytest'],
|
||||
cmdclass={'test': PyTest},
|
||||
)
|
||||
|
||||