Skip to content

Commit

Permalink
0.13.0 (#105)
Browse files Browse the repository at this point in the history
* style: change max line length to 88

* style: clean up test code styles

* feat: support subscript node for varname

* docs: update README.md

* ci: remove python3.8 from CI

* 0.13.0
  • Loading branch information
pwwang authored Feb 5, 2024
1 parent be560cc commit ea1ec82
Show file tree
Hide file tree
Showing 13 changed files with 415 additions and 275 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.8, 3.9, "3.10", "3.11", "3.12-dev"]
python-version: [3.9, "3.10", "3.11", "3.12-dev"]

steps:
- uses: actions/checkout@v3
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ Special thanks to [@HanyuuLu][2] to give up the name `varname` in pypi for this
func = function2() # func == 'func'

a = lambda: 0
a.b = function() # a.b == 'b'
a.b = function() # a.b == 'a.b'
```

### The decorator way to register `__varname__` to functions/classes
Expand Down
2 changes: 1 addition & 1 deletion README.raw.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ Special thanks to [@HanyuuLu][2] to give up the name `varname` in pypi for this
func = function2() # func == 'func'

a = lambda: 0
a.b = function() # a.b == 'b'
a.b = function() # a.b == 'a.b'
```

### The decorator way to register `__varname__` to functions/classes
Expand Down
8 changes: 8 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Change Log

## 0.13.0

- style: change max line length to 88
- style: clean up test code styles
- feat: support subscript node for varname (#104)
- ci: remove python3.8 from CI
- breaking!: `varname` of `a.b` now returns `"a.b"` instead of `"a"`

## 0.12.2

- Add `helpers.exec_code` function to replace `exec` so that source code available at runtime
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "poetry.masonry.api"

[tool.poetry]
name = "varname"
version = "0.12.2"
version = "0.13.0"
description = "Dark magics about variable names in python."
authors = [ "pwwang <[email protected]>",]
license = "MIT"
Expand Down Expand Up @@ -42,6 +42,6 @@ show_error_codes = true
strict_optional = false

[tool.black]
line-length = 80
line-length = 88
target-version = ['py37', 'py38', 'py39', 'py310']
include = '\.pyi?$'
57 changes: 10 additions & 47 deletions tests/test_argname.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@
from functools import singledispatch

import pytest
from varname import *
from varname import (
argname,
UsingExecWarning,
ImproperUseError,
VarnameRetrievingError,
)


def test_argname():
Expand Down Expand Up @@ -72,7 +77,7 @@ def func(a):


def test_argname_non_argument():
x = 1
x = 1 # noqa F841
y = lambda: argname("x")
with pytest.raises(ImproperUseError, match="'x' is not a valid argument"):
y()
Expand All @@ -96,7 +101,7 @@ def func(a, b, c, d=4):


def test_argname_funcnode_not_call():
x = 1
x = 1 # noqa F841

class Foo:

Expand Down Expand Up @@ -194,7 +199,7 @@ def func(*args, **kwargs):

def test_argname_argname_node_na():
source = textwrap.dedent(
f"""\
"""\
from varname import argname
def func(a):
return argname(a)
Expand Down Expand Up @@ -222,17 +227,6 @@ def func(a):
exec("x=1; func(x)")


def test_argname_func_na():
def func(a):
return argname("a")

with pytest.raises(
VarnameRetrievingError,
match="The source code of 'argname' calling is not available",
):
exec("x=1; func(x)")


def test_argname_wrapper():
def decorator(f):
def wrapper(arg, *more_args):
Expand Down Expand Up @@ -264,7 +258,7 @@ def func(a, *args, **kwargs):

def test_argname_nosuch_varpos_arg():
def func(a, *args):
another = []
another = [] # noqa F841
return argname("a", "*another")

x = y = 1
Expand All @@ -283,36 +277,6 @@ def func(a, b):
assert names == "x"


def test_argname_singledispatched():
# GH53
@singledispatch
def add(a, b):
aname = argname("a", "b", func=add.dispatch(object))
return aname + (1,) # distinguish

@add.register(int)
def add_int(a, b):
aname = argname("a", "b", func=add_int)
return aname + (2,)

@add.register(str)
def add_str(a, b):
aname = argname("a", "b", dispatch=str)
return aname + (3,)

x = y = 1
out = add(x, y)
assert out == ("x", "y", 2)

t = s = "a"
out = add(t, s)
assert out == ("t", "s", 3)

p = q = 1.2
out = add(p, q)
assert out == ("p", "q", 1)


def test_argname_func_na():
def func(a):
return argname("a")
Expand Down Expand Up @@ -427,7 +391,6 @@ def __setitem__(self, name, value) -> None:
self.__dict__["meta"]["name2"] = argname("name", vars_only=False)
self.__dict__["meta"]["value"] = argname("value")


a = A()
out = a.x
assert out == "'x'"
Expand Down
59 changes: 33 additions & 26 deletions tests/test_bytecode_nameof.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@
import pytest
import unittest
from varname.utils import bytecode_nameof as bytecode_nameof_cached
from varname import *
from varname import nameof, varname, ImproperUseError, VarnameRetrievingError

# config.debug = True


def bytecode_nameof(frame):
frame = sys._getframe(frame)
return bytecode_nameof_cached(frame.f_code, frame.f_lasti)


def nameof_both(var, *more_vars):
"""Test both implementations at the same time"""
result = nameof(var, *more_vars, frame=2)
Expand All @@ -18,58 +21,62 @@ def nameof_both(var, *more_vars):
assert result == bytecode_nameof(frame=2)
return result


class Weird:
def __add__(self, other):
bytecode_nameof(frame=2)


class TestNameof(unittest.TestCase):
def test_original_nameof(self):
x = 1
self.assertEqual(nameof(x), 'x')
self.assertEqual(nameof_both(x), 'x')
self.assertEqual(bytecode_nameof(x), 'x')
self.assertEqual(nameof(x), "x")
self.assertEqual(nameof_both(x), "x")
self.assertEqual(bytecode_nameof(x), "x")

def test_bytecode_nameof_wrong_node(self):
with pytest.raises(
VarnameRetrievingError,
match="Did you call 'nameof' in a weird way",
VarnameRetrievingError,
match="Did you call 'nameof' in a weird way",
):
Weird() + Weird()

def test_bytecode_pytest_nameof_fail(self):
with pytest.raises(
VarnameRetrievingError,
match=("Found the variable name '@py_assert2' "
"which is obviously wrong."),
VarnameRetrievingError,
match=(
"Found the variable name '@py_assert2' " "which is obviously wrong."
),
):
lam = lambda: 0
lam.a = 1
assert bytecode_nameof(lam.a) == 'a'
assert bytecode_nameof(lam.a) == "a"

def test_nameof(self):
a = 1
b = nameof_both(a)
assert b == 'a'
assert b == "a"
nameof2 = nameof_both
c = nameof2(a, b)
assert b == 'a'
assert c == ('a', 'b')
assert b == "a"
assert c == ("a", "b")

def func():
return varname() + 'abc'
return varname() + "abc"

f = func()
assert f == 'fabc'
assert f == "fabc"

self.assertEqual(nameof_both(f), 'f')
self.assertEqual('f', nameof_both(f))
self.assertEqual(nameof_both(f), "f")
self.assertEqual("f", nameof_both(f))
self.assertEqual(len(nameof_both(f)), 1)

fname1 = fname = nameof_both(f)
self.assertEqual(fname, 'f')
self.assertEqual(fname1, 'f')
self.assertEqual(fname, "f")
self.assertEqual(fname1, "f")

with pytest.raises(ImproperUseError):
nameof_both(a==1)
nameof_both(a == 1)

with pytest.raises(VarnameRetrievingError):
bytecode_nameof(a == 1)
Expand All @@ -79,30 +86,30 @@ def func():
# nameof_both()

def test_nameof_statements(self):
a = {'test': 1}
a = {"test": 1}
test = {}
del a[nameof_both(test)]
assert a == {}

def func():
return nameof_both(test)

assert func() == 'test'
assert func() == "test"

def func2():
yield nameof_both(test)

assert list(func2()) == ['test']
assert list(func2()) == ["test"]

def func3():
raise ValueError(nameof_both(test))

with pytest.raises(ValueError) as verr:
func3()
assert str(verr.value) == 'test'
assert str(verr.value) == "test"

for i in [0]:
self.assertEqual(nameof_both(test), 'test')
self.assertEqual(nameof_both(test), "test")
self.assertEqual(len(nameof_both(test)), 4)

def test_nameof_expr(self):
Expand All @@ -126,4 +133,4 @@ def test_nameof_expr(self):
self.assertEqual(nameof_both(lam.lam.lam.lam), "lam")
self.assertEqual(nameof_both(lams[0].lam), "lam")
self.assertEqual(nameof_both(lams[0].lam.a), "a")
self.assertEqual(nameof_both((lam() or lams[0]).lam.a), "a")
self.assertEqual(nameof_both((lam() or lams[0]).lam.a), "a")
Loading

0 comments on commit ea1ec82

Please sign in to comment.