From c1c61a7dd4fc2c7169c108a42ef607dff27ec46c Mon Sep 17 00:00:00 2001 From: "David J. Malan" <malan@harvard.edu> Date: Mon, 23 Oct 2017 12:12:17 -0400 Subject: [PATCH 1/2] removed get_char, tidied comments --- src/cs50/cs50.py | 28 +++++---------- test/cs50/__init__.py | 21 +++++++++++ test/cs50/cs50.py | 81 +++++++++++++++++++++++++++++++++++++++++++ test/cs50/sql.py | 43 +++++++++++++++++++++++ 4 files changed, 154 insertions(+), 19 deletions(-) create mode 100644 test/cs50/__init__.py create mode 100644 test/cs50/cs50.py create mode 100644 test/cs50/sql.py diff --git a/src/cs50/cs50.py b/src/cs50/cs50.py index b03cf04..03007a4 100644 --- a/src/cs50/cs50.py +++ b/src/cs50/cs50.py @@ -3,6 +3,7 @@ import re import sys + class flushfile(): """ Disable buffering for standard output and standard error. @@ -18,9 +19,12 @@ def __getattr__(self, name): def write(self, x): self.f.write(x) self.f.flush() + + sys.stderr = flushfile(sys.stderr) sys.stdout = flushfile(sys.stdout) + def eprint(*args, **kwargs): """ Print an error message to standard error, prefixing it with @@ -32,22 +36,6 @@ def eprint(*args, **kwargs): print("{}:{}: ".format(filename, lineno), end="") print(*args, end=end, file=sys.stderr, sep=sep) -def get_char(prompt=None): - """ - Read a line of text from standard input and return the equivalent char; - if text is not a single char, user is prompted to retry. If line can't - be read, return None. - """ - while True: - s = get_string(prompt) - if s is None: - return None - if len(s) == 1: - return s[0] - - # temporarily here for backwards compatibility - if prompt is None: - print("Retry: ", end="") def get_float(prompt=None): """ @@ -69,6 +57,7 @@ def get_float(prompt=None): if prompt is None: print("Retry: ", end="") + def get_int(prompt=None): """ Read a line of text from standard input and return the equivalent int; @@ -82,12 +71,12 @@ def get_int(prompt=None): if re.search(r"^[+-]?\d+$", s): try: i = int(s, 10) - if type(i) is int: # could become long in Python 2 + if type(i) is int: # Could become long in Python 2 return i except ValueError: pass - # temporarily here for backwards compatibility + # Temporarily here for backwards compatibility if prompt is None: print("Retry: ", end="") @@ -108,10 +97,11 @@ def get_long(prompt=None): except ValueError: pass - # temporarily here for backwards compatibility + # Temporarily here for backwards compatibility if prompt is None: print("Retry: ", end="") + def get_string(prompt=None): """ Read a line of text from standard input and return it as a string, diff --git a/test/cs50/__init__.py b/test/cs50/__init__.py new file mode 100644 index 0000000..2ec0ec0 --- /dev/null +++ b/test/cs50/__init__.py @@ -0,0 +1,21 @@ +from .cs50 import * + +class CustomImporter(object): + """ + Import cs50.SQL lazily. + + http://dangerontheranger.blogspot.com/2012/07/how-to-use-sysmetapath-with-python.html + """ + def find_module(self, fullname, path=None): + if fullname == "cs50.SQL": + return self + return None + def load_module(self, fullname): + print("1") + if fullname != "cs50.SQL": + raise ImportError(fullname) + print("2") + from .sql import SQL + print("3") + return SQL +sys.meta_path.append(CustomImporter()) diff --git a/test/cs50/cs50.py b/test/cs50/cs50.py new file mode 100644 index 0000000..657f405 --- /dev/null +++ b/test/cs50/cs50.py @@ -0,0 +1,81 @@ +from __future__ import print_function +import re +import sys + +class flushfile(): + """ + Disable buffering for standard output and standard error. + + http://stackoverflow.com/a/231216 + """ + def __init__(self, f): + self.f = f + + def __getattr__(self, name): + return object.__getattribute__(self.f, name) + + def write(self, x): + self.f.write(x) + self.f.flush() +sys.stderr = flushfile(sys.stderr) +sys.stdout = flushfile(sys.stdout) + +def get_char(): + """Read a line of text from standard input and return the equivalent char.""" + while True: + s = get_string() + if s is None: + return None + if len(s) == 1: + return s[0] + print("Retry: ", end="") + +def get_float(): + """Read a line of text from standard input and return the equivalent float.""" + while True: + s = get_string() + if s is None: + return None + if len(s) > 0 and re.search(r"^[+-]?\d*(?:\.\d*)?$", s): + try: + return float(s) + except ValueError: + pass + print("Retry: ", end="") + +def get_int(): + """Read a line of text from standard input and return the equivalent int.""" + while True: + s = get_string(); + if s is None: + return None + if re.search(r"^[+-]?\d+$", s): + try: + i = int(s, 10) + if type(i) is int: # could become long in Python 2 + return i + except ValueError: + pass + print("Retry: ", end="") + +if sys.version_info.major != 3: + def get_long(): + """Read a line of text from standard input and return the equivalent long.""" + while True: + s = get_string(); + if s is None: + return None + if re.search(r"^[+-]?\d+$", s): + try: + return long(s, 10) + except ValueError: + pass + print("Retry: ", end="") + +def get_string(): + """Read a line of text from standard input and return it as a string.""" + try: + s = sys.stdin.readline() + return re.sub(r"(?:\r|\r\n|\n)$", "", s) + except ValueError: + return None diff --git a/test/cs50/sql.py b/test/cs50/sql.py new file mode 100644 index 0000000..db974e3 --- /dev/null +++ b/test/cs50/sql.py @@ -0,0 +1,43 @@ +import sqlalchemy + +class SQL(object): + """TODO""" + + def __init__(self, url): + """TODO""" + try: + self.engine = sqlalchemy.create_engine(url) + except Exception as e: + raise RuntimeError(e) + + def execute(self, text, *multiparams, **params): + """TODO""" + try: + + # http://docs.sqlalchemy.org/en/latest/core/sqlelement.html#sqlalchemy.sql.expression.text + # https://groups.google.com/forum/#!topic/sqlalchemy/FfLwKT1yQlg + # http://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.Engine.execute + # http://docs.sqlalchemy.org/en/latest/faq/sqlexpressions.html#how-do-i-render-sql-expressions-as-strings-possibly-with-bound-parameters-inlined + statement = sqlalchemy.text(text).bindparams(*multiparams, **params) + result = self.engine.execute(str(statement.compile(compile_kwargs={"literal_binds": True}))) + + # SELECT + if result.returns_rows: + rows = result.fetchall() + return [dict(row) for row in rows] + + # INSERT + elif result.lastrowid is not None: + return result.lastrowid + + # DELETE, UPDATE + else: + return result.rowcount + + except sqlalchemy.exc.IntegrityError: + return None + + except Exception as e: + raise RuntimeError(e) + + From c99f84177b3e17f891d9e03684fb72da6d246129 Mon Sep 17 00:00:00 2001 From: "David J. Malan" <malan@harvard.edu> Date: Mon, 23 Oct 2017 12:12:44 -0400 Subject: [PATCH 2/2] upped version --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 1c49faf..a5eaed9 100644 --- a/setup.py +++ b/setup.py @@ -16,5 +16,5 @@ package_dir={"": "src"}, packages=["cs50"], url="https://github.com/cs50/python-cs50", - version="2.2.0" + version="2.3.0" )