dypy

Toolkit for Dynamic Python code manipulations

https://github.com/vahidzee/dypy

Science Score: 44.0%

This score indicates how likely this project is to be science-related based on various indicators:

  • CITATION.cff file
    Found CITATION.cff file
  • codemeta.json file
    Found codemeta.json file
  • .zenodo.json file
    Found .zenodo.json file
  • DOI references
  • Academic publication links
  • Committers with academic emails
  • Institutional organization owner
  • JOSS paper metadata
  • Scientific vocabulary similarity
    Low similarity (11.0%) to scientific vocabulary

Keywords

dynamic-code-execution dynamic-objects functional-programming lazy-evaluation
Last synced: 4 months ago · JSON representation ·

Repository

Toolkit for Dynamic Python code manipulations

Basic Info
  • Host: GitHub
  • Owner: vahidzee
  • License: mit
  • Language: Python
  • Default Branch: main
  • Homepage:
  • Size: 282 KB
Statistics
  • Stars: 11
  • Watchers: 2
  • Forks: 1
  • Open Issues: 6
  • Releases: 0
Topics
dynamic-code-execution dynamic-objects functional-programming lazy-evaluation
Created about 3 years ago · Last pushed about 1 year ago
Metadata Files
Readme License Citation

README.md

Dynamic Python (DyPy): a toolset for dynamic python code manipulations

Have you ever found yourself coding up boilerplates to handle different scenarios? It's most likely that you have thought about using python's eval or exec in order to decouple some part of your code to be specified and evaluated later on at run-time. But, you have probably also come accross people who discourage you from using eval/exec. This is because programs with eval/exec are considered vulnarable and can be used to execute malicious code.

While this is true in general, but in many cases, you do not care about security concerns, and your highest priority is implementing a quick solution to a general problem which could be solved by using eval or exec. This is where dypy comes in. It allows you to use eval and exec effectively by providing utilities to dynamically compile code, lookup variables and lazily evaluate them.

Table of Contents - Dynamic Python (DyPy): a toolset for dynamic python code manipulations - Installation - Usage - Dynamic Evaluation - Variable Lookup - Dynamic Function Evaluation - Variable Assignment - License - Citation

Installation

bash pip install dypy

Usage

Dynamic Evaluation

You can use dypy.eval to combine the functionality of dypy.eval_function (see here) and dypy.get_value (see here). You can do as follows:

```python import dypy

dypy.eval("math.cos") # at MEMADDRESS> (math is imported through getvalue) dypy.eval("math.cos", dynamicargs=True)(2, verbose=True) # 3, verbose is ignored (and math is imported through getvalue) dypy.eval("def myfunction(x): return x + 1", functionofinterest="myfunction") # dypy.eval("def myfunction(x): return x + y", functionofinterest="myfunction", context={"y": 2})(2) # 4 ```

Variable Lookup

You can use dypy.get_value to lookup a variable as a string and then evaluate it. This is useful when you want to use a variable that is not defined in the current scope. You can do as follows:

```python from dypy import get_value

getvalue("math.pi") # 3.141592653589793 getvalue("math.cos(0)") # won't evaluate, this is not a variable but a call to a variable get_value("math.cos")(0) # 1.0

import math get_value("cos", context=math) # math.cos

getvalue("somethingthatdoesnotexist") # raises NameError getvalue("somethingthatdoesnotexist", strict=False) # None ```

get_value supports looking up variables in a module or package in your current working directory as well (as opposed to python's import which only supports looking up variables in the python standard library and installed packages). This is useful when you want to create a script that can be run from anywhere and still be able to access variables in the current working directory.

For example, imagine you create your own python package with a runnable script that sorts files in a directory. You can use get_value to lookup a config.sort function in the current working directory. This way, you can create a config.py file in the current working directory and define your own sorting function. Or use a default sorting function if the config.py file does not exist.

Your code would look like this:

```python from dypy import get_value

def sortfiles(): sortfunction = getvalue("config.sort", strict=False) or defaultsort # do something with sort ```

Although this example is somewhat contrived, such a use case is very common in data science and machine learning. Imagine writing a package for training a Deep Learning model. You can use get_value to lookup custom Dataset classes and model implementations and this way, people can use your package without the need to modifying your code, because they can simply inject their own implementations in places where you have used get_value.

Another potential use case is defining Neural Network layers. You can use get_value to lookup custom layers and use them in your model. Such as:

```python from dypy import get_value import torch

class MyLinearBlock(torch.nn.Module): def init(self, infeatures, outfeatures, activation="torch.nn.ReLU"): super().init() self.linear = torch.nn.Linear(infeatures, outfeatures) self.activation = get_value(activation, strict=False)

def forward(self, x):
    x = self.linear(x)
    x = self.activation(x) if self.activation else x
    return x

```

This way, you can change the activation function by simply changing the activation argument. For example, you can use torch.nn.Sigmoid or torch.nn.Tanh or even a custom activation function that you have defined in the current working directory or use one from a 3rd party package.

Dynamic Function Evaluation

What if you want to generate python programs dynamically? Meaning that you have a string that contains python code and you want to inject it into your program. You can use dypy.eval_function to evaluate a piece of code and retrieve a function. You can do as follows:

```python from dypy import eval_function

evalfunction("lambda x: x + 1") # at MEMADDRESS>

evalfunction("def myfunction(x): return x + 1") # wont work, this is not a function,

but a code block and you need to mention your functionofinterest in that code block

evalfunction("def myfunction(x): return x + 1", functionofinterest="myfunction") # <function myfunction at MEM_ADDRESS> ```

eval_function accepts three types of function descriptors:

  1. A lambda function, e.g. lambda x: x + 1, or a code which evaluates to a callable object, math.cos (in this case, the values being looked up should be present in the evaluation context, more on this later).
  2. A code block, which can contain multiple lines and functions, in which case you need to specify the name of the function of interest using the function_of_interest argument. eval_function will evaluate the code block and retrieve your function of interest.
  3. A dictionary of "code", ["context", "functionofinterest"] pairs. Useful when you are using eval_function on top of a configuration file, in which case you can specify the code and the context for each function of interest.

When evaluating a function descriptor, you can specify a context in which the code will be evaluated. This is useful when you want to use variables that are not defined in the current scope. dypy has a context registry that you can use as a global context for all your function evaluations.

```python from dypy import evalfunction, registercontext import math

register_context(math, "math") # register math package as a context

you can also use register(math), which will use the name of the package as the context name

evalfunction("math.cos") # at MEMADDRESS> (math is looked up through the context registry) ```

You can also specify a context for each function evaluation using the context argument. The context is a dictionary of variable names and their values. You can do as follows:

python eval_function("def my_function(x): return x + y", function_of_interest="my_function", context={"y": 1})(2) # 3

You can also optionally set dynamic_args=True, when evaluating a function. This will create a function that intelligently evaluates its arguments, by wrapping it using dypy.dynamic_args_wrapper. Functions wrapped by dypy.dynamic_args_wrapper preprocess arguments passed to them, and ignore arguments that are not defined in the function signature. For instance:

python eval_function("lambda x: x + 1", dynamic_args=True)(2, verbose=True) # 3, verbose is ignored

Variable Assignment

There are times when you want to assign a variable in a dynamic manner. Meaning that you want to change a variable's value that is not necessarily defined in the current scope. You can use dypy.set_value to do so. You can do as follows:

```python from dypy import set_value

setvalue("somepackage.my_function", lambda x: x + 1)

changing the value of pi in math package

set_value("math.pi", 3.14)

now if you import math, math.pi will be 3.14

import math math.pi # 3.14 ```

License

dypy is licensed under the MIT License. See LICENSE for the full license text.

Citation

If you use dypy in your research, please cite this repository as described in CITATION.cff.

Owner

  • Name: Vahid Zehtab
  • Login: vahidzee
  • Kind: user
  • Location: Toronto, ON
  • Company: University of Toronto

Applied & Theoretical Deep Learning Researcher MSc. CS @ UofT | BSc. CE @ Sharif University of Technology

Citation (CITATION.cff)

cff-version: 1.2.0
title: '"DyPy": Python toolset for dynamic code manipulations'
message: >-
  If you use this software, please cite it using the
  metadata from this file.
type: software
authors:
  - given-names: Vahid
    family-names: Zehtab
    email: vahid@zehtab.me
repository-code: "https://github.com/vahidzee/dypy/"
abstract: >-
  A python package for 
keywords:
  - Dynamic Function Creation
  - Dynamic Object Creation
  - Dynamic Code Generation
  - Dynamic Code Manipulation
  - Dynamic Code Injection
  - Dynamic Code Execution
  - Lazy Function Evaluation
  - Lazy Variable Evaluation
  - Lazy Object Evaluation
license: MIT
date-released: "2022-11-30"

GitHub Events

Total
  • Push event: 1
Last Year
  • Push event: 1

Committers

Last synced: almost 3 years ago

All Time
  • Total Commits: 16
  • Total Committers: 3
  • Avg Commits per committer: 5.333
  • Development Distribution Score (DDS): 0.563
Top Committers
Name Email Commits
hamidreza h****i@g****m 7
vahidzee v****e@g****m 6
Vahid Zehtab 3****e@u****m 3

Issues and Pull Requests

Last synced: 5 months ago

All Time
  • Total issues: 9
  • Total pull requests: 3
  • Average time to close issues: about 12 hours
  • Average time to close pull requests: about 7 hours
  • Total issue authors: 2
  • Total pull request authors: 1
  • Average comments per issue: 0.56
  • Average comments per pull request: 0.0
  • Merged pull requests: 3
  • Bot issues: 0
  • Bot pull requests: 0
Past Year
  • Issues: 0
  • Pull requests: 0
  • Average time to close issues: N/A
  • Average time to close pull requests: N/A
  • Issue authors: 0
  • Pull request authors: 0
  • Average comments per issue: 0
  • Average comments per pull request: 0
  • Merged pull requests: 0
  • Bot issues: 0
  • Bot pull requests: 0
Top Authors
Issue Authors
  • HamidrezaKmK (6)
  • vahidzee (3)
Pull Request Authors
  • HamidrezaKmK (3)
Top Labels
Issue Labels
enhancement (4)
Pull Request Labels

Packages

  • Total packages: 1
  • Total downloads:
    • pypi 32 last-month
  • Total dependent packages: 1
  • Total dependent repositories: 2
  • Total versions: 2
  • Total maintainers: 1
pypi.org: dypy

A toolset for dynamic python code manipulations

  • Versions: 2
  • Dependent Packages: 1
  • Dependent Repositories: 2
  • Downloads: 32 Last month
Rankings
Dependent packages count: 4.7%
Dependent repos count: 11.6%
Stargazers count: 16.5%
Average: 18.2%
Forks count: 22.6%
Downloads: 35.7%
Maintainers (1)
Last synced: 5 months ago

Dependencies

.github/workflows/publish-python.yml actions
  • actions/checkout v2 composite
  • actions/setup-python v2 composite
setup.py pypi