
Security Fundamentals
Obfuscation 101: Unmasking the Tricks Behind Malicious Code
Attackers use obfuscation to hide malware in open source packages. Learn how to spot these techniques across npm, PyPI, Maven, and more.
Rsg is a tool that helps creating randomly generated nested data structures, from simple built-in structures as lists, dictionaries and tuples, to custom composite class hierarchies.
In its current state, this library is merely a toy project with a few basic utilities, created with the intent of experimenting with python decorators and language inspection. It was originally a function that generated random yaml files for testing purposes, that quickly grew to become a generic subpackage that had no dependencies and could be exported as a separate python package.
Generators are subclasses of Rsg
with special "generator" methods:
class RsgFooBar(Rsg):
@generator("foo")
def generate_foo(self):
return "foo"
@generator("bar")
def generate_bar(self):
return "bar"
This class genertes either "foo"
or "bar"
with equal chance:
rsg = RsgFooBar()
[print(next(rsg)) for _ in range(10)]
# bar foo foo bar foo foo bar bar foo foo
You can set a custom chance for each generator method, by setting the keyword agument
named <METHOD_NAME>_chance
in the object constructor. Probabilities are normalized
automatically, so you don't need to ensure they sum up to one.
rsg = RsgFooBar(foo_chance=0.8, bar_chance=0.2)
[print(next(rsg)) for _ in range(10)]
# foo foo bar foo foo foo foo foo foo bar
Chances values all default to 1.0, you can set a custom default value when decorating a generator method. Default values are used only when a chance value is not specified in the object constructor.
@generator("foo", default_chance=0.2)
What if a generator method needs parameters? In this example we want to make a generator of random powers of a number (a parameter), with the maximum exponent bounded by anohter parameter.
To do so, just add any amount of parameters to a generator method, you can use both positional and keyword arguments, without the need to implement a custom constructor for your class.
class RsgPowers(Rsg):
@generator("power")
def generate_power(self, base: int, max_exp: int = 5):
exp = randint(0, max_exp)
return base**exp
To set the declared parameters, just pass them to the class constructor, as if you had actually implemented it!
rsg = RsgPowers(base=2, max_exp=10)
[print(next(rsg)) for _ in range(10)]
# 512 1024 16 128 32 1024 64 8 8 1
In the previous example, the parameter max_exp
has a default value of 5
, this means
that you don't have to explicitly set it in the object constructor. On the other hand,
the base
parameter doesn't have a default value, and so it must be set explicitly.
A generator method can be of two types:
Let's make a generator of lists-of-lists-of-lists-of-l...
class RsgList(Rsg):
@generator("list")
def generate_list(self, children: Iterable[Any]) -> list:
return list(children)
To make it recursive, you just need to add an argument named children
to the method.
This argument will contain an iterable of N randomly generated children objects.
The children objects are generated with the same generator used for the parent object.
Recusion is governed by the following parameters:
min_depth
- The minimum number of recursions before a leaf object can be generated.
Ignored if no composite generators are available.max_depth
- The maximum number of recursions. Must be >= min_depth
.min_breadth
- The minimum number of children per recursion step. If no leaf
generators are available, on the last recursion step min_breadth
is forced to 0.max_breadth
- The maximum number of children per recursion step.rsg = RsgList(min_depth=1, max_depth=3, min_breadth=2, max_breadth=4)
print(next(rsg))
# [[[[], []], [[], []], [[], []], [[], []]], [[[], [], [], []], [[], []], [[], []], [[], []]]]
You can combine any Rsg
by simply inheriting from them:
class RsgMixed(RsgFooBar, RsgList, RsgPowers):
pass
You can still set all parameters of the base classes, remember to set the required ones,
or otherwise you will get an AttributeError
!
rsg = RsgMixed(
base=3,
foo_chance=0.1,
bar_chance=0.1,
power_chance=0.4,
list_chance=0.4,
min_depth=2,
max_depth=3,
min_breadth=2,
max_breadth=4,
)
print(next(rsg))
# [[[9, 243, 'foo', 'bar'], 27, ['foo', 3]], ['foo', [243, 81, 243]], ['foo', 243]]
Rsg provides generators for the following built-in types:
int
- rsg.core.RsgInt
generates uniform integer values.float
- rsg.core.RsgFloat
generates uniform float values.str
- rsg.core.RsgStr
generates random strings containing a uniform random number
of letters, digits and punctuations.list
- rsg.core.RsgList
generates nested lists.tuple
- rsg.core.RsgTuple
generates nested tuples.dict
- rsg.core.RsgDict
generates nested dicts with valid python identifiers
as keys.In addition, rsg.core.RsgBase
combines all previous generators into one:
from rsg.core import RsgBase
rsg = RsgBase(min_depth=1, max_depth=4, min_breadth=1, max_breadth=3)
print(next(rsg))
# [
# ((0.73354,), (0.12835, '[^U`zq')),
# [643, ["QiX0@'", [0.95934, 0.27090, 0.66838]]],
# [{'N_dHLJUZA': 0.00379, 'D0N0uK1_eH': [667, 0.29715], 'SjWKcs_D': {'IMUUZH': 630}}]
# ]
FAQs
Random Structure Generator
We found that rsg demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security Fundamentals
Attackers use obfuscation to hide malware in open source packages. Learn how to spot these techniques across npm, PyPI, Maven, and more.
Security News
Join Socket for exclusive networking events, rooftop gatherings, and one-on-one meetings during BSidesSF and RSA 2025 in San Francisco.
Security News
Biome's v2.0 beta introduces custom plugins, domain-specific linting, and type-aware rules while laying groundwork for HTML support and embedded language features in 2025.