Skip to content

Commit

Permalink
Merge pull request #2042 from brython-dev/revert-2036-randomness-over…
Browse files Browse the repository at this point in the history
…haul

Revert "Overhaul of the randomness-related parts of the standard library"
  • Loading branch information
PierreQuentel authored Sep 19, 2022
2 parents 4674beb + cea9824 commit 9cede31
Show file tree
Hide file tree
Showing 16 changed files with 1,300 additions and 1,525 deletions.
6 changes: 0 additions & 6 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,6 @@ node_modules/
# Files created by make_dist
npm/*.js
setup/data/*.js
scripts/last_modifs.json
scripts/python.gram.js_actions
scripts/python*.gram
www/src/brython_no_static.js
www/src/full_grammar.js
www/static_tutorial/

# Files created by make_doc
www/static_doc
Expand Down
11 changes: 0 additions & 11 deletions www/src/Lib/_operator.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,3 @@ def _compare_digest(a, b):
return a == b
raise TypeError("unsupported operand types")

def index(a):
# See https://stackoverflow.com/questions/65551469/operator-index-with-custom-class-instance
# for the reason this implementation is necessary.

try:
index_method = a.__index__
except AttributeError as e:
# For compatibility with CPython (and also PyPy), raise a TypeError here instead of an AttributeError.
raise TypeError(f"'{type(a)}' object cannot be interpreted as an integer") from e
else:
return index_method()
99 changes: 99 additions & 0 deletions www/src/Lib/_random.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
from browser import window, alert

def _randint(a, b):
return int(window.Math.random()*(b-a+1)+a)

def _rand_with_seed(x, rand_obj):
# if rand_obj.state is not a safe integer, Math.sin will return the same
# result for consecutive values : use the rest of division by 360
degrees = rand_obj._state % 360
x = window.Math.sin(degrees/(2*window.Math.PI)) * 10000
# Adding 1 is not reliable because of current integer implementation
# If rand_obj._state is not a "safe integer" in the range [-2**53, 2**53]
# the increment between 2 different values is a power of 2
# It is stored in an attribute of rand_obj to avoid having to compute it
# for each iteration
if not hasattr(rand_obj, 'incr'):
rand_obj.incr = 1
rand_obj._state += rand_obj.incr
return x - window.Math.floor(x)

def _urandom(n, rand_obj=None):
"""urandom(n) -> str
Return n random bytes suitable for cryptographic use."""

if rand_obj is None or rand_obj._state is None:
randbytes= [_randint(0,255) for i in range(n)]
else:
randbytes= []
for i in range(n):
randbytes.append(int(256*_rand_with_seed(i, rand_obj)))
return bytes(randbytes)

class Random:
"""Random number generator base class used by bound module functions.
Used to instantiate instances of Random to get generators that don't
share state.
Class Random can also be subclassed if you want to use a different basic
generator of your own devising: in that case, override the following
methods: random(), seed(), getstate(), and setstate().
Optionally, implement a getrandbits() method so that randrange()
can cover arbitrarily large ranges.
"""
#random
#seed
#getstate
#setstate


VERSION = 3 # used by getstate/setstate

def __init__(self, x=None):
"""Initialize an instance.
Optional argument x controls seeding, as for Random.seed().
"""

self._state=x

def seed(self, a=None, version=2):
"""Initialize internal state from hashable object.
None or no argument seeds from current time or from an operating
system specific randomness source if available.
For version 2 (the default), all of the bits are used if *a* is a str,
bytes, or bytearray. For version 1, the hash() of *a* is used instead.
If *a* is an int, all bits are used.
"""

self._state=a
self.gauss_next = None

def getstate(self):
"""Return internal state; can be passed to setstate() later."""
return self._state

def setstate(self, state):
"""Restore internal state from object returned by getstate()."""
self._state=state

def random(self):
"""Get the next random number in the range [0.0, 1.0)."""
return window.Math.random()

def getrandbits(self, k):
"""getrandbits(k) -> x. Generates a long int with k random bits."""
if k <= 0:
raise ValueError('number of bits must be greater than zero')
if k != int(k):
raise TypeError('number of bits should be an integer')
numbytes = (k + 7) // 8 # bits / 8 and rounded up
x = int.from_bytes(_urandom(numbytes, self), 'big')

return x >> (numbytes * 8 - k) # trim excess bits
Loading

0 comments on commit 9cede31

Please sign in to comment.