Skip to content
Merged
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
25 changes: 10 additions & 15 deletions mathics/builtin/files.py
Original file line number Diff line number Diff line change
Expand Up @@ -3812,6 +3812,8 @@ class FileHash(Builtin):
<dt>'FileHash[$file$, $type$]'
<dd>returns an integer hash of the specified $type$ for the given $file$.</dd>
<dd>The types supported are "MD5", "Adler32", "CRC32", "SHA", "SHA224", "SHA256", "SHA384", and "SHA512".</dd>
<dt>'FileHash[$file$, $type$, $format$]'
<dd>gives a hash code in the specified format.</dd>
</dl>

>> FileHash["ExampleData/sunflowers.jpg"]
Expand Down Expand Up @@ -3840,19 +3842,20 @@ class FileHash(Builtin):
#> FileHash["ExampleData/sunflowers.jpg", xyzsymbol]
= FileHash[ExampleData/sunflowers.jpg, xyzsymbol]
#> FileHash["ExampleData/sunflowers.jpg", "xyzstr"]
= FileHash[ExampleData/sunflowers.jpg, xyzstr]
= FileHash[ExampleData/sunflowers.jpg, xyzstr, Integer]
#> FileHash[xyzsymbol]
= FileHash[xyzsymbol]
"""

rules = {
"FileHash[filename_String]": 'FileHash[filename, "MD5"]',
"FileHash[filename_String]": 'FileHash[filename, "MD5", "Integer"]',
"FileHash[filename_String, hashtype_String]": 'FileHash[filename, hashtype, "Integer"]',
}

attributes = ("Protected", "ReadProtected")

def apply(self, filename, hashtype, evaluation):
"FileHash[filename_String, hashtype_String]"
def apply(self, filename, hashtype, format, evaluation):
"FileHash[filename_String, hashtype_String, format_String]"
py_filename = filename.get_string_value()

try:
Expand All @@ -3865,7 +3868,7 @@ def apply(self, filename, hashtype, evaluation):
e.message(evaluation)
return

return Hash.compute(lambda update: update(dump), hashtype.get_string_value())
return Hash.compute(lambda update: update(dump), hashtype.get_string_value(), format.get_string_value())


class FileDate(Builtin):
Expand Down Expand Up @@ -4803,6 +4806,7 @@ def apply(self, pathname, evaluation):
return SymbolTrue
return SymbolFalse


class Needs(Builtin):
"""
<dl>
Expand Down Expand Up @@ -4922,7 +4926,6 @@ def apply(self, context, evaluation):
curr_ctxt = evaluation.definitions.get_current_context()
contextstr = curr_ctxt + contextstr[1:]
context = String(contextstr)

if not valid_context_name(contextstr):
evaluation.message('Needs', 'ctx', Expression(
'Needs', context), 1, '`')
Expand All @@ -4932,19 +4935,11 @@ def apply(self, context, evaluation):
if test_loaded.is_true():
# Already loaded
return SymbolNull

# TODO: Figure out why this raises the message:
# "Select::normal: Nonatomic expression expected."
already_loaded = Expression('MemberQ',
Symbol('System`$Packages'), context)
already_loaded = already_loaded.evaluate(evaluation).is_true()
if already_loaded:
return SymbolNull

result = Expression('Get', context).evaluate(evaluation)

if result == SymbolFailed:
evaluation.message("Needs", "nocont", context)
return SymbolFailed

return SymbolNull

32 changes: 24 additions & 8 deletions mathics/builtin/numeric.py
Original file line number Diff line number Diff line change
Expand Up @@ -1340,6 +1340,8 @@ class Hash(Builtin):
<dt>'Hash[$expr$, $type$]'
<dd>returns an integer hash of the specified $type$ for the given $expr$.</dd>
<dd>The types supported are "MD5", "Adler32", "CRC32", "SHA", "SHA224", "SHA256", "SHA384", and "SHA512".</dd>
<dt>'Hash[$expr$, $type$, $format$]'
<dd>Returns the hash in the especified format.</dd>
</dl>

> Hash["The Adventures of Huckleberry Finn"]
Expand All @@ -1358,11 +1360,12 @@ class Hash(Builtin):
= 58042316473471877315442015469706095084

>> Hash[{a, b, c}, "xyzstr"]
= Hash[{a, b, c}, xyzstr]
= Hash[{a, b, c}, xyzstr, Integer]
"""

rules = {
"Hash[expr_]": 'Hash[expr, "MD5"]',
"Hash[expr_]": 'Hash[expr, "MD5", "Integer"]',
"Hash[expr_, type_String]": 'Hash[expr, type, "Integer"]',
}

attributes = ("Protected", "ReadProtected")
Expand All @@ -1380,17 +1383,30 @@ class Hash(Builtin):
}

@staticmethod
def compute(user_hash, py_hashtype):
def compute(user_hash, py_hashtype, py_format):
hash_func = Hash._supported_hashes.get(py_hashtype)
if hash_func is None: # unknown hash function?
return # in order to return original Expression
h = hash_func()
user_hash(h.update)
return from_python(int(h.hexdigest(), 16))

def apply(self, expr, hashtype, evaluation):
"Hash[expr_, hashtype_String]"
return Hash.compute(expr.user_hash, hashtype.get_string_value())
res = h.hexdigest()
if py_format in ('HexString', "HexStringLittleEndian") :
return from_python(res)
res = int(res, 16)
if py_format == "DecimalString":
return from_python(str(res))
elif py_format == "ByteArray":
print("Not implemented. Return a string")
return from_python(str(res))
# Default: Integer
return from_python(res)


def apply(self, expr, hashtype, outformat, evaluation):
"Hash[expr_, hashtype_String, outformat_String]"
return Hash.compute(expr.user_hash,
hashtype.get_string_value(),
outformat.get_string_value())


class TypeEscalation(Exception):
Expand Down