Skip to content

Commit

Permalink
Restructure project directory layout
Browse files Browse the repository at this point in the history
This commit brings the directory layout in line with current
recommendations by the Python Packaging Authority and others.

    Before                        After

    |-- setup.py                  |-- setup.py
    |                             |-- src/
    |                             |   `-- pydot/
    |                             |       |-- __init__.py
    |-- pydot.py                  |       |-- core.py
    |-- dot_parser.py             |       `-- dot_parser.py
    `-- test/                     `-- test/
        `-- pydot_unittest.py         `-- pydot_unittest.py

There are many opinions on what would be the best directory layout for
a Python project, particularly on whether or not to use an additional
`src/` layer. For example:

- https://blog.ionelmc.ro/2014/05/25/python-packaging/#the-structure
- pypa/packaging.python.org#320
- https://github.com/pypa/packaging.python.org/blob/7866cb69f1aa290a13c94da77cfb46a079cfcfa2/source/tutorials/packaging-projects.rst#a-simple-project
- https://stackoverflow.com/questions/193161/what-is-the-best-project-structure-for-a-python-application

Suffice to say, I can basically understand the arguments in favor of a
`src/` layout and do not find the arguments against it strong enough
not to use it.

Moved the dunder global variables (`__version__` etc.) to `__init__.py`
to ensure they remain available to the user doing `import pydot`. (They
would not be included in `from pydot.core import *` because their names
start with an underscore and I did not want to start keeping `__all__`
just for this.) A test for `pydot.__version__` is added to the
testsuite as well.

.... TODO: Something about separating parsing from core or not? ...

Discussed in pydot#171, pydot#230 and pydot#271.

Special thanks to Kostis Anagnostopoulos (@ankostis) for his advice.
  • Loading branch information
peternowee committed Jul 12, 2021
1 parent 4d45fff commit ed751c9
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 9 deletions.
37 changes: 37 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,43 @@ Pydot versions since 1.4.2 adhere to [PEP 440-style semantic versioning]
------------------

Changed:
- Reorganized package/module structure. (#230)
The `pydot` package is installed as a directory now instead of as
two modules:

Before (pydot 0.x, 1.x) After (pydot 2.x)

site-packages/ site-packages/
|-- pydot.py `-- pydot/
`-- dot_parser.py |-- __init__.py
|-- core.py
|-- dot_parser.py
`-- ...

This is mostly an internal change that should go unnoticed by most
users, especially those upgrading through `pip` or a software
distribution. `import pydot` should work as it did before.
Special cases:
- `import dot_parser` no longer works. Change it to
`from pydot import dot_parser` or see if you can use the wrappers
`pydot.graph_from_dot_data()` or `pydot.graph_from_dot_file()`.

**USER FEEDBACK REQUESTED**
We assume pydot users do not often directly `import dot_parser`.
If you do, please report your reasons, so that we can consider
making it available again before the final release of pydot 2.0:
https://github.com/pydot/pydot/issues/230

- If you use pydot from a (cloned) pydot source tree:
- The pydot source modules moved from the top directory to
subdirectory `src/pydot/`.
- When using a `PYTHONPATH` environment variable: Append `/src`,
e.g. `PYTHONPATH=~/Development/pydot/src`. If you need to switch
between pydot 1.x and pydot 2.x, add both, e.g.
`PYTHONPATH=~/Development/pydot/src:~/Development/pydot`
- When using an editable install (development mode): Re-run
`pip install -e .` from the top directory of the source tree to
update the links.
- API (minor): Renamed the first parameter of the parser functions
listed below from `str` to `s`. These functions primarily exist for
internal use and would normally be called using positional arguments,
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[zest.releaser]
python-file-with-version = pydot.py
python-file-with-version = src/pydot/__init__.py
release=no
push-changes=no
create-wheel=yes
Expand Down
5 changes: 3 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def get_long_description():


def get_version():
pydot_py = os.path.join(CURRENT_DIR, "pydot.py")
pydot_py = os.path.join(CURRENT_DIR, "src", "pydot", "__init__.py")
_version_re = re.compile(r"__version__\s+=\s+(?P<version>.*)")
with codecs.open(pydot_py, "r", encoding="utf8") as f:
match = _version_re.search(f.read())
Expand All @@ -32,6 +32,8 @@ def get_version():
setup(
name="pydot",
version=get_version(),
package_dir={"": "src"},
packages=["pydot"],
description="Python interface to Graphviz's Dot",
author="Ero Carrera",
author_email="ero.carrera@gmail.com",
Expand Down Expand Up @@ -64,7 +66,6 @@ def get_version():
],
long_description=get_long_description(),
long_description_content_type="text/markdown",
py_modules=["pydot", "dot_parser"],
install_requires=["pyparsing>=2.1.4"],
extras_require={
"dev": [
Expand Down
7 changes: 7 additions & 0 deletions src/pydot/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"""An interface to GraphViz."""

__author__ = "Ero Carrera"
__version__ = "2.0.0.dev0"
__license__ = "MIT"

from pydot.core import *
7 changes: 1 addition & 6 deletions pydot.py → src/pydot/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import warnings

try:
import dot_parser
from pydot import dot_parser
except Exception as e:
warnings.warn(
"`pydot` could not import `dot_parser`, "
Expand All @@ -19,11 +19,6 @@
)


__author__ = "Ero Carrera"
__version__ = "2.0.0.dev0"
__license__ = "MIT"


# fmt: off
GRAPH_ATTRIBUTES = {
"Damping", "K", "URL", "aspect", "bb", "bgcolor",
Expand Down
File renamed without changes.
3 changes: 3 additions & 0 deletions test/pydot_unittest.py
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,9 @@ def test_graph_from_incidence_matrix(self):
s = " ".join(g.to_string().split())
self.assertEqual(s, "graph G { 1 -- 2; 2 -- 3; }")

def test_version(self):
self.assertIsInstance(pydot.__version__, str)


def check_path():
not_check = parse_args()
Expand Down

0 comments on commit ed751c9

Please sign in to comment.