-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #98 from openpassword/develop
Release?
- Loading branch information
Showing
72 changed files
with
6,247 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
[run] | ||
branch = True | ||
|
||
[report] | ||
show_missing = True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
*.pyc | ||
__pycache__/ | ||
.coverage | ||
.coverage.* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
checks: | ||
python: | ||
code_rating: true | ||
duplicate_code: true | ||
variables_unused_wildcard_import: true | ||
variables_used_before_assignment: true | ||
variables_unused_variable: true | ||
variables_unused_import: true | ||
variables_unused_argument: true | ||
variables_unpacking_non_sequence: true | ||
variables_undefined_variable: true | ||
variables_undefined_loop_variable: true | ||
variables_undefined_all_variable: true | ||
variables_unbalanced_tuple_unpacking: true | ||
variables_redefined_outer_name: true | ||
variables_redefined_builtin: true | ||
variables_redefine_in_handler: true | ||
variables_no_name_in_module: true | ||
variables_invalid_all_object: true | ||
variables_global_variable_undefined: true | ||
variables_global_variable_not_assigned: true | ||
variables_global_statement: true | ||
variables_global_at_module_level: true | ||
typecheck_unexpected_keyword_arg: true | ||
typecheck_too_many_function_args: true | ||
typecheck_redundant_keyword_arg: true | ||
typecheck_not_callable: true | ||
typecheck_no_value_for_parameter: true | ||
typecheck_no_member: true | ||
typecheck_missing_kwoa: true | ||
typecheck_maybe_no_member: true | ||
typecheck_duplicate_keyword_arg: true | ||
typecheck_assignment_from_none: true | ||
typecheck_assignment_from_no_return: true | ||
string_unused_format_string_key: true | ||
string_truncated_format_string: true | ||
string_too_many_format_args: true | ||
string_too_few_format_args: true | ||
string_mixed_format_string: true | ||
string_missing_format_string_key: true | ||
string_format_needs_mapping: true | ||
string_constant_anomalous_unicode_escape_in_string: true | ||
string_constant_anomalous_backslash_in_string: true | ||
string_bad_str_strip_call: true | ||
string_bad_format_string_key: true | ||
string_bad_format_character: true | ||
open_mode_bad_open_mode: true | ||
newstyle_bad_super_call: true | ||
miscellaneous_fixme: true | ||
logging_unsupported_format: true | ||
logging_too_many_args: true | ||
logging_too_few_args: true | ||
logging_not_lazy: true | ||
logging_format_truncated: true | ||
imports_wildcard_import: true | ||
imports_relative_import: true | ||
imports_reimported: true | ||
imports_import_self: true | ||
imports_import_error: true | ||
imports_deprecated_module: true | ||
imports_cyclic_import: true | ||
format_unnecessary_semicolon: true | ||
format_trailing_whitespace: true | ||
format_superfluous_parens: true | ||
format_old_ne_operator: true | ||
format_multiple_statements: true | ||
format_mixed_indentation: true | ||
format_missing_final_newline: true | ||
format_lowercase_l_suffix: true | ||
format_line_too_long: | ||
max_length: '120' | ||
format_bad_whitespace: true | ||
format_bad_indentation: | ||
indentation: '4 spaces' | ||
format_backtick: true | ||
exceptions_raising_string: true | ||
exceptions_raising_non_exception: true | ||
exceptions_raising_bad_type: true | ||
exceptions_pointless_except: true | ||
exceptions_notimplemented_raised: true | ||
exceptions_catching_non_exception: true | ||
exceptions_broad_except: true | ||
exceptions_binary_op_exception: true | ||
exceptions_bare_except: true | ||
exceptions_bad_except_order: true | ||
design_interface_not_implemented: true | ||
design_abstract_class_not_used: true | ||
classes_valid_slots: true | ||
classes_super_init_not_called: true | ||
classes_signature_differs: true | ||
classes_protected_access: true | ||
classes_non_parent_init_called: true | ||
classes_non_iterator_returned: true | ||
classes_no_self_argument: true | ||
classes_no_method_argument: true | ||
classes_missing_interface_method: true | ||
classes_method_hidden: true | ||
classes_interface_is_not_class: true | ||
classes_bad_staticmethod_argument: true | ||
classes_bad_mcs_method_argument: true | ||
classes_bad_mcs_classmethod_argument: true | ||
classes_bad_context_manager: true | ||
classes_bad_classmethod_argument: true | ||
classes_attribute_defined_outside_init: true | ||
classes_arguments_differ: true | ||
classes_access_member_before_definition: true | ||
classes_abstract_method: true | ||
basic_yield_outside_function: true | ||
basic_useless_else_on_loop: true | ||
basic_unreachable: true | ||
basic_unnecessary_pass: true | ||
basic_unnecessary_lambda: true | ||
basic_star_args: true | ||
basic_return_outside_function: true | ||
basic_return_in_init: true | ||
basic_return_arg_in_generator: true | ||
basic_pointless_string_statement: true | ||
basic_pointless_statement: true | ||
basic_old_raise_syntax: true | ||
basic_not_in_loop: true | ||
basic_nonexistent_operator: true | ||
basic_missing_reversed_argument: true | ||
basic_missing_module_attribute: true | ||
basic_lost_exception: true | ||
basic_invalid_name: | ||
functions: '[a-z_][a-z0-9_]{2,80}$' | ||
variables: '[a-z_][a-z0-9_]{2,80}$' | ||
whitelisted_names: 'i,j,k,ex,Run,_' | ||
constants: '(([A-Z_][A-Z0-9_]*)|(__.*__))$' | ||
attributes: '[a-z_][a-z0-9_]{2,30}$' | ||
arguments: '[a-z_][a-z0-9_]{2,30}$' | ||
class_attributes: '([A-Za-z_][A-Za-z0-9_]{2,80}|(__.*__))$' | ||
inline_vars: '[A-Za-z_][A-Za-z0-9_]*$' | ||
classes: '[A-Z_][a-zA-Z0-9]+$' | ||
modules: '(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$' | ||
methods: '[a-z_][a-z0-9_]{2,80}$' | ||
basic_init_is_generator: true | ||
basic_function_redefined: true | ||
basic_expression_not_assigned: true | ||
basic_exec_used: true | ||
basic_eval_used: true | ||
basic_duplicate_key: true | ||
basic_duplicate_argument_name: true | ||
basic_dangerous_default_value: true | ||
basic_assert_on_tuple: true | ||
basic_abstract_class_instantiated: true | ||
basic_bad_reversed_sequence: true | ||
|
||
filter: | ||
excluded_paths: | ||
- spec/* | ||
- tests/* | ||
- features/* | ||
|
||
build: | ||
environment: | ||
python: 3.4.1 | ||
dependencies: | ||
override: | ||
- "pip3 install -r requirements.txt" | ||
|
||
tools: | ||
external_code_coverage: true | ||
|
||
before_commands: | ||
- "pip3 install -r requirements.txt" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,14 @@ | ||
language: python | ||
python: | ||
- "3.3" | ||
- "3.4" | ||
# command to run tests | ||
script: nosetests | ||
script: sh bin/tests | ||
|
||
notifications: | ||
irc: | ||
channels: | ||
- "chat.freenode.net#openpassword" | ||
on_success: always | ||
on_failure: always | ||
skip_join: true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
# CONTRIBUTING | ||
|
||
## The Development Philosophy | ||
|
||
Blimey is developed under the MIT license, which means it's Open Source and that we're accepting contributions to the project. | ||
|
||
If you're thinking about contributing to blimey, this page is the place to start. | ||
|
||
We try to build blimey as a robust piece of software, with a simple and elegant design. To try and achieve this we apply the principles of emergent design, and expect contributions to do so as well. | ||
|
||
Quoting "The RSpec Book": | ||
|
||
> "BDD calls Test-Driven Development coding by example, which places emphasis on using examples to drive out the behaviour of the code. The fact that these examples become tests once the code is written is a secondary concern" | ||
So, what does this mean in the context of blimey? | ||
It means that we couldn't care less about "code coverage" or writing tests for the sake of doing it. | ||
It means that we write examples of how we imagine our code will be used, before writing our code, and then we write the minimum amount of code to make the expectations of those examples to pass. | ||
It means that we don't do a lot of upfront design, instead, we let it emerge as a response to our examples. | ||
|
||
The consequences of this are often: small, simple and clean methods and classes. Responsibility separation in methods and classes. Injection of dependencies. And a number of other advantages that become clear as the software progresses. | ||
|
||
## Tools | ||
|
||
Blimey is developed in **Python 3**. We try to keep the number of dependencies low, so currently we're using the following tools to help us achieve our goals: | ||
|
||
* nose - A testing framework for Python | ||
* spec - A nose plugin to allow for a more BBD like output | ||
* fudge - A mocking framework for Python | ||
* tissue - A nose plugin to check code for PEP8 style violations | ||
* pbkdf2 - A python library for implementing the [Password-Based Key Derivation Function 2](http://en.wikipedia.org/wiki/PBKDF2) | ||
* pycrypto - A python cryptography library | ||
|
||
To install node you'll need to run pip. Depending on your setup, you pip executable might be called pip or pip3: | ||
|
||
`pip3 install nose` | ||
|
||
For the remaining tools, you can take advantage of the requirements.txt contained in the repository: | ||
|
||
`pip3 install -r requirements.txt --use-mirrors` | ||
|
||
## Running the examples | ||
|
||
To run the examples you'll just need to run the script provided in bin/tests. From the root of the project execute the following: | ||
|
||
`bin/tests` | ||
|
||
This will run nosetests and pep8 with the appropriate parameters. | ||
|
||
## Writing a feature | ||
|
||
Here's a guide for how to develop a feature following the development philosophy described above. | ||
Let's imagine we're writing a class called *LightBulb* inside the *blimey* package: | ||
|
||
- Create a file called `spec/blimey/light_bulb_spec.py` | ||
- Import the (still inexistent) class you're going to write: | ||
|
||
```python | ||
from blimey.light_bulb import LightBulb | ||
``` | ||
|
||
- Inside that file, create a class called *LightBulbSpec* | ||
- Create the first example, describing one behaviour of your class, start with the word "it". Let's say *it_should_be_lit_after_being_turned_on* which shoud look something like this: | ||
|
||
```python | ||
from nose.tools import * | ||
from blimey.light_bulb import LightBulb | ||
|
||
|
||
class LightBulbSpec: | ||
def it_should_be_lit_after_being_turned_on(self): | ||
bulb = LightBulb() | ||
bulb.turn_on() | ||
|
||
eq_(bulb.turned_on(), True) | ||
|
||
``` | ||
- Run `bin/tests` | ||
- Fix any code styling issues that it may report | ||
- At this point you should get the following error `ImportError: No module named 'blimey.light_bulb'`. Fix it by creating the file `blimey/light_bulb.py`. | ||
- Run `bin/tests` again. You should now get the error `ImportError: cannot import name LightBulb`. | ||
- Create the *LightBulb* class inside the `blimey.light_bulb`. At this point your class should have nothing else other then a *pass* statement. | ||
|
||
```python | ||
class LightBulb: | ||
pass | ||
|
||
``` | ||
- Run `bin/tests` again. The error should now be `AttributeError: 'LightBulb' object has no attribute 'turn_on'`. So let's create it. | ||
|
||
```python | ||
class LightBulb: | ||
|
||
def turn_on(self): | ||
pass | ||
|
||
``` | ||
- Once more run `bin/tests`. You should be getting the hang of this now, we're letting our example lead what we do. It's important not to write more than what our example is leading us to do, otherwise our design won't emerge from our idealised example. Now you should get this error `AttributeError: 'LightBulb' object has no attribute 'turned_on'`, so let's write our turned_on method. | ||
|
||
```python | ||
class LightBulb: | ||
|
||
def turn_on(self): | ||
pass | ||
|
||
def turned_on(self): | ||
return True | ||
|
||
``` | ||
- Run `bin/tests` and all our tests should now pass. But..., our LightBulb class doesn't seem all that useful. turned_on always return *True*. What's up with that? Well, that's all we need it to do for now, but our light bulb does more that just stay lit. So, let's describe another behaviour. Let's say, `it_should_not_lit_before_being_turned_on`. | ||
|
||
```python | ||
from nose.tools import * | ||
from blimey.light_bulb import LightBulb | ||
|
||
|
||
class LightBulbSpec: | ||
def it_should_be_lit_after_being_turned_on(self): | ||
bulb = LightBulb() | ||
bulb.turn_on() | ||
|
||
eq_(bulb.turned_on(), True) | ||
|
||
def it_should_not_lit_before_being_turned_on(self): | ||
bulb = LightBulb() | ||
eq_(bulb.turned_on(), False) | ||
|
||
``` | ||
- Now our `it should not lit before being turned on` test is failling with the following error `AssertionError: True != False`. Ok, so our example is telling us to change our behaviour, so let's do it. Although we could do this in one step, for clarity sake let's do it in two: | ||
|
||
```python | ||
class LightBulb: | ||
def __init__(self): | ||
self._on = False | ||
|
||
def turn_on(self): | ||
pass | ||
|
||
def turned_on(self): | ||
return self._on | ||
|
||
``` | ||
- We fixed our test, but we broke `it should be lit after being turned on`. This is our example driving us to change our incorrect implementation. In response to this we fix the turn_on method: | ||
|
||
```python | ||
class LightBulb: | ||
def __init__(self): | ||
self._on = False | ||
|
||
def turn_on(self): | ||
self._on = True | ||
|
||
def turned_on(self): | ||
return self._on | ||
|
||
``` | ||
|
||
This should drive our implementation to be simple and make our interface a result of what we wish we had, producing better and clear code. | ||
In this example refactoring is not needed due to it's extreme simplicity, but **every time you get green, stop, look at both your code and your tests, and search for possible ways of improving it without changing or adding functionality**. Rename methods and properties which have names that are not explicit enough, remove complexity, generally clean your code. Do only one change at a time and alway run the tests after making the change. This step is vital to achieve the goals to which this methodology aspires. | ||
|
||
## Making pull requests | ||
|
||
Before making a pull request, be sure to run nose and pep8, using the bin/tests script, to ensure that your code is ready to be merged. | ||
Both specs and code should follow the pep8 standards. | ||
|
||
To make this easier, we provide a git_hooks folder that contains a pre-commit hook, that will do the work for you. Just copy it to your repository git hooks folder. From the base folder of your repository do: | ||
|
||
`cp ./git_hooks/pre_commit .git/hooks` |
Oops, something went wrong.