basilisk-engine 0.1.38__py3-none-any.whl → 0.1.39__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of basilisk-engine might be problematic. Click here for more details.

Files changed (97) hide show
  1. basilisk/__init__.py +26 -26
  2. basilisk/audio/sound.py +27 -27
  3. basilisk/bsk_assets/cube.obj +48 -48
  4. basilisk/collisions/broad/broad_aabb.py +102 -102
  5. basilisk/collisions/broad/broad_bvh.py +137 -137
  6. basilisk/collisions/collider.py +95 -95
  7. basilisk/collisions/collider_handler.py +226 -226
  8. basilisk/collisions/narrow/contact_manifold.py +95 -95
  9. basilisk/collisions/narrow/dataclasses.py +34 -34
  10. basilisk/collisions/narrow/deprecated.py +46 -46
  11. basilisk/collisions/narrow/epa.py +91 -91
  12. basilisk/collisions/narrow/gjk.py +66 -66
  13. basilisk/collisions/narrow/graham_scan.py +24 -24
  14. basilisk/collisions/narrow/helper.py +29 -29
  15. basilisk/collisions/narrow/line_intersections.py +106 -106
  16. basilisk/collisions/narrow/sutherland_hodgman.py +75 -75
  17. basilisk/config.py +53 -53
  18. basilisk/draw/draw.py +100 -100
  19. basilisk/draw/draw_handler.py +178 -178
  20. basilisk/draw/font_renderer.py +28 -28
  21. basilisk/engine.py +165 -165
  22. basilisk/generic/abstract_bvh.py +15 -15
  23. basilisk/generic/abstract_custom.py +133 -133
  24. basilisk/generic/collisions.py +70 -70
  25. basilisk/generic/input_validation.py +82 -82
  26. basilisk/generic/math.py +18 -7
  27. basilisk/generic/matrices.py +35 -35
  28. basilisk/generic/meshes.py +72 -72
  29. basilisk/generic/quat.py +142 -142
  30. basilisk/generic/quat_methods.py +7 -7
  31. basilisk/generic/raycast_result.py +26 -26
  32. basilisk/generic/vec3.py +143 -143
  33. basilisk/input/__init__.py +0 -0
  34. basilisk/input/mouse.py +62 -0
  35. basilisk/input/path.py +14 -0
  36. basilisk/input_output/IO_handler.py +91 -91
  37. basilisk/input_output/clock.py +49 -49
  38. basilisk/input_output/keys.py +43 -43
  39. basilisk/input_output/mouse.py +90 -90
  40. basilisk/input_output/path.py +14 -14
  41. basilisk/mesh/cube.py +33 -33
  42. basilisk/mesh/mesh.py +233 -233
  43. basilisk/mesh/mesh_from_data.py +150 -150
  44. basilisk/mesh/model.py +271 -271
  45. basilisk/mesh/narrow_aabb.py +89 -89
  46. basilisk/mesh/narrow_bvh.py +91 -91
  47. basilisk/mesh/narrow_primative.py +23 -23
  48. basilisk/nodes/helper.py +28 -28
  49. basilisk/nodes/node.py +709 -704
  50. basilisk/nodes/node_handler.py +97 -97
  51. basilisk/particles/particle_handler.py +64 -64
  52. basilisk/particles/particle_renderer.py +93 -93
  53. basilisk/physics/impulse.py +112 -112
  54. basilisk/physics/physics_body.py +43 -43
  55. basilisk/physics/physics_engine.py +35 -35
  56. basilisk/render/batch.py +103 -103
  57. basilisk/render/bloom.py +107 -107
  58. basilisk/render/camera.py +260 -260
  59. basilisk/render/chunk.py +108 -108
  60. basilisk/render/chunk_handler.py +167 -167
  61. basilisk/render/frame.py +110 -110
  62. basilisk/render/framebuffer.py +202 -202
  63. basilisk/render/image.py +120 -120
  64. basilisk/render/image_handler.py +120 -120
  65. basilisk/render/light.py +96 -96
  66. basilisk/render/light_handler.py +58 -58
  67. basilisk/render/material.py +232 -232
  68. basilisk/render/material_handler.py +133 -133
  69. basilisk/render/post_process.py +146 -146
  70. basilisk/render/shader.py +134 -134
  71. basilisk/render/shader_handler.py +85 -85
  72. basilisk/render/sky.py +120 -120
  73. basilisk/scene.py +290 -290
  74. basilisk/shaders/batch.frag +289 -289
  75. basilisk/shaders/batch.vert +117 -117
  76. basilisk/shaders/bloom_downsample.frag +42 -42
  77. basilisk/shaders/bloom_frame.frag +24 -24
  78. basilisk/shaders/bloom_upsample.frag +33 -33
  79. basilisk/shaders/crt.frag +31 -31
  80. basilisk/shaders/draw.frag +25 -25
  81. basilisk/shaders/draw.vert +25 -25
  82. basilisk/shaders/filter.frag +22 -22
  83. basilisk/shaders/frame.frag +12 -12
  84. basilisk/shaders/frame.vert +13 -13
  85. basilisk/shaders/geometry.frag +10 -10
  86. basilisk/shaders/geometry.vert +41 -41
  87. basilisk/shaders/normal.frag +62 -62
  88. basilisk/shaders/normal.vert +96 -96
  89. basilisk/shaders/particle.frag +76 -76
  90. basilisk/shaders/particle.vert +86 -86
  91. basilisk/shaders/sky.frag +23 -23
  92. basilisk/shaders/sky.vert +13 -13
  93. {basilisk_engine-0.1.38.dist-info → basilisk_engine-0.1.39.dist-info}/METADATA +89 -89
  94. basilisk_engine-0.1.39.dist-info/RECORD +114 -0
  95. {basilisk_engine-0.1.38.dist-info → basilisk_engine-0.1.39.dist-info}/WHEEL +1 -1
  96. basilisk_engine-0.1.38.dist-info/RECORD +0 -111
  97. {basilisk_engine-0.1.38.dist-info → basilisk_engine-0.1.39.dist-info}/top_level.txt +0 -0
basilisk/engine.py CHANGED
@@ -1,166 +1,166 @@
1
- import os
2
- from sys import platform
3
- os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = "hide"
4
- import pygame as pg
5
- import moderngl as mgl
6
- import glcontext # For packaging (so it isnt a hidden import)
7
- from .render.shader_handler import ShaderHandler
8
- from .render.material_handler import MaterialHandler
9
- from .render.frame import Frame
10
- from .draw.draw_handler import DrawHandler
11
- from .config import Config
12
- from .input_output.mouse import Mouse
13
- from .input_output.clock import Clock
14
- from .input_output.IO_handler import IO
15
- from .mesh.cube import Cube
16
-
17
- class Engine():
18
- win_size: tuple
19
- """Size of the engine window in pixels"""
20
- ctx: mgl.Context
21
- """ModernGL context used by the engine"""
22
- clock: Clock
23
- """Basilisk clock used to keep track of time"""
24
- shader_handler: ShaderHandler=None
25
- """Handler for all shaders used in all scenes of the engine"""
26
- material_handler: MaterialHandler=None
27
- """Handler for all materials and images in all scenes"""
28
- frame: Frame=None
29
- """Default render target for all locations. Rendered to the screen at the end of the frame"""
30
- config: Config
31
- """Object containing all global attributes"""
32
- delta_time: float
33
- """Time in seconds that passed between the last frame"""
34
- time: float
35
- """Total time the engine has been running"""
36
- running: bool=True
37
- """True if the engine is still running"""
38
- mouse: Mouse
39
- """Object containing information about the user's mouse"""
40
- root: str
41
- """Path to the root directory containing internal data"""
42
- current_frame_updated: bool=False
43
- """Flag for if the engine has been updated this frame"""
44
- keys: list[bool]
45
- """List of all keyboard inputs as booleans"""
46
- previous_keys: list[bool]
47
- """List of all keyoard inputs from the last frame as booleans"""
48
-
49
- def __init__(self, win_size=(800, 800), title="Basilisk Engine", vsync=None, max_fps=None, grab_mouse=True, headless=False, resizable=True) -> None:
50
- """
51
- Basilisk Engine Class. Sets up the engine enviornment and allows the user to interact with Basilisk
52
- Args:
53
- win_size: tuple
54
- The initial window size of the engine
55
- title: str
56
- The title of the engine window
57
- vsync: bool
58
- Flag for running engine with vsync enabled
59
- headless: bool
60
- Flag for headless rendering
61
- """
62
-
63
- # Save the window size
64
- self.win_size = win_size
65
-
66
- # Initialize pygame and set OpenGL attributes
67
- pg.init()
68
- pg.display.gl_set_attribute(pg.GL_CONTEXT_MAJOR_VERSION, 3)
69
- pg.display.gl_set_attribute(pg.GL_CONTEXT_MINOR_VERSION, 3)
70
- pg.display.gl_set_attribute(pg.GL_CONTEXT_PROFILE_MASK, pg.GL_CONTEXT_PROFILE_CORE)
71
-
72
- # Platform settings
73
- if platform == 'win32' : self.platform = 'windows'
74
- elif platform == 'darwin': self.platform = 'mac'
75
- else: self.platform = 'linux'
76
- if vsync == None: vsync = True if self.platform == 'linux' else False
77
-
78
- # Initializae the pygame display
79
- self.headless = headless
80
- if headless:
81
- pg.display.set_mode((300, 50), vsync=vsync, flags=pg.OPENGL | pg.DOUBLEBUF)
82
- pg.display.iconify()
83
- else:
84
- if resizable: pg.display.set_mode(self.win_size, vsync=vsync, flags=pg.OPENGL | pg.DOUBLEBUF | pg.RESIZABLE)
85
- else: pg.display.set_mode(self.win_size, vsync=vsync, flags=pg.OPENGL | pg.DOUBLEBUF)
86
-
87
- # Initalize pygame sound moduel sound
88
- pg.mixer.pre_init(44100, -16, 2, 512)
89
- pg.mixer.init()
90
- pg.mixer.set_num_channels(64)
91
- pg.mixer.music.set_volume(100/100)
92
-
93
- # MGL context setup
94
- self.ctx = mgl.create_context()
95
- self.ctx.enable(flags=mgl.DEPTH_TEST | mgl.CULL_FACE | mgl.BLEND)
96
-
97
- # Global attributes referenced by the handlers
98
- self.config = Config(self)
99
- self.root = os.path.dirname(__file__)
100
- self.cube = Cube(self)
101
- self.fbos = []
102
-
103
- # Handlers
104
- self.clock = Clock(self, max_fps)
105
- self.IO = IO(self, grab_mouse=grab_mouse, caption=title)
106
- self.material_handler = MaterialHandler(self)
107
- self.shader_handler = ShaderHandler(self)
108
- self.draw_handler = DrawHandler(self)
109
- self.frame = Frame(self)
110
- self.material_handler.set_base()
111
-
112
- def _update(self) -> None:
113
- """
114
- Internal engine update.
115
- Updates all input, physics, and time variables. Clears the frame.
116
- """
117
-
118
- if self.current_frame_updated: return
119
-
120
- for fbo in self.fbos: fbo.clear()
121
- self.clock.update()
122
- self.IO.update()
123
-
124
- self.current_frame_updated = True
125
-
126
-
127
- def update(self) -> None:
128
- """
129
- Calls internal update if needed
130
- Renders the draw handler
131
- Renders the engine's frame to the screen.
132
- """
133
-
134
-
135
- # Must update the frame
136
- if not self.current_frame_updated: self._update()
137
- if not self.running: return
138
-
139
- # Render all draw calls from the past frame
140
- self.frame.use()
141
- self.draw_handler.render()
142
-
143
- # Clear the screen and render the frame
144
- self.ctx.screen.use()
145
- self.ctx.clear()
146
- self.frame.render()
147
- pg.display.flip()
148
-
149
- self.frame.clear()
150
-
151
-
152
- # Allow for the engine to take in input again
153
- self.current_frame_updated = False
154
-
155
- def quit(self) -> None:
156
- """
157
- Stops the engine and releases all memory
158
- """
159
-
160
- pg.quit()
161
- self.ctx.release()
162
- self.running = False
163
-
164
-
165
- @property
1
+ import os
2
+ from sys import platform
3
+ os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = "hide"
4
+ import pygame as pg
5
+ import moderngl as mgl
6
+ import glcontext # For packaging (so it isnt a hidden import)
7
+ from .render.shader_handler import ShaderHandler
8
+ from .render.material_handler import MaterialHandler
9
+ from .render.frame import Frame
10
+ from .draw.draw_handler import DrawHandler
11
+ from .config import Config
12
+ from .input_output.mouse import Mouse
13
+ from .input_output.clock import Clock
14
+ from .input_output.IO_handler import IO
15
+ from .mesh.cube import Cube
16
+
17
+ class Engine():
18
+ win_size: tuple
19
+ """Size of the engine window in pixels"""
20
+ ctx: mgl.Context
21
+ """ModernGL context used by the engine"""
22
+ clock: Clock
23
+ """Basilisk clock used to keep track of time"""
24
+ shader_handler: ShaderHandler=None
25
+ """Handler for all shaders used in all scenes of the engine"""
26
+ material_handler: MaterialHandler=None
27
+ """Handler for all materials and images in all scenes"""
28
+ frame: Frame=None
29
+ """Default render target for all locations. Rendered to the screen at the end of the frame"""
30
+ config: Config
31
+ """Object containing all global attributes"""
32
+ delta_time: float
33
+ """Time in seconds that passed between the last frame"""
34
+ time: float
35
+ """Total time the engine has been running"""
36
+ running: bool=True
37
+ """True if the engine is still running"""
38
+ mouse: Mouse
39
+ """Object containing information about the user's mouse"""
40
+ root: str
41
+ """Path to the root directory containing internal data"""
42
+ current_frame_updated: bool=False
43
+ """Flag for if the engine has been updated this frame"""
44
+ keys: list[bool]
45
+ """List of all keyboard inputs as booleans"""
46
+ previous_keys: list[bool]
47
+ """List of all keyoard inputs from the last frame as booleans"""
48
+
49
+ def __init__(self, win_size=(800, 800), title="Basilisk Engine", vsync=None, max_fps=None, grab_mouse=True, headless=False, resizable=True) -> None:
50
+ """
51
+ Basilisk Engine Class. Sets up the engine enviornment and allows the user to interact with Basilisk
52
+ Args:
53
+ win_size: tuple
54
+ The initial window size of the engine
55
+ title: str
56
+ The title of the engine window
57
+ vsync: bool
58
+ Flag for running engine with vsync enabled
59
+ headless: bool
60
+ Flag for headless rendering
61
+ """
62
+
63
+ # Save the window size
64
+ self.win_size = win_size
65
+
66
+ # Initialize pygame and set OpenGL attributes
67
+ pg.init()
68
+ pg.display.gl_set_attribute(pg.GL_CONTEXT_MAJOR_VERSION, 3)
69
+ pg.display.gl_set_attribute(pg.GL_CONTEXT_MINOR_VERSION, 3)
70
+ pg.display.gl_set_attribute(pg.GL_CONTEXT_PROFILE_MASK, pg.GL_CONTEXT_PROFILE_CORE)
71
+
72
+ # Platform settings
73
+ if platform == 'win32' : self.platform = 'windows'
74
+ elif platform == 'darwin': self.platform = 'mac'
75
+ else: self.platform = 'linux'
76
+ if vsync == None: vsync = True if self.platform == 'linux' else False
77
+
78
+ # Initializae the pygame display
79
+ self.headless = headless
80
+ if headless:
81
+ pg.display.set_mode((300, 50), vsync=vsync, flags=pg.OPENGL | pg.DOUBLEBUF)
82
+ pg.display.iconify()
83
+ else:
84
+ if resizable: pg.display.set_mode(self.win_size, vsync=vsync, flags=pg.OPENGL | pg.DOUBLEBUF | pg.RESIZABLE)
85
+ else: pg.display.set_mode(self.win_size, vsync=vsync, flags=pg.OPENGL | pg.DOUBLEBUF)
86
+
87
+ # Initalize pygame sound moduel sound
88
+ pg.mixer.pre_init(44100, -16, 2, 512)
89
+ pg.mixer.init()
90
+ pg.mixer.set_num_channels(64)
91
+ pg.mixer.music.set_volume(100/100)
92
+
93
+ # MGL context setup
94
+ self.ctx = mgl.create_context()
95
+ self.ctx.enable(flags=mgl.DEPTH_TEST | mgl.CULL_FACE | mgl.BLEND)
96
+
97
+ # Global attributes referenced by the handlers
98
+ self.config = Config(self)
99
+ self.root = os.path.dirname(__file__)
100
+ self.cube = Cube(self)
101
+ self.fbos = []
102
+
103
+ # Handlers
104
+ self.clock = Clock(self, max_fps)
105
+ self.IO = IO(self, grab_mouse=grab_mouse, caption=title)
106
+ self.material_handler = MaterialHandler(self)
107
+ self.shader_handler = ShaderHandler(self)
108
+ self.draw_handler = DrawHandler(self)
109
+ self.frame = Frame(self)
110
+ self.material_handler.set_base()
111
+
112
+ def _update(self) -> None:
113
+ """
114
+ Internal engine update.
115
+ Updates all input, physics, and time variables. Clears the frame.
116
+ """
117
+
118
+ if self.current_frame_updated: return
119
+
120
+ for fbo in self.fbos: fbo.clear()
121
+ self.clock.update()
122
+ self.IO.update()
123
+
124
+ self.current_frame_updated = True
125
+
126
+
127
+ def update(self) -> None:
128
+ """
129
+ Calls internal update if needed
130
+ Renders the draw handler
131
+ Renders the engine's frame to the screen.
132
+ """
133
+
134
+
135
+ # Must update the frame
136
+ if not self.current_frame_updated: self._update()
137
+ if not self.running: return
138
+
139
+ # Render all draw calls from the past frame
140
+ self.frame.use()
141
+ self.draw_handler.render()
142
+
143
+ # Clear the screen and render the frame
144
+ self.ctx.screen.use()
145
+ self.ctx.clear()
146
+ self.frame.render()
147
+ pg.display.flip()
148
+
149
+ self.frame.clear()
150
+
151
+
152
+ # Allow for the engine to take in input again
153
+ self.current_frame_updated = False
154
+
155
+ def quit(self) -> None:
156
+ """
157
+ Stops the engine and releases all memory
158
+ """
159
+
160
+ pg.quit()
161
+ self.ctx.release()
162
+ self.running = False
163
+
164
+
165
+ @property
166
166
  def shader(self): return self._shader
@@ -1,16 +1,16 @@
1
- import glm
2
-
3
-
4
- class AbstractAABB():
5
- top_right: glm.vec3
6
- """The furthest positive corner of the AABB"""
7
- bottom_left: glm.vec3
8
- """The furthest negative corner of the AABB"""
9
- a: ...
10
- """Binary child 1"""
11
- b: ...
12
- """Binary child 2"""
13
-
14
- class AbstractBVH():
15
- root: AbstractAABB
1
+ import glm
2
+
3
+
4
+ class AbstractAABB():
5
+ top_right: glm.vec3
6
+ """The furthest positive corner of the AABB"""
7
+ bottom_left: glm.vec3
8
+ """The furthest negative corner of the AABB"""
9
+ a: ...
10
+ """Binary child 1"""
11
+ b: ...
12
+ """Binary child 2"""
13
+
14
+ class AbstractBVH():
15
+ root: AbstractAABB
16
16
  """Root aabb used for the start of all collisions"""
@@ -1,134 +1,134 @@
1
- import glm
2
- import numpy as np
3
-
4
-
5
- class Custom():
6
-
7
- def normalize(self):
8
- """
9
- Inplace normalizes the vector
10
- """
11
- self._data = glm.normalize(self._data)
12
- return self
13
-
14
- def apply_function(): ... # will be overridden by child custom classes
15
-
16
- # math functions
17
- def add(self, other):
18
- def func(a, b): return a + b
19
- return self.apply_function(other, func, 'addition')
20
-
21
- def subtract(self, other):
22
- def func(a, b): return a - b
23
- return self.apply_function(other, func, 'subtraction')
24
-
25
- def rhs_subtract(self, other):
26
- def func(a, b): return b - a
27
- return self.apply_function(other, func, 'subtraction')
28
-
29
- def multiply(self, other):
30
- def func(a, b): return a * b
31
- return self.apply_function(other, func, 'multiplication')
32
-
33
- def divide(self, other):
34
- def func(a, b): return a / b
35
- return self.apply_function(other, func, 'division')
36
-
37
- def rhs_divide(self, other):
38
- def func(a, b): return b / a
39
- return self.apply_function(other, func, 'division')
40
-
41
- def floor_divide(self, other):
42
- def func(a, b): return a // b
43
- return self.apply_function(other, func, 'division')
44
-
45
- def rhs_floor_divide(self, other):
46
- def func(a, b): return b // a
47
- return self.apply_function(other, func, 'division')
48
-
49
- def mod(self, other):
50
- def func(a, b): return a % b
51
- return self.apply_function(other, func, 'modulus')
52
-
53
- def rhs_mod(self, other):
54
- def func(a, b): return b % a
55
- return self.apply_function(other, func, 'modulus')
56
-
57
- def pow(self, other):
58
- def func(a, b): return a ** b
59
- return self.apply_function(other, func, 'power')
60
-
61
- def rhs_pow(self, other):
62
- def func(a, b): return b ** a
63
- return self.apply_function(other, func, 'power')
64
-
65
- def __add__(self, other): return self.add(other) # this + that
66
- def __radd__(self, other): return self.add(other) # that + this
67
- def __iadd__(self, other): # this += that
68
- self = self.add(other)
69
- return self
70
-
71
- def __sub__(self, other): return self.subtract(other)
72
- def __rsub__(self, other): return self.rhs_subtract(other) # non-commutative
73
- def __isub__(self, other):
74
- self = self.subtract(other)
75
- return self
76
-
77
- def __mul__(self, other): return self.multiply(other)
78
- def __rmul__(self, other): return self.multiply(other)
79
- def __imul__(self, other):
80
- self = self.multiply(other)
81
- return self
82
-
83
- def __truediv__(self, other): return self.divide(other)
84
- def __rtruediv__(self, other): return self.rhs_divide(other) # non-commutative
85
- def __itruediv__(self, other):
86
- self = self.divide(other)
87
- return self
88
-
89
- def __floordiv__(self, other): return self.floor_divide(other)
90
- def __rfloordiv__(self, other): return self.rhs_floor_divide(other) # non-commutative
91
- def __ifloordiv__(self, other):
92
- self = self.floor_divide(other)
93
- return self
94
-
95
- def __mod__(self, other): return self.mod(other)
96
- def __rmod__(self, other): return self.rhs_mod(other)
97
- def __imod__(self, other):
98
- self = self.mod(other)
99
- return self
100
-
101
- def __pow__(self, other): return self.pow(other)
102
- def __rpow__(self, other): return self.rhs_pow(other)
103
- def __ipow__(self, other):
104
- self = self.pow(other)
105
- return self
106
-
107
- # comparison functions
108
- def __eq__(self, other):
109
- if isinstance(other, Custom): return self.data == other.data
110
- return self.data == other
111
-
112
- def __ne__(self, other):
113
- if isinstance(other, Custom): return self.data != other.data
114
- return self.data != other
115
-
116
- def __lt__(self, other):
117
- if isinstance(other, Custom): return self.data < other.data
118
- return self.data < other
119
-
120
- def __gt__(self, other):
121
- if isinstance(other, Custom): return self.data > other.data
122
- return self.data > other
123
-
124
- def __le__(self, other):
125
- if isinstance(other, Custom): return self.data <= other.data
126
- return self.data <= other
127
-
128
- def __ge__(self, other):
129
- if isinstance(other, Custom): return self.data >= other.data
130
- return self.data >= other
131
-
132
- # unary operators
133
- def __pos__(self):
1
+ import glm
2
+ import numpy as np
3
+
4
+
5
+ class Custom():
6
+
7
+ def normalize(self):
8
+ """
9
+ Inplace normalizes the vector
10
+ """
11
+ self._data = glm.normalize(self._data)
12
+ return self
13
+
14
+ def apply_function(): ... # will be overridden by child custom classes
15
+
16
+ # math functions
17
+ def add(self, other):
18
+ def func(a, b): return a + b
19
+ return self.apply_function(other, func, 'addition')
20
+
21
+ def subtract(self, other):
22
+ def func(a, b): return a - b
23
+ return self.apply_function(other, func, 'subtraction')
24
+
25
+ def rhs_subtract(self, other):
26
+ def func(a, b): return b - a
27
+ return self.apply_function(other, func, 'subtraction')
28
+
29
+ def multiply(self, other):
30
+ def func(a, b): return a * b
31
+ return self.apply_function(other, func, 'multiplication')
32
+
33
+ def divide(self, other):
34
+ def func(a, b): return a / b
35
+ return self.apply_function(other, func, 'division')
36
+
37
+ def rhs_divide(self, other):
38
+ def func(a, b): return b / a
39
+ return self.apply_function(other, func, 'division')
40
+
41
+ def floor_divide(self, other):
42
+ def func(a, b): return a // b
43
+ return self.apply_function(other, func, 'division')
44
+
45
+ def rhs_floor_divide(self, other):
46
+ def func(a, b): return b // a
47
+ return self.apply_function(other, func, 'division')
48
+
49
+ def mod(self, other):
50
+ def func(a, b): return a % b
51
+ return self.apply_function(other, func, 'modulus')
52
+
53
+ def rhs_mod(self, other):
54
+ def func(a, b): return b % a
55
+ return self.apply_function(other, func, 'modulus')
56
+
57
+ def pow(self, other):
58
+ def func(a, b): return a ** b
59
+ return self.apply_function(other, func, 'power')
60
+
61
+ def rhs_pow(self, other):
62
+ def func(a, b): return b ** a
63
+ return self.apply_function(other, func, 'power')
64
+
65
+ def __add__(self, other): return self.add(other) # this + that
66
+ def __radd__(self, other): return self.add(other) # that + this
67
+ def __iadd__(self, other): # this += that
68
+ self = self.add(other)
69
+ return self
70
+
71
+ def __sub__(self, other): return self.subtract(other)
72
+ def __rsub__(self, other): return self.rhs_subtract(other) # non-commutative
73
+ def __isub__(self, other):
74
+ self = self.subtract(other)
75
+ return self
76
+
77
+ def __mul__(self, other): return self.multiply(other)
78
+ def __rmul__(self, other): return self.multiply(other)
79
+ def __imul__(self, other):
80
+ self = self.multiply(other)
81
+ return self
82
+
83
+ def __truediv__(self, other): return self.divide(other)
84
+ def __rtruediv__(self, other): return self.rhs_divide(other) # non-commutative
85
+ def __itruediv__(self, other):
86
+ self = self.divide(other)
87
+ return self
88
+
89
+ def __floordiv__(self, other): return self.floor_divide(other)
90
+ def __rfloordiv__(self, other): return self.rhs_floor_divide(other) # non-commutative
91
+ def __ifloordiv__(self, other):
92
+ self = self.floor_divide(other)
93
+ return self
94
+
95
+ def __mod__(self, other): return self.mod(other)
96
+ def __rmod__(self, other): return self.rhs_mod(other)
97
+ def __imod__(self, other):
98
+ self = self.mod(other)
99
+ return self
100
+
101
+ def __pow__(self, other): return self.pow(other)
102
+ def __rpow__(self, other): return self.rhs_pow(other)
103
+ def __ipow__(self, other):
104
+ self = self.pow(other)
105
+ return self
106
+
107
+ # comparison functions
108
+ def __eq__(self, other):
109
+ if isinstance(other, Custom): return self.data == other.data
110
+ return self.data == other
111
+
112
+ def __ne__(self, other):
113
+ if isinstance(other, Custom): return self.data != other.data
114
+ return self.data != other
115
+
116
+ def __lt__(self, other):
117
+ if isinstance(other, Custom): return self.data < other.data
118
+ return self.data < other
119
+
120
+ def __gt__(self, other):
121
+ if isinstance(other, Custom): return self.data > other.data
122
+ return self.data > other
123
+
124
+ def __le__(self, other):
125
+ if isinstance(other, Custom): return self.data <= other.data
126
+ return self.data <= other
127
+
128
+ def __ge__(self, other):
129
+ if isinstance(other, Custom): return self.data >= other.data
130
+ return self.data >= other
131
+
132
+ # unary operators
133
+ def __pos__(self):
134
134
  return self