File: info_coding_standard.rst

package info (click to toggle)
pyrr 0.10.3-5
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 956 kB
  • sloc: python: 5,865; makefile: 132; sh: 23
file content (227 lines) | stat: -rw-r--r-- 5,896 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
.. _coding_standard:

Coding Standard
***************

* Follow PEP-8


.. _coding_standard_modules:

Modules
=======

Each value type is given its own module.

Functions that reside in these modules include:

* Creation

* Conversion

* Manipulation


.. _coding_standard_functions:

Functions
=========

* Existing numpy operations shall be wrapped where it may not be obvious how to perform the operation.

A good example::

    def multiply(m1, m2):
        # it may not be obvious that the 'dot' operator is the
        # equivalent of multiplication when using arrays as matrices
        # so this is good to help point users in the right direction
        return numpy.dot(m1, m2)

A bad example::

    def add(v1, v2):
        # this functionality is too obvious and too basic
        return v1 + v2

* Functions shall not modify data in-place.

* Procedural and Class implementations shall remain in lock-step.


.. _coding_standard_function_names:

Function names
==============

* Each type shall provide convenience *create* functions for conversions and other initialisations.

* Each type shall have a basic *create* function which returns a zero-ed type, where it makes sense.

A good example::

    # vector3.py
    def create(x=0., y=0., z=0., dtype=None):
        if isinstance(x, (list, np.ndarray)):
            raise ValueError('Function requires non-list arguments')
        return np.array([x,y,z], dtype=dtype)

    def create_unit_length_x(dtype=None):
        return np.array([1.0, 0.0, 0.0], dtype=dtype)

    def create_unit_length_y(dtype=None):
        return np.array([0.0, 1.0, 0.0], dtype=dtype)

    def create_unit_length_z(dtype=None):
        return np.array([0.0, 0.0, 1.0], dtype=dtype)


A bad example::

    # matrix33.py
    def create():
        # matrices aren't initialised manually
        # so this isn't ok
        pass

* Conversion functions shall be prefixed with *create_from_* followed by the type being converted from::

    def create_from_matrix(matrix):
        # converts from one type to another
        # this would have to support both matrix33 and matrix44
        pass

    def create_from_matrix33(matrix):
        # converts from a very specific type
        # only has to support matrix33
        pass


.. _coding_standard_supplimentary_data:

Supplimentary Data
==================

When dealing with arrays and other complex data types, it is helpful to provide methods to identify which array index relates to what data.

A good method to do this is to provide a class definition which contains these values::

    class index:
        x = 0
        y = 1
        z = 2
        w = 3


.. _coding_standard_tests:

Tests
=====

* A test class for each module shall be provided in the *pyrr/test* directory.

* A test class shall be the only class in the test module.

* Each source file shall have its own test file.

* Each test function shall have a test case associated with it

* All test cases for a function shall be in a single test function

.. _coding_standard_layout:

Layout
======

These are not strict rules, but are merely suggestions to keep the layout of code in Pyrr consistent.

* Code shall be spaced vertically where doing so helps the readability of complex mathematical functions. Vertical spacing shall be performed at variable or data type boundaries.

A good example::

    # laying out over multiple lines helps improve readability.
    # brackets and parenthesis are laid out to more clearly indicate
    # the end of an array / type.
    # where appropriate, values are still laid out horizontally.
    # provide links where appropriate
    #  http://www.example.com/a/link/to/a/relevant/explanation/of/this/code
    my_value = numpy.array([
        # X = some comment about how X is calculated
        (0.0, 0.0, 0.0),
        # Y = some comment about how Y is calculated
        (1.0, 1.0, 1.0)
    ], dtype=[('position', 'float32', (3,))]
    )

    # laying out parameters vertically can improve readability.
    # we'll be less likely to accidently pass an invalid value
    # and we can more easily, and more clearly, add logic to the parameters.
    some_complex_function_call(
        param_one,
        param_two,
        param_three,
        param_four,
        True if param_five else False,
    )

A more complicated example::

    return np.array(
        [
            # m1
            [
                # m11 = 1.0 - 2.0 * (q.y * q.y + q.z * q.z)
                1.0 - 2.0 * (y2 + z2),
                # m21 = 2.0 * (q.x * q.y + q.w * q.z)
                2.0 * (xy + wz),
                # m31 = 2.0 * (q.x * q.z - q.w * q.y)
                2.0 * (xz - wy),
            ],
            # m2
            [
                # m12 = 2.0 * (q.x * q.y - q.w * q.z)
                2.0 * (xy - wz),
                # m22 = 1.0 - 2.0 * (q.x * q.x + q.z * q.z)
                1.0 - 2.0 * (x2 + z2),
                # m32 = 2.0 * (q.y * q.z + q.w * q.x)
                2.0 * (yz + wx),
            ],
            # m3
            [
                # m13 = 2.0 * ( q.x * q.z + q.w * q.y)
                2.0 * (xz + wy),
                # m23 = 2.0 * (q.y * q.z - q.w * q.x)
                2.0 * (yz - wx),
                # m33 = 1.0 - 2.0 * (q.x * q.x + q.y * q.y)
                1.0 - 2.0 * (x2 + y2),
            ]
        ],
        dtype=dtype
    )

A bad example::

    # leaving this on a single line would not compromise readability
    my_value = numpy.empty(
        (3,)
    )

The same applies to function definitions::

    def some_function(that_takes, many_parameters, and_is, hard_to_read, because, its_so, big):
        pass

Should become::

    def some_function(
        that_takes,
        many_parameters,
        and_is,
        hard_to_read,
        because,
        its_so,
        big
    ):
        pass


* Code may extend beyond 80 columns, where appropriate.