copyable 0.0.0.dev0__tar.gz → 0.0.0.dev2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: copyable
3
- Version: 0.0.0.dev0
4
- Summary: copyable
3
+ Version: 0.0.0.dev2
4
+ Summary: This project provides a copyable ABC.
5
5
  Author-email: Johannes <johannes.programming@gmail.com>
6
6
  License: The MIT License (MIT)
7
7
 
@@ -27,6 +27,7 @@ License: The MIT License (MIT)
27
27
  Project-URL: Download, https://pypi.org/project/copyable/#files
28
28
  Project-URL: Index, https://pypi.org/project/copyable/
29
29
  Project-URL: Source, https://github.com/johannes-programming/copyable/
30
+ Project-URL: Website, https://copyable.johannes-programming.online/
30
31
  Classifier: Development Status :: 2 - Pre-Alpha
31
32
  Classifier: License :: OSI Approved :: MIT License
32
33
  Classifier: Natural Language :: English
@@ -38,6 +39,7 @@ Classifier: Typing :: Typed
38
39
  Requires-Python: >=3.11
39
40
  Description-Content-Type: text/x-rst
40
41
  License-File: LICENSE.txt
42
+ Requires-Dist: setdoc<2,>=1.2.7
41
43
  Dynamic: license-file
42
44
 
43
45
  ========
@@ -18,13 +18,15 @@ classifiers = [
18
18
  "Programming Language :: Python :: 3 :: Only",
19
19
  "Typing :: Typed",
20
20
  ]
21
- dependencies = []
22
- description = "copyable"
21
+ dependencies = [
22
+ "setdoc>=1.2.7,<2",
23
+ ]
24
+ description = "This project provides a copyable ABC."
23
25
  keywords = []
24
26
  name = "copyable"
25
27
  readme = "README.rst"
26
28
  requires-python = ">=3.11"
27
- version = "0.0.0.dev0"
29
+ version = "0.0.0.dev2"
28
30
 
29
31
  [project.license]
30
32
  file = "LICENSE.txt"
@@ -33,3 +35,4 @@ file = "LICENSE.txt"
33
35
  Download = "https://pypi.org/project/copyable/#files"
34
36
  Index = "https://pypi.org/project/copyable/"
35
37
  Source = "https://github.com/johannes-programming/copyable/"
38
+ Website = "https://copyable.johannes-programming.online/"
@@ -1,5 +1,2 @@
1
1
  from copyable.core import *
2
2
  from copyable.tests import *
3
-
4
- if __name__ == "__main__":
5
- main()
@@ -0,0 +1,16 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import *
3
+
4
+ import setdoc
5
+
6
+ __all__ = ["Copyable"]
7
+
8
+
9
+ class Copyable(ABC):
10
+ __slots__ = ()
11
+
12
+ __hash__ = None
13
+
14
+ @abstractmethod
15
+ @setdoc.basic
16
+ def copy(self: Self) -> Self: ...
@@ -0,0 +1,60 @@
1
+ import inspect
2
+ import unittest
3
+ from abc import ABCMeta
4
+ from typing import *
5
+
6
+ from copyable.core import Copyable
7
+
8
+
9
+ class TestCopyable(unittest.TestCase):
10
+ def test_is_abstract(self: Self) -> None:
11
+ # Copyable must be an abstract base class and not directly instantiable.
12
+ self.assertIsInstance(Copyable, ABCMeta)
13
+ with self.assertRaises(TypeError):
14
+ Copyable() # type: ignore[abstract]
15
+
16
+ def test_slots_hash_and_abstractmethod(self: Self) -> None:
17
+ copy_attr: Any
18
+ # __slots__ is explicitly empty and __hash__ disabled.
19
+ self.assertTrue(hasattr(Copyable, "__slots__"))
20
+ self.assertEqual(getattr(Copyable, "__slots__"), ())
21
+ self.assertIsNone(getattr(Copyable, "__hash__"))
22
+
23
+ # "copy" exists and is marked abstract.
24
+ self.assertTrue(hasattr(Copyable, "copy"))
25
+ copy_attr = getattr(Copyable, "copy")
26
+ self.assertTrue(getattr(copy_attr, "__isabstractmethod__", False))
27
+
28
+ def test_copy_signature_and_annotations(self: Self) -> None:
29
+ # Ensure there's a "copy" method and it has type hints present.
30
+ # Note: runtime "Self" may or may not resolve depending on Python version;
31
+ # we just verify annotations are present and consistent.
32
+ hints: dict[str, Any]
33
+ sig: inspect.Signature
34
+ params: list[inspect.Parameter]
35
+ self.assertTrue(callable(getattr(Copyable, "copy")))
36
+ hints = get_type_hints(Copyable.copy, include_extras=True)
37
+ self.assertIn("return", hints)
38
+
39
+ sig = inspect.signature(Copyable.copy)
40
+ params = list(sig.parameters.values())
41
+ self.assertEqual(len(params), 1)
42
+ self.assertEqual(params[0].name, "self")
43
+
44
+ def test_subclass_must_implement_copy(self: Self) -> None:
45
+ class Bad(Copyable):
46
+ pass
47
+
48
+ class Good(Copyable):
49
+ def copy(self: Self) -> Self:
50
+ return self
51
+
52
+ g: Good
53
+ with self.assertRaises(TypeError):
54
+ Bad() # still abstract
55
+ g = Good()
56
+ self.assertIs(g.copy(), g)
57
+
58
+
59
+ if __name__ == "__main__":
60
+ unittest.main()
@@ -0,0 +1,43 @@
1
+ from __future__ import annotations
2
+
3
+ import unittest
4
+ from typing import *
5
+
6
+ from copyable.core import Copyable
7
+
8
+
9
+ class TestCopyable(unittest.TestCase):
10
+ def test_copyable_cannot_be_instantiated(self: Self) -> None:
11
+ with self.assertRaises(TypeError):
12
+ Copyable() # abstract
13
+
14
+ def test_subclass_without_copy_is_abstract(self: Self) -> None:
15
+ class Bad(Copyable):
16
+ pass
17
+
18
+ with self.assertRaises(TypeError):
19
+ Bad()
20
+
21
+ def test_copy_returns_same_type_and_new_instance(self: Self) -> None:
22
+ class Point(Copyable):
23
+ __slots__ = ("x", "y")
24
+
25
+ def __init__(self: Self, x: int, y: int) -> None:
26
+ self.x = x
27
+ self.y = y
28
+
29
+ def copy(self: Self) -> Self:
30
+ return type(self)(self.x, self.y)
31
+
32
+ p: Point
33
+ c: Point
34
+ p = Point(1, 2)
35
+ c = p.copy()
36
+
37
+ self.assertIsInstance(c, Point)
38
+ self.assertIsNot(c, p)
39
+ self.assertEqual((c.x, c.y), (p.x, p.y))
40
+
41
+
42
+ if __name__ == "__main__":
43
+ unittest.main()
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: copyable
3
- Version: 0.0.0.dev0
4
- Summary: copyable
3
+ Version: 0.0.0.dev2
4
+ Summary: This project provides a copyable ABC.
5
5
  Author-email: Johannes <johannes.programming@gmail.com>
6
6
  License: The MIT License (MIT)
7
7
 
@@ -27,6 +27,7 @@ License: The MIT License (MIT)
27
27
  Project-URL: Download, https://pypi.org/project/copyable/#files
28
28
  Project-URL: Index, https://pypi.org/project/copyable/
29
29
  Project-URL: Source, https://github.com/johannes-programming/copyable/
30
+ Project-URL: Website, https://copyable.johannes-programming.online/
30
31
  Classifier: Development Status :: 2 - Pre-Alpha
31
32
  Classifier: License :: OSI Approved :: MIT License
32
33
  Classifier: Natural Language :: English
@@ -38,6 +39,7 @@ Classifier: Typing :: Typed
38
39
  Requires-Python: >=3.11
39
40
  Description-Content-Type: text/x-rst
40
41
  License-File: LICENSE.txt
42
+ Requires-Dist: setdoc<2,>=1.2.7
41
43
  Dynamic: license-file
42
44
 
43
45
  ========
@@ -4,11 +4,12 @@ README.rst
4
4
  pyproject.toml
5
5
  setup.cfg
6
6
  src/copyable/__init__.py
7
- src/copyable/__main__.py
8
7
  src/copyable.egg-info/PKG-INFO
9
8
  src/copyable.egg-info/SOURCES.txt
10
9
  src/copyable.egg-info/dependency_links.txt
10
+ src/copyable.egg-info/requires.txt
11
11
  src/copyable.egg-info/top_level.txt
12
12
  src/copyable/core/__init__.py
13
13
  src/copyable/tests/__init__.py
14
- src/copyable/tests/test_1984.py
14
+ src/copyable/tests/test_0.py
15
+ src/copyable/tests/test_1.py
@@ -0,0 +1 @@
1
+ setdoc<2,>=1.2.7
@@ -1,4 +0,0 @@
1
- from copyable import main
2
-
3
- if __name__ == "__main__":
4
- main()
@@ -1,8 +0,0 @@
1
- from typing import *
2
-
3
- __all__ = ["main"]
4
-
5
-
6
- def main(args: Optional[Iterable] = None) -> None:
7
- "This function prints 'Hello World!'."
8
- print("Hello World!")
@@ -1,11 +0,0 @@
1
- import unittest
2
- from typing import *
3
-
4
-
5
- class Test1984(unittest.TestCase):
6
- def test_1984(self: Self) -> None:
7
- self.assertEqual(2 + 2, 4, "Ignorance is Strength")
8
-
9
-
10
- if __name__ == "__main__":
11
- unittest.main()
File without changes
File without changes
File without changes
File without changes