GithubHelp home page GithubHelp logo

andreacensi / contracts Goto Github PK

View Code? Open in Web Editor NEW
399.0 399.0 61.0 12.48 MB

PyContracts is a Python package that allows to declare constraints on function parameters and return values. Contracts can be specified using Python3 annotations, or inside a docstring. PyContracts supports a basic type system, variables binding, arithmetic constraints, and has several specialized contracts and an extension API.

Home Page: http://andreacensi.github.io/contracts/

License: Other

Makefile 0.75% Python 99.25%

contracts's People

Contributors

adampalay avatar andreacensi avatar cpennington avatar hayd avatar joshblum avatar koffie avatar singuliere avatar slorg1 avatar textbook avatar xion avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

contracts's Issues

Boolean values are allowed to be returned when int required.

This small example should be all that is needed to explain the problem.

from contracts import contract

@contract(url=str, returns=int)
def validate_url(url=""):
    """ returns True if the input is a valid url """
    return False

print validate_url("google.com")
# False

Map functionality for collection types

I also noticed, and maybe I am wrong, that I cannot easily apply a custom validation function over all objects of a collection, be they a dict or list. This may be something that others will find useful as well. For example, maybe I want to validate that all items in a list are only alpha-numeric, have at most 2 numerals and say are no longer than 30 chars.

Anyway, sounds esoteric, but I have use for this today.

Add isNotNone support

Hello. I propose the following syntax to implement

@contract(arg="notNone")
def function(arg):
  pass

Action: perform the following python code

assert(arg is not None)

Built in support for higher order functions contracts?

Hi Andrea!

I only quickly skimmed through the docs, so I might missed something, but it seems that it's not possible to (out of the box) declare a contract on the function that takes function as an argument and returns another function. I'm dealing with a lot of functional-style code lately and I thought that this could be very handy in certain situations. I'm guessing it's possible to add support for this via custom contracts easily (haven't tried yet, but I'm going to) and what I'd like to know is if has a chance of becoming built in if implemented. (For example of this feature check here: http://docs.racket-lang.org/guide/contract-func.html#(part._.Contracts_on_.Higher-order_.Functions) )

Also, in some contracts library for CoffeeScript (which wasn't actually working IIRC :)) I saw an idea of embedding object's invariants into its methods' contracts. This should be easy enough, given the fact that self is explicitly passed in Python, but it would require having a syntax for making contracts for objects' attributes, which I didn't see built in either? I think I'll be exploring some possibilities in the course of next few weeks, I just wanted to know what do you, as an author and maintainer, think about these ideas.

Best regards,
Piotr Klibert

Better context in tracebacks when contracts fail?

The exception messages on contract failures can be very long, which makes it more difficult to find the context of the code where the contract failed. I wonder if the standard contract message should try to re-embed some of the lines surrounding the failure location towards the bottom of the exception message?

A set is considered to be a sequence

Hi, I've just faced a problem that seq fails to match a set:

Expected a sequence, got 'set'.
checking: seq for value: Instance of set: set(['\xa3\x9a\x05\x10\xa7l\xc61\x8e', '\xd... [clip]

Is it by design?

Abstraction of dimensionality?

I was curious for the numpy part of the library if you had considered anything like abstracting over lists of dimensions?

Would love to be able to write something like this:

@contract
def batch_matrix_multiply(a,  b):
    ''' Multiplies two batches fo matrices together.

        :param a: The first tensor, must end in MxN.
         :type a: array[*xMxN],M>0,N>0

        :param b: The second tensor, must end in NxP
         :type b: array[*xNxP],P>0

          :rtype: array[*xMxP]
    '''

cannot specify parameter type as file in docstring

Is there a way to specify that a parameter's type is file in the docstring?
The expression ":type in_file: file" does not work, nor do other formats I could think of.
(Note that the decorator "@contract(in_file=file)" works, but I'd like to use the docstring.)

String contracts don't accept ! (not)

Hello,

If I try using this

@contract(txt_pn='str, != ""', returns='list(str, != ""')
def load_txt2lst(txt_pn):
    # type: (str) -> List[str]
    ...

or this

@contract(txt_pn='str, != \'\'', returns='list(str, != \'\'')
def load_txt2lst(txt_pn):
    # type: (str) -> List[str]
    ...

this error is returned

...
    return parse_contract_string_actual(string)
  File "C:\Users\JMatos\Envs\solve_sudoku\lib\site-packages\contracts\main_actua
l.py", line 41, in parse_contract_string_actual
    raise ContractSyntaxError(msg, where=where)
contracts.interface.ContractSyntaxError: Expected operation with ["!"] (at char
13), (line:1, col:14)

 line  1 |list(str, != ""
                       \u2191

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "solve_sudoku.py", line 58, in <module>
    @contract(txt_pn='str, != ""', returns='list(str, != ""')
  File "C:\Users\JMatos\Envs\solve_sudoku\lib\site-packages\contracts\main.py",
line 149, in tmp_wrap
    raise e.copy()
contracts.interface.ContractSyntaxError: Expected operation with ["!"] (at char
13), (line:1, col:14)

 line  1 |list(str, != ""
                       \u2191

I am doing something wrong or is it a bug?

I'm using Python 3.5.4 32b and pycontracts 1.8.3 under Windows 7 Pro x64.

Thanks,

JM

Better support for generic iterators

write now it is possible to do

new_contract('alistofstrings', 'list(string)')

but not

new_contract('aniteratorofstrings', 'Iterator(string)')

or

new_contract('aniteratorofstrings', 'Sequence(string)')

This really stifles polymorphism. I want it to accept a tuple, or a list, etc. Maybe I'm
missing something?

NB: (On a related note, I'd like something that would accept generators too, but that has it's own problems).

Variable binding in new_contract

With the following code:

from contracts import contract, new_contract

new_contract('vector', 'list[N]')

@contract
def foo(X: 'vector', y: 'vector'):
    pass

foo([1, 2, 3], [1, 2])

I would've expected it to fail since the two lists have different lengths, but it doesn't throw an error. However, if I don't use new_contract, it works. Is this the intended behaviour? If so, how would I get the behaviour that I want? I'm using version 1.7.15.

Different behaviour when using 2 contract notations

Hello,

I'm just trying out pycontracts and found this strange behavior when using different contract notations.
I import my module and run the function with an invalid argument and the contract's checks work fine when using this notation:

square_size = 9  # type: int

nr_rows = square_size  # type: int
nr_cols = square_size  # type: int

@contract(row_nr='int, >= 0, < $nr_rows', col_nr='int, >= 0, < $nr_cols',
                  returns='int,>= 0, < $square_size')
def loc2square_nr(row_nr, col_nr):
    # type: (int, int) -> int
    """Convert location (row, column) to square number.

    (int, int) -> int

    :param row_nr: Row number to convert to square number.
    :param col_nr: Column number to convert to square number.
    :return: Square number.
    """
    square_nr = (int(row_nr / square_side) * square_side
                 + int(col_nr / square_side))  # type: int

    return square_nr

But if I change the contract notation to inside the docstring, like this:

square_size = 9  # type: int

nr_rows = square_size  # type: int
nr_cols = square_size  # type: int

@contract
def loc2square_nr(row_nr, col_nr):
    # type: (int, int) -> int
    """Convert location (row, column) to square number.

    :param row_nr: Row number to convert to square number.
    :type row_nr: int, >= 0, < $nr_rows
    :param col_nr: Column number to convert to square number.
    :type col_nr: int, >= 0, < $nr_cols
    :return: Square number.
    :rtype: int, >= 0, < $square_size
    """
    square_nr = (int(row_nr / square_side) * square_side
                 + int(col_nr / square_side))  # type: int

    return square_nr

Python returns a huge error when importing the module (I called it base.py).
This is the final part of the error:

    value = self._parseNoCache(instring, loc, doActions, callPreParse)
  File "C:\Users\JMatos\Envs\solve_sudoku\lib\site-packages\pyparsing.py", line
1405, in _parseNoCache
    tokens = fn( instring, tokensStart, retTokens )
  File "C:\Users\JMatos\Envs\solve_sudoku\lib\site-packages\pyparsing.py", line
1049, in wrapper
    ret = func(*args[limit[0]:])
  File "C:\Users\JMatos\Envs\solve_sudoku\lib\site-packages\contracts\utils.py",
 line 247, in f2
    return f(*args, **kwargs)
  File "C:\Users\JMatos\Envs\solve_sudoku\lib\site-packages\contracts\library\sc
oped_variables.py", line 95, in scoped_parse_action
    val = _lookup_from_calling_scope(tokens[0])
  File "C:\Users\JMatos\Envs\solve_sudoku\lib\site-packages\contracts\library\sc
oped_variables.py", line 67, in _lookup_from_calling_scope
    raise ExternalScopedVariableNotFound(token)
contracts.interface.ExternalScopedVariableNotFound: Token not found: 'square_siz
e'.
>>>

If I understand correctly, pycontracts doesn't recognize the variable square_size in the 2nd notation. But it does on the 1st.

I'm using Python 32b 3.5.4 with pycontracts 1.8.3. I'm running on a Windows 7 Pro x64 PC.

Thanks,

JM

pyparsing 2.1.6 breaks pycontracts

It works if I use pyparsing 2.1.5. Here's the traceback:

Python 3.5.1 (default, Jul 12 2016, 22:16:50) 
[GCC 4.9.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import contracts  
Traceback (most recent call last):
  File "/usr/lib/python3.5/site-packages/contracts/useful_contracts/numbers.py", line 6, in <module>
    import numpy  # @UnusedImport
ImportError: No module named 'numpy'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 1501, in _parseCache
    value = self._parseNoCache(instring, loc, doActions, callPreParse)
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 1392, in _parseNoCache
    tokens = fn( instring, tokensStart, retTokens )
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 1036, in wrapper
    ret = func(*args[limit[0]:])
  File "/usr/lib/python3.5/site-packages/contracts/library/suggester.py", line 108, in parse_action
    raise ParseSyntaxException(pe)
pyparsing.ParseSyntaxException: Unknown identifier 'float'. Did you mean 'Float'? (at char 0), (line:1, col:1)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.5/site-packages/contracts/__init__.py", line 44, in <module>
    from .useful_contracts import *
  File "/usr/lib/python3.5/site-packages/contracts/useful_contracts/__init__.py", line 8, in <module>
    from .numbers import *
  File "/usr/lib/python3.5/site-packages/contracts/useful_contracts/numbers.py", line 8, in <module>
    new_contract('float', 'Float')
  File "/usr/lib/python3.5/site-packages/contracts/main.py", line 535, in new_contract
    return new_contract_impl(*args)
  File "/usr/lib/python3.5/site-packages/contracts/main.py", line 562, in new_contract_impl
    c = parse_contract_string(identifier)
  File "/usr/lib/python3.5/site-packages/contracts/main.py", line 649, in parse_contract_string
    return parse_contract_string_actual(string)
  File "/usr/lib/python3.5/site-packages/contracts/main_actual.py", line 30, in parse_contract_string_actual
    parseAll=True)[0]
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 1594, in parseString
    loc, tokens = self._parse( instring, 0 )
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 1501, in _parseCache
    value = self._parseNoCache(instring, loc, doActions, callPreParse)
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 1366, in _parseNoCache
    loc,tokens = self.parseImpl( instring, preloc, doActions )
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 3567, in parseImpl
    return self.expr._parse( instring, loc, doActions, callPreParse=False )
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 1501, in _parseCache
    value = self._parseNoCache(instring, loc, doActions, callPreParse)
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 1366, in _parseNoCache
    loc,tokens = self.parseImpl( instring, preloc, doActions )
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 3373, in parseImpl
    ret = e._parse( instring, loc, doActions )
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 1501, in _parseCache
    value = self._parseNoCache(instring, loc, doActions, callPreParse)
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 1366, in _parseNoCache
    loc,tokens = self.parseImpl( instring, preloc, doActions )
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 3567, in parseImpl
    return self.expr._parse( instring, loc, doActions, callPreParse=False )
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 1501, in _parseCache
    value = self._parseNoCache(instring, loc, doActions, callPreParse)
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 1366, in _parseNoCache
    loc,tokens = self.parseImpl( instring, preloc, doActions )
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 3567, in parseImpl
    return self.expr._parse( instring, loc, doActions, callPreParse=False )
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 1501, in _parseCache
    value = self._parseNoCache(instring, loc, doActions, callPreParse)
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 1366, in _parseNoCache
    loc,tokens = self.parseImpl( instring, preloc, doActions )
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 3373, in parseImpl
    ret = e._parse( instring, loc, doActions )
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 1501, in _parseCache
    value = self._parseNoCache(instring, loc, doActions, callPreParse)
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 1366, in _parseNoCache
    loc,tokens = self.parseImpl( instring, preloc, doActions )
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 3567, in parseImpl
    return self.expr._parse( instring, loc, doActions, callPreParse=False )
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 1501, in _parseCache
    value = self._parseNoCache(instring, loc, doActions, callPreParse)
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 1366, in _parseNoCache
    loc,tokens = self.parseImpl( instring, preloc, doActions )
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 3221, in parseImpl
    loc, resultlist = self.exprs[0]._parse( instring, loc, doActions, callPreParse=False )
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 1501, in _parseCache
    value = self._parseNoCache(instring, loc, doActions, callPreParse)
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 1366, in _parseNoCache
    loc,tokens = self.parseImpl( instring, preloc, doActions )
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 3221, in parseImpl
    loc, resultlist = self.exprs[0]._parse( instring, loc, doActions, callPreParse=False )
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 1501, in _parseCache
    value = self._parseNoCache(instring, loc, doActions, callPreParse)
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 1366, in _parseNoCache
    loc,tokens = self.parseImpl( instring, preloc, doActions )
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 3567, in parseImpl
    return self.expr._parse( instring, loc, doActions, callPreParse=False )
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 1501, in _parseCache
    value = self._parseNoCache(instring, loc, doActions, callPreParse)
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 1366, in _parseNoCache
    loc,tokens = self.parseImpl( instring, preloc, doActions )
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 3373, in parseImpl
    ret = e._parse( instring, loc, doActions )
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 1501, in _parseCache
    value = self._parseNoCache(instring, loc, doActions, callPreParse)
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 1366, in _parseNoCache
    loc,tokens = self.parseImpl( instring, preloc, doActions )
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 3567, in parseImpl
    return self.expr._parse( instring, loc, doActions, callPreParse=False )
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 1501, in _parseCache
    value = self._parseNoCache(instring, loc, doActions, callPreParse)
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 1366, in _parseNoCache
    loc,tokens = self.parseImpl( instring, preloc, doActions )
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 3221, in parseImpl
    loc, resultlist = self.exprs[0]._parse( instring, loc, doActions, callPreParse=False )
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 1501, in _parseCache
    value = self._parseNoCache(instring, loc, doActions, callPreParse)
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 1366, in _parseNoCache
    loc,tokens = self.parseImpl( instring, preloc, doActions )
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 3221, in parseImpl
    loc, resultlist = self.exprs[0]._parse( instring, loc, doActions, callPreParse=False )
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 1501, in _parseCache
    value = self._parseNoCache(instring, loc, doActions, callPreParse)
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 1366, in _parseNoCache
    loc,tokens = self.parseImpl( instring, preloc, doActions )
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 3567, in parseImpl
    return self.expr._parse( instring, loc, doActions, callPreParse=False )
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 1501, in _parseCache
    value = self._parseNoCache(instring, loc, doActions, callPreParse)
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 1366, in _parseNoCache
    loc,tokens = self.parseImpl( instring, preloc, doActions )
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 3373, in parseImpl
    ret = e._parse( instring, loc, doActions )
  File "/usr/lib/python3.5/site-packages/pyparsing.py", line 1504, in _parseCache
    cache.set(lookup, pe.__class__(*pe.args))
TypeError: __init__() takes 2 positional arguments but 4 were given
>>> 

Errors cause nosetests to be unable to continue, due to contract redefinition

Consider a file foo.py (note, this is condensed from the real test case; apologies for typos, etc.):

from contracts import contract, new_contract

@new_contract
def myContract(inst):
    return isinstance(inst, object)

class Foo(object):
    @contract
    def __init__(self, a):
        """
        :type a: number,$$%^^&
        """
        pass

If foo gets imported in multiple test cases (we're running them via python setup.py nosetests), then the following occurs:

======================================================================
ERROR: Failure: ContractSyntaxError (Expected "(" (at char 8), (line:1, col:9)

 line  1 >number,$$%^^&
                  ^
                  |
                  here or nearby)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/nose/loader.py", line 390, in loadTestsFromName
    addr.filename, addr.module)
  File "/usr/local/lib/python2.7/dist-packages/nose/importer.py", line 39, in importFromPath
    return self.importFromDir(dir_path, fqname)
  File "/usr/local/lib/python2.7/dist-packages/nose/importer.py", line 86, in importFromDir
    mod = load_module(part_fqname, fh, filename, desc)
...
  File "/usr/local/lib/python2.7/dist-packages/contracts/main.py", line 159, in contract_decorator
    return contracts_decorate(function, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/contracts/main.py", line 224, in contracts_decorate
    for x in accepts_dict])
  File "/usr/local/lib/python2.7/dist-packages/contracts/main.py", line 306, in parse_flexible_spec
    return parse_contract_string(spec)
  File "/usr/local/lib/python2.7/dist-packages/contracts/main.py", line 80, in parse_contract_string
    raise ContractSyntaxError(msg, where=where)
ContractSyntaxError: Expected "(" (at char 8), (line:1, col:9)

 line  1 >number,$$%^^&
                  ^
                  |
                  here or nearby

======================================================================
ERROR: Failure: ValueError (Tried to redefine 'myContract' with a definition that looks different to me.
 - old: CheckCallable(<function myContract at 0x3198410>)
 - new: CheckCallable(<function myContract at 0x39427d0>)
)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/nose/loader.py", line 390, in loadTestsFromName
    addr.filename, addr.module)
  File "/usr/local/lib/python2.7/dist-packages/nose/importer.py", line 39, in importFromPath
    return self.importFromDir(dir_path, fqname)
  File "/usr/local/lib/python2.7/dist-packages/nose/importer.py", line 86, in importFromDir
    mod = load_module(part_fqname, fh, filename, desc)
...
  File "/usr/local/lib/python2.7/dist-packages/contracts/main.py", line 493, in new_contract
    new_contract_impl(identifier, function)
  File "/usr/local/lib/python2.7/dist-packages/contracts/main.py", line 577, in new_contract_impl
    raise ValueError(msg)
ValueError: Tried to redefine 'myContract' with a definition that looks different to me.
 - old: CheckCallable(<function myContract at 0x3198410>)
 - new: CheckCallable(<function myContract at 0x39427d0>)

The ValueError is repeated for every subsequent test case that imports foo, even if the class with the broken definition is not used. This can make it difficult to find the real error when there are a large number of test cases.

Improve string support

Hello,

Starting from a very simple integer-related contract:
int,(-1 | 1)

I've tried to write the same kind of contract, but for string values, e.g.:
string,(a | b)

Unfortunately, that syntax is not accepted by PyContracts.

It would also be nice to introduce regexp in contracts, to be matched against string values.

Thanks.

1.7.7 release on PyPI doesn't build for Python 3

setup.py fails with the following error, and the code doesn't seem to be here :/

Traceback (most recent call last):
  File "setup.py", line 35, in <module>
    version = get_version(filename='src/contracts/__init__.py')
  File "setup.py", line 24, in get_version
    with file(filename) as f:
NameError: name 'file' is not defined

Docstring can't see local variables

Full tracebak here

In [13]: @contract
def fn(x):
        ''':type x: $SeqRecord'''
        return x.seq
.....
.....
raise RuntimeError("Cound not find a scope to lookup %s" % token)

ExternalScopedVariableNotFound: Token not found: 'SeqRecord'.

But it works fine outside of docstring:

In [13]: @contract(x='$SeqRecord')
def fn(x):
        return x.seq
In[14] # no error

Support for parametrized types annotations in Python3 (e.g. List[int])

Hi,
I have example

@contract
def double(x:List[int]) -> List[int]:
    return list(map(lambda x:x*2, x))


double([1.245])  # doesn't complain about type problem
double(False)  #complains about type problem (correctly)

that currently doesn't work but it should (and I believe it's already implemented because same functionality works using contracts-native string annotation). Is there any plan to support fully Python 3 types?

http://andreacensi.github.io/contracts/api_lowlevel.html typo

new_contract('valid_name', lambda s: isinstance(s, str) and len(s)>0)
@contract(names='dict(int: (valid_name, int))')
def process_accounting(records):
    ...

should be

new_contract('valid_name', lambda s: isinstance(s, str) and len(s)>0)
@contract(records='dict(int: (valid_name, int))')
def process_accounting(records):
    ...

`number` does not respect `long`

In [32]: @contract(a='number')
    ...: def foo(a):
    ...:     return a
In [33]: foo(9999999L)
 . . . .  . . .  . 
.................. # long error outptut here
 ------- (end clauses) -------
checking: float|int|uint      for value: Instance of <type 'long'>: 9999999L   
checking: $(float|int|uint)   for value: Instance of <type 'long'>: 9999999L   
checking: number              for value: Instance of <type 'long'>: 9999999L   
Variables bound in inner context:

Unicode strings for contract names

Hi,
first of all, thanks for your awesome library!
Second, I added your library in a project of mine where I include unicode_literals (from __ future __) in all the modules, that is causing me some issues with your library because the contract decorator expects a lot of things but not a unicode object.

I was wondering if you could check on contracts/main.py:337 if the spec is an instance of basestring instead of str so that unicode will also match.

Thanks!

Error reporting for custom contracts

Hi Andrea,

I'm trying to define a custom contract using the new_contract function and the ist function from contracts.library.miscellaneous_aliases as follows:

new_contract('virConnect', ist(libvirt.virConnect))

The actual checking of the argument type works, i.e. fails when the argument is not an instance of libvirt.virConnect. However, when it fails, the error message is not properly displayed. I'm getting the following exception:

Traceback (most recent call last):
  File "/usr/lib/python2.7/site-packages/pyqcy/integration.py", line 60, in test
    run_tests([prop], verbosity=0, propagate_exc=True)
  File "/usr/lib/python2.7/site-packages/pyqcy/runner.py", line 68, in run_tests
    failure.propagate_failure()
  File "/usr/lib/python2.7/site-packages/pyqcy/properties.py", line 127, in test_one
    result.tags = self.__execute_test(coroutine)
  File "/usr/lib/python2.7/site-packages/pyqcy/properties.py", line 148, in __execute_test
    obj = next(coroutine)
  File "/usr/lib/python2.7/site-packages/pyqcy/properties.py", line 81, in generator_func
    func(*args, **kwargs)
  File "/home/anton/repos/openstack-neat/tests/test_collector.py", line 58, in get_current_vms
    collector.get_current_vms(1)
  File "<string>", line 2, in get_current_vms
  File "/usr/lib/python2.7/site-packages/contracts/main.py", line 261, in contracts_checker
    accepts_parsed[arg]._check_contract(context, bound[arg])
  File "/usr/lib/python2.7/site-packages/contracts/interface.py", line 219, in _check_contract
    self.check_contract(context, value)
  File "/usr/lib/python2.7/site-packages/contracts/library/extensions.py", line 23, in check_contract
    self.contract._check_contract(context, value)
  File "/usr/lib/python2.7/site-packages/contracts/interface.py", line 219, in _check_contract
    self.check_contract(context, value)
  File "/usr/lib/python2.7/site-packages/contracts/library/extensions.py", line 69, in check_contract
    raise ValueError(msg)
CheckError: <unprintable CheckError object>

I suppose instead of , there should be a message like 'Value is not an instance of virConnect'. Do you know what the problem is?

Thanks,
Anton

Any added functionality for adding type + value checks?

I am looking for a method to add type + value checks to function arguments
eg.

  • storing a list of acceptable values most suitably in a class.
  • accessing these values and comparing the value passed to the argument against these in the function defined for the new contracts.
  • able to easily extract the acceptable set of values for later use.

Runtime is ~an order of magnitude slower than manual constraint writing

I tested this on my machine

import time
from contracts import contract

@contract(a='int,>0', b='list[N],N>0', returns='list[N]')
def c(a, b):
    return [a * i for i in b]

def d(a, b):
    assert isinstance(a, int)
    assert a > 0
    assert isinstance(b, list)
    assert len(b) > 0
    out = [a * i for i in b]
    assert len(out) == len(b)
    return out

tic = time.time()
x = list(range(100))
for i in range(1000):
    x = c(5, x)
tic2 = time.time()
print(tic2-tic)
x = list(range(100))
for i in range(1000):
    x = d(5, x)
tic3 = time.time()
print(tic3-tic2)

Found the result to be

$ python ttest.py
0.5048160552978516
0.07861089706420898

Are there any additional checks that are missing in my manual implementation?

Custom exception messages on breach of contract

@AndreaCensi, contracts is an awesome library, but I think one thing that would make it better, at least to me, is ability to define custom exceptions. For example, say I define a custom Type and then I want a specific error to be raised, ideally being able to pass parameters to that error, which would then allow me to do try/except and have a typical error object with .args and .message elements.

I have not really looked at implementation details, but seems it should be doable.

Simpler syntax for checking type name

Suggested by @doctoryes:

One point we've agreed upon here: It'd be nice to not have to specify new_contract('Foo', Foo) for our own classes. Instead, it'd be nice if PyContracts could just search the namespace for the classname when it's specified in a contract.

There is a similar undocumented feature that uses the expression isinstance(classname):

 @contract(x="isinstance(BlockKey)")
 def f(x):
     pass

This checks that the name of the type of x or any of its base classes is BlockKey.

(String matching is good because this way PyContracts doesn't need to import modules or search namespaces.)

The current syntax isinstance(name) is too verbose, and this this is a common enough use case that it deserves a more intuitive syntax. The main reason that this feature is undocumented because I couldn't decide on a good compact syntax.

Some possibilities:

@contract(x="^BlockKey")
@contract(x="$BlockKey")
@contract(x="@BlockKey")

or, in general, <glyph>ClassName.

Some non-possibilities:

This one is intuitive enough but it clashes with "<" used as numerical comparison:

@contract(x="<BlockKey") 

We cannot use simply:

@contract(x="BlockKey")  

because it makes many expressions ambiguous; for example lisst becomes a valid contract (a class named lisst) instead of a mispelling of list.

Certain bad annotations result in AttributeError (fixed, patch included)

Currently if you use the @contract decorator with a function that has something like
"""
:param myparam: something
"""
without specifying a :type myparam: you receive a traceback that looks like

File "[snip]/python2.6/site-packages/contracts/main.py", line 345, in remove_quotes
if x.startswith('') and x.endswith('') and len(x) > 3:
AttributeError: 'NoneType' object has no attribute 'startswith'

This is because on line 363, params[name].type is None, which is then passed into the remove_quotes function.

The following patch filters out malparsed params, thus stopping the error.

Patch follows:

@@ -356,6 +356,11 @@

     # These are the annotations
     params = annotations.params
+    #ignore non parsable params (TODO, perhaps warn?)
+    for name in params.keys():
+        if params[name].type is None:
+            del params[name]
+
     name2type = dict([(name, remove_quotes(params[name].type))
                        for name in params])

Add 'in' support

Hello. I propose the following syntax to implement

@contract(arg="str,in('a','b','c')")
def function(arg):
  pass

Action: perform the following python code

assert(arg in {'a', 'b', 'c'})

Contracts does not stop execution immediately having found an unexpected OR null input

Hi.

I think I have stumbled upon a bug or if not a bug then atleast an counterintuitive feature.
Consider the following code:

#!/usr/bin/python3
# -*- coding: utf8 -*-

from contracts import contract

class ObjectThatWillSeeDeathBeforeBeingBorn(object):

    @contract
    def __init__(self, TestingString: 'str[>0]'):
        print('String given as parameter: %s.' % TestingString)
        print('ID of ObjectThatWillSeeDeathBeforeBeingBorn: %s.' % id(self))

    def __del__(self):
        print('ID of object being killed: %s.' % id(self))


NewObjectForTestingTheBug = ObjectThatWillSeeDeathBeforeBeingBorn()

When executed as listed above we will get this as output:

$ python3 contracts_possible_bug.py 
ID of object being killed: 139899159500840.
Traceback (most recent call last):
  File "contracts_possible_bug.py", line 17, in <module>
    NewObjectForTestingTheBug = ObjectThatWillSeeDeathBeforeBeingBorn()
TypeError: __init__() missing 1 required positional argument: 'TestingString'

The notable thing here is that we don't get any output from init but we do get output from del.

If we modify the last line so it looks like this:
NewObjectForTestingTheBug = ObjectThatWillSeeDeathBeforeBeingBorn(42)
the output looks like this:

$ python3 contracts_possible_bug.py 
Traceback (most recent call last):
  File "contracts_possible_bug.py", line 17, in <module>
    NewObjectForTestingTheBug = ObjectThatWillSeeDeathBeforeBeingBorn(42)
  File "<decorator-gen-1>", line 2, in __init__
  File "/usr/local/lib/python3.5/dist-packages/contracts/main.py", line 260, in contracts_checker
    raise e
  File "/usr/local/lib/python3.5/dist-packages/contracts/main.py", line 255, in contracts_checker
    accepts_parsed[arg]._check_contract(context, bound[arg], silent=False)
  File "/usr/local/lib/python3.5/dist-packages/contracts/interface.py", line 439, in _check_contract
    self.check_contract(context, value, silent)
  File "/usr/local/lib/python3.5/dist-packages/contracts/library/strings.py", line 19, in check_contract
    value=value, context=context)
contracts.interface.ContractNotRespected: Breach for argument 'TestingString' to ObjectThatWillSeeDeathBeforeBeingBorn:__init__().
Expected a string, got 'int'.
checking: str[>0]   for value: Instance of <class 'int'>: 42   
Variables bound in inner context:
- self: Instance of <class '__main__.ObjectThatWillSeeDeathBeforeBeingBorn'>: <__main__.ObjectThatWillSeeDeathBeforeBeingBorn object at 0x7fe... [clip]
ID of object being killed: 140638653347880.

I had expected that when a breach of contract has been found everything grinds to a halt but we can see that in both cases code still gets executed.

Last but not least, thank You for Your great work on contracts!

List of defined contracts failing oddly

I'm attempting to match a list of a newly defined contract (using a function), however contracts.check is running the function with some odd arguments.

import contracts
import types


def cheese(tmp):
        print 'seeing value', tmp
        return False

contracts.check("list[int]", [1])
contracts.new_contract("cheese", cheese)
contracts.check("cheese|list[cheese]|None", [ZeroDivisionError])

When run it returns

seeing value [<type 'exceptions.ZeroDivisionError'>]
seeing value 1
Traceback (most recent call last):
  File "failtest.py", line 10, in <module>
  contracts.check("cheese|list[cheese]|None", [ZeroDivisionError])
  File "/var/envs/node/lib/python2.6/site-packages/contracts/main.py", line 422, in check
   raise e
contracts.interface.ContractNotRespected: Could not satisfy any of the 3 clauses in    cheese|list[cheese]|None.
 ---- Clause #1:   cheese
 | Value does not pass criteria of cheese() (module: __main__).
 | checking: function cheese()      for value: Instance of list: [<type 'exceptions.ZeroDivisionError'>]   
 | checking: cheese                 for value: Instance of list: [<type 'exceptions.ZeroDivisionError'>]   
 ---- Clause #2:   list[cheese]
 | Value does not pass criteria of cheese() (module: __main__).
 | checking: function cheese()      for value: Instance of int: 1                                          
 | checking: cheese                 for value: Instance of int: 1                                          
 | checking: list[cheese]           for value: Instance of list: [<type 'exceptions.ZeroDivisionError'>]   
 ---- Clause #3:   None
 | Value does not pass criteria of is_None() (module: contracts.library.miscellaneous_aliases).
 | checking: function is_None()      for value: Instance of list: [<type 'exceptions.ZeroDivisionError'>]   
 | checking: None                    for value: Instance of list: [<type 'exceptions.ZeroDivisionError'>]   
------- (end clauses) -------
checking: cheese|list[cheese]|None      for value: Instance of list: [<type 'exceptions.ZeroDivisionError'>]  

Which, is odd. Specificity i'm wondering why the contract handler for cheese gets run with "1" as an argument. I'm thinking that it might be because the parser is getting confused about it being a variable?

Error to extend the library

Hello,

I trying to doing a contract that return a post-condition as:

@contract(x=object)
def method(x)->x.operation(5):
    return x.operation(5)

I don't know if I'm doing something wrong or if not supportable, in the second case i want to request your help to do it, in order to extend the library.
Also i want to know if exist someway to construct an invariant into an object.

Thanks.

:param: without accompanying :type: results in "AttributeError: 'NoneType' object has no attribute 'startswith'"

The following script will produce an error:

#!/usr/bin/env python

from contracts import contract

@contract
def foo(bar, baz):
    '''
        :param bar: A thing.
        :type bar: str
        :param baz: Another thing.
    '''
    print bar, baz

if __name__ == '__main__':
    foo('hello', 'world')

The traceback is:

Traceback (most recent call last):
  File "foo.py", line 5, in <module>
    @contract
  File "/Users/geordan/src/contracts/src/contracts/main.py", line 166, in contract_decorator
    return contracts_decorate(function, **kwargs)
  File "/Users/geordan/src/contracts/src/contracts/main.py", line 228, in contracts_decorate
    accepts_dict, returns = parse_contracts_from_docstring(function)
  File "/Users/geordan/src/contracts/src/contracts/main.py", line 362, in parse_contracts_from_docstring
    for name in params])
  File "/Users/geordan/src/contracts/src/contracts/main.py", line 347, in remove_quotes
    if x.startswith('``') and x.endswith('``') and len(x) > 3:
AttributeError: 'NoneType' object has no attribute 'startswith'

When declaring a class, I cannot refer to the class in a contract...?

The following code doesn't work:

class CommodityType(object):
    """
    A generic commodity type.
    """
    def __init__(self, symbol):
    self.symbol = symbol

    # @contract(other=CommodityType)
    def __eq__(self, other):
    return self.symbol == other.symbol

It complains that CommodityType is not defined. Is there any way around this problem? I was trying to avoid having an isinstance check inside.

Thanks,

Checking post-conditions with returns

Similar to an older issue regarding the "tried to redefine 'xxx' with a definition that looks different to me" error (#4 ), we can get the same problem when trying to redefine returns. Think of the case that we create two new contracts for different methods and we want in both cases to check their post condition, using the special name "returns". For example in case in one method we want the return type to be bool and in another int we will get the following error:
ValueError: Tried to redefine 'returns' with a definition that looks different to me.

  • old: SeparateContext(CheckType(bool))
  • new: SeparateContext(CheckType(int))

Since checking what different function returns will always require "returns" redefinition wouldn't be better to add a check in main.py just before throwing the error and in case the identifier is "returns" just ignore it and continue? Is there any other way to do this postcondition checking other than using the "returns"?

Also, any plans for supporting invariants? I checked this issue #10 already and I am wondering if you plan to develop this any time soon...

Front ... for dimensionality

It is often convention to have the fixed dimensions in a numpy array be leading dimensions. However it seems like this syntax is not supported. Would it be possible to do this?

@contract
def batch_matrix_multiply(a,  b):
    ''' Multiplies two batches fo matrices together.

        :param a: The first tensor, must end in MxN.
         :type a: array[...xMxN],M>0,N>0

        :param b: The second tensor, must end in NxP
         :type b: array[...xNxP],P>0

          :rtype: array[...xMxP]
    '''

contracts on class structure

It would be helpful to check custom types.

For example if an instance of a class is defined as such :

class CustomClass(object):
    class_member = 42
    def __init__(self):
        inst_member = 23

cc_inst = CustomClass()

It would be useful to have a contract for a function that require such an instance.
To keep python duck-typing semantic, we can check the instance members (just like we do for dict), but checking one by one :

@contract("object(class_member: int, inst_member: int)")
def process_custom(custom_class_instance):
    [...]

This way any object that has an int class_member and an int inst_member will satisfy the contract.

I am posting this issue because I haven't found any way to do this currently...

Add numpy 'object' data type contract

First of all, I want to thank you for this project. This is really great work and design. I'm using it to develop satellite data processing pipelines at NASA Goddard.

Currently, using 'object' as a data type is not supported. A NumPy array with a datatype 'object' holds references to Python objects. Sometimes, it is useful to have a numpy array of object: unlike a list, a numpy object array can support multiple dimensions and advanced slicing.

This is a feature request to add the 'object' datatype to the contract specification for numpy arrays.

Reference:
https://andreacensi.github.io/contracts/reference.html#numpy-specific-contracts

"In 3.8 it will stop working": collections import has moved

When I run my coverage.py test suite under Python 3.7, I see this:

/Users/ned/coverage/v4.5.x/.tox/py37/lib/python3.7/site-packages/contracts/library/miscellaneous_aliases.py:19: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
  m_new_contract('Container', ist(collections.Container))
/Users/ned/coverage/v4.5.x/.tox/py37/lib/python3.7/site-packages/contracts/library/miscellaneous_aliases.py:21: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
  m_new_contract('Iterable', ist(collections.Iterable))
/Users/ned/coverage/v4.5.x/.tox/py37/lib/python3.7/site-packages/contracts/library/miscellaneous_aliases.py:23: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
  m_new_contract('Hashable', ist(collections.Hashable))
/Users/ned/coverage/v4.5.x/.tox/py37/lib/python3.7/site-packages/contracts/library/miscellaneous_aliases.py:27: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
  m_new_contract('Iterator', ist(collections.Iterator))
/Users/ned/coverage/v4.5.x/.tox/py37/lib/python3.7/site-packages/contracts/library/miscellaneous_aliases.py:28: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
  m_new_contract('Sized', ist(collections.Sized))
/Users/ned/coverage/v4.5.x/.tox/py37/lib/python3.7/site-packages/contracts/library/miscellaneous_aliases.py:29: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
  m_new_contract('Callable', ist(collections.Callable))
/Users/ned/coverage/v4.5.x/.tox/py37/lib/python3.7/site-packages/contracts/library/miscellaneous_aliases.py:30: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
  m_new_contract('Sequence', ist(collections.Sequence))
/Users/ned/coverage/v4.5.x/.tox/py37/lib/python3.7/site-packages/contracts/library/miscellaneous_aliases.py:31: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
  m_new_contract('Set', ist(collections.Set))
/Users/ned/coverage/v4.5.x/.tox/py37/lib/python3.7/site-packages/contracts/library/miscellaneous_aliases.py:32: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
  m_new_contract('MutableSequence', ist(collections.MutableSequence))
/Users/ned/coverage/v4.5.x/.tox/py37/lib/python3.7/site-packages/contracts/library/miscellaneous_aliases.py:33: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
  m_new_contract('MutableSet', ist(collections.MutableSet))
/Users/ned/coverage/v4.5.x/.tox/py37/lib/python3.7/site-packages/contracts/library/miscellaneous_aliases.py:34: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
  m_new_contract('Mapping', ist(collections.Mapping))
/Users/ned/coverage/v4.5.x/.tox/py37/lib/python3.7/site-packages/contracts/library/miscellaneous_aliases.py:35: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
  m_new_contract('MutableMapping', ist(collections.MutableMapping))

How to define parametrized contracts?

This is related to #23

I'd like do define a custom contract using something like

def checker(value, x):
     return value <= x  # dumb example

new_contract('foo(x)', checker)

minimum_value = 5

@contract(value='foo(minimum_value)')
def bar(value):
     sqrt(value - 5)

bar(6) # fine
bar(5) # fine
bar(4) # Contract violation

That is, I would like to put a parameter x in my contract definition, have the value of x extracted from the scope where the contract decorator is used, and pass both the value of the contract parameter and the value of the function input passed into my checker function.

This seems to be possible, given builtin contracts like isinstance(Foo). Is there a way to use new_contract function/decorator to set up similar contracts, or do I need to build a manual Contract subclass?

Exponential dimension relations in numpy arrays

Hi Andrea,

I am working with numpy in high dimensional spaces for machine learning. I would like to use pycontracts to check dimension which have an exponential dependency e.g.:

arg1="array[N,M]", returns="array[N**M]"

Is there a way to check this? Is it alternatively possible to pass the dimension symbols (N,M,..) to contract defined by a function?

Best
Stefan

Can the number contract allow numpy.number?

Currently, the 'number' contract does not allow instances of numpy.float32 (or numpy.number in general), which surprised me. I think it would be nice to either:

  • Change 'number' to include numpy.number
  • Add a new default contract that is similar to 'number' with a different name that includes numpy.number
  • Update the documentation to explicitly mention that numpy numbers aren't allowed with 'number'

I think that it would be a change to https://github.com/AndreaCensi/contracts/blob/master/src/contracts/library/types_misc.py#L48 :

try:
    import numpy
    number_types = (Number, numpy.number)
except ImportError:
    number_types = Number

add_contract(Keyword('number').setParseAction(CheckType.parse_action(number_types)))

For reference, here is the MRO for numpy.float32:

>>> inspect.getmro(numpy.float32)
(<type 'numpy.float32'>, <type 'numpy.floating'>, <type 'numpy.inexact'>, <type 'numpy.number'>, <type 'numpy.generic'>, <type 'object'>)

Thanks!

File README.rst not included from sdist distribution

The file README.rst (referenced in setup.py) is not included when the sdist distribution is built. The following patch will add a MANIFEST.in file so README.rst will be included:

diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..bb37a27
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1 @@
+include *.rst

logging.basicConfig()

Hi pycontracts contributors,

Wonder is it possible to remove logging.basicConfig() in contracts/src/contracts/init.py:5.

Usually when importing pycontracts as a lib, we have our own logging handlers setup, and calling basicConfig will cause duplicated logging.

Thanks
Gengyu

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.