Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: CI

on:
push:
branches: ["master", "main"]
pull_request:
branches: ["master", "main"]

jobs:
test:
name: "Python ${{ matrix.python-version }}"
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.8", "3.10", "3.12"]

steps:
- uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install package and test dependencies
run: |
python -m pip install --upgrade pip
pip install .[test]

- name: Run unit tests and doc tests with coverage
run: |
pytest \
--cov=pyeval \
--cov-report=term-missing \
--cov-report=xml:coverage.xml \
--cov-report=html:coverage-html \
src/pyeval/tests/

- name: Upload coverage HTML report
if: matrix.python-version == '3.12'
uses: actions/upload-artifact@v4
with:
name: coverage-report
path: coverage-html/

- name: Upload coverage XML (for external tools)
if: matrix.python-version == '3.12'
uses: actions/upload-artifact@v4
with:
name: coverage-xml
path: coverage.xml
26 changes: 26 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Python
__pycache__/
*.py[cod]
*.egg-info/
dist/
build/
*.egg

# Virtual environments
.venv/
venv/
env/

# Nix
result
result-*

# pytest
.pytest_cache/
.coverage
htmlcov/

# Editor
.idea/
.vscode/
*.swp
8 changes: 0 additions & 8 deletions .hgignore

This file was deleted.

1 change: 0 additions & 1 deletion MANIFEST.in

This file was deleted.

3 changes: 0 additions & 3 deletions bin/pyeval

This file was deleted.

59 changes: 59 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
{
description = "pyeval - Conveniently evaluate Python expressions from the shell";

inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
};

outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = nixpkgs.legacyPackages.${system};
python = pkgs.python3;

pyeval = python.pkgs.buildPythonPackage {
pname = "pyeval";
version = "0.3.0";
format = "pyproject";

src = ./.;

nativeBuildInputs = [
python.pkgs.setuptools
];

meta = with pkgs.lib; {
description = "Conveniently evaluate Python expressions from the shell";
license = licenses.gpl3;
mainProgram = "pyeval";
};
};
in {
packages = {
default = pyeval;
pyeval = pyeval;
};

apps.default = flake-utils.lib.mkApp {
drv = pyeval;
name = "pyeval";
};

devShells.default = pkgs.mkShell {
packages = [
(python.withPackages (ps: with ps; [
pip
pytest
setuptools
]))
];

shellHook = ''
export PYTHONPATH="$PWD/src:$PYTHONPATH"
echo "pyeval dev shell — run 'pytest src/pyeval/tests' to test"
'';
};
}
);
}
15 changes: 0 additions & 15 deletions lib/pyeval/doc/encoding.txt

This file was deleted.

34 changes: 34 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
[build-system]
requires = ["setuptools>=61"]
build-backend = "setuptools.build_meta"

[project]
name = "pyeval"
version = "0.3.0"
description = "Conveniently evaluate Python expressions from the shell"
authors = [{name = "Nathan Wilcox", email = "nejucomo@gmail.com"}]
license = {text = "GPLv3"}
requires-python = ">=3.8"

[project.scripts]
pyeval = "pyeval.main:main"

[project.optional-dependencies]
test = ["pytest", "pytest-cov"]

[tool.setuptools.packages.find]
where = ["src"]

[tool.setuptools.package-data]
pyeval = ["doc/*.txt"]

[tool.pytest.ini_options]
addopts = "--tb=short"
testpaths = ["src/pyeval/tests"]

[tool.coverage.run]
branch = true
source = ["pyeval"]

[tool.coverage.report]
show_missing = true
43 changes: 0 additions & 43 deletions run_tests.sh

This file was deleted.

24 changes: 0 additions & 24 deletions setup.py

This file was deleted.

File renamed without changes.
30 changes: 9 additions & 21 deletions lib/pyeval/autoimporter.py → src/pyeval/autoimporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@
from weakref import WeakKeyDictionary


class AutoImporter(object):

class AutoImporter (object):
class Proxy(object):
pass # BaseClass exposed so client code can use isinstance(x, AutoImporter.Proxy)

class Proxy (object):
pass # BaseClass exposed so client code can use isinstance(x, AutoImport.Proxy)

class ModInfo (object):
class ModInfo(object):
def __init__(self, mod):
self.mod = mod

Expand All @@ -21,26 +20,15 @@ def name(self):

@property
def path(self):
try:
path = self.mod.__file__
except AttributeError:
return None
else:
if path.endswith('.pyc'):
path = path[:-1]

return path

return getattr(self.mod, '__file__', None)

def __init__(self):
self._proxyInfo = WeakKeyDictionary()

def proxyImport(self, name):

mod = __import__(name)
for name in name.split('.')[1:]:
mod = getattr(mod, name)

for part in name.split('.')[1:]:
mod = getattr(mod, part)
return self._proxyWrap(mod)

def mod(self, proxy):
Expand All @@ -64,7 +52,7 @@ def _proxyWrap(self, mod):
ai = self
modinfo = ai.ModInfo(mod)

class BoundProxy (ai.Proxy):
class BoundProxy(ai.Proxy):
def __repr__(_):
modrepr = repr(mod)
assert modrepr.startswith('<') and modrepr.endswith('>'), modrepr
Expand All @@ -73,7 +61,7 @@ def __repr__(_):
def __getattribute__(_, name):
try:
x = getattr(mod, name)
except AttributeError, outerError:
except AttributeError as outerError:
try:
x = ai.proxyImport(modinfo.name + '.' + name)
except ImportError:
Expand Down
File renamed without changes.
5 changes: 1 addition & 4 deletions lib/pyeval/display.py → src/pyeval/display.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,5 @@ def displayPretty(obj):


def getEncoding():
# NOTE: I do not know how well this will work in practice:
# If sys.stdout.encoding is not set (because stdout is not a terminal),
# we use LC_CTYPE *anyway*.
return (getattr(sys.stdout, 'encoding', None)
or os.environ.get('LC_CTYPE', 'UTF-8').split( '.', 1 )[-1])
or os.environ.get('LC_CTYPE', 'UTF-8').split('.', 1)[-1])
File renamed without changes.
13 changes: 13 additions & 0 deletions src/pyeval/doc/encoding.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
In Python 3, text encoding is handled transparently by the standard
library. The 'p()' magic function uses Python's built-in print(),
which respects sys.stdout.encoding automatically.

The 'encoding' magic variable still provides access to the detected
encoding, selected in this order:

1. sys.stdout.encoding
2. The substring of the LC_CTYPE environment variable after the rightmost '.'
3. UTF-8

Several display functions, such as sh() and p(), rely on Python's
standard print() which handles unicode natively.
File renamed without changes.
5 changes: 2 additions & 3 deletions lib/pyeval/doc/help.txt → src/pyeval/doc/help.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,16 @@ argument. For example:
To examine source docstrings any object, such as a class, pass it to help
as a function:

$ pyeval 'help(BaseHTTPServer.HTTPServer)'
$ pyeval 'help(http.server.HTTPServer)'
...

There is a special case for AutoImporter module proxies, so that the
original module is passed on to the pydoc help system:

$ pyeval 'help(BaseHTTPServer)'
$ pyeval 'help(http.server)'
...

To use the interactive help system of pydoc, call it directly:

$ pyeval 'pydoc.help()'
...

File renamed without changes.
2 changes: 1 addition & 1 deletion lib/pyeval/doc/magic.txt → src/pyeval/doc/magic.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ of dict. A MagicScope has two special properties:
* unbound references are passed through to a "fallthrough" handler.

The standard fallthrough handler attempts to find the reference in
__builtin__, or if it is not there, it delegates to an AutoImporter
builtins, or if it is not there, it delegates to an AutoImporter
instance. For more detail about the AutoImporter mechanism, run:

$ pyeval help AutoImporter
Expand Down
Loading