Skip to content

Commit

Permalink
fix: support more corner cases
Browse files Browse the repository at this point in the history
  • Loading branch information
CNSeniorious000 committed Apr 13, 2024
1 parent 440200a commit c2aba88
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 8 deletions.
87 changes: 85 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,86 @@
# literal-dict
# Literal Dict

JavaScript-like object definition syntax in Python
`literal-dict` is a Python utility that allows for the creation of dictionary objects with a syntax reminiscent of JavaScript object notation. This tool is particularly useful for developers looking to streamline their code by reducing the verbosity commonly associated with dictionary creation in Python.

## Features

- **Intuitive Variable Inclusion**: Create Python dictionaries using a syntax similar to JavaScript objects: automatically uses variable names as keys, simplifying the process of dictionary creation.
- **Flexible Dictionary Implementations**: Supports custom dictionary implementations, enabling behaviors like ordered dictionaries, default dictionaries, dot dictionaries, and more.
- **Various Python Distribution Supports**: This package is tested under almost every popular python implementations.

## Installation

```bash
pip install literal-dict
```

## Usage

### Basic Dictionary Creation

Start by importing `DictBuilder` from the package:

```py
from literal_dict import DictBuilder
```

Create a `DictBuilder` instance:

```py
d = DictBuilder()
```

Now, you can create dictionaries with a simplified syntax:

```py
name = "Muspi Merol"
age = 20

user = d[name, age, "active": True]
print(user) # Output: {'name': 'Muspi Merol', 'age': 20, 'active': True}
```

### Using Custom Dictionary Implementations

`DictBuilder` allows specifying a custom dict-like type:

#### Example with `types.SimpleNamespace`

Using `SimpleNamespace` from the `types` module allows for attribute-style access to dictionary keys. This can make your code cleaner and more readable in some cases.

```python
from types import SimpleNamespace

from literal_dict import DictBuilder

d = DictBuilder(lambda dict: SimpleNamespace(**dict))

name = "Muspi Merol"
email = "me@promplate.dev"

person = d[name, email]
print(person.name) # Output: Muspi Merol
print(person.email) # Output: me@promplate.dev
```

Note: When using `SimpleNamespace`, the returned object is not a dictionary but an instance of `SimpleNamespace`, which allows for dot-notation access to the attributes.

#### Example with `collections.defaultdict`

```py
from collections import defaultdict
from functools import partial

from literal_dict import DictBuilder

d = DictBuilder(partial(defaultdict, int))

a = 1

obj = d[a, "b":2]
print(obj["c"]) # Output: 0, since 'c' does not exist, it returns the default int value
```

## Conclusion

The `Literal Dict Builder` offers a succinct and intuitive way to create dictionaries in Python, drawing inspiration from JavaScript's object notation. Its support for custom dictionary implementations adds a layer of flexibility, allowing developers to tailor their data structures to fit their needs.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "literal-dict"
version = "1.0.0"
version = "1.0.1"
description = "Use JavaScript-like object definition syntax in Python"
authors = [{ name = "Muspi Merol", email = "me@muspimerol.site" }]
dependencies = []
Expand Down
20 changes: 15 additions & 5 deletions src/literal_dict.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
from inspect import currentframe
from typing import Generic, Mapping, Sequence, Type, TypeVar, Union, cast
from typing import Callable, Generic, Mapping, Sequence, TypeVar, Union, cast

T = TypeVar("T")
D = TypeVar("D", bound=Mapping)


class DictBuilder(Generic[D]):
def __init__(self, mapping_type: Type[D] = dict):
self.mapping_type = mapping_type
def __init__(self, mapping_constructor: Callable[[dict], D] = dict):
self.constructor = mapping_constructor

def __getitem__(self, args: Union[slice, T, Sequence[Union[slice, T]]]) -> D:
if not isinstance(args, tuple):
Expand All @@ -29,5 +29,15 @@ def __getitem__(self, args: Union[slice, T, Sequence[Union[slice, T]]]) -> D:
if var is arg:
obj[name] = arg
break

return self.mapping_type(obj) if self.mapping_type is not dict else obj # type: ignore
else:
for name, var in caller_frame.f_globals.items():
if var is arg:
obj[name] = arg
break
else:
for name, var in caller_frame.f_builtins.items():
if var is arg:
obj[name] = arg
break

return self.constructor(obj) if self.constructor is not dict else obj # type: ignore
18 changes: 18 additions & 0 deletions test.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,21 @@ def __getattr__(self, key):
d = DictBuilder(DotDict)
a = 1
assert d[a].a == a


def test_global_reference():
d = DictBuilder()

def f():
assert d[DictBuilder] == {"DictBuilder": DictBuilder}

f()


def test_builtin_reference():
d = DictBuilder()

def f():
assert d[print] == {"print": print}

f()

0 comments on commit c2aba88

Please sign in to comment.