semvec/pypi-packages huggingface dataset:
moodle-tools 1.1.0
A collection of tools to simplify working with Moodle quizzes.
Requires Python: >=3.11
Keywords: moodle, teaching

# Moodle Tools

This repository contains a collection of tools to simplify working with Moodle quizzes.

## Tools

- `make-questions`: Generate Moodle quiz questions from simple YAML documents to minimize the use of the web interface.
- `analyze-results`: Analyze the results of a Moodle quiz to improve question quality.

## Installation

`moodle-tools` is distributed as a Python package.
You can install it from PyPI using `pip`:

```bash
pip install moodle-tools
```

### Local Installation

Either clone the repository:

```bash
git clone https://git.tu-berlin.de/dima/moodle-tools
cd moodle-tools
python3 -m venv venv
source venv/bin/activate
pip install .
```

Or directly install it from GitLab:

```bash
pip install git+https://git.tu-berlin.de/dima/moodle-tools
```

### Optional Question Types

Specialized question types that require additional dependencies are not installed by
default. To use them, you need to install the respective dependency group with
`pip install "moodle-tools[GROUPNAME]"`. The following groups are available:

- `isda`: Adds support for `CoderunnerDDLQuestion`, `CoderunnerDQLQuestion`, and `CoderunnerStreamingQuestion` questions.

For example, to install the `isda` questions execute:

```bash
pip install "moodle-tools[isda]"
```

## Usage

Once installed, you can access the tools as Python modules or via their command line
interface.

```python
from moodle_tools import make_questions, analyze_results
```

```bash
make-questions -h
analyze-results -h
```

## Documentation

The [API documentation](https://dima.gitlab-pages.tu-berlin.de/moodle-tools) of
`moodle-tools` is hosted on GitLab pages.

## Contributing

If you want to contribute a bug fix or feature to `moodle-tools`, please open an issue
first to ensure that your intended contribution aligns with the project.

Different to a user installation, you also need to install the `dev` requirements and
activate `pre-commit` in your copy of the repository before making a commit.

```bash
# Activate your virtual environment first
pip install -e ".[dev]"
pre-commit install
```

The source code for Moodle's XML parser is located [here](https://github.com/moodle/moodle/tree/main/question/format/xml)
in case we need to reverse engineer behavior changes.
signals-py 0.1.0.post1
send and receive signals
Requires Python: >=3.12

# signals
this project ports django's [signal dispatcher](https://docs.djangoproject.com/en/5.2/topics/signals/) so it can be used with any app


## Installation
```bash
pip install signals-py
```

(note that while it's installed as `signals-py`, the package name is `signals`)


## usage
for a full exploration check django's [docs](https://docs.djangoproject.com/en/5.2/topics/signals/)

but in essance:

### craete a signal:
```python
from signals.dispatch import Signal

my_costum_signal = Signal()
```

### define receviers
to connect a function/method as a recevier:
```python
from somewhere import my_costum_signal


def my_recevier(**kwargs):
    print("signal was sent!!")


my_costum_signal.connect(my_recevier)
```

or use the decorator
```python
from signals.dispatch import recevier
from somewhere import my_costum_signal


@recevier(my_costum_signal)
def my_recevier(**kwargs):
    print("signal was sent!!")

```

receviers can be async function/methods as well

```python
from somewhere import my_costum_signal


async def my_recevier(**kwargs):
    print("signal was sent!!")


my_costum_signal.connect(my_recevier)
```

or

```python
from signals.dispatch import recevier
from somewhere import my_costum_signal


@recevier(my_costum_signal)
async def my_recevier(**kwargs):
    print("signal was sent!!")

```


### send signals
to send a signal, simply call `.send()`:

```python
from somewhere import my_costum_signal

my_costum_signal.send(sender=object())
```

the sender argument is usually the class that's sending the signal (via `self.__class__`),
but it can be anything.

if one of the receviers raises an exception, it gets raise right there so other receviers won't be called.


or you can call `.send_robust()`, which ensures all receviers are called even if exceptions are raised
```python
from somewhere import my_costum_signal

my_costum_signal.send_robust(sender=object())
```

both `.send()` and `.send_robust()` have an async version, called `.asend()` and `.asend_robust()`

```python
from somewhere import my_costum_signal


async def do_some_work():
    await my_costum_signal.asend(sender=object)
    # or
    await my_costum_signal.asend_robust(sender=object)
```

all the sending methods return a list of tuples,
the first item in the tuple is the recevier, the second is the value returned by the recevier
if `send_robust` or `asend_robust` is used, if a recevier raises an exception, the exception will be the second item in the tuple.

### disconnect a recevier
to disconnect a recevier from a signal simply do:
```python
from somewhere import my_costum_signal
from receviers_home import my_recevier

my_costum_signal.disconnect(my_recevier)
```


## how async/sync receviers are treated
if you use `.send()` (or other sync ways to send), all sync receviers are called normally,
async receviers are wrappe in a single `asgiref.sync.async_to_sync` call.

if you use `.asend()` (or other async ways to send), async receviers are scheduled via `asyncio.gather()`
sync receviers are wrapped with a single `asgiref.sync.sync_to_async` then passed to the same `asyncio.gather()`