diff --git a/include/pocketpy/pocketpy.h b/include/pocketpy/pocketpy.h index 7c3a48f3..73f2445f 100644 --- a/include/pocketpy/pocketpy.h +++ b/include/pocketpy/pocketpy.h @@ -172,7 +172,7 @@ py_i64 py_toint(py_Ref); /// Convert a `float` object in python to `double`. py_f64 py_tofloat(py_Ref); /// Cast a `int` or `float` object in python to `double`. -/// If successful, returns true and set the value to `out`. +/// If successful, return true and set the value to `out`. /// Otherwise, return false and raise `TypeError`. bool py_castfloat(py_Ref, py_f64* out) PY_RAISE; /// Convert a `bool` object in python to `bool`. @@ -203,6 +203,9 @@ void* py_touserdata(py_Ref); /// Get the type of the object. py_Type py_typeof(py_Ref self); +/// Get type by module and name. e.g. `py_gettype("time", "struct_time")`. +/// Return `0` if not found. +py_Type py_gettype(const char* module, py_Name name); /// Check if the object is exactly the given type. bool py_istype(py_Ref, py_Type); /// Check if the object is an instance of the given type. diff --git a/python/datetime.py b/python/datetime.py index 62b286b3..e7ad4f4c 100644 --- a/python/datetime.py +++ b/python/datetime.py @@ -1,4 +1,5 @@ from time import localtime +import operator class timedelta: def __init__(self, days=0, seconds=0): @@ -13,25 +14,10 @@ class timedelta: return NotImplemented return (self.days, self.seconds) == (other.days, other.seconds) - def __lt__(self, other: 'timedelta') -> bool: + def __ne__(self, other: 'timedelta') -> bool: if type(other) is not timedelta: return NotImplemented - return (self.days, self.seconds) < (other.days, other.seconds) - - def __le__(self, other: 'timedelta') -> bool: - if type(other) is not timedelta: - return NotImplemented - return (self.days, self.seconds) <= (other.days, other.seconds) - - def __gt__(self, other: 'timedelta') -> bool: - if type(other) is not timedelta: - return NotImplemented - return (self.days, self.seconds) > (other.days, other.seconds) - - def __ge__(self, other: 'timedelta') -> bool: - if type(other) is not timedelta: - return NotImplemented - return (self.days, self.seconds) >= (other.days, other.seconds) + return (self.days, self.seconds) != (other.days, other.seconds) class date: @@ -44,31 +30,33 @@ class date: def today(): t = localtime() return date(t.tm_year, t.tm_mon, t.tm_mday) + + def __cmp(self, other, op): + if not isinstance(other, date): + return NotImplemented + if self.year != other.year: + return op(self.year, other.year) + if self.month != other.month: + return op(self.month, other.month) + return op(self.day, other.day) def __eq__(self, other: 'date') -> bool: - if type(other) is not date: - return NotImplemented - return (self.year, self.month, self.day) == (other.year, other.month, other.day) + return self.__cmp(other, operator.eq) + + def __ne__(self, other: 'date') -> bool: + return self.__cmp(other, operator.ne) def __lt__(self, other: 'date') -> bool: - if type(other) is not date: - return NotImplemented - return (self.year, self.month, self.day) < (other.year, other.month, other.day) + return self.__cmp(other, operator.lt) def __le__(self, other: 'date') -> bool: - if type(other) is not date: - return NotImplemented - return (self.year, self.month, self.day) <= (other.year, other.month, other.day) + return self.__cmp(other, operator.le) def __gt__(self, other: 'date') -> bool: - if type(other) is not date: - return NotImplemented - return (self.year, self.month, self.day) > (other.year, other.month, other.day) + return self.__cmp(other, operator.gt) def __ge__(self, other: 'date') -> bool: - if type(other) is not date: - return NotImplemented - return (self.year, self.month, self.day) >= (other.year, other.month, other.day) + return self.__cmp(other, operator.ge) def __str__(self): return f"{self.year}-{self.month:02}-{self.day:02}" @@ -108,41 +96,37 @@ class datetime(date): def __repr__(self): return f"datetime.datetime({self.year}, {self.month}, {self.day}, {self.hour}, {self.minute}, {self.second})" + def __cmp(self, other, op): + if not isinstance(other, datetime): + return NotImplemented + if self.year != other.year: + return op(self.year, other.year) + if self.month != other.month: + return op(self.month, other.month) + if self.day != other.day: + return op(self.day, other.day) + if self.hour != other.hour: + return op(self.hour, other.hour) + if self.minute != other.minute: + return op(self.minute, other.minute) + return op(self.second, other.second) + def __eq__(self, other) -> bool: - if type(other) is not datetime: - return NotImplemented - return (self.year, self.month, self.day, self.hour, self.minute, self.second) ==\ - (other.year, other.month, other.day, - other.hour, other.minute, other.second) - + return self.__cmp(other, operator.eq) + + def __ne__(self, other) -> bool: + return self.__cmp(other, operator.ne) + def __lt__(self, other) -> bool: - if type(other) is not datetime: - return NotImplemented - return (self.year, self.month, self.day, self.hour, self.minute, self.second) <\ - (other.year, other.month, other.day, - other.hour, other.minute, other.second) - + return self.__cmp(other, operator.lt) + def __le__(self, other) -> bool: - if type(other) is not datetime: - return NotImplemented - return (self.year, self.month, self.day, self.hour, self.minute, self.second) <=\ - (other.year, other.month, other.day, - other.hour, other.minute, other.second) - + return self.__cmp(other, operator.le) + def __gt__(self, other) -> bool: - if type(other) is not datetime: - return NotImplemented - return (self.year, self.month, self.day, self.hour, self.minute, self.second) >\ - (other.year, other.month, other.day, - other.hour, other.minute, other.second) - + return self.__cmp(other, operator.gt) + def __ge__(self, other) -> bool: - if type(other) is not datetime: - return NotImplemented - return (self.year, self.month, self.day, self.hour, self.minute, self.second) >=\ - (other.year, other.month, other.day, - other.hour, other.minute, other.second) + return self.__cmp(other, operator.ge) - def timestamp(self) -> float: - raise NotImplementedError diff --git a/src/common/_generated.c b/src/common/_generated.c index aef582bc..4baa1c19 100644 --- a/src/common/_generated.c +++ b/src/common/_generated.c @@ -6,7 +6,7 @@ const char kPythonLibs_bisect[] = "\"\"\"Bisection algorithms.\"\"\"\n\ndef inso const char kPythonLibs_builtins[] = "from pkpy import next as __pkpy_next\n\ndef all(iterable):\n for i in iterable:\n if not i:\n return False\n return True\n\ndef any(iterable):\n for i in iterable:\n if i:\n return True\n return False\n\ndef enumerate(iterable, start=0):\n n = start\n for elem in iterable:\n yield n, elem\n n += 1\n\ndef sum(iterable):\n res = 0\n for i in iterable:\n res += i\n return res\n\ndef map(f, iterable):\n for i in iterable:\n yield f(i)\n\ndef filter(f, iterable):\n for i in iterable:\n if f(i):\n yield i\n\ndef zip(a, b):\n a = iter(a)\n b = iter(b)\n while True:\n ai = __pkpy_next(a)\n bi = __pkpy_next(b)\n if ai is StopIteration or bi is StopIteration:\n break\n yield ai, bi\n\ndef reversed(iterable):\n a = list(iterable)\n a.reverse()\n return a\n\ndef sorted(iterable, key=None, reverse=False):\n a = list(iterable)\n a.sort(key=key, reverse=reverse)\n return a\n\n##### str #####\ndef __format_string(self: str, *args, **kwargs) -> str:\n def tokenizeString(s: str):\n tokens = []\n L, R = 0,0\n \n mode = None\n curArg = 0\n # lookingForKword = False\n \n while(R int:\n n = 0\n for item in self:\n if item == x:\n n += 1\n return n\n \n def extend(self, iterable: Iterable[T]):\n for x in iterable:\n self.append(x)\n\n def extendleft(self, iterable: Iterable[T]):\n for x in iterable:\n self.appendleft(x)\n \n def pop(self) -> T:\n if self._head == self._tail:\n raise IndexError(\"pop from an empty deque\")\n self._tail = (self._tail - 1 + self._capacity) % self._capacity\n return self._data[self._tail]\n \n def popleft(self) -> T:\n if self._head == self._tail:\n raise IndexError(\"pop from an empty deque\")\n x = self._data[self._head]\n self._head = (self._head + 1) % self._capacity\n return x\n \n def clear(self):\n i = self._head\n while i != self._tail:\n self._data[i] = None\n i = (i + 1) % self._capacity\n self._head = 0\n self._tail = 0\n\n def rotate(self, n: int = 1):\n if len(self) == 0:\n return\n if n > 0:\n n = n % len(self)\n for _ in range(n):\n self.appendleft(self.pop())\n elif n < 0:\n n = -n % len(self)\n for _ in range(n):\n self.append(self.popleft())\n\n def __len__(self) -> int:\n return (self._tail - self._head + self._capacity) % self._capacity\n\n def __contains__(self, x: object) -> bool:\n for item in self:\n if item == x:\n return True\n return False\n \n def __iter__(self):\n i = self._head\n while i != self._tail:\n yield self._data[i]\n i = (i + 1) % self._capacity\n\n def __eq__(self, other: object) -> bool:\n if not isinstance(other, deque):\n return NotImplemented\n if len(self) != len(other):\n return False\n for x, y in zip(self, other):\n if x != y:\n return False\n return True\n \n def __ne__(self, other: object) -> bool:\n if not isinstance(other, deque):\n return NotImplemented\n return not self == other\n \n def __repr__(self) -> str:\n return f\"deque({list(self)!r})\"\n\n"; -const char kPythonLibs_datetime[] = "from time import localtime\n\nclass timedelta:\n def __init__(self, days=0, seconds=0):\n self.days = days\n self.seconds = seconds\n\n def __repr__(self):\n return f\"datetime.timedelta(days={self.days}, seconds={self.seconds})\"\n\n def __eq__(self, other: 'timedelta') -> bool:\n if type(other) is not timedelta:\n return NotImplemented\n return (self.days, self.seconds) == (other.days, other.seconds)\n\n def __lt__(self, other: 'timedelta') -> bool:\n if type(other) is not timedelta:\n return NotImplemented\n return (self.days, self.seconds) < (other.days, other.seconds)\n\n def __le__(self, other: 'timedelta') -> bool:\n if type(other) is not timedelta:\n return NotImplemented\n return (self.days, self.seconds) <= (other.days, other.seconds)\n\n def __gt__(self, other: 'timedelta') -> bool:\n if type(other) is not timedelta:\n return NotImplemented\n return (self.days, self.seconds) > (other.days, other.seconds)\n\n def __ge__(self, other: 'timedelta') -> bool:\n if type(other) is not timedelta:\n return NotImplemented\n return (self.days, self.seconds) >= (other.days, other.seconds)\n\n\nclass date:\n def __init__(self, year: int, month: int, day: int):\n self.year = year\n self.month = month\n self.day = day\n\n @staticmethod\n def today():\n t = localtime()\n return date(t.tm_year, t.tm_mon, t.tm_mday)\n\n def __eq__(self, other: 'date') -> bool:\n if type(other) is not date:\n return NotImplemented\n return (self.year, self.month, self.day) == (other.year, other.month, other.day)\n\n def __lt__(self, other: 'date') -> bool:\n if type(other) is not date:\n return NotImplemented\n return (self.year, self.month, self.day) < (other.year, other.month, other.day)\n\n def __le__(self, other: 'date') -> bool:\n if type(other) is not date:\n return NotImplemented\n return (self.year, self.month, self.day) <= (other.year, other.month, other.day)\n\n def __gt__(self, other: 'date') -> bool:\n if type(other) is not date:\n return NotImplemented\n return (self.year, self.month, self.day) > (other.year, other.month, other.day)\n\n def __ge__(self, other: 'date') -> bool:\n if type(other) is not date:\n return NotImplemented\n return (self.year, self.month, self.day) >= (other.year, other.month, other.day)\n\n def __str__(self):\n return f\"{self.year}-{self.month:02}-{self.day:02}\"\n\n def __repr__(self):\n return f\"datetime.date({self.year}, {self.month}, {self.day})\"\n\n\nclass datetime(date):\n def __init__(self, year: int, month: int, day: int, hour: int, minute: int, second: int):\n super().__init__(year, month, day)\n # Validate and set hour, minute, and second\n if not 0 <= hour <= 23:\n raise ValueError(\"Hour must be between 0 and 23\")\n self.hour = hour\n if not 0 <= minute <= 59:\n raise ValueError(\"Minute must be between 0 and 59\")\n self.minute = minute\n if not 0 <= second <= 59:\n raise ValueError(\"Second must be between 0 and 59\")\n self.second = second\n\n def date(self) -> date:\n return date(self.year, self.month, self.day)\n\n @staticmethod\n def now():\n t = localtime()\n tm_sec = t.tm_sec\n if tm_sec == 60:\n tm_sec = 59\n return datetime(t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, tm_sec)\n\n def __str__(self):\n return f\"{self.year}-{self.month:02}-{self.day:02} {self.hour:02}:{self.minute:02}:{self.second:02}\"\n\n def __repr__(self):\n return f\"datetime.datetime({self.year}, {self.month}, {self.day}, {self.hour}, {self.minute}, {self.second})\"\n\n def __eq__(self, other) -> bool:\n if type(other) is not datetime:\n return NotImplemented\n return (self.year, self.month, self.day, self.hour, self.minute, self.second) ==\x5c\n (other.year, other.month, other.day,\n other.hour, other.minute, other.second)\n\n def __lt__(self, other) -> bool:\n if type(other) is not datetime:\n return NotImplemented\n return (self.year, self.month, self.day, self.hour, self.minute, self.second) <\x5c\n (other.year, other.month, other.day,\n other.hour, other.minute, other.second)\n\n def __le__(self, other) -> bool:\n if type(other) is not datetime:\n return NotImplemented\n return (self.year, self.month, self.day, self.hour, self.minute, self.second) <=\x5c\n (other.year, other.month, other.day,\n other.hour, other.minute, other.second)\n\n def __gt__(self, other) -> bool:\n if type(other) is not datetime:\n return NotImplemented\n return (self.year, self.month, self.day, self.hour, self.minute, self.second) >\x5c\n (other.year, other.month, other.day,\n other.hour, other.minute, other.second)\n\n def __ge__(self, other) -> bool:\n if type(other) is not datetime:\n return NotImplemented\n return (self.year, self.month, self.day, self.hour, self.minute, self.second) >=\x5c\n (other.year, other.month, other.day,\n other.hour, other.minute, other.second)\n\n def timestamp(self) -> float:\n raise NotImplementedError\n\n"; +const char kPythonLibs_datetime[] = "from time import localtime\nimport operator\n\nclass timedelta:\n def __init__(self, days=0, seconds=0):\n self.days = days\n self.seconds = seconds\n\n def __repr__(self):\n return f\"datetime.timedelta(days={self.days}, seconds={self.seconds})\"\n\n def __eq__(self, other: 'timedelta') -> bool:\n if type(other) is not timedelta:\n return NotImplemented\n return (self.days, self.seconds) == (other.days, other.seconds)\n\n def __ne__(self, other: 'timedelta') -> bool:\n if type(other) is not timedelta:\n return NotImplemented\n return (self.days, self.seconds) != (other.days, other.seconds)\n\n\nclass date:\n def __init__(self, year: int, month: int, day: int):\n self.year = year\n self.month = month\n self.day = day\n\n @staticmethod\n def today():\n t = localtime()\n return date(t.tm_year, t.tm_mon, t.tm_mday)\n \n def __cmp(self, other, op):\n if not isinstance(other, date):\n return NotImplemented\n if self.year != other.year:\n return op(self.year, other.year)\n if self.month != other.month:\n return op(self.month, other.month)\n return op(self.day, other.day)\n\n def __eq__(self, other: 'date') -> bool:\n return self.__cmp(other, operator.eq)\n \n def __ne__(self, other: 'date') -> bool:\n return self.__cmp(other, operator.ne)\n\n def __lt__(self, other: 'date') -> bool:\n return self.__cmp(other, operator.lt)\n\n def __le__(self, other: 'date') -> bool:\n return self.__cmp(other, operator.le)\n\n def __gt__(self, other: 'date') -> bool:\n return self.__cmp(other, operator.gt)\n\n def __ge__(self, other: 'date') -> bool:\n return self.__cmp(other, operator.ge)\n\n def __str__(self):\n return f\"{self.year}-{self.month:02}-{self.day:02}\"\n\n def __repr__(self):\n return f\"datetime.date({self.year}, {self.month}, {self.day})\"\n\n\nclass datetime(date):\n def __init__(self, year: int, month: int, day: int, hour: int, minute: int, second: int):\n super().__init__(year, month, day)\n # Validate and set hour, minute, and second\n if not 0 <= hour <= 23:\n raise ValueError(\"Hour must be between 0 and 23\")\n self.hour = hour\n if not 0 <= minute <= 59:\n raise ValueError(\"Minute must be between 0 and 59\")\n self.minute = minute\n if not 0 <= second <= 59:\n raise ValueError(\"Second must be between 0 and 59\")\n self.second = second\n\n def date(self) -> date:\n return date(self.year, self.month, self.day)\n\n @staticmethod\n def now():\n t = localtime()\n tm_sec = t.tm_sec\n if tm_sec == 60:\n tm_sec = 59\n return datetime(t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, tm_sec)\n\n def __str__(self):\n return f\"{self.year}-{self.month:02}-{self.day:02} {self.hour:02}:{self.minute:02}:{self.second:02}\"\n\n def __repr__(self):\n return f\"datetime.datetime({self.year}, {self.month}, {self.day}, {self.hour}, {self.minute}, {self.second})\"\n\n def __cmp(self, other, op):\n if not isinstance(other, datetime):\n return NotImplemented\n if self.year != other.year:\n return op(self.year, other.year)\n if self.month != other.month:\n return op(self.month, other.month)\n if self.day != other.day:\n return op(self.day, other.day)\n if self.hour != other.hour:\n return op(self.hour, other.hour)\n if self.minute != other.minute:\n return op(self.minute, other.minute)\n return op(self.second, other.second)\n\n def __eq__(self, other) -> bool:\n return self.__cmp(other, operator.eq)\n \n def __ne__(self, other) -> bool:\n return self.__cmp(other, operator.ne)\n \n def __lt__(self, other) -> bool:\n return self.__cmp(other, operator.lt)\n \n def __le__(self, other) -> bool:\n return self.__cmp(other, operator.le)\n \n def __gt__(self, other) -> bool:\n return self.__cmp(other, operator.gt)\n \n def __ge__(self, other) -> bool:\n return self.__cmp(other, operator.ge)\n\n\n"; const char kPythonLibs_functools[] = "class cache:\n def __init__(self, f):\n self.f = f\n self.cache = {}\n\n def __call__(self, *args):\n if args not in self.cache:\n self.cache[args] = self.f(*args)\n return self.cache[args]\n \ndef reduce(function, sequence, initial=...):\n it = iter(sequence)\n if initial is ...:\n try:\n value = next(it)\n except StopIteration:\n raise TypeError(\"reduce() of empty sequence with no initial value\")\n else:\n value = initial\n for element in it:\n value = function(value, element)\n return value\n\nclass partial:\n def __init__(self, f, *args, **kwargs):\n self.f = f\n if not callable(f):\n raise TypeError(\"the first argument must be callable\")\n self.args = args\n self.kwargs = kwargs\n\n def __call__(self, *args, **kwargs):\n kwargs.update(self.kwargs)\n return self.f(*self.args, *args, **kwargs)\n\n"; const char kPythonLibs_heapq[] = "# Heap queue algorithm (a.k.a. priority queue)\ndef heappush(heap, item):\n \"\"\"Push item onto heap, maintaining the heap invariant.\"\"\"\n heap.append(item)\n _siftdown(heap, 0, len(heap)-1)\n\ndef heappop(heap):\n \"\"\"Pop the smallest item off the heap, maintaining the heap invariant.\"\"\"\n lastelt = heap.pop() # raises appropriate IndexError if heap is empty\n if heap:\n returnitem = heap[0]\n heap[0] = lastelt\n _siftup(heap, 0)\n return returnitem\n return lastelt\n\ndef heapreplace(heap, item):\n \"\"\"Pop and return the current smallest value, and add the new item.\n\n This is more efficient than heappop() followed by heappush(), and can be\n more appropriate when using a fixed-size heap. Note that the value\n returned may be larger than item! That constrains reasonable uses of\n this routine unless written as part of a conditional replacement:\n\n if item > heap[0]:\n item = heapreplace(heap, item)\n \"\"\"\n returnitem = heap[0] # raises appropriate IndexError if heap is empty\n heap[0] = item\n _siftup(heap, 0)\n return returnitem\n\ndef heappushpop(heap, item):\n \"\"\"Fast version of a heappush followed by a heappop.\"\"\"\n if heap and heap[0] < item:\n item, heap[0] = heap[0], item\n _siftup(heap, 0)\n return item\n\ndef heapify(x):\n \"\"\"Transform list into a heap, in-place, in O(len(x)) time.\"\"\"\n n = len(x)\n # Transform bottom-up. The largest index there's any point to looking at\n # is the largest with a child index in-range, so must have 2*i + 1 < n,\n # or i < (n-1)/2. If n is even = 2*j, this is (2*j-1)/2 = j-1/2 so\n # j-1 is the largest, which is n//2 - 1. If n is odd = 2*j+1, this is\n # (2*j+1-1)/2 = j so j-1 is the largest, and that's again n//2-1.\n for i in reversed(range(n//2)):\n _siftup(x, i)\n\n# 'heap' is a heap at all indices >= startpos, except possibly for pos. pos\n# is the index of a leaf with a possibly out-of-order value. Restore the\n# heap invariant.\ndef _siftdown(heap, startpos, pos):\n newitem = heap[pos]\n # Follow the path to the root, moving parents down until finding a place\n # newitem fits.\n while pos > startpos:\n parentpos = (pos - 1) >> 1\n parent = heap[parentpos]\n if newitem < parent:\n heap[pos] = parent\n pos = parentpos\n continue\n break\n heap[pos] = newitem\n\ndef _siftup(heap, pos):\n endpos = len(heap)\n startpos = pos\n newitem = heap[pos]\n # Bubble up the smaller child until hitting a leaf.\n childpos = 2*pos + 1 # leftmost child position\n while childpos < endpos:\n # Set childpos to index of smaller child.\n rightpos = childpos + 1\n if rightpos < endpos and not heap[childpos] < heap[rightpos]:\n childpos = rightpos\n # Move the smaller child up.\n heap[pos] = heap[childpos]\n pos = childpos\n childpos = 2*pos + 1\n # The leaf at pos is empty now. Put newitem there, and bubble it up\n # to its final resting place (by sifting its parents down).\n heap[pos] = newitem\n _siftdown(heap, startpos, pos)"; const char kPythonLibs_itertools[] = "from pkpy import next\n\ndef zip_longest(a, b):\n a = iter(a)\n b = iter(b)\n while True:\n ai = next(a)\n bi = next(b)\n if ai is StopIteration and bi is StopIteration:\n break\n if ai is StopIteration:\n ai = None\n if bi is StopIteration:\n bi = None\n yield ai, bi\n"; diff --git a/src/interpreter/vm.c b/src/interpreter/vm.c index 08691348..11359f0c 100644 --- a/src/interpreter/vm.c +++ b/src/interpreter/vm.c @@ -330,7 +330,9 @@ py_Type pk_newtype(const char* name, } py_Type py_newtype(const char* name, py_Type base, const py_GlobalRef module, void (*dtor)(void*)) { - return pk_newtype(name, base, module, dtor, false, false); + py_Type type = pk_newtype(name, base, module, dtor, false, false); + if(module) py_setdict(module, py_name(name), py_tpobject(type)); + return type; } static bool diff --git a/src/modules/time.c b/src/modules/time.c index f03d5e2b..506d3e3b 100644 --- a/src/modules/time.c +++ b/src/modules/time.c @@ -1,6 +1,6 @@ #include "pocketpy/pocketpy.h" +#include "pocketpy/interpreter/vm.h" #include "time.h" -#include #define NANOS_PER_SEC 1000000000 @@ -51,10 +51,53 @@ static bool time_sleep(int argc, py_Ref argv) { return true; } +static bool time_localtime(int argc, py_Ref argv) { + PY_CHECK_ARGC(0); + py_Type tp_struct_time = py_gettype("time", py_name("struct_time")); + assert(tp_struct_time); + struct tm* ud = py_newobject(py_retval(), tp_struct_time, 0, sizeof(struct tm)); + time_t t = time(NULL); + *ud = *localtime(&t); + return true; +} + +#define DEF_STRUCT_TIME__PROPERTY(name, expr) \ + static bool struct_time__##name(int argc, py_Ref argv) { \ + PY_CHECK_ARGC(1); \ + struct tm* tm = py_touserdata(argv); \ + py_newint(py_retval(), expr); \ + return true; \ + } + +DEF_STRUCT_TIME__PROPERTY(tm_year, tm->tm_year + 1900) +DEF_STRUCT_TIME__PROPERTY(tm_mon, tm->tm_mon + 1) +DEF_STRUCT_TIME__PROPERTY(tm_mday, tm->tm_mday) +DEF_STRUCT_TIME__PROPERTY(tm_hour, tm->tm_hour) +DEF_STRUCT_TIME__PROPERTY(tm_min, tm->tm_min) +DEF_STRUCT_TIME__PROPERTY(tm_sec, tm->tm_sec) +DEF_STRUCT_TIME__PROPERTY(tm_wday, (tm->tm_wday + 6) % 7) +DEF_STRUCT_TIME__PROPERTY(tm_yday, tm->tm_yday + 1) +DEF_STRUCT_TIME__PROPERTY(tm_isdst, tm->tm_isdst) + +#undef DEF_STRUCT_TIME__PROPERTY + void pk__add_module_time() { py_Ref mod = py_newmodule("time"); + py_Type tp_struct_time = py_newtype("struct_time", tp_object, mod, NULL); + + py_bindproperty(tp_struct_time, "tm_year", struct_time__tm_year, NULL); + py_bindproperty(tp_struct_time, "tm_mon", struct_time__tm_mon, NULL); + py_bindproperty(tp_struct_time, "tm_mday", struct_time__tm_mday, NULL); + py_bindproperty(tp_struct_time, "tm_hour", struct_time__tm_hour, NULL); + py_bindproperty(tp_struct_time, "tm_min", struct_time__tm_min, NULL); + py_bindproperty(tp_struct_time, "tm_sec", struct_time__tm_sec, NULL); + py_bindproperty(tp_struct_time, "tm_wday", struct_time__tm_wday, NULL); + py_bindproperty(tp_struct_time, "tm_yday", struct_time__tm_yday, NULL); + py_bindproperty(tp_struct_time, "tm_isdst", struct_time__tm_isdst, NULL); + py_bindfunc(mod, "time", time_time); py_bindfunc(mod, "time_ns", time_time_ns); py_bindfunc(mod, "sleep", time_sleep); + py_bindfunc(mod, "localtime", time_localtime); } \ No newline at end of file diff --git a/src/public/cast.c b/src/public/cast.c index 3f8d7806..5369663b 100644 --- a/src/public/cast.c +++ b/src/public/cast.c @@ -57,4 +57,12 @@ bool py_issubclass(py_Type derived, py_Type base) { return false; } -py_Type py_typeof(py_Ref self) { return self->type; } \ No newline at end of file +py_Type py_typeof(py_Ref self) { return self->type; } + +py_Type py_gettype(const char* module, py_Name name) { + py_Ref mod = py_getmodule(module); + if(!mod) return 0; + py_Ref object = py_getdict(mod, name); + if(object && py_istype(object, tp_type)) return py_totype(object); + return 0; +} \ No newline at end of file diff --git a/tests/79_datetime.py b/tests/79_datetime.py index d5c3e3f7..2114cc98 100644 --- a/tests/79_datetime.py +++ b/tests/79_datetime.py @@ -4,11 +4,6 @@ import datetime def test_timedelta(): assert datetime.timedelta(days=1) == datetime.timedelta(days=1) assert datetime.timedelta(days=1) != datetime.timedelta(days=2) - assert datetime.timedelta(days=1, seconds=1) >= datetime.timedelta(days=1) - assert datetime.timedelta(days=0, seconds=1) <= datetime.timedelta(days=1) - assert datetime.timedelta(days=1, seconds=1) < datetime.timedelta(days=2) - assert datetime.timedelta(days=1, seconds=1) > datetime.timedelta(days=0) - def test_date(): assert datetime.date(2023, 8, 5) == datetime.date(2023, 8, 5) @@ -18,7 +13,6 @@ def test_date(): assert datetime.date(2024, 8, 5) > datetime.date(2023, 8, 6) assert datetime.date(2023, 8, 5) < datetime.date(2024, 8, 6) - def test_datetime(): assert datetime.datetime( 2023, 8, 5, 12, 0, 0) == datetime.datetime(2023, 8, 5, 12, 0, 0) @@ -33,7 +27,6 @@ def test_datetime(): assert datetime.datetime( 2023, 8, 5, 12, 0, 0) <= datetime.datetime(2023, 8, 5, 12, 1, 0) - test_timedelta() test_date() test_datetime()